Bug Description
When attempting to add a season to the tracker (e.g. via the Season detail page / track modal), POST /media_save crashes with HTTP 500:
django.db.utils.IntegrityError: duplicate key value violates unique constraint "app_tv_unique_item_user"
DETAIL: Key (user_id, item_id)=(1, 12457) already exists.
Because the form submission fails with a 500 error, browser navigation falls back to GET /media_save, displaying a blank page with HTTP ERROR 405 (Method Not Allowed).
Root Cause
- In
app/models/tv.py -> Season.get_tv():
is_anime_bucket = self.item.library_media_type == MediaTypes.ANIME.value
def _bucket_scoped(queryset):
if is_anime_bucket:
return queryset.filter(item__library_media_type=MediaTypes.ANIME.value)
return queryset.exclude(item__library_media_type=MediaTypes.ANIME.value)
- If a show was originally created in the library under
library_media_type="anime", but a new season is accessed/created via a route/metadata where library_media_type="tv" (or vice-versa), _bucket_scoped() raises TV.DoesNotExist because the existing TV row has the other bucket type.
- In
except TV.DoesNotExist:, get_tv() assumes no TV record exists for the user and tries to create a new TV(item=item, user=self.user).
- However,
Item.objects.get_or_create(...) finds the existing parent show Item, so saving the new TV instance attempts to insert a duplicate (user_id, item_id) pair, violating the UniqueConstraint on TV.
Additional Bug in Item.fetch_releases()
Item.fetch_releases() in app/models/item.py calls events.tasks.reload_calendar.apply_async(...), but events/__init__.py is empty and app/models/item.py only does import events, causing:
AttributeError: module 'events' has no attribute 'tasks'
Proposed Fix
- In
app/models/tv.py -> Season.get_tv():
Add a fallback check before creating a new TV instance:
except TV.DoesNotExist:
existing_tv = (
TV.objects.filter(
item__media_id=self.item.media_id,
item__media_type=MediaTypes.TV.value,
item__season_number=None,
item__source=self.item.source,
user=self.user,
)
.order_by("id")
.first()
)
if existing_tv is not None:
return existing_tv
- In
events/__init__.py:
Add from . import tasks so events.tasks is always available when importing events.
Bug Description
When attempting to add a season to the tracker (e.g. via the Season detail page / track modal),
POST /media_savecrashes withHTTP 500:Because the form submission fails with a 500 error, browser navigation falls back to
GET /media_save, displaying a blank page withHTTP ERROR 405 (Method Not Allowed).Root Cause
app/models/tv.py->Season.get_tv():library_media_type="anime", but a new season is accessed/created via a route/metadata wherelibrary_media_type="tv"(or vice-versa),_bucket_scoped()raisesTV.DoesNotExistbecause the existingTVrow has the other bucket type.except TV.DoesNotExist:,get_tv()assumes noTVrecord exists for the user and tries to create a newTV(item=item, user=self.user).Item.objects.get_or_create(...)finds the existing parent showItem, so saving the newTVinstance attempts to insert a duplicate(user_id, item_id)pair, violating theUniqueConstraintonTV.Additional Bug in
Item.fetch_releases()Item.fetch_releases()inapp/models/item.pycallsevents.tasks.reload_calendar.apply_async(...), butevents/__init__.pyis empty andapp/models/item.pyonly doesimport events, causing:AttributeError: module 'events' has no attribute 'tasks'Proposed Fix
app/models/tv.py->Season.get_tv():Add a fallback check before creating a new
TVinstance:events/__init__.py:Add
from . import taskssoevents.tasksis always available when importingevents.