diff --git a/vrobbler/apps/scrobbles/importers/webdav.py b/vrobbler/apps/scrobbles/importers/webdav.py index 1aef8ba..95e811c 100644 --- a/vrobbler/apps/scrobbles/importers/webdav.py +++ b/vrobbler/apps/scrobbles/importers/webdav.py @@ -226,6 +226,32 @@ def scan_webdav_for_retroarch(webdav_client, user_id): if not downloaded: return 0 + # Compute content hash of all downloaded files + import hashlib + + hasher = hashlib.md5() + for basename in downloaded: + filepath = os.path.join(download_dir, basename) + hasher.update(basename.encode()) + with open(filepath, "rb") as f: + hasher.update(f.read()) + content_hash = hasher.hexdigest() + + # Skip if the last completed import already has this hash + last_import = ( + RetroarchImport.objects.filter( + user_id=user_id, processed_finished__isnull=False + ) + .order_by("-processed_finished") + .first() + ) + if last_import and last_import.files_hash == content_hash: + logger.info( + "Retroarch lrtl files unchanged for user, skipping", + extra={"user_id": user_id}, + ) + return 0 + zip_path = os.path.join( download_dir, f"retroarch-batch-{datetime.now().strftime('%Y%m%d%H%M%S')}.zip" ) @@ -236,6 +262,7 @@ def scan_webdav_for_retroarch(webdav_client, user_id): imp = RetroarchImport.objects.create( user_id=user_id, original_filename=f"batch-{len(downloaded)}-files", + files_hash=content_hash, ) with open(zip_path, "rb") as f: imp.lrtl_file.save( @@ -243,9 +270,10 @@ def scan_webdav_for_retroarch(webdav_client, user_id): ) process_retroarch_import.delay(imp.id) logger.info( - "Queued retroarch import %s with %d file(s)", + "Queued retroarch import %s with %d file(s) (hash=%s)", imp.uuid, len(downloaded), + content_hash[:12], ) return 1 finally: diff --git a/vrobbler/apps/scrobbles/migrations/0080_retroarchimport_files_hash.py b/vrobbler/apps/scrobbles/migrations/0080_retroarchimport_files_hash.py new file mode 100644 index 0000000..60901d7 --- /dev/null +++ b/vrobbler/apps/scrobbles/migrations/0080_retroarchimport_files_hash.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.29 on 2026-05-22 16:24 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("scrobbles", "0079_retroarchimport_lrtl_file"), + ] + + operations = [ + migrations.AddField( + model_name="retroarchimport", + name="files_hash", + field=models.CharField(blank=True, max_length=64, null=True), + ), + ] diff --git a/vrobbler/apps/scrobbles/models.py b/vrobbler/apps/scrobbles/models.py index 5e09cd1..ca8e7cf 100644 --- a/vrobbler/apps/scrobbles/models.py +++ b/vrobbler/apps/scrobbles/models.py @@ -401,6 +401,7 @@ class RetroarchImport(BaseFileImportMixin): original_filename = models.CharField(max_length=255, **BNULL) lrtl_file = models.FileField(upload_to="scrobbles/lrtl_file/", **BNULL) + files_hash = models.CharField(max_length=64, **BNULL) def process(self, import_all=False, force=False): """Import scrobbles found on Retroarch"""