mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-10-27 11:18:14 +01:00 
			
		
		
		
	Update scanner, music meta tags and fix issue with force update
This commit is contained in:
		
							parent
							
								
									5410aae8fc
								
							
						
					
					
						commit
						9de7be1cb4
					
				@ -19,7 +19,7 @@ class CoverManager {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getCoverDirectory(libraryItem) {
 | 
			
		||||
    if (this.db.serverSettings.storeCoverWithItem && !libraryItem.isFile) {
 | 
			
		||||
    if (this.db.serverSettings.storeCoverWithItem && !libraryItem.isFile && !libraryItem.isMusic) {
 | 
			
		||||
      return libraryItem.path
 | 
			
		||||
    } else {
 | 
			
		||||
      return Path.posix.join(this.ItemMetadataPath, libraryItem.id)
 | 
			
		||||
 | 
			
		||||
@ -131,7 +131,7 @@ class AudioFile {
 | 
			
		||||
    this.channels = probeData.channels
 | 
			
		||||
    this.channelLayout = probeData.channelLayout
 | 
			
		||||
    this.chapters = probeData.chapters || []
 | 
			
		||||
    this.metaTags = probeData.audioFileMetadata
 | 
			
		||||
    this.metaTags = probeData.audioMetaTags
 | 
			
		||||
    this.embeddedCoverArt = probeData.embeddedCoverArt
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -167,9 +167,7 @@ class AudioFile {
 | 
			
		||||
    let hasUpdated = false
 | 
			
		||||
 | 
			
		||||
    const newjson = scannedAudioFile.toJSON()
 | 
			
		||||
    if (this.manuallyVerified) newjson.manuallyVerified = true
 | 
			
		||||
    if (this.exclude) newjson.exclude = true
 | 
			
		||||
    newjson.addedAt = this.addedAt
 | 
			
		||||
    const ignoreKeys = ['manuallyVerified', 'exclude', 'addedAt', 'updatedAt']
 | 
			
		||||
 | 
			
		||||
    for (const key in newjson) {
 | 
			
		||||
      if (key === 'metadata') {
 | 
			
		||||
@ -185,7 +183,7 @@ class AudioFile {
 | 
			
		||||
        if (this.syncChapters(newjson.chapters || [])) {
 | 
			
		||||
          hasUpdated = true
 | 
			
		||||
        }
 | 
			
		||||
      } else if (this[key] !== newjson[key]) {
 | 
			
		||||
      } else if (!ignoreKeys.includes(key) && this[key] !== newjson[key]) {
 | 
			
		||||
        this[key] = newjson[key]
 | 
			
		||||
        hasUpdated = true
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
@ -131,6 +131,12 @@ class Music {
 | 
			
		||||
    this.audioFile = audioFile
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setMetadataFromAudioFile(overrideExistingDetails = false) {
 | 
			
		||||
    if (!this.audioFile) return false
 | 
			
		||||
    if (!this.audioFile.metaTags) return false
 | 
			
		||||
    return this.metadata.setDataFromAudioMetaTags(this.audioFile.metaTags, overrideExistingDetails)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  syncMetadataFiles(textMetadataFiles, opfMetadataOverrideDetails) {
 | 
			
		||||
    return false
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -21,6 +21,15 @@ class AudioMetaTags {
 | 
			
		||||
    this.tagLanguage = null
 | 
			
		||||
    this.tagASIN = null
 | 
			
		||||
    this.tagOverdriveMediaMarker = null
 | 
			
		||||
    this.tagOriginalYear = null
 | 
			
		||||
    this.tagReleaseCountry = null
 | 
			
		||||
    this.tagReleaseType = null
 | 
			
		||||
    this.tagReleaseStatus = null
 | 
			
		||||
    this.tagISRC = null
 | 
			
		||||
    this.tagMusicBrainzTrackId = null
 | 
			
		||||
    this.tagMusicBrainzAlbumId = null
 | 
			
		||||
    this.tagMusicBrainzAlbumArtistId = null
 | 
			
		||||
    this.tagMusicBrainzArtistId = null
 | 
			
		||||
 | 
			
		||||
    if (metadata) {
 | 
			
		||||
      this.construct(metadata)
 | 
			
		||||
@ -29,7 +38,7 @@ class AudioMetaTags {
 | 
			
		||||
 | 
			
		||||
  toJSON() {
 | 
			
		||||
    // Only return the tags that are actually set
 | 
			
		||||
    var json = {}
 | 
			
		||||
    const json = {}
 | 
			
		||||
    for (const key in this) {
 | 
			
		||||
      if (key.startsWith('tag') && this[key]) {
 | 
			
		||||
        json[key] = this[key]
 | 
			
		||||
@ -38,6 +47,51 @@ class AudioMetaTags {
 | 
			
		||||
    return json
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get trackNumAndTotal() {
 | 
			
		||||
    const data = {
 | 
			
		||||
      number: null,
 | 
			
		||||
      total: null
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Track ID3 tag might be "3/10" or just "3"
 | 
			
		||||
    if (this.tagTrack) {
 | 
			
		||||
      const trackParts = this.tagTrack.split('/').map(part => Number(part))
 | 
			
		||||
      if (trackParts.length > 0) {
 | 
			
		||||
        // Fractional track numbers not supported
 | 
			
		||||
        data.number = !isNaN(trackParts[0]) ? Math.trunc(trackParts[0]) : null
 | 
			
		||||
      }
 | 
			
		||||
      if (trackParts.length > 1) {
 | 
			
		||||
        data.total = !isNaN(trackParts[1]) ? trackParts[1] : null
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return data
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get discNumAndTotal() {
 | 
			
		||||
    const data = {
 | 
			
		||||
      number: null,
 | 
			
		||||
      total: null
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (this.tagDisc) {
 | 
			
		||||
      const discParts = this.tagDisc.split('/').map(p => Number(p))
 | 
			
		||||
      if (discParts.length > 0) {
 | 
			
		||||
        data.number = !isNaN(discParts[0]) ? Math.trunc(discParts[0]) : null
 | 
			
		||||
      }
 | 
			
		||||
      if (discParts.length > 1) {
 | 
			
		||||
        data.total = !isNaN(discParts[1]) ? discParts[1] : null
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return data
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get discNumber() { return this.discNumAndTotal.number }
 | 
			
		||||
  get discTotal() { return this.discNumAndTotal.total }
 | 
			
		||||
  get trackNumber() { return this.trackNumAndTotal.number }
 | 
			
		||||
  get trackTotal() { return this.trackNumAndTotal.total }
 | 
			
		||||
 | 
			
		||||
  construct(metadata) {
 | 
			
		||||
    this.tagAlbum = metadata.tagAlbum || null
 | 
			
		||||
    this.tagArtist = metadata.tagArtist || null
 | 
			
		||||
@ -60,6 +114,15 @@ class AudioMetaTags {
 | 
			
		||||
    this.tagLanguage = metadata.tagLanguage || null
 | 
			
		||||
    this.tagASIN = metadata.tagASIN || null
 | 
			
		||||
    this.tagOverdriveMediaMarker = metadata.tagOverdriveMediaMarker || null
 | 
			
		||||
    this.tagOriginalYear = metadata.tagOriginalYear || null
 | 
			
		||||
    this.tagReleaseCountry = metadata.tagReleaseCountry || null
 | 
			
		||||
    this.tagReleaseType = metadata.tagReleaseType || null
 | 
			
		||||
    this.tagReleaseStatus = metadata.tagReleaseStatus || null
 | 
			
		||||
    this.tagISRC = metadata.tagISRC || null
 | 
			
		||||
    this.tagMusicBrainzTrackId = metadata.tagMusicBrainzTrackId || null
 | 
			
		||||
    this.tagMusicBrainzAlbumId = metadata.tagMusicBrainzAlbumId || null
 | 
			
		||||
    this.tagMusicBrainzAlbumArtistId = metadata.tagMusicBrainzAlbumArtistId || null
 | 
			
		||||
    this.tagMusicBrainzArtistId = metadata.tagMusicBrainzArtistId || null
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Data parsed in prober.js
 | 
			
		||||
@ -85,6 +148,15 @@ class AudioMetaTags {
 | 
			
		||||
    this.tagLanguage = payload.file_tag_language || null
 | 
			
		||||
    this.tagASIN = payload.file_tag_asin || null
 | 
			
		||||
    this.tagOverdriveMediaMarker = payload.file_tag_overdrive_media_marker || null
 | 
			
		||||
    this.tagOriginalYear = payload.file_tag_originalyear || null
 | 
			
		||||
    this.tagReleaseCountry = payload.file_tag_releasecountry || null
 | 
			
		||||
    this.tagReleaseType = payload.file_tag_releasetype || null
 | 
			
		||||
    this.tagReleaseStatus = payload.file_tag_releasestatus || null
 | 
			
		||||
    this.tagISRC = payload.file_tag_isrc || null
 | 
			
		||||
    this.tagMusicBrainzTrackId = payload.file_tag_musicbrainz_trackid || null
 | 
			
		||||
    this.tagMusicBrainzAlbumId = payload.file_tag_musicbrainz_albumid || null
 | 
			
		||||
    this.tagMusicBrainzAlbumArtistId = payload.file_tag_musicbrainz_albumartistid || null
 | 
			
		||||
    this.tagMusicBrainzArtistId = payload.file_tag_musicbrainz_artistid || null
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setDataFromTone(tags) {
 | 
			
		||||
@ -114,9 +186,18 @@ class AudioMetaTags {
 | 
			
		||||
      tagLanguage: payload.file_tag_language || null,
 | 
			
		||||
      tagASIN: payload.file_tag_asin || null,
 | 
			
		||||
      tagOverdriveMediaMarker: payload.file_tag_overdrive_media_marker || null,
 | 
			
		||||
      tagOriginalYear: payload.file_tag_originalyear || null,
 | 
			
		||||
      tagReleaseCountry: payload.file_tag_releasecountry || null,
 | 
			
		||||
      tagReleaseType: payload.file_tag_releasetype || null,
 | 
			
		||||
      tagReleaseStatus: payload.file_tag_releasestatus || null,
 | 
			
		||||
      tagISRC: payload.file_tag_isrc || null,
 | 
			
		||||
      tagMusicBrainzTrackId: payload.file_tag_musicbrainz_trackid || null,
 | 
			
		||||
      tagMusicBrainzAlbumId: payload.file_tag_musicbrainz_albumid || null,
 | 
			
		||||
      tagMusicBrainzAlbumArtistId: payload.file_tag_musicbrainz_albumartistid || null,
 | 
			
		||||
      tagMusicBrainzArtistId: payload.file_tag_musicbrainz_artistid || null
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    var hasUpdates = false
 | 
			
		||||
    let hasUpdates = false
 | 
			
		||||
    for (const key in dataMap) {
 | 
			
		||||
      if (dataMap[key] !== this[key]) {
 | 
			
		||||
        this[key] = dataMap[key]
 | 
			
		||||
 | 
			
		||||
@ -306,11 +306,9 @@ class BookMetadata {
 | 
			
		||||
        // tagToUse = mapping.altTag
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (value && typeof value === 'string') { // Trim whitespace
 | 
			
		||||
        value = value.trim()
 | 
			
		||||
      }
 | 
			
		||||
      if (value && typeof value === 'string') {
 | 
			
		||||
        value = value.trim() // Trim whitespace
 | 
			
		||||
 | 
			
		||||
      if (value) {
 | 
			
		||||
        if (mapping.key === 'narrators' && (!this.narrators.length || overrideExistingDetails)) {
 | 
			
		||||
          updatePayload.narrators = this.parseNarratorsTag(value)
 | 
			
		||||
        } else if (mapping.key === 'authors' && (!this.authors.length || overrideExistingDetails)) {
 | 
			
		||||
@ -335,13 +333,13 @@ class BookMetadata {
 | 
			
		||||
 | 
			
		||||
  // Returns array of names in First Last format
 | 
			
		||||
  parseNarratorsTag(narratorsTag) {
 | 
			
		||||
    var parsed = parseNameString.parse(narratorsTag)
 | 
			
		||||
    const parsed = parseNameString.parse(narratorsTag)
 | 
			
		||||
    return parsed ? parsed.names : []
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Return array of authors minified with placeholder id
 | 
			
		||||
  parseAuthorsTag(authorsTag) {
 | 
			
		||||
    var parsed = parseNameString.parse(authorsTag)
 | 
			
		||||
    const parsed = parseNameString.parse(authorsTag)
 | 
			
		||||
    if (!parsed) return []
 | 
			
		||||
    return (parsed.names || []).map((au) => {
 | 
			
		||||
      return {
 | 
			
		||||
@ -353,7 +351,7 @@ class BookMetadata {
 | 
			
		||||
 | 
			
		||||
  parseGenresTag(genreTag) {
 | 
			
		||||
    if (!genreTag || !genreTag.length) return []
 | 
			
		||||
    var separators = ['/', '//', ';']
 | 
			
		||||
    const separators = ['/', '//', ';']
 | 
			
		||||
    for (let i = 0; i < separators.length; i++) {
 | 
			
		||||
      if (genreTag.includes(separators[i])) {
 | 
			
		||||
        return genreTag.split(separators[i]).map(genre => genre.trim()).filter(g => !!g)
 | 
			
		||||
 | 
			
		||||
@ -4,13 +4,31 @@ const { areEquivalent, copyValue, cleanStringForSearch, getTitleIgnorePrefix, ge
 | 
			
		||||
class MusicMetadata {
 | 
			
		||||
  constructor(metadata) {
 | 
			
		||||
    this.title = null
 | 
			
		||||
    this.artist = null
 | 
			
		||||
    this.artists = [] // Array of strings
 | 
			
		||||
    this.album = null
 | 
			
		||||
    this.albumArtist = null
 | 
			
		||||
    this.genres = [] // Array of strings
 | 
			
		||||
    this.composer = null
 | 
			
		||||
    this.originalYear = null
 | 
			
		||||
    this.releaseDate = null
 | 
			
		||||
    this.releaseCountry = null
 | 
			
		||||
    this.releaseType = null
 | 
			
		||||
    this.releaseStatus = null
 | 
			
		||||
    this.recordLabel = null
 | 
			
		||||
    this.language = null
 | 
			
		||||
    this.explicit = false
 | 
			
		||||
 | 
			
		||||
    this.discNumber = null
 | 
			
		||||
    this.discTotal = null
 | 
			
		||||
    this.trackNumber = null
 | 
			
		||||
    this.trackTotal = null
 | 
			
		||||
 | 
			
		||||
    this.isrc = null
 | 
			
		||||
    this.musicBrainzTrackId = null
 | 
			
		||||
    this.musicBrainzAlbumId = null
 | 
			
		||||
    this.musicBrainzAlbumArtistId = null
 | 
			
		||||
    this.musicBrainzArtistId = null
 | 
			
		||||
 | 
			
		||||
    if (metadata) {
 | 
			
		||||
      this.construct(metadata)
 | 
			
		||||
    }
 | 
			
		||||
@ -18,23 +36,55 @@ class MusicMetadata {
 | 
			
		||||
 | 
			
		||||
  construct(metadata) {
 | 
			
		||||
    this.title = metadata.title
 | 
			
		||||
    this.artist = metadata.artist
 | 
			
		||||
    this.artists = metadata.artists ? [...metadata.artists] : []
 | 
			
		||||
    this.album = metadata.album
 | 
			
		||||
    this.albumArtist = metadata.albumArtist
 | 
			
		||||
    this.genres = metadata.genres ? [...metadata.genres] : []
 | 
			
		||||
    this.composer = metadata.composer || null
 | 
			
		||||
    this.originalYear = metadata.originalYear || null
 | 
			
		||||
    this.releaseDate = metadata.releaseDate || null
 | 
			
		||||
    this.language = metadata.language
 | 
			
		||||
    this.releaseCountry = metadata.releaseCountry || null
 | 
			
		||||
    this.releaseType = metadata.releaseType || null
 | 
			
		||||
    this.releaseStatus = metadata.releaseStatus || null
 | 
			
		||||
    this.recordLabel = metadata.recordLabel || null
 | 
			
		||||
    this.language = metadata.language || null
 | 
			
		||||
    this.explicit = !!metadata.explicit
 | 
			
		||||
    this.discNumber = metadata.discNumber || null
 | 
			
		||||
    this.discTotal = metadata.discTotal || null
 | 
			
		||||
    this.trackNumber = metadata.trackNumber || null
 | 
			
		||||
    this.trackTotal = metadata.trackTotal || null
 | 
			
		||||
    this.isrc = metadata.isrc || null
 | 
			
		||||
    this.musicBrainzTrackId = metadata.musicBrainzTrackId || null
 | 
			
		||||
    this.musicBrainzAlbumId = metadata.musicBrainzAlbumId || null
 | 
			
		||||
    this.musicBrainzAlbumArtistId = metadata.musicBrainzAlbumArtistId || null
 | 
			
		||||
    this.musicBrainzArtistId = metadata.musicBrainzArtistId || null
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  toJSON() {
 | 
			
		||||
    return {
 | 
			
		||||
      title: this.title,
 | 
			
		||||
      artist: this.artist,
 | 
			
		||||
      artists: [...this.artists],
 | 
			
		||||
      album: this.album,
 | 
			
		||||
      albumArtist: this.albumArtist,
 | 
			
		||||
      genres: [...this.genres],
 | 
			
		||||
      composer: this.composer,
 | 
			
		||||
      originalYear: this.originalYear,
 | 
			
		||||
      releaseDate: this.releaseDate,
 | 
			
		||||
      releaseCountry: this.releaseCountry,
 | 
			
		||||
      releaseType: this.releaseType,
 | 
			
		||||
      releaseStatus: this.releaseStatus,
 | 
			
		||||
      recordLabel: this.recordLabel,
 | 
			
		||||
      language: this.language,
 | 
			
		||||
      explicit: this.explicit
 | 
			
		||||
      explicit: this.explicit,
 | 
			
		||||
      discNumber: this.discNumber,
 | 
			
		||||
      discTotal: this.discTotal,
 | 
			
		||||
      trackNumber: this.trackNumber,
 | 
			
		||||
      trackTotal: this.trackTotal,
 | 
			
		||||
      isrc: this.isrc,
 | 
			
		||||
      musicBrainzTrackId: this.musicBrainzTrackId,
 | 
			
		||||
      musicBrainzAlbumId: this.musicBrainzAlbumId,
 | 
			
		||||
      musicBrainzAlbumArtistId: this.musicBrainzAlbumArtistId,
 | 
			
		||||
      musicBrainzArtistId: this.musicBrainzArtistId
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -42,12 +92,28 @@ class MusicMetadata {
 | 
			
		||||
    return {
 | 
			
		||||
      title: this.title,
 | 
			
		||||
      titleIgnorePrefix: this.titlePrefixAtEnd,
 | 
			
		||||
      artist: this.artist,
 | 
			
		||||
      artists: [...this.artists],
 | 
			
		||||
      album: this.album,
 | 
			
		||||
      albumArtist: this.albumArtist,
 | 
			
		||||
      genres: [...this.genres],
 | 
			
		||||
      composer: this.composer,
 | 
			
		||||
      originalYear: this.originalYear,
 | 
			
		||||
      releaseDate: this.releaseDate,
 | 
			
		||||
      releaseCountry: this.releaseCountry,
 | 
			
		||||
      releaseType: this.releaseType,
 | 
			
		||||
      releaseStatus: this.releaseStatus,
 | 
			
		||||
      recordLabel: this.recordLabel,
 | 
			
		||||
      language: this.language,
 | 
			
		||||
      explicit: this.explicit
 | 
			
		||||
      explicit: this.explicit,
 | 
			
		||||
      discNumber: this.discNumber,
 | 
			
		||||
      discTotal: this.discTotal,
 | 
			
		||||
      trackNumber: this.trackNumber,
 | 
			
		||||
      trackTotal: this.trackTotal,
 | 
			
		||||
      isrc: this.isrc,
 | 
			
		||||
      musicBrainzTrackId: this.musicBrainzTrackId,
 | 
			
		||||
      musicBrainzAlbumId: this.musicBrainzAlbumId,
 | 
			
		||||
      musicBrainzAlbumArtistId: this.musicBrainzAlbumArtistId,
 | 
			
		||||
      musicBrainzArtistId: this.musicBrainzArtistId
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -68,7 +134,7 @@ class MusicMetadata {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  searchQuery(query) { // Returns key if match is found
 | 
			
		||||
    const keysToCheck = ['title', 'artist', 'album']
 | 
			
		||||
    const keysToCheck = ['title', 'album']
 | 
			
		||||
    for (const key of keysToCheck) {
 | 
			
		||||
      if (this[key] && cleanStringForSearch(String(this[key])).includes(query)) {
 | 
			
		||||
        return {
 | 
			
		||||
@ -100,5 +166,154 @@ class MusicMetadata {
 | 
			
		||||
    }
 | 
			
		||||
    return hasUpdates
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  parseArtistsTag(artistsTag) {
 | 
			
		||||
    if (!artistsTag || !artistsTag.length) return []
 | 
			
		||||
    const separators = ['/', '//', ';']
 | 
			
		||||
    for (let i = 0; i < separators.length; i++) {
 | 
			
		||||
      if (artistsTag.includes(separators[i])) {
 | 
			
		||||
        return artistsTag.split(separators[i]).map(artist => artist.trim()).filter(a => !!a)
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return [artistsTag]
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  parseGenresTag(genreTag) {
 | 
			
		||||
    if (!genreTag || !genreTag.length) return []
 | 
			
		||||
    const separators = ['/', '//', ';']
 | 
			
		||||
    for (let i = 0; i < separators.length; i++) {
 | 
			
		||||
      if (genreTag.includes(separators[i])) {
 | 
			
		||||
        return genreTag.split(separators[i]).map(genre => genre.trim()).filter(g => !!g)
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return [genreTag]
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setDataFromAudioMetaTags(audioFileMetaTags, overrideExistingDetails = false) {
 | 
			
		||||
    const MetadataMapArray = [
 | 
			
		||||
      {
 | 
			
		||||
        tag: 'tagTitle',
 | 
			
		||||
        key: 'title',
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        tag: 'tagArtist',
 | 
			
		||||
        key: 'artists'
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        tag: 'tagAlbumArtist',
 | 
			
		||||
        key: 'albumArtist'
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        tag: 'tagAlbum',
 | 
			
		||||
        key: 'album',
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        tag: 'tagPublisher',
 | 
			
		||||
        key: 'recordLabel'
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        tag: 'tagComposer',
 | 
			
		||||
        key: 'composer'
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        tag: 'tagDate',
 | 
			
		||||
        key: 'releaseDate'
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        tag: 'tagReleaseCountry',
 | 
			
		||||
        key: 'releaseCountry'
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        tag: 'tagReleaseType',
 | 
			
		||||
        key: 'releaseType'
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        tag: 'tagReleaseStatus',
 | 
			
		||||
        key: 'releaseStatus'
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        tag: 'tagOriginalYear',
 | 
			
		||||
        key: 'originalYear'
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        tag: 'tagGenre',
 | 
			
		||||
        key: 'genres'
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        tag: 'tagLanguage',
 | 
			
		||||
        key: 'language'
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        tag: 'tagLanguage',
 | 
			
		||||
        key: 'language'
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        tag: 'tagISRC',
 | 
			
		||||
        key: 'isrc'
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        tag: 'tagMusicBrainzTrackId',
 | 
			
		||||
        key: 'musicBrainzTrackId'
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        tag: 'tagMusicBrainzAlbumId',
 | 
			
		||||
        key: 'musicBrainzAlbumId'
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        tag: 'tagMusicBrainzAlbumArtistId',
 | 
			
		||||
        key: 'musicBrainzAlbumArtistId'
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        tag: 'tagMusicBrainzArtistId',
 | 
			
		||||
        key: 'musicBrainzArtistId'
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        tag: 'trackNumber',
 | 
			
		||||
        key: 'trackNumber'
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        tag: 'trackTotal',
 | 
			
		||||
        key: 'trackTotal'
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        tag: 'discNumber',
 | 
			
		||||
        key: 'discNumber'
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        tag: 'discTotal',
 | 
			
		||||
        key: 'discTotal'
 | 
			
		||||
      }
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    const updatePayload = {}
 | 
			
		||||
 | 
			
		||||
    // Metadata is only mapped to the music track if it is empty
 | 
			
		||||
    MetadataMapArray.forEach((mapping) => {
 | 
			
		||||
      let value = audioFileMetaTags[mapping.tag]
 | 
			
		||||
      // let tagToUse = mapping.tag
 | 
			
		||||
      if (!value && mapping.altTag) {
 | 
			
		||||
        value = audioFileMetaTags[mapping.altTag]
 | 
			
		||||
        // tagToUse = mapping.altTag
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (value && typeof value === 'string') {
 | 
			
		||||
        value = value.trim() // Trim whitespace
 | 
			
		||||
 | 
			
		||||
        if (mapping.key === 'artists' && (!this.artists.length || overrideExistingDetails)) {
 | 
			
		||||
          updatePayload.artists = this.parseArtistsTag(value)
 | 
			
		||||
        } else if (mapping.key === 'genres' && (!this.genres.length || overrideExistingDetails)) {
 | 
			
		||||
          updatePayload.genres = this.parseGenresTag(value)
 | 
			
		||||
        } else if (!this[mapping.key] || overrideExistingDetails) {
 | 
			
		||||
          updatePayload[mapping.key] = value
 | 
			
		||||
          // Logger.debug(`[Book] Mapping metadata to key ${tagToUse} => ${mapping.key}: ${updatePayload[mapping.key]}`)
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    if (Object.keys(updatePayload).length) {
 | 
			
		||||
      return this.update(updatePayload)
 | 
			
		||||
    }
 | 
			
		||||
    return false
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
module.exports = MusicMetadata
 | 
			
		||||
@ -93,8 +93,8 @@ class MediaFileScanner {
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const audioFile = new AudioFile()
 | 
			
		||||
      audioFile.trackNumFromMeta = probeData.trackNumber
 | 
			
		||||
      audioFile.discNumFromMeta = probeData.discNumber
 | 
			
		||||
      audioFile.trackNumFromMeta = probeData.audioMetaTags.trackNumber
 | 
			
		||||
      audioFile.discNumFromMeta = probeData.audioMetaTags.discNumber
 | 
			
		||||
      if (mediaType === 'book') {
 | 
			
		||||
        const { trackNumber, discNumber } = this.getTrackAndDiscNumberFromFilename(mediaMetadataFromScan, libraryFile)
 | 
			
		||||
        audioFile.trackNumFromFilename = trackNumber
 | 
			
		||||
@ -303,6 +303,18 @@ class MediaFileScanner {
 | 
			
		||||
          hasUpdated = true
 | 
			
		||||
        } else if (libraryItem.media.audioFile && libraryItem.media.audioFile.updateFromScan(mediaScanResult.audioFiles[0])) {
 | 
			
		||||
          hasUpdated = true
 | 
			
		||||
          console.log('Updated from scan')
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (libraryItem.media.setMetadataFromAudioFile()) {
 | 
			
		||||
          hasUpdated = true
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // If the audio track has no title meta tag then use the audio file name
 | 
			
		||||
        if (!libraryItem.media.metadata.title && libraryItem.media.audioFile) {
 | 
			
		||||
          const audioFileName = libraryItem.media.audioFile.metadata.filename
 | 
			
		||||
          libraryItem.media.metadata.title = Path.basename(audioFileName, Path.extname(audioFileName))
 | 
			
		||||
          hasUpdated = true
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
const AudioFileMetadata = require('../objects/metadata/AudioMetaTags')
 | 
			
		||||
const AudioMetaTags = require('../objects/metadata/AudioMetaTags')
 | 
			
		||||
 | 
			
		||||
class MediaProbeData {
 | 
			
		||||
  constructor(probeData) {
 | 
			
		||||
@ -19,7 +19,7 @@ class MediaProbeData {
 | 
			
		||||
    this.sampleRate = null
 | 
			
		||||
    this.chapters = []
 | 
			
		||||
 | 
			
		||||
    this.audioFileMetadata = null
 | 
			
		||||
    this.audioMetaTags = null
 | 
			
		||||
 | 
			
		||||
    this.trackNumber = null
 | 
			
		||||
    this.trackTotal = null
 | 
			
		||||
@ -34,8 +34,8 @@ class MediaProbeData {
 | 
			
		||||
 | 
			
		||||
  construct(probeData) {
 | 
			
		||||
    for (const key in probeData) {
 | 
			
		||||
      if (key === 'audioFileMetadata' && probeData[key]) {
 | 
			
		||||
        this[key] = new AudioFileMetadata(probeData[key])
 | 
			
		||||
      if (key === 'audioMetaTags' && probeData[key]) {
 | 
			
		||||
        this[key] = new AudioMetaTags(probeData[key])
 | 
			
		||||
      } else if (this[key] !== undefined) {
 | 
			
		||||
        this[key] = probeData[key]
 | 
			
		||||
      }
 | 
			
		||||
@ -48,61 +48,35 @@ class MediaProbeData {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setData(data) {
 | 
			
		||||
    var audioStream = data.audio_stream
 | 
			
		||||
    this.embeddedCoverArt = data.video_stream ? this.getEmbeddedCoverArt(data.video_stream) : null
 | 
			
		||||
    this.format = data.format
 | 
			
		||||
    this.duration = data.duration
 | 
			
		||||
    this.size = data.size
 | 
			
		||||
 | 
			
		||||
    this.audioStream = audioStream
 | 
			
		||||
    this.audioStream = data.audio_stream
 | 
			
		||||
    this.videoStream = this.embeddedCoverArt ? null : data.video_stream || null
 | 
			
		||||
 | 
			
		||||
    this.bitRate = audioStream.bit_rate || data.bit_rate
 | 
			
		||||
    this.codec = audioStream.codec
 | 
			
		||||
    this.timeBase = audioStream.time_base
 | 
			
		||||
    this.language = audioStream.language
 | 
			
		||||
    this.channelLayout = audioStream.channel_layout
 | 
			
		||||
    this.channels = audioStream.channels
 | 
			
		||||
    this.sampleRate = audioStream.sample_rate
 | 
			
		||||
    this.bitRate = this.audioStream.bit_rate || data.bit_rate
 | 
			
		||||
    this.codec = this.audioStream.codec
 | 
			
		||||
    this.timeBase = this.audioStream.time_base
 | 
			
		||||
    this.language = this.audioStream.language
 | 
			
		||||
    this.channelLayout = this.audioStream.channel_layout
 | 
			
		||||
    this.channels = this.audioStream.channels
 | 
			
		||||
    this.sampleRate = this.audioStream.sample_rate
 | 
			
		||||
    this.chapters = data.chapters || []
 | 
			
		||||
 | 
			
		||||
    if (data.tags) { // New for tone library data (toneProber.js)
 | 
			
		||||
      this.audioFileMetadata = new AudioFileMetadata()
 | 
			
		||||
      this.audioFileMetadata.setDataFromTone(data.tags)
 | 
			
		||||
    } else { // Data from ffprobe (prober.js)
 | 
			
		||||
      var metatags = {}
 | 
			
		||||
      for (const key in data) {
 | 
			
		||||
        if (data[key] && key.startsWith('file_tag')) {
 | 
			
		||||
          metatags[key] = data[key]
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    this.audioMetaTags = new AudioMetaTags()
 | 
			
		||||
    this.audioMetaTags.setData(data.tags)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
      this.audioFileMetadata = new AudioFileMetadata()
 | 
			
		||||
      this.audioFileMetadata.setData(metatags)
 | 
			
		||||
    }
 | 
			
		||||
  setDataFromTone(data) {
 | 
			
		||||
    // TODO: Implement
 | 
			
		||||
 | 
			
		||||
    // Track ID3 tag might be "3/10" or just "3"
 | 
			
		||||
    if (this.audioFileMetadata.tagTrack) {
 | 
			
		||||
      var trackParts = this.audioFileMetadata.tagTrack.split('/').map(part => Number(part))
 | 
			
		||||
      if (trackParts.length > 0) {
 | 
			
		||||
        // Fractional track numbers not supported
 | 
			
		||||
        this.trackNumber = !isNaN(trackParts[0]) ? Math.trunc(trackParts[0]) : null
 | 
			
		||||
      }
 | 
			
		||||
      if (trackParts.length > 1) {
 | 
			
		||||
        this.trackTotal = !isNaN(trackParts[1]) ? trackParts[1] : null
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Parse disc tag
 | 
			
		||||
    if (this.audioFileMetadata.tagDisc) {
 | 
			
		||||
      var discParts = this.audioFileMetadata.tagDisc.split('/').map(p => Number(p))
 | 
			
		||||
      if (discParts.length > 0) {
 | 
			
		||||
        this.discNumber = !isNaN(discParts[0]) ? Math.trunc(discParts[0]) : null
 | 
			
		||||
      }
 | 
			
		||||
      if (discParts.length > 1) {
 | 
			
		||||
        this.discTotal = !isNaN(discParts[1]) ? discParts[1] : null
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    this.format = data.format
 | 
			
		||||
    this.duration = data.duration
 | 
			
		||||
    this.size = data.size
 | 
			
		||||
    this.audioMetaTags = new AudioMetaTags()
 | 
			
		||||
    this.audioMetaTags.setDataFromTone(data.tags)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
module.exports = MediaProbeData
 | 
			
		||||
@ -73,7 +73,7 @@ function tryGrabChannelLayout(stream) {
 | 
			
		||||
function tryGrabTags(stream, ...tags) {
 | 
			
		||||
  if (!stream.tags) return null
 | 
			
		||||
  for (let i = 0; i < tags.length; i++) {
 | 
			
		||||
    var value = stream.tags[tags[i]] || stream.tags[tags[i].toUpperCase()]
 | 
			
		||||
    const value = stream.tags[tags[i]] || stream.tags[tags[i].toUpperCase()]
 | 
			
		||||
    if (value && value.trim()) return value.trim()
 | 
			
		||||
  }
 | 
			
		||||
  return null
 | 
			
		||||
@ -182,6 +182,15 @@ function parseTags(format, verbose) {
 | 
			
		||||
    file_tag_isbn: tryGrabTags(format, 'isbn'),
 | 
			
		||||
    file_tag_language: tryGrabTags(format, 'language', 'lang'),
 | 
			
		||||
    file_tag_asin: tryGrabTags(format, 'asin'),
 | 
			
		||||
    file_tag_originalyear: tryGrabTags(format, 'originalyear'),
 | 
			
		||||
    file_tag_releasecountry: tryGrabTags(format, 'MusicBrainz Album Release Country', 'releasecountry'),
 | 
			
		||||
    file_tag_releasestatus: tryGrabTags(format, 'MusicBrainz Album Status', 'releasestatus', 'musicbrainz_albumstatus'),
 | 
			
		||||
    file_tag_releasetype: tryGrabTags(format, 'MusicBrainz Album Type', 'releasetype', 'musicbrainz_albumtype'),
 | 
			
		||||
    file_tag_isrc: tryGrabTags(format, 'tsrc', 'isrc'),
 | 
			
		||||
    file_tag_musicbrainz_trackid: tryGrabTags(format, 'MusicBrainz Release Track Id', 'musicbrainz_releasetrackid'),
 | 
			
		||||
    file_tag_musicbrainz_albumid: tryGrabTags(format, 'MusicBrainz Album Id', 'musicbrainz_albumid'),
 | 
			
		||||
    file_tag_musicbrainz_albumartistid: tryGrabTags(format, 'MusicBrainz Album Artist Id', 'musicbrainz_albumartistid'),
 | 
			
		||||
    file_tag_musicbrainz_artistid: tryGrabTags(format, 'MusicBrainz Artist Id', 'musicbrainz_artistid'),
 | 
			
		||||
 | 
			
		||||
    // Not sure if these are actually used yet or not
 | 
			
		||||
    file_tag_creation_time: tryGrabTags(format, 'creation_time'),
 | 
			
		||||
@ -213,20 +222,18 @@ function getDefaultAudioStream(audioStreams) {
 | 
			
		||||
 | 
			
		||||
function parseProbeData(data, verbose = false) {
 | 
			
		||||
  try {
 | 
			
		||||
    var { format, streams, chapters } = data
 | 
			
		||||
    const { format, streams, chapters } = data
 | 
			
		||||
 | 
			
		||||
    var sizeBytes = !isNaN(format.size) ? Number(format.size) : null
 | 
			
		||||
    var sizeMb = sizeBytes !== null ? Number((sizeBytes / (1024 * 1024)).toFixed(2)) : null
 | 
			
		||||
    const sizeBytes = !isNaN(format.size) ? Number(format.size) : null
 | 
			
		||||
    const sizeMb = sizeBytes !== null ? Number((sizeBytes / (1024 * 1024)).toFixed(2)) : null
 | 
			
		||||
 | 
			
		||||
    // Logger.debug('Parsing Data for', Path.basename(format.filename))
 | 
			
		||||
    var tags = parseTags(format, verbose)
 | 
			
		||||
    var cleanedData = {
 | 
			
		||||
    let cleanedData = {
 | 
			
		||||
      format: format.format_long_name || format.name || 'Unknown',
 | 
			
		||||
      duration: !isNaN(format.duration) ? Number(format.duration) : null,
 | 
			
		||||
      size: sizeBytes,
 | 
			
		||||
      sizeMb,
 | 
			
		||||
      bit_rate: !isNaN(format.bit_rate) ? Number(format.bit_rate) : null,
 | 
			
		||||
      ...tags
 | 
			
		||||
      tags: parseTags(format, verbose)
 | 
			
		||||
    }
 | 
			
		||||
    if (verbose && format.tags) {
 | 
			
		||||
      cleanedData.rawTags = format.tags
 | 
			
		||||
@ -234,11 +241,11 @@ function parseProbeData(data, verbose = false) {
 | 
			
		||||
 | 
			
		||||
    const cleaned_streams = streams.map(s => parseMediaStreamInfo(s, streams, cleanedData.bit_rate))
 | 
			
		||||
    cleanedData.video_stream = cleaned_streams.find(s => s.type === 'video')
 | 
			
		||||
    var audioStreams = cleaned_streams.filter(s => s.type === 'audio')
 | 
			
		||||
    const audioStreams = cleaned_streams.filter(s => s.type === 'audio')
 | 
			
		||||
    cleanedData.audio_stream = getDefaultAudioStream(audioStreams)
 | 
			
		||||
 | 
			
		||||
    if (cleanedData.audio_stream && cleanedData.video_stream) {
 | 
			
		||||
      var videoBitrate = cleanedData.video_stream.bit_rate
 | 
			
		||||
      const videoBitrate = cleanedData.video_stream.bit_rate
 | 
			
		||||
      // If audio stream bitrate larger then video, most likely incorrect
 | 
			
		||||
      if (cleanedData.audio_stream.bit_rate > videoBitrate) {
 | 
			
		||||
        cleanedData.video_stream.bit_rate = cleanedData.bit_rate
 | 
			
		||||
@ -247,10 +254,9 @@ function parseProbeData(data, verbose = false) {
 | 
			
		||||
 | 
			
		||||
    // If format does not have tags, check audio stream (https://github.com/advplyr/audiobookshelf/issues/256)
 | 
			
		||||
    if (!format.tags && cleanedData.audio_stream && cleanedData.audio_stream.tags) {
 | 
			
		||||
      var tags = parseTags(cleanedData.audio_stream)
 | 
			
		||||
      cleanedData = {
 | 
			
		||||
        ...cleanedData,
 | 
			
		||||
        ...tags
 | 
			
		||||
        tags: parseTags(cleanedData.audio_stream, verbose)
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -277,13 +283,13 @@ function probe(filepath, verbose = false) {
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      var rawProbeData = parseProbeData(raw, verbose)
 | 
			
		||||
      const rawProbeData = parseProbeData(raw, verbose)
 | 
			
		||||
      if (!rawProbeData || (!rawProbeData.audio_stream && !rawProbeData.video_stream)) {
 | 
			
		||||
        return {
 | 
			
		||||
          error: rawProbeData ? 'Invalid media file: no audio or video streams found' : 'Probe Failed'
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        var probeData = new MediaProbeData()
 | 
			
		||||
        const probeData = new MediaProbeData()
 | 
			
		||||
        probeData.setData(rawProbeData)
 | 
			
		||||
        return probeData
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
@ -95,11 +95,7 @@ function groupFileItemsIntoLibraryItemDirs(mediaType, fileItems) {
 | 
			
		||||
  if (mediaType === 'music') {
 | 
			
		||||
    const audioFileGroup = {}
 | 
			
		||||
    fileItems.filter(i => isMediaFile(mediaType, i.extension)).forEach((item) => {
 | 
			
		||||
      if (!item.reldirpath) {
 | 
			
		||||
        audioFileGroup[item.name] = item.name
 | 
			
		||||
      } else {
 | 
			
		||||
        audioFileGroup[item.reldirpath] = [item.name]
 | 
			
		||||
      }
 | 
			
		||||
      audioFileGroup[item.path] = item.path
 | 
			
		||||
    })
 | 
			
		||||
    return audioFileGroup
 | 
			
		||||
  }
 | 
			
		||||
@ -201,7 +197,14 @@ async function scanFolder(libraryMediaType, folder, serverSettings = {}) {
 | 
			
		||||
    let isFile = false // item is not in a folder
 | 
			
		||||
    let libraryItemData = null
 | 
			
		||||
    let fileObjs = []
 | 
			
		||||
    if (libraryItemPath === libraryItemGrouping[libraryItemPath]) {
 | 
			
		||||
    if (libraryMediaType === 'music') {
 | 
			
		||||
      libraryItemData = {
 | 
			
		||||
        path: Path.posix.join(folderPath, libraryItemPath),
 | 
			
		||||
        relPath: libraryItemPath
 | 
			
		||||
      }
 | 
			
		||||
      fileObjs = await cleanFileObjects(folderPath, [libraryItemPath])
 | 
			
		||||
      isFile = true
 | 
			
		||||
    } else if (libraryItemPath === libraryItemGrouping[libraryItemPath]) {
 | 
			
		||||
      // Media file in root only get title
 | 
			
		||||
      libraryItemData = {
 | 
			
		||||
        mediaMetadata: {
 | 
			
		||||
@ -344,23 +347,8 @@ function getPodcastDataFromDir(folderPath, relPath) {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getMusicDataFromDir(folderPath, relPath, fileNames) {
 | 
			
		||||
  relPath = relPath.replace(/\\/g, '/')
 | 
			
		||||
 | 
			
		||||
  const firstFileName = fileNames.length ? fileNames[0] : ''
 | 
			
		||||
  return {
 | 
			
		||||
    mediaMetadata: {
 | 
			
		||||
      title: Path.basename(firstFileName, Path.extname(firstFileName))
 | 
			
		||||
    },
 | 
			
		||||
    relPath: relPath, // relative music audio file path i.e. /Some Folder/..
 | 
			
		||||
    path: Path.posix.join(folderPath, relPath) // i.e. /music/Some Folder/..
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getDataFromMediaDir(libraryMediaType, folderPath, relPath, serverSettings, fileNames) {
 | 
			
		||||
  if (libraryMediaType === 'music') {
 | 
			
		||||
    return getMusicDataFromDir(folderPath, relPath, fileNames)
 | 
			
		||||
  } else if (libraryMediaType === 'podcast') {
 | 
			
		||||
  if (libraryMediaType === 'podcast') {
 | 
			
		||||
    return getPodcastDataFromDir(folderPath, relPath)
 | 
			
		||||
  } else if (libraryMediaType === 'book') {
 | 
			
		||||
    var parseSubtitle = !!serverSettings.scannerParseSubtitle
 | 
			
		||||
 | 
			
		||||
@ -147,7 +147,7 @@ module.exports.probe = (filepath, verbose = false) => {
 | 
			
		||||
    }
 | 
			
		||||
    const rawProbeData = parseProbeDump(dumpPayload)
 | 
			
		||||
    const probeData = new MediaProbeData()
 | 
			
		||||
    probeData.setData(rawProbeData)
 | 
			
		||||
    probeData.setDataFromTone(rawProbeData)
 | 
			
		||||
    return probeData
 | 
			
		||||
  }).catch((error) => {
 | 
			
		||||
    Logger.error(`[toneProber] Failed to probe file at path "${filepath}"`, error)
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user