diff --git a/vrobbler/apps/scrobbles/management/commands/fix_playback_position.py b/vrobbler/apps/scrobbles/management/commands/fix_playback_position.py new file mode 100644 index 0000000..8ba8391 --- /dev/null +++ b/vrobbler/apps/scrobbles/management/commands/fix_playback_position.py @@ -0,0 +1,69 @@ +from datetime import timedelta + +from django.core.management.base import BaseCommand +from django.db.models import F, Q + +from vrobbler.apps.scrobbles.models import Scrobble + + +class Command(BaseCommand): + help = "Recalculate playback_position_seconds for scrobbles of a given media type" + + def add_arguments(self, parser): + parser.add_argument( + "media_type", + type=str, + help="Media type to fix (e.g., Video, Track, VideoGame)", + ) + parser.add_argument( + "--dry-run", + action="store_true", + help="Show what would be changed without making changes", + ) + + def handle(self, *args, **options): + media_type = options["media_type"] + dry_run = options["dry_run"] + + valid_types = [choice[0] for choice in Scrobble.MediaType.choices] + if media_type not in valid_types: + self.stdout.write( + self.style.ERROR( + f"Invalid media_type '{media_type}'. Valid types: {', '.join(valid_types)}" + ) + ) + return + + scrobbles = Scrobble.objects.filter( + media_type=media_type, + timestamp__isnull=False, + stop_timestamp__isnull=False, + ) + + total = scrobbles.count() + self.stdout.write(f"Found {total} scrobbles of type '{media_type}'") + + updated = 0 + for scrobble in scrobbles.iterator(): + calculated = int( + (scrobble.stop_timestamp - scrobble.timestamp).total_seconds() + ) + if scrobble.playback_position_seconds != calculated: + self.stdout.write( + f" Scrobble {scrobble.id}: {scrobble.playback_position_seconds} -> {calculated}" + ) + if not dry_run: + scrobble.playback_position_seconds = calculated + scrobble.save(update_fields=["playback_position_seconds"]) + updated += 1 + + if dry_run: + self.stdout.write( + self.style.WARNING( + f"Dry run: would update {updated} scrobbles. Use without --dry-run to apply." + ) + ) + else: + self.stdout.write( + self.style.SUCCESS(f"Updated {updated} scrobbles") + )