mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-11-04 03:17:00 -05:00 
			
		
		
		
	Add:Parsing tags from OPF metadata #602, Update:OPF parser to check for prefix on package/metadata/meta objects
This commit is contained in:
		
							parent
							
								
									7e5ab477b2
								
							
						
					
					
						commit
						139ee013a7
					
				@ -225,6 +225,7 @@ class Book {
 | 
				
			|||||||
  // Look for desc.txt, reader.txt, metadata.abs and opf file then update details if found
 | 
					  // Look for desc.txt, reader.txt, metadata.abs and opf file then update details if found
 | 
				
			||||||
  async syncMetadataFiles(textMetadataFiles, opfMetadataOverrideDetails) {
 | 
					  async syncMetadataFiles(textMetadataFiles, opfMetadataOverrideDetails) {
 | 
				
			||||||
    var metadataUpdatePayload = {}
 | 
					    var metadataUpdatePayload = {}
 | 
				
			||||||
 | 
					    var tagsUpdated = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var descTxt = textMetadataFiles.find(lf => lf.metadata.filename === 'desc.txt')
 | 
					    var descTxt = textMetadataFiles.find(lf => lf.metadata.filename === 'desc.txt')
 | 
				
			||||||
    if (descTxt) {
 | 
					    if (descTxt) {
 | 
				
			||||||
@ -264,8 +265,13 @@ class Book {
 | 
				
			|||||||
        var opfMetadata = await parseOpfMetadataXML(xmlText)
 | 
					        var opfMetadata = await parseOpfMetadataXML(xmlText)
 | 
				
			||||||
        if (opfMetadata) {
 | 
					        if (opfMetadata) {
 | 
				
			||||||
          for (const key in opfMetadata) {
 | 
					          for (const key in opfMetadata) {
 | 
				
			||||||
            // Add genres only if genres are empty
 | 
					
 | 
				
			||||||
            if (key === 'genres') {
 | 
					            if (key === 'tags') { // Add tags only if tags are empty
 | 
				
			||||||
 | 
					              if (opfMetadata.tags.length && (!this.tags.length || opfMetadataOverrideDetails)) {
 | 
				
			||||||
 | 
					                this.tags = opfMetadata.tags
 | 
				
			||||||
 | 
					                tagsUpdated = true
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            } else if (key === 'genres') { // Add genres only if genres are empty
 | 
				
			||||||
              if (opfMetadata.genres.length && (!this.metadata.genres.length || opfMetadataOverrideDetails)) {
 | 
					              if (opfMetadata.genres.length && (!this.metadata.genres.length || opfMetadataOverrideDetails)) {
 | 
				
			||||||
                metadataUpdatePayload[key] = opfMetadata.genres
 | 
					                metadataUpdatePayload[key] = opfMetadata.genres
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
@ -290,9 +296,9 @@ class Book {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (Object.keys(metadataUpdatePayload).length) {
 | 
					    if (Object.keys(metadataUpdatePayload).length) {
 | 
				
			||||||
      return this.metadata.update(metadataUpdatePayload)
 | 
					      return this.metadata.update(metadataUpdatePayload) || tagsUpdated
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return false
 | 
					    return tagsUpdated
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  searchQuery(query) {
 | 
					  searchQuery(query) {
 | 
				
			||||||
 | 
				
			|||||||
@ -70,14 +70,14 @@ function fetchLanguage(metadata) {
 | 
				
			|||||||
  return fetchTagString(metadata, 'dc:language')
 | 
					  return fetchTagString(metadata, 'dc:language')
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function fetchSeries(metadata) {
 | 
					function fetchSeries(metadataMeta) {
 | 
				
			||||||
  if (typeof metadata.meta == "undefined") return null
 | 
					  if (!metadataMeta) return null
 | 
				
			||||||
  return fetchTagString(metadata.meta, "calibre:series")
 | 
					  return fetchTagString(metadataMeta, "calibre:series")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function fetchVolumeNumber(metadata) {
 | 
					function fetchVolumeNumber(metadataMeta) {
 | 
				
			||||||
  if (typeof metadata.meta == "undefined") return null
 | 
					  if (!metadataMeta) return null
 | 
				
			||||||
  return fetchTagString(metadata.meta, "calibre:series_index")
 | 
					  return fetchTagString(metadataMeta, "calibre:series_index")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function fetchNarrators(creators, metadata) {
 | 
					function fetchNarrators(creators, metadata) {
 | 
				
			||||||
@ -91,21 +91,42 @@ function fetchNarrators(creators, metadata) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function fetchTags(metadata) {
 | 
				
			||||||
 | 
					  if (!metadata['dc:tag'] || !metadata['dc:tag'].length) return []
 | 
				
			||||||
 | 
					  return metadata['dc:tag'].filter(tag => (typeof tag === 'string'))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function stripPrefix(str) {
 | 
				
			||||||
 | 
					  if (!str) return ''
 | 
				
			||||||
 | 
					  return str.split(':').pop()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module.exports.parseOpfMetadataXML = async (xml) => {
 | 
					module.exports.parseOpfMetadataXML = async (xml) => {
 | 
				
			||||||
  var json = await xmlToJSON(xml)
 | 
					  var json = await xmlToJSON(xml)
 | 
				
			||||||
  if (!json || !json.package || !json.package.metadata) return null
 | 
					
 | 
				
			||||||
  var metadata = json.package.metadata
 | 
					  if (!json) return null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Handle <package ...> or with prefix <ns0:package ...>
 | 
				
			||||||
 | 
					  const packageKey = Object.keys(json).find(key => stripPrefix(key) === 'package')
 | 
				
			||||||
 | 
					  if (!packageKey) return null
 | 
				
			||||||
 | 
					  const prefix = packageKey.split(':').shift()
 | 
				
			||||||
 | 
					  var metadata = prefix ? json[packageKey][`${prefix}:metadata`] || json[packageKey].metadata : json[packageKey].metadata
 | 
				
			||||||
 | 
					  if (!metadata) return null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (Array.isArray(metadata)) {
 | 
					  if (Array.isArray(metadata)) {
 | 
				
			||||||
    if (!metadata.length) return null
 | 
					    if (!metadata.length) return null
 | 
				
			||||||
    metadata = metadata[0]
 | 
					    metadata = metadata[0]
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (typeof metadata.meta != "undefined") {
 | 
					  const metadataMeta = prefix ? metadata[`${prefix}:meta`] || metadata.meta : metadata.meta
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  metadata.meta = {}
 | 
					  metadata.meta = {}
 | 
				
			||||||
    for (var match of xml.matchAll(/<meta name="(?<name>.+)" content="(?<content>.+)"\/>/g)) {
 | 
					  if (metadataMeta && metadataMeta.length) {
 | 
				
			||||||
      metadata.meta[match.groups['name']] = [match.groups['content']]
 | 
					    metadataMeta.forEach((meta) => {
 | 
				
			||||||
 | 
					      if (meta && meta['$'] && meta['$'].name) {
 | 
				
			||||||
 | 
					        metadata.meta[meta['$'].name] = [meta['$'].content || '']
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  var creators = parseCreators(metadata)
 | 
					  var creators = parseCreators(metadata)
 | 
				
			||||||
@ -119,8 +140,9 @@ module.exports.parseOpfMetadataXML = async (xml) => {
 | 
				
			|||||||
    description: fetchDescription(metadata),
 | 
					    description: fetchDescription(metadata),
 | 
				
			||||||
    genres: fetchGenres(metadata),
 | 
					    genres: fetchGenres(metadata),
 | 
				
			||||||
    language: fetchLanguage(metadata),
 | 
					    language: fetchLanguage(metadata),
 | 
				
			||||||
    series: fetchSeries(metadata),
 | 
					    series: fetchSeries(metadata.meta),
 | 
				
			||||||
    sequence: fetchVolumeNumber(metadata)
 | 
					    sequence: fetchVolumeNumber(metadata.meta),
 | 
				
			||||||
 | 
					    tags: fetchTags(metadata)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  return data
 | 
					  return data
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user