mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-02-10 00:18:06 +01:00
Fix:Embedded chapters sort order #3007
This commit is contained in:
parent
ff169f3fd0
commit
5bbcb9cac3
@ -8,11 +8,11 @@ const LibraryItem = require('../models/LibraryItem')
|
|||||||
const AudioFile = require('../objects/files/AudioFile')
|
const AudioFile = require('../objects/files/AudioFile')
|
||||||
|
|
||||||
class AudioFileScanner {
|
class AudioFileScanner {
|
||||||
constructor() { }
|
constructor() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is array of numbers sequential, i.e. 1, 2, 3, 4
|
* Is array of numbers sequential, i.e. 1, 2, 3, 4
|
||||||
* @param {number[]} nums
|
* @param {number[]} nums
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
isSequential(nums) {
|
isSequential(nums) {
|
||||||
@ -27,8 +27,8 @@ class AudioFileScanner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove
|
* Remove
|
||||||
* @param {number[]} nums
|
* @param {number[]} nums
|
||||||
* @returns {number[]}
|
* @returns {number[]}
|
||||||
*/
|
*/
|
||||||
removeDupes(nums) {
|
removeDupes(nums) {
|
||||||
@ -44,8 +44,8 @@ class AudioFileScanner {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Order audio files by track/disc number
|
* Order audio files by track/disc number
|
||||||
* @param {string} libraryItemRelPath
|
* @param {string} libraryItemRelPath
|
||||||
* @param {import('../models/Book').AudioFileObject[]} audioFiles
|
* @param {import('../models/Book').AudioFileObject[]} audioFiles
|
||||||
* @returns {import('../models/Book').AudioFileObject[]}
|
* @returns {import('../models/Book').AudioFileObject[]}
|
||||||
*/
|
*/
|
||||||
runSmartTrackOrder(libraryItemRelPath, audioFiles) {
|
runSmartTrackOrder(libraryItemRelPath, audioFiles) {
|
||||||
@ -103,8 +103,8 @@ class AudioFileScanner {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get track and disc number from audio filename
|
* Get track and disc number from audio filename
|
||||||
* @param {{title:string, subtitle:string, series:string, sequence:string, publishedYear:string, narrators:string}} mediaMetadataFromScan
|
* @param {{title:string, subtitle:string, series:string, sequence:string, publishedYear:string, narrators:string}} mediaMetadataFromScan
|
||||||
* @param {LibraryItem.LibraryFileObject} audioLibraryFile
|
* @param {LibraryItem.LibraryFileObject} audioLibraryFile
|
||||||
* @returns {{trackNumber:number, discNumber:number}}
|
* @returns {{trackNumber:number, discNumber:number}}
|
||||||
*/
|
*/
|
||||||
getTrackAndDiscNumberFromFilename(mediaMetadataFromScan, audioLibraryFile) {
|
getTrackAndDiscNumberFromFilename(mediaMetadataFromScan, audioLibraryFile) {
|
||||||
@ -146,10 +146,10 @@ class AudioFileScanner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {string} mediaType
|
* @param {string} mediaType
|
||||||
* @param {LibraryItem.LibraryFileObject} libraryFile
|
* @param {LibraryItem.LibraryFileObject} libraryFile
|
||||||
* @param {{title:string, subtitle:string, series:string, sequence:string, publishedYear:string, narrators:string}} mediaMetadataFromScan
|
* @param {{title:string, subtitle:string, series:string, sequence:string, publishedYear:string, narrators:string}} mediaMetadataFromScan
|
||||||
* @returns {Promise<AudioFile>}
|
* @returns {Promise<AudioFile>}
|
||||||
*/
|
*/
|
||||||
async scan(mediaType, libraryFile, mediaMetadataFromScan) {
|
async scan(mediaType, libraryFile, mediaMetadataFromScan) {
|
||||||
@ -181,7 +181,7 @@ class AudioFileScanner {
|
|||||||
/**
|
/**
|
||||||
* Scan LibraryFiles and return AudioFiles
|
* Scan LibraryFiles and return AudioFiles
|
||||||
* @param {string} mediaType
|
* @param {string} mediaType
|
||||||
* @param {import('./LibraryItemScanData')} libraryItemScanData
|
* @param {import('./LibraryItemScanData')} libraryItemScanData
|
||||||
* @param {LibraryItem.LibraryFileObject[]} audioLibraryFiles
|
* @param {LibraryItem.LibraryFileObject[]} audioLibraryFiles
|
||||||
* @returns {Promise<AudioFile[]>}
|
* @returns {Promise<AudioFile[]>}
|
||||||
*/
|
*/
|
||||||
@ -193,15 +193,15 @@ class AudioFileScanner {
|
|||||||
for (let i = batch; i < Math.min(batch + batchSize, audioLibraryFiles.length); i++) {
|
for (let i = batch; i < Math.min(batch + batchSize, audioLibraryFiles.length); i++) {
|
||||||
proms.push(this.scan(mediaType, audioLibraryFiles[i], libraryItemScanData.mediaMetadata))
|
proms.push(this.scan(mediaType, audioLibraryFiles[i], libraryItemScanData.mediaMetadata))
|
||||||
}
|
}
|
||||||
results.push(...await Promise.all(proms).then((scanResults) => scanResults.filter(sr => sr)))
|
results.push(...(await Promise.all(proms).then((scanResults) => scanResults.filter((sr) => sr))))
|
||||||
}
|
}
|
||||||
|
|
||||||
return results
|
return results
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {AudioFile} audioFile
|
* @param {AudioFile} audioFile
|
||||||
* @returns {object}
|
* @returns {object}
|
||||||
*/
|
*/
|
||||||
probeAudioFile(audioFile) {
|
probeAudioFile(audioFile) {
|
||||||
@ -211,10 +211,10 @@ class AudioFileScanner {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Set book metadata & chapters from audio file meta tags
|
* Set book metadata & chapters from audio file meta tags
|
||||||
*
|
*
|
||||||
* @param {string} bookTitle
|
* @param {string} bookTitle
|
||||||
* @param {import('../models/Book').AudioFileObject} audioFile
|
* @param {import('../models/Book').AudioFileObject} audioFile
|
||||||
* @param {Object} bookMetadata
|
* @param {Object} bookMetadata
|
||||||
* @param {import('./LibraryScan')} libraryScan
|
* @param {import('./LibraryScan')} libraryScan
|
||||||
*/
|
*/
|
||||||
setBookMetadataFromAudioMetaTags(bookTitle, audioFiles, bookMetadata, libraryScan) {
|
setBookMetadataFromAudioMetaTags(bookTitle, audioFiles, bookMetadata, libraryScan) {
|
||||||
@ -243,7 +243,7 @@ class AudioFileScanner {
|
|||||||
{
|
{
|
||||||
tag: 'tagAlbum',
|
tag: 'tagAlbum',
|
||||||
altTag: 'tagTitle',
|
altTag: 'tagTitle',
|
||||||
key: 'title',
|
key: 'title'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
tag: 'tagArtist',
|
tag: 'tagArtist',
|
||||||
@ -311,9 +311,9 @@ class AudioFileScanner {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Set podcast metadata from first audio file
|
* Set podcast metadata from first audio file
|
||||||
*
|
*
|
||||||
* @param {import('../models/Book').AudioFileObject} audioFile
|
* @param {import('../models/Book').AudioFileObject} audioFile
|
||||||
* @param {Object} podcastMetadata
|
* @param {Object} podcastMetadata
|
||||||
* @param {import('./LibraryScan')} libraryScan
|
* @param {import('./LibraryScan')} libraryScan
|
||||||
*/
|
*/
|
||||||
setPodcastMetadataFromAudioMetaTags(audioFile, podcastMetadata, libraryScan) {
|
setPodcastMetadataFromAudioMetaTags(audioFile, podcastMetadata, libraryScan) {
|
||||||
@ -343,7 +343,7 @@ class AudioFileScanner {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
tag: 'tagPodcastType',
|
tag: 'tagPodcastType',
|
||||||
key: 'podcastType',
|
key: 'podcastType'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -370,7 +370,7 @@ class AudioFileScanner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {import('../models/PodcastEpisode')} podcastEpisode Not the model when creating new podcast
|
* @param {import('../models/PodcastEpisode')} podcastEpisode Not the model when creating new podcast
|
||||||
* @param {import('./ScanLogger')} scanLogger
|
* @param {import('./ScanLogger')} scanLogger
|
||||||
*/
|
*/
|
||||||
@ -391,7 +391,7 @@ class AudioFileScanner {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
tag: 'tagDisc',
|
tag: 'tagDisc',
|
||||||
key: 'season',
|
key: 'season'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
tag: 'tagTrack',
|
tag: 'tagTrack',
|
||||||
@ -446,7 +446,7 @@ class AudioFileScanner {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} bookTitle
|
* @param {string} bookTitle
|
||||||
* @param {AudioFile[]} audioFiles
|
* @param {AudioFile[]} audioFiles
|
||||||
* @param {import('./LibraryScan')} libraryScan
|
* @param {import('./LibraryScan')} libraryScan
|
||||||
* @returns {import('../models/Book').ChapterObject[]}
|
* @returns {import('../models/Book').ChapterObject[]}
|
||||||
*/
|
*/
|
||||||
@ -464,12 +464,7 @@ class AudioFileScanner {
|
|||||||
// If first audio file has embedded chapters then use embedded chapters
|
// If first audio file has embedded chapters then use embedded chapters
|
||||||
if (audioFiles[0].chapters?.length) {
|
if (audioFiles[0].chapters?.length) {
|
||||||
// If all files chapters are the same, then only make chapters for the first file
|
// If all files chapters are the same, then only make chapters for the first file
|
||||||
if (
|
if (audioFiles.length === 1 || (audioFiles.length > 1 && audioFiles[0].chapters.length === audioFiles[1].chapters?.length && audioFiles[0].chapters.every((c, i) => c.title === audioFiles[1].chapters[i].title && c.start === audioFiles[1].chapters[i].start))) {
|
||||||
audioFiles.length === 1 ||
|
|
||||||
audioFiles.length > 1 &&
|
|
||||||
audioFiles[0].chapters.length === audioFiles[1].chapters?.length &&
|
|
||||||
audioFiles[0].chapters.every((c, i) => c.title === audioFiles[1].chapters[i].title && c.start === audioFiles[1].chapters[i].start)
|
|
||||||
) {
|
|
||||||
libraryScan.addLog(LogLevel.DEBUG, `setChapters: Using embedded chapters in first audio file ${audioFiles[0].metadata?.path}`)
|
libraryScan.addLog(LogLevel.DEBUG, `setChapters: Using embedded chapters in first audio file ${audioFiles[0].metadata?.path}`)
|
||||||
chapters = audioFiles[0].chapters.map((c) => ({ ...c }))
|
chapters = audioFiles[0].chapters.map((c) => ({ ...c }))
|
||||||
} else {
|
} else {
|
||||||
@ -479,12 +474,13 @@ class AudioFileScanner {
|
|||||||
|
|
||||||
audioFiles.forEach((file) => {
|
audioFiles.forEach((file) => {
|
||||||
if (file.duration) {
|
if (file.duration) {
|
||||||
const afChapters = file.chapters?.map((c) => ({
|
const afChapters =
|
||||||
...c,
|
file.chapters?.map((c) => ({
|
||||||
id: c.id + currChapterId,
|
...c,
|
||||||
start: c.start + currStartTime,
|
id: c.id + currChapterId,
|
||||||
end: c.end + currStartTime,
|
start: c.start + currStartTime,
|
||||||
})) ?? []
|
end: c.end + currStartTime
|
||||||
|
})) ?? []
|
||||||
chapters = chapters.concat(afChapters)
|
chapters = chapters.concat(afChapters)
|
||||||
|
|
||||||
currChapterId += file.chapters?.length ?? 0
|
currChapterId += file.chapters?.length ?? 0
|
||||||
@ -494,12 +490,11 @@ class AudioFileScanner {
|
|||||||
return chapters
|
return chapters
|
||||||
}
|
}
|
||||||
} else if (audioFiles.length > 1) {
|
} else if (audioFiles.length > 1) {
|
||||||
|
|
||||||
// In some cases the ID3 title tag for each file is the chapter title, the criteria to determine if this will be used
|
// In some cases the ID3 title tag for each file is the chapter title, the criteria to determine if this will be used
|
||||||
// 1. Every audio file has an ID3 title tag set
|
// 1. Every audio file has an ID3 title tag set
|
||||||
// 2. None of the title tags are the same as the book title
|
// 2. None of the title tags are the same as the book title
|
||||||
// 3. Every ID3 title tag is unique
|
// 3. Every ID3 title tag is unique
|
||||||
const metaTagTitlesFound = [...new Set(audioFiles.map(af => af.metaTags?.tagTitle).filter(tagTitle => !!tagTitle && tagTitle !== bookTitle))]
|
const metaTagTitlesFound = [...new Set(audioFiles.map((af) => af.metaTags?.tagTitle).filter((tagTitle) => !!tagTitle && tagTitle !== bookTitle))]
|
||||||
const useMetaTagAsTitle = metaTagTitlesFound.length === audioFiles.length
|
const useMetaTagAsTitle = metaTagTitlesFound.length === audioFiles.length
|
||||||
|
|
||||||
// Build chapters from audio files
|
// Build chapters from audio files
|
||||||
@ -528,8 +523,8 @@ class AudioFileScanner {
|
|||||||
/**
|
/**
|
||||||
* Parse a genre string into multiple genres
|
* Parse a genre string into multiple genres
|
||||||
* @example "Fantasy;Sci-Fi;History" => ["Fantasy", "Sci-Fi", "History"]
|
* @example "Fantasy;Sci-Fi;History" => ["Fantasy", "Sci-Fi", "History"]
|
||||||
*
|
*
|
||||||
* @param {string} genreTag
|
* @param {string} genreTag
|
||||||
* @returns {string[]}
|
* @returns {string[]}
|
||||||
*/
|
*/
|
||||||
parseGenresString(genreTag) {
|
parseGenresString(genreTag) {
|
||||||
@ -537,10 +532,13 @@ class AudioFileScanner {
|
|||||||
const separators = ['/', '//', ';']
|
const separators = ['/', '//', ';']
|
||||||
for (let i = 0; i < separators.length; i++) {
|
for (let i = 0; i < separators.length; i++) {
|
||||||
if (genreTag.includes(separators[i])) {
|
if (genreTag.includes(separators[i])) {
|
||||||
return genreTag.split(separators[i]).map(genre => genre.trim()).filter(g => !!g)
|
return genreTag
|
||||||
|
.split(separators[i])
|
||||||
|
.map((genre) => genre.trim())
|
||||||
|
.filter((g) => !!g)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return [genreTag]
|
return [genreTag]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
module.exports = new AudioFileScanner()
|
module.exports = new AudioFileScanner()
|
||||||
|
@ -20,7 +20,7 @@ function tryGrabBitRate(stream, all_streams, total_bit_rate) {
|
|||||||
var tagDuration = stream.tags.DURATION || stream.tags['DURATION-eng'] || stream.tags['DURATION_eng']
|
var tagDuration = stream.tags.DURATION || stream.tags['DURATION-eng'] || stream.tags['DURATION_eng']
|
||||||
var tagBytes = stream.tags.NUMBER_OF_BYTES || stream.tags['NUMBER_OF_BYTES-eng'] || stream.tags['NUMBER_OF_BYTES_eng']
|
var tagBytes = stream.tags.NUMBER_OF_BYTES || stream.tags['NUMBER_OF_BYTES-eng'] || stream.tags['NUMBER_OF_BYTES_eng']
|
||||||
if (tagDuration && tagBytes && !isNaN(tagDuration) && !isNaN(tagBytes)) {
|
if (tagDuration && tagBytes && !isNaN(tagDuration) && !isNaN(tagBytes)) {
|
||||||
var bps = Math.floor(Number(tagBytes) * 8 / Number(tagDuration))
|
var bps = Math.floor((Number(tagBytes) * 8) / Number(tagDuration))
|
||||||
if (bps && !isNaN(bps)) {
|
if (bps && !isNaN(bps)) {
|
||||||
return bps
|
return bps
|
||||||
}
|
}
|
||||||
@ -33,7 +33,7 @@ function tryGrabBitRate(stream, all_streams, total_bit_rate) {
|
|||||||
estimated_bit_rate -= Number(stream.bit_rate)
|
estimated_bit_rate -= Number(stream.bit_rate)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if (!all_streams.find(s => s.codec_type === 'audio' && s.bit_rate && Number(s.bit_rate) > estimated_bit_rate)) {
|
if (!all_streams.find((s) => s.codec_type === 'audio' && s.bit_rate && Number(s.bit_rate) > estimated_bit_rate)) {
|
||||||
return estimated_bit_rate
|
return estimated_bit_rate
|
||||||
} else {
|
} else {
|
||||||
return total_bit_rate
|
return total_bit_rate
|
||||||
@ -73,7 +73,7 @@ function tryGrabChannelLayout(stream) {
|
|||||||
function tryGrabTags(stream, ...tags) {
|
function tryGrabTags(stream, ...tags) {
|
||||||
if (!stream.tags) return null
|
if (!stream.tags) return null
|
||||||
for (let i = 0; i < tags.length; i++) {
|
for (let i = 0; i < tags.length; i++) {
|
||||||
const tagKey = Object.keys(stream.tags).find(t => t.toLowerCase() === tags[i].toLowerCase())
|
const tagKey = Object.keys(stream.tags).find((t) => t.toLowerCase() === tags[i].toLowerCase())
|
||||||
const value = stream.tags[tagKey]
|
const value = stream.tags[tagKey]
|
||||||
if (value && value.trim()) return value.trim()
|
if (value && value.trim()) return value.trim()
|
||||||
}
|
}
|
||||||
@ -101,7 +101,7 @@ function parseMediaStreamInfo(stream, all_streams, total_bit_rate) {
|
|||||||
|
|
||||||
if (info.type === 'video') {
|
if (info.type === 'video') {
|
||||||
info.profile = stream.profile || null
|
info.profile = stream.profile || null
|
||||||
info.is_avc = (stream.is_avc !== '0' && stream.is_avc !== 'false')
|
info.is_avc = stream.is_avc !== '0' && stream.is_avc !== 'false'
|
||||||
info.pix_fmt = stream.pix_fmt || null
|
info.pix_fmt = stream.pix_fmt || null
|
||||||
info.frame_rate = tryGrabFrameRate(stream)
|
info.frame_rate = tryGrabFrameRate(stream)
|
||||||
info.width = !isNaN(stream.width) ? Number(stream.width) : null
|
info.width = !isNaN(stream.width) ? Number(stream.width) : null
|
||||||
@ -123,7 +123,6 @@ function isNullOrNaN(val) {
|
|||||||
return val === null || isNaN(val)
|
return val === null || isNaN(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Example chapter object
|
/* Example chapter object
|
||||||
* {
|
* {
|
||||||
"id": 71,
|
"id": 71,
|
||||||
@ -137,23 +136,28 @@ function isNullOrNaN(val) {
|
|||||||
}
|
}
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
function parseChapters(chapters) {
|
function parseChapters(_chapters) {
|
||||||
if (!chapters) return []
|
if (!_chapters) return []
|
||||||
let index = 0
|
|
||||||
return chapters.map(chap => {
|
|
||||||
let title = chap['TAG:title'] || chap.title || ''
|
|
||||||
if (!title && chap.tags?.title) title = chap.tags.title
|
|
||||||
|
|
||||||
const timebase = chap.time_base?.includes('/') ? Number(chap.time_base.split('/')[1]) : 1
|
return _chapters
|
||||||
const start = !isNullOrNaN(chap.start_time) ? Number(chap.start_time) : !isNullOrNaN(chap.start) ? Number(chap.start) / timebase : 0
|
.map((chap) => {
|
||||||
const end = !isNullOrNaN(chap.end_time) ? Number(chap.end_time) : !isNullOrNaN(chap.end) ? Number(chap.end) / timebase : 0
|
let title = chap['TAG:title'] || chap.title || ''
|
||||||
return {
|
if (!title && chap.tags?.title) title = chap.tags.title
|
||||||
id: index++,
|
|
||||||
start,
|
const timebase = chap.time_base?.includes('/') ? Number(chap.time_base.split('/')[1]) : 1
|
||||||
end,
|
const start = !isNullOrNaN(chap.start_time) ? Number(chap.start_time) : !isNullOrNaN(chap.start) ? Number(chap.start) / timebase : 0
|
||||||
title
|
const end = !isNullOrNaN(chap.end_time) ? Number(chap.end_time) : !isNullOrNaN(chap.end) ? Number(chap.end) / timebase : 0
|
||||||
}
|
return {
|
||||||
})
|
start,
|
||||||
|
end,
|
||||||
|
title
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.toSorted((a, b) => a.start - b.start)
|
||||||
|
.map((chap, index) => {
|
||||||
|
chap.id = index
|
||||||
|
return chap
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseTags(format, verbose) {
|
function parseTags(format, verbose) {
|
||||||
@ -210,7 +214,7 @@ function parseTags(format, verbose) {
|
|||||||
file_tag_movement: tryGrabTags(format, 'movement', 'mvin'),
|
file_tag_movement: tryGrabTags(format, 'movement', 'mvin'),
|
||||||
file_tag_genre1: tryGrabTags(format, 'tmp_genre1', 'genre1'),
|
file_tag_genre1: tryGrabTags(format, 'tmp_genre1', 'genre1'),
|
||||||
file_tag_genre2: tryGrabTags(format, 'tmp_genre2', 'genre2'),
|
file_tag_genre2: tryGrabTags(format, 'tmp_genre2', 'genre2'),
|
||||||
file_tag_overdrive_media_marker: tryGrabTags(format, 'OverDrive MediaMarkers'),
|
file_tag_overdrive_media_marker: tryGrabTags(format, 'OverDrive MediaMarkers')
|
||||||
}
|
}
|
||||||
for (const key in tags) {
|
for (const key in tags) {
|
||||||
if (!tags[key]) {
|
if (!tags[key]) {
|
||||||
@ -224,7 +228,7 @@ function parseTags(format, verbose) {
|
|||||||
function getDefaultAudioStream(audioStreams) {
|
function getDefaultAudioStream(audioStreams) {
|
||||||
if (!audioStreams || !audioStreams.length) return null
|
if (!audioStreams || !audioStreams.length) return null
|
||||||
if (audioStreams.length === 1) return audioStreams[0]
|
if (audioStreams.length === 1) return audioStreams[0]
|
||||||
var defaultStream = audioStreams.find(a => a.is_default)
|
var defaultStream = audioStreams.find((a) => a.is_default)
|
||||||
if (!defaultStream) return audioStreams[0]
|
if (!defaultStream) return audioStreams[0]
|
||||||
return defaultStream
|
return defaultStream
|
||||||
}
|
}
|
||||||
@ -248,9 +252,9 @@ function parseProbeData(data, verbose = false) {
|
|||||||
cleanedData.rawTags = format.tags
|
cleanedData.rawTags = format.tags
|
||||||
}
|
}
|
||||||
|
|
||||||
const cleaned_streams = streams.map(s => parseMediaStreamInfo(s, streams, cleanedData.bit_rate))
|
const cleaned_streams = streams.map((s) => parseMediaStreamInfo(s, streams, cleanedData.bit_rate))
|
||||||
cleanedData.video_stream = cleaned_streams.find(s => s.type === 'video')
|
cleanedData.video_stream = cleaned_streams.find((s) => s.type === 'video')
|
||||||
const audioStreams = cleaned_streams.filter(s => s.type === 'audio')
|
const audioStreams = cleaned_streams.filter((s) => s.type === 'audio')
|
||||||
cleanedData.audio_stream = getDefaultAudioStream(audioStreams)
|
cleanedData.audio_stream = getDefaultAudioStream(audioStreams)
|
||||||
|
|
||||||
if (cleanedData.audio_stream && cleanedData.video_stream) {
|
if (cleanedData.audio_stream && cleanedData.video_stream) {
|
||||||
@ -280,8 +284,8 @@ function parseProbeData(data, verbose = false) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Run ffprobe on audio filepath
|
* Run ffprobe on audio filepath
|
||||||
* @param {string} filepath
|
* @param {string} filepath
|
||||||
* @param {boolean} [verbose=false]
|
* @param {boolean} [verbose=false]
|
||||||
* @returns {import('../scanner/MediaProbeData')|{error:string}}
|
* @returns {import('../scanner/MediaProbeData')|{error:string}}
|
||||||
*/
|
*/
|
||||||
function probe(filepath, verbose = false) {
|
function probe(filepath, verbose = false) {
|
||||||
@ -290,7 +294,7 @@ function probe(filepath, verbose = false) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return ffprobe(filepath)
|
return ffprobe(filepath)
|
||||||
.then(raw => {
|
.then((raw) => {
|
||||||
if (raw.error) {
|
if (raw.error) {
|
||||||
return {
|
return {
|
||||||
error: raw.error.string
|
error: raw.error.string
|
||||||
@ -318,7 +322,7 @@ module.exports.probe = probe
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Ffprobe for audio file path
|
* Ffprobe for audio file path
|
||||||
*
|
*
|
||||||
* @param {string} filepath
|
* @param {string} filepath
|
||||||
* @returns {Object} ffprobe json output
|
* @returns {Object} ffprobe json output
|
||||||
*/
|
*/
|
||||||
@ -327,11 +331,10 @@ function rawProbe(filepath) {
|
|||||||
ffprobe.FFPROBE_PATH = process.env.FFPROBE_PATH
|
ffprobe.FFPROBE_PATH = process.env.FFPROBE_PATH
|
||||||
}
|
}
|
||||||
|
|
||||||
return ffprobe(filepath)
|
return ffprobe(filepath).catch((err) => {
|
||||||
.catch((err) => {
|
return {
|
||||||
return {
|
error: err
|
||||||
error: err
|
}
|
||||||
}
|
})
|
||||||
})
|
|
||||||
}
|
}
|
||||||
module.exports.rawProbe = rawProbe
|
module.exports.rawProbe = rawProbe
|
||||||
|
Loading…
Reference in New Issue
Block a user