Files
vrobbler/vrobbler/apps/scrobbles/tasks.py

206 lines
6.1 KiB
Python

import logging
from datetime import timedelta
from celery import shared_task
from charts.utils import (
build_charts_since,
build_daily_charts,
build_monthly_charts,
build_weekly_charts,
build_yearly_charts,
)
from django.apps import apps
from django.contrib.auth import get_user_model
from django.utils import timezone
logger = logging.getLogger(__name__)
User = get_user_model()
MEDIA_TYPES = [
"artist",
"album",
"track",
"tv_series",
"video",
"podcast",
"board_game",
"trail",
"food",
"book",
]
@shared_task
def check_twitch_channels_for_vods():
"""Check recent Twitch channel scrobbles for matching VODs."""
from scrobbles.models import Scrobble
cutoff = timezone.now() - timedelta(hours=48)
channel_scrobbles = Scrobble.objects.filter(
media_type=Scrobble.MediaType.CHANNEL,
timestamp__gte=cutoff,
)
logger.info(f"[twitch_vods] Checking {channel_scrobbles.count()} channel scrobbles")
matched_count = 0
for scrobble in channel_scrobbles:
if not scrobble.channel or not scrobble.channel.twitch_id:
continue
try:
from videos.sources.twitch import get_channel_vods
vods = get_channel_vods(scrobble.channel.twitch_id)
scrobble_time = scrobble.timestamp
for vod in vods:
if not vod.get("published_at"):
continue
from videos.sources import twitch as twitch_source
vod_time = twitch_source.parse_twitch_datetime(vod["published_at"])
if not vod_time:
continue
time_diff = (vod_time - scrobble_time).total_seconds()
if 0 < time_diff <= 86400:
from videos.models import Video
video = Video.get_from_twitch_id(vod["id"], overwrite=True)
if video:
video.scrobble_for_user(
scrobble.user_id,
status="stopped",
source="Twitch VOD",
)
matched_count += 1
logger.info(
f"[twitch_vods] Matched VOD {vod['id']} for channel scrobble {scrobble.id}"
)
break
except Exception as e:
logger.warning(
f"[twitch_vods] Error processing scrobble {scrobble.id}: {e}"
)
logger.info(f"[twitch_vods] Matched {matched_count} VODs")
@shared_task
def process_retroarch_import(import_id):
RetroarchImport = apps.get_model("scrobbles", "RetroarchImport")
retroarch_import = RetroarchImport.objects.filter(id=import_id).first()
if not retroarch_import:
logger.warn(f"RetroarchImport not found with id {import_id}")
retroarch_import.process()
@shared_task
def process_lastfm_import(import_id):
LastFmImport = apps.get_model("scrobbles", "LastFMImport")
lastfm_import = LastFmImport.objects.filter(id=import_id).first()
if not lastfm_import:
logger.warn(f"LastFmImport not found with id {import_id}")
lastfm_import.process()
@shared_task
def process_tsv_import(import_id):
model_path = "scrobbles.AudioscrobblerTSVImport"
AudioScrobblerTSVImport = apps.get_model(model_path)
tsv_import = AudioScrobblerTSVImport.objects.filter(id=import_id).first()
if not tsv_import:
logger.warn(f"AudioScrobblerTSVImport not found with id {import_id}")
tsv_import.process()
@shared_task
def process_koreader_import(import_id):
KoReaderImport = apps.get_model("scrobbles", "KoReaderImport")
koreader_import = KoReaderImport.objects.filter(id=import_id).first()
if not koreader_import:
logger.warn(f"KOReaderImport not found with id {import_id}")
koreader_import.process()
@shared_task
def create_yesterdays_charts():
"""Build/update charts for all users starting from last known record."""
for user in User.objects.all():
build_charts_since(user)
@shared_task
def build_charts_for_user(user_id):
"""Build charts for a specific user starting from last known record."""
user = User.objects.filter(id=user_id).first()
if not user:
logger.error(f"User with id {user_id} not found")
return
logger.info(f"Building charts for {user}")
build_charts_since(user)
@shared_task
def rebuild_weekly_charts():
"""Rebuild weekly charts for all users for the just-completed week."""
now = timezone.now()
year, week, _ = now.isocalendar()
for user in User.objects.all():
build_weekly_charts(user, year, week, MEDIA_TYPES)
logger.info(f"Rebuilt weekly charts for week {week}, {year}")
@shared_task
def rebuild_monthly_charts():
"""Rebuild monthly charts for all users for the just-completed month."""
now = timezone.now()
year, month = now.year, now.month
if month == 1:
month = 12
year -= 1
else:
month -= 1
for user in User.objects.all():
build_monthly_charts(user, year, month, MEDIA_TYPES)
logger.info(f"Rebuilt monthly charts for {month}/{year}")
@shared_task
def rebuild_yearly_charts():
"""Rebuild yearly charts for all users for the just-completed year."""
now = timezone.now()
year = now.year - 1
for user in User.objects.all():
build_yearly_charts(user, year, MEDIA_TYPES)
logger.info(f"Rebuilt yearly charts for {year}")
@shared_task
def update_charts_for_timestamp(user_id, year, month, day, week):
"""Update charts for a specific time period."""
user = User.objects.filter(id=user_id).first()
if not user:
logger.error(f"User with id {user_id} not found")
return
try:
build_daily_charts(user, year, month, day, MEDIA_TYPES)
build_weekly_charts(user, year, week, MEDIA_TYPES)
build_monthly_charts(user, year, month, MEDIA_TYPES)
build_yearly_charts(user, year, MEDIA_TYPES)
date_str = f"{year}-{month:02d}-{day:02d}"
logger.info(f"[charts] Updated charts for {user} on {date_str}")
except Exception as e:
logger.error(f"[charts] Failed to update charts: {e}")