From d2ed22d22972dc68a1d9962ff53e42d818ba4302 Mon Sep 17 00:00:00 2001 From: Jonathan Bernard Date: Wed, 16 Mar 2016 05:49:29 -0500 Subject: [PATCH] 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). --- .../com/jdbernard/wdiwtlt/MediaLibrary.groovy | 28 +++++++++++++------ .../com/jdbernard/wdiwtlt/db/DbApi.groovy | 4 +++ 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/core/src/main/groovy/com/jdbernard/wdiwtlt/MediaLibrary.groovy b/core/src/main/groovy/com/jdbernard/wdiwtlt/MediaLibrary.groovy index 828664f..599d4b5 100644 --- a/core/src/main/groovy/com/jdbernard/wdiwtlt/MediaLibrary.groovy +++ b/core/src/main/groovy/com/jdbernard/wdiwtlt/MediaLibrary.groovy @@ -70,17 +70,31 @@ public class MediaLibrary { return null } def relPath = getRelativePath(libraryRoot, f) - MediaFile mf = dbapi.getMediaFileByFilePath(relPath) + MediaFile found = dbapi.getMediaFileByFilePath(relPath) - if (mf) { + if (found) { logger.info( "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 - mf = new MediaFile() def af - try { af = AudioFileIO.read(f) } catch (Exception e) { logger.info("Ignoring a file because I can't " + @@ -91,7 +105,6 @@ public class MediaLibrary { def fileTag = af.tag mf.name = fileTag?.getFirst(TITLE)?.trim() ?: f.name - mf.filePath = relPath mf.comment = fileTag?.getAll(COMMENT)?.collect { it.trim() }?.join('\n\n') mf.discNumber = safeToInteger(fileTag?.getFirst(DISC_NO)) ?: 1 mf.trackNumber = safeToInteger(fileTag?.getFirst(TRACK)) @@ -110,9 +123,6 @@ public class MediaLibrary { mf.metaInfoSource = MediaFile.FILE_LOCATION albumNames = [folderParts.peekLast()] } - // Hash the file - mf.fileHash = f.withInputStream { DigestUtils.md5Hex(it) } - dbapi.withTransaction { dbapi.create(mf) associateWithArtistsAndAlbums(mf, artistNames, albumNames, diff --git a/core/src/main/groovy/com/jdbernard/wdiwtlt/db/DbApi.groovy b/core/src/main/groovy/com/jdbernard/wdiwtlt/db/DbApi.groovy index 6b8dd8f..02a0126 100644 --- a/core/src/main/groovy/com/jdbernard/wdiwtlt/db/DbApi.groovy +++ b/core/src/main/groovy/com/jdbernard/wdiwtlt/db/DbApi.groovy @@ -411,6 +411,10 @@ public class DbApi { def files = getBy(MediaFile, ['file_path'], [filePath]) return files ? files[0] : null } + public MediaFile getMediaFileByFileHash(String fileHash) { + def files = getBy(MediaFile, ['file_hash'], [fileHash]) + return files ? files[0] : null } + public List getMediaFilesWhere(Map params) { def query = new StringBuilder() def sqlParams = []