Rescanning now finds moved files by their hash.
More precisely, the MediaLibrary matches up files based on their file hash. If it finds a files that matches an already known entry it doesn't create a new entry, only updates the file path to the found file in the existing entry. This is useful if files get re-organized or if an existing database is loaded at an entirely new library root that contains mostly the same files (relocating the library to another computer for example). This method preserves information added to the database that was not originally present in the ID3 tags in the media files (custom tags, name corrections, etc).
This commit is contained in:
parent
07fa7559ac
commit
d2ed22d229
@ -70,17 +70,31 @@ public class MediaLibrary {
|
|||||||
return null }
|
return null }
|
||||||
|
|
||||||
def relPath = getRelativePath(libraryRoot, f)
|
def relPath = getRelativePath(libraryRoot, f)
|
||||||
MediaFile mf = dbapi.getMediaFileByFilePath(relPath)
|
MediaFile found = dbapi.getMediaFileByFilePath(relPath)
|
||||||
|
|
||||||
if (mf) {
|
if (found) {
|
||||||
logger.info(
|
logger.info(
|
||||||
"Ignoring a media file I already know about: {}", relPath)
|
"Ignoring a media file I already know about: {}", relPath)
|
||||||
return mf }
|
return found }
|
||||||
|
|
||||||
|
MediaFile mf = new MediaFile()
|
||||||
|
mf.filePath = relPath
|
||||||
|
|
||||||
|
// Hash the file
|
||||||
|
mf.fileHash = f.withInputStream { DigestUtils.md5Hex(it) }
|
||||||
|
|
||||||
|
// Look for an entry for that hash
|
||||||
|
found = dbapi.getMediaFileByFileHash(mf.fileHash)
|
||||||
|
|
||||||
|
if (found) {
|
||||||
|
logger.info('Found a media file by hash in a new location. ' +
|
||||||
|
"I'm updating my relative path to this file:\n\t{}\n\t\t--> {}.",
|
||||||
|
found.filePath, mf.filePath)
|
||||||
|
found.filePath = mf.filePath
|
||||||
|
return dbapi.update(found) }
|
||||||
|
|
||||||
// Read in the media's tags
|
// Read in the media's tags
|
||||||
mf = new MediaFile()
|
|
||||||
def af
|
def af
|
||||||
|
|
||||||
try { af = AudioFileIO.read(f) }
|
try { af = AudioFileIO.read(f) }
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
logger.info("Ignoring a file because I can't " +
|
logger.info("Ignoring a file because I can't " +
|
||||||
@ -91,7 +105,6 @@ public class MediaLibrary {
|
|||||||
def fileTag = af.tag
|
def fileTag = af.tag
|
||||||
|
|
||||||
mf.name = fileTag?.getFirst(TITLE)?.trim() ?: f.name
|
mf.name = fileTag?.getFirst(TITLE)?.trim() ?: f.name
|
||||||
mf.filePath = relPath
|
|
||||||
mf.comment = fileTag?.getAll(COMMENT)?.collect { it.trim() }?.join('\n\n')
|
mf.comment = fileTag?.getAll(COMMENT)?.collect { it.trim() }?.join('\n\n')
|
||||||
mf.discNumber = safeToInteger(fileTag?.getFirst(DISC_NO)) ?: 1
|
mf.discNumber = safeToInteger(fileTag?.getFirst(DISC_NO)) ?: 1
|
||||||
mf.trackNumber = safeToInteger(fileTag?.getFirst(TRACK))
|
mf.trackNumber = safeToInteger(fileTag?.getFirst(TRACK))
|
||||||
@ -110,9 +123,6 @@ public class MediaLibrary {
|
|||||||
mf.metaInfoSource = MediaFile.FILE_LOCATION
|
mf.metaInfoSource = MediaFile.FILE_LOCATION
|
||||||
albumNames = [folderParts.peekLast()] }
|
albumNames = [folderParts.peekLast()] }
|
||||||
|
|
||||||
// Hash the file
|
|
||||||
mf.fileHash = f.withInputStream { DigestUtils.md5Hex(it) }
|
|
||||||
|
|
||||||
dbapi.withTransaction {
|
dbapi.withTransaction {
|
||||||
dbapi.create(mf)
|
dbapi.create(mf)
|
||||||
associateWithArtistsAndAlbums(mf, artistNames, albumNames,
|
associateWithArtistsAndAlbums(mf, artistNames, albumNames,
|
||||||
|
@ -411,6 +411,10 @@ public class DbApi {
|
|||||||
def files = getBy(MediaFile, ['file_path'], [filePath])
|
def files = getBy(MediaFile, ['file_path'], [filePath])
|
||||||
return files ? files[0] : null }
|
return files ? files[0] : null }
|
||||||
|
|
||||||
|
public MediaFile getMediaFileByFileHash(String fileHash) {
|
||||||
|
def files = getBy(MediaFile, ['file_hash'], [fileHash])
|
||||||
|
return files ? files[0] : null }
|
||||||
|
|
||||||
public List<MediaFile> getMediaFilesWhere(Map params) {
|
public List<MediaFile> getMediaFilesWhere(Map params) {
|
||||||
def query = new StringBuilder()
|
def query = new StringBuilder()
|
||||||
def sqlParams = []
|
def sqlParams = []
|
||||||
|
Loading…
Reference in New Issue
Block a user