Update importing to include some logging
This commit is contained in:
@ -13,7 +13,7 @@ class ScrobbleInline(admin.TabularInline):
|
||||
@admin.register(AudioScrobblerTSVImport)
|
||||
class AudioScrobblerTSVImportAdmin(admin.ModelAdmin):
|
||||
date_hierarchy = "created"
|
||||
list_display = ("id", "tsv_file", "created")
|
||||
list_display = ("uuid", "created", "process_count", "tsv_file")
|
||||
ordering = ("-created",)
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.1.5 on 2023-02-03 22:53
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('scrobbles', '0013_audioscrobblertsvimport_processed_on'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='audioscrobblertsvimport',
|
||||
name='process_log',
|
||||
field=models.TextField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
@ -0,0 +1,29 @@
|
||||
# Generated by Django 4.1.5 on 2023-02-03 23:36
|
||||
|
||||
from django.db import migrations, models
|
||||
import scrobbles.models
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('scrobbles', '0014_audioscrobblertsvimport_process_log'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='audioscrobblertsvimport',
|
||||
name='uuid',
|
||||
field=models.UUIDField(default=uuid.uuid4, editable=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='audioscrobblertsvimport',
|
||||
name='tsv_file',
|
||||
field=models.FileField(
|
||||
blank=True,
|
||||
null=True,
|
||||
upload_to=scrobbles.models.AudioScrobblerTSVImport.get_path,
|
||||
),
|
||||
),
|
||||
]
|
||||
@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.1.5 on 2023-02-03 23:44
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('scrobbles', '0015_audioscrobblertsvimport_uuid_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='audioscrobblertsvimport',
|
||||
name='process_count',
|
||||
field=models.IntegerField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
@ -18,18 +18,27 @@ BNULL = {"blank": True, "null": True}
|
||||
|
||||
|
||||
class AudioScrobblerTSVImport(TimeStampedModel):
|
||||
tsv_file = models.FileField(
|
||||
upload_to="audioscrobbler-uploads/%Y/%m-%d/", **BNULL
|
||||
)
|
||||
def get_path(instance, filename):
|
||||
extension = filename.split('.')[-1]
|
||||
uuid = instance.uuid
|
||||
return f'audioscrobbler-uploads/{uuid}.{extension}'
|
||||
|
||||
uuid = models.UUIDField(editable=False, default=uuid4)
|
||||
tsv_file = models.FileField(upload_to=get_path, **BNULL)
|
||||
processed_on = models.DateTimeField(**BNULL)
|
||||
process_log = models.TextField(**BNULL)
|
||||
process_count = models.IntegerField(**BNULL)
|
||||
|
||||
def __str__(self):
|
||||
return f"Audioscrobbler TSV upload: {self.tsv_file.path}"
|
||||
if self.tsv_file:
|
||||
return f"Audioscrobbler TSV upload: {self.tsv_file.path}"
|
||||
return f"Audioscrobbler TSV upload {self.id}"
|
||||
|
||||
def save(self, **kwargs):
|
||||
"""On save, attempt to import the TSV file"""
|
||||
|
||||
return super().save(**kwargs)
|
||||
super().save(**kwargs)
|
||||
self.process()
|
||||
return
|
||||
|
||||
def process(self, force=False):
|
||||
from scrobbles.tsv import process_audioscrobbler_tsv_file
|
||||
@ -38,9 +47,21 @@ class AudioScrobblerTSVImport(TimeStampedModel):
|
||||
logger.info(f"{self} already processed on {self.processed_on}")
|
||||
return
|
||||
|
||||
process_audioscrobbler_tsv_file(self.tsv_file.path)
|
||||
scrobbles = process_audioscrobbler_tsv_file(self.tsv_file.path)
|
||||
if scrobbles:
|
||||
self.process_log = f"Created {len(scrobbles)} scrobbles"
|
||||
for scrobble in scrobbles:
|
||||
scrobble_str = f"{scrobble.id}\t{scrobble.timestamp}\t{scrobble.track.title}\t"
|
||||
self.process_log += f"\n{scrobble_str}"
|
||||
self.process_count = len(scrobbles)
|
||||
else:
|
||||
self.process_log = f"Created no new scrobbles"
|
||||
self.process_count = 0
|
||||
|
||||
self.processed_on = timezone.now()
|
||||
self.save(update_fields=['processed_on'])
|
||||
self.save(
|
||||
update_fields=['processed_on', 'process_count', 'process_log']
|
||||
)
|
||||
|
||||
|
||||
class ChartRecord(TimeStampedModel):
|
||||
|
||||
@ -1,5 +1,11 @@
|
||||
from rest_framework import serializers
|
||||
from scrobbles.models import Scrobble
|
||||
from scrobbles.models import Scrobble, AudioScrobblerTSVImport
|
||||
|
||||
|
||||
class AudioScrobblerTSVImportSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = AudioScrobblerTSVImport
|
||||
fields = ('tsv_file',)
|
||||
|
||||
|
||||
class ScrobbleSerializer(serializers.ModelSerializer):
|
||||
|
||||
@ -96,3 +96,4 @@ def process_audioscrobbler_tsv_file(file_path):
|
||||
f"Created {len(created)} scrobbles",
|
||||
extra={'created_scrobbles': created},
|
||||
)
|
||||
return created
|
||||
|
||||
@ -7,6 +7,11 @@ urlpatterns = [
|
||||
path('', views.scrobble_endpoint, name='api-list'),
|
||||
path('finish/<slug:uuid>', views.scrobble_finish, name='finish'),
|
||||
path('cancel/<slug:uuid>', views.scrobble_cancel, name='cancel'),
|
||||
path(
|
||||
'audioscrobbler-file-upload/',
|
||||
views.import_audioscrobbler_file,
|
||||
name='audioscrobbler-file-upload',
|
||||
),
|
||||
path('jellyfin/', views.jellyfin_websocket, name='jellyfin-websocket'),
|
||||
path('mopidy/', views.mopidy_websocket, name='mopidy-websocket'),
|
||||
]
|
||||
|
||||
@ -11,7 +11,12 @@ from django.views.decorators.csrf import csrf_exempt
|
||||
from django.views.generic import FormView
|
||||
from django.views.generic.list import ListView
|
||||
from rest_framework import status
|
||||
from rest_framework.decorators import api_view, permission_classes
|
||||
from rest_framework.decorators import (
|
||||
api_view,
|
||||
parser_classes,
|
||||
permission_classes,
|
||||
)
|
||||
from rest_framework.parsers import MultiPartParser
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
from scrobbles.constants import (
|
||||
@ -29,7 +34,10 @@ from scrobbles.scrobblers import (
|
||||
mopidy_scrobble_podcast,
|
||||
mopidy_scrobble_track,
|
||||
)
|
||||
from scrobbles.serializers import ScrobbleSerializer
|
||||
from scrobbles.serializers import (
|
||||
AudioScrobblerTSVImportSerializer,
|
||||
ScrobbleSerializer,
|
||||
)
|
||||
from scrobbles.thesportsdb import lookup_event_from_thesportsdb
|
||||
|
||||
from vrobbler.apps.music.aggregators import (
|
||||
@ -187,6 +195,29 @@ def mopidy_websocket(request):
|
||||
return Response({'scrobble_id': scrobble.id}, status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
@permission_classes([IsAuthenticated])
|
||||
@api_view(['POST'])
|
||||
@parser_classes([MultiPartParser])
|
||||
def import_audioscrobbler_file(request):
|
||||
"""Takes a TSV file in the Audioscrobbler format, saves it and processes the
|
||||
scrobbles.
|
||||
"""
|
||||
scrobbles_created = []
|
||||
# tsv_file = request.FILES[0]
|
||||
|
||||
file_serializer = AudioScrobblerTSVImportSerializer(data=request.data)
|
||||
if file_serializer.is_valid():
|
||||
import_file = file_serializer.save()
|
||||
return Response(
|
||||
{'scrobble_ids': scrobbles_created}, status=status.HTTP_200_OK
|
||||
)
|
||||
else:
|
||||
return Response(
|
||||
file_serializer.errors, status=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
@permission_classes([IsAuthenticated])
|
||||
@api_view(['GET'])
|
||||
|
||||
@ -179,7 +179,11 @@
|
||||
{% for scrobble in object_list %}
|
||||
<tr>
|
||||
<td>{{scrobble.timestamp|naturaltime}}</td>
|
||||
{% if scrobble.track.album.cover_image %}
|
||||
<td><img src="{{scrobble.track.album.cover_image.url}}" width=50 height=50 style="border:1px solid black;" /></td>
|
||||
{% else %}
|
||||
<td>{{scrobble.track.album.name}}</td>
|
||||
{% endif %}
|
||||
<td>{{scrobble.track.title}}</td>
|
||||
<td>{{scrobble.track.artist.name}}</td>
|
||||
</tr>
|
||||
|
||||
Reference in New Issue
Block a user