mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2026-05-19 09:51:39 +00:00
Add chapter title scraping and improve error logging
This commit is contained in:
parent
e8d65ceb88
commit
b4b126e39f
2 changed files with 61 additions and 45 deletions
|
|
@ -1,40 +1,32 @@
|
||||||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
||||||
// README at: https://github.com/devcontainers/templates/tree/main/src/javascript-node
|
// README at: https://github.com/devcontainers/templates/tree/main/src/javascript-node
|
||||||
{
|
{
|
||||||
"name": "Audiobookshelf",
|
"name": "Audiobookshelf",
|
||||||
"build": {
|
"build": {
|
||||||
"dockerfile": "Dockerfile",
|
"dockerfile": "Dockerfile",
|
||||||
// Update 'VARIANT' to pick a Node version: 18, 16, 14.
|
// Update 'VARIANT' to pick a Node version: 18, 16, 14.
|
||||||
// Append -bullseye or -buster to pin to an OS version.
|
// Append -bullseye or -buster to pin to an OS version.
|
||||||
// Use -bullseye variants on local arm64/Apple Silicon.
|
// Use -bullseye variants on local arm64/Apple Silicon.
|
||||||
"args": {
|
"args": {
|
||||||
"VARIANT": "20"
|
"VARIANT": "20"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mounts": [
|
"mounts": ["source=abs-server-node_modules,target=${containerWorkspaceFolder}/node_modules,type=volume", "source=abs-client-node_modules,target=${containerWorkspaceFolder}/client/node_modules,type=volume", "source=/home/harry/Music/ABS-Dev,target=/podcasts,type=bind,consistency=cached"],
|
||||||
"source=abs-server-node_modules,target=${containerWorkspaceFolder}/node_modules,type=volume",
|
// Features to add to the dev container. More info: https://containers.dev/features.
|
||||||
"source=abs-client-node_modules,target=${containerWorkspaceFolder}/client/node_modules,type=volume"
|
// "features": {},
|
||||||
],
|
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||||
// Features to add to the dev container. More info: https://containers.dev/features.
|
"forwardPorts": [3000, 3333],
|
||||||
// "features": {},
|
// Use 'postCreateCommand' to run commands after the container is created.
|
||||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
"postCreateCommand": "sh .devcontainer/post-create.sh",
|
||||||
"forwardPorts": [
|
// Configure tool-specific properties.
|
||||||
3000,
|
"customizations": {
|
||||||
3333
|
// Configure properties specific to VS Code.
|
||||||
],
|
"vscode": {
|
||||||
// Use 'postCreateCommand' to run commands after the container is created.
|
// Add the IDs of extensions you want installed when the container is created.
|
||||||
"postCreateCommand": "sh .devcontainer/post-create.sh",
|
"extensions": ["dbaeumer.vscode-eslint", "octref.vetur"]
|
||||||
// Configure tool-specific properties.
|
}
|
||||||
"customizations": {
|
},
|
||||||
// Configure properties specific to VS Code.
|
"runArgs": ["-p=3333:3333"]
|
||||||
"vscode": {
|
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
||||||
// Add the IDs of extensions you want installed when the container is created.
|
// "remoteUser": "root"
|
||||||
"extensions": [
|
}
|
||||||
"dbaeumer.vscode-eslint",
|
|
||||||
"octref.vetur"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
|
||||||
// "remoteUser": "root"
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
const { DataTypes, Model } = require('sequelize')
|
const { DataTypes, Model } = require('sequelize')
|
||||||
const libraryItemsPodcastFilters = require('../utils/queries/libraryItemsPodcastFilters')
|
const libraryItemsPodcastFilters = require('../utils/queries/libraryItemsPodcastFilters')
|
||||||
const Logger = require('../Logger')
|
const Logger = require('../Logger')
|
||||||
|
const { logger } = require('sequelize/lib/utils/logger')
|
||||||
/**
|
/**
|
||||||
* @typedef ChapterObject
|
* @typedef ChapterObject
|
||||||
* @property {number} id
|
* @property {number} id
|
||||||
|
|
@ -87,11 +88,15 @@ class PodcastEpisode extends Model {
|
||||||
} else if (rssPodcastEpisode.chapters?.length) {
|
} else if (rssPodcastEpisode.chapters?.length) {
|
||||||
podcastEpisode.chapters = rssPodcastEpisode.chapters.map((ch) => ({ ...ch }))
|
podcastEpisode.chapters = rssPodcastEpisode.chapters.map((ch) => ({ ...ch }))
|
||||||
} else {
|
} else {
|
||||||
const timeMarkerRegex = /\b(\d{1,2}):(\d{1,2})(?::(\d{1,2}))?\b/m
|
const timeMarkerRegex = /\b(\d{1,2}):(\d{1,2})(?::(\d{1,2}))?\b/
|
||||||
|
const chapterTitleRegex = /\b\d{1,2}:\d{1,2}(?::\d{1,2})?\b(.+)$/
|
||||||
|
|
||||||
Logger.debug("Podcast didn't have chapters", rssPodcastEpisode.title)
|
Logger.debug("Podcast episode doesn't have chapters, attempting to generate them from timestamps", rssPodcastEpisode.title)
|
||||||
|
|
||||||
|
var errorMessage = null
|
||||||
var descriptionLines = podcastEpisode.description.split('</p>')
|
var descriptionLines = podcastEpisode.description.split('</p>')
|
||||||
|
var chaptersToPush = []
|
||||||
|
|
||||||
for (let i = 0; i < descriptionLines.length; i++) {
|
for (let i = 0; i < descriptionLines.length; i++) {
|
||||||
let line = descriptionLines[i]
|
let line = descriptionLines[i]
|
||||||
Logger.debug('Description Line:', line)
|
Logger.debug('Description Line:', line)
|
||||||
|
|
@ -99,7 +104,7 @@ class PodcastEpisode extends Model {
|
||||||
let match = timeMarkerRegex.exec(line)
|
let match = timeMarkerRegex.exec(line)
|
||||||
if (match == null) continue
|
if (match == null) continue
|
||||||
|
|
||||||
Logger.debug('matches:', match)
|
Logger.debug('Matches:', match)
|
||||||
|
|
||||||
let first = match[1]
|
let first = match[1]
|
||||||
let second = match[2]
|
let second = match[2]
|
||||||
|
|
@ -118,23 +123,42 @@ class PodcastEpisode extends Model {
|
||||||
{
|
{
|
||||||
minutes = Number(first)
|
minutes = Number(first)
|
||||||
seconds = Number(second)
|
seconds = Number(second)
|
||||||
|
} else {
|
||||||
|
// Unknown timestamp state
|
||||||
|
errorMessage = `Unknown timestamp format in description, line ${line}`
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
let startTime = seconds + minutes * 60 + hours * 60 * 60
|
let startTime = seconds + minutes * 60 + hours * 60 * 60
|
||||||
let chapter = { title: `Chapter ${i}`, id: i, start: startTime }
|
let chapterTitleMatch = chapterTitleRegex.exec(line)
|
||||||
|
Logger.debug('Chapter Title Matches:', chapterTitleMatch)
|
||||||
|
|
||||||
|
if (chapterTitleMatch == null && chapterTitleMatch.length >= 2) {
|
||||||
|
// Unknown chapter state
|
||||||
|
errorMessage = `Unable to get chapter title from description, line ${line}`
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
let chapter = { title: chapterTitleMatch[1].trim(), id: i, start: startTime }
|
||||||
|
|
||||||
if (podcastEpisode.chapters.length > 0) {
|
if (podcastEpisode.chapters.length > 0) {
|
||||||
podcastEpisode.chapters[podcastEpisode.chapters.length - 1].end = startTime
|
podcastEpisode.chapters[podcastEpisode.chapters.length - 1].end = startTime
|
||||||
}
|
}
|
||||||
|
|
||||||
podcastEpisode.chapters.push(chapter)
|
chaptersToPush.push(chapter)
|
||||||
|
|
||||||
Logger.debug('Added chapter', chapter)
|
Logger.debug('Added chapter', chapter)
|
||||||
}
|
}
|
||||||
if (podcastEpisode.chapters.length > 0) {
|
if (errorMessage == null) {
|
||||||
podcastEpisode.chapters[podcastEpisode.chapters.length - 1].end = podcastEpisode.audioFile.duration
|
if (podcastEpisode.chapters.length > 0) {
|
||||||
|
podcastEpisode.chapters[podcastEpisode.chapters.length - 1].end = podcastEpisode.audioFile.duration
|
||||||
|
}
|
||||||
|
|
||||||
|
podcastEpisode.chapters.push(...chaptersToPush)
|
||||||
|
Logger.debug(`Successfully gnerated ${podcastEpisode.chapters.length} chapters`)
|
||||||
|
} else {
|
||||||
|
logger.error(`Unable generate chapters from podcast description, error '${errorMessage}`)
|
||||||
}
|
}
|
||||||
Logger.debug('Chapters', podcastEpisode.chapters)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.create(podcastEpisode)
|
return this.create(podcastEpisode)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue