Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cd5dc25642 | |||
| 9c2355978e | |||
| 4b9b785e50 | |||
| 050b2b9d77 | |||
| d12cca304f | |||
| 8603bbd5cb | |||
| 749e74a54c | |||
| 7b3692ef7b | |||
| c49f6a1740 | |||
| 1d813e4643 |
16
PROJECT.org
16
PROJECT.org
@ -92,7 +92,7 @@ fetching and simple saving.
|
||||
:LOGBOOK:
|
||||
CLOCK: [2025-07-09 Wed 09:55]--[2025-07-09 Wed 10:15] => 0:20
|
||||
:END:
|
||||
* Backlog [4/27]
|
||||
* Backlog [2/25]
|
||||
** TODO [#C] Create small utility to clean up tracks scrobbled with wonky playback times :vrobbler:personal:bug:music:scrobbles:
|
||||
** TODO [#C] Move to using more robust mopidy-webhooks pacakge form pypi :utility:improvement:
|
||||
:PROPERTIES:
|
||||
@ -414,7 +414,6 @@ Could be as simple as a JSON form on the scrobble detail page (do I have have on
|
||||
** TODO [#B] Add webdav syncing to retroarch imports :vrobbler:videogames:webdav:feature:project:personal:
|
||||
** TODO [#B] Add CSV endpoint for book scrobbles that LibraryThing can ingest :personal:project:books:feature:export:
|
||||
https://app.todoist.com/app/task/add-a-csv-endpoint-for-users-book-reads-that-library-thing-can-ingest-6X7QPMRp265xMXqg#comment-6X7QrXq6gJjMP4hg
|
||||
** TODO [#B] Add youtube link in place of IMDB on video detail page :vrobbler:feature:videos:personal:project:
|
||||
** TODO [#B] Fix PuzzleLogData has no attribute form :vrobbler:puzzles:personal:project:logdata:
|
||||
** TODO [#B] Scrape ComicBookRoundUp ratings for comic book metadata :vrobbler:books:feature:comicbook:personal:project:
|
||||
|
||||
@ -446,6 +445,19 @@ https://life.lab.unbl.ink/scrobble/e39779c8-62a5-46a6-bdef-fb7662810dc6/start/
|
||||
|
||||
This may have already been resolved ... need to just confirm it.
|
||||
** TODO [#A] Find page numbers for comic books from ComicVine :vrobbler:feature:books:personal:project:
|
||||
* Version 35.0 [3/3]
|
||||
** DONE [#B] Add youtube link in place of IMDB on video detail page :vrobbler:feature:videos:personal:project:
|
||||
:PROPERTIES:
|
||||
:ID: 84064bd6-2258-a4de-f048-b131db9465c9
|
||||
:END:
|
||||
** DONE [#B] Add missing API lookups to resolve broken scrobbles endpoint :vrobbler:feature:api:scrobbles:personal:project:
|
||||
:PROPERTIES:
|
||||
:ID: 0f668a54-f587-3b17-353e-3a56969d3a82
|
||||
:END:
|
||||
** DONE [#A] IMDB lookups are not working :vrobbler:bug:videos:personal:project:
|
||||
:PROPERTIES:
|
||||
:ID: d1ba1ca1-509b-13a9-1307-b2dc94a2eafe
|
||||
:END:
|
||||
* Version 34.0 [4/4]
|
||||
** DONE [#A] Use bgg-api for BoardGameGeek lookups :vrobbler:feature:boardgames:personal:project:
|
||||
:PROPERTIES:
|
||||
|
||||
5141
poetry.lock
generated
5141
poetry.lock
generated
File diff suppressed because it is too large
Load Diff
@ -5,7 +5,7 @@ description = ""
|
||||
authors = ["Colin Powell <colin@unbl.ink>"]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = ">=3.9,<3.12"
|
||||
python = ">=3.11,<3.14"
|
||||
Django = "^4.0.3"
|
||||
django-extensions = "^3.1.5"
|
||||
python-dateutil = "^2.8.2"
|
||||
@ -16,8 +16,8 @@ httpx = "<=0.27.2"
|
||||
djangorestframework = "^3.13.1"
|
||||
Markdown = "^3.3.6"
|
||||
django-filter = "^21.1"
|
||||
Pillow = "^9.0.1"
|
||||
psycopg2 = "^2.9.3"
|
||||
Pillow = "^10.0.0"
|
||||
psycopg2 = "2.9.10"
|
||||
dj-database-url = "^0.5.0"
|
||||
django-mathfilters = "^1.0.0"
|
||||
django-allauth = "^0.50.0"
|
||||
@ -28,7 +28,7 @@ django-markdownify = "^0.9.1"
|
||||
gunicorn = "^20.1.0"
|
||||
django-simple-history = "^3.1.1"
|
||||
musicbrainzngs = "^0.7.1"
|
||||
cinemagoer = "^2022.12.27"
|
||||
cinemagoerng = {git = "https://github.com/cinemagoer/cinemagoerng"}
|
||||
pysportsdb = "^0.1.0"
|
||||
pytz = "^2022.7.1"
|
||||
django-redis = "^5.2.0"
|
||||
@ -41,11 +41,11 @@ beautifulsoup4 = "^4.11.2"
|
||||
django-storages = "^1.13.2"
|
||||
stream-sqlite = "^0.0.41"
|
||||
ipython = "^8.14.0"
|
||||
pendulum = "^2.1.2"
|
||||
pendulum = "^3"
|
||||
trafilatura = "^1.6.3"
|
||||
django-imagekit = "^5.0.0"
|
||||
thefuzz = "^0.22.1"
|
||||
dataclass-wizard = "0.22.0"
|
||||
dataclass-wizard = "^0.35.0"
|
||||
webdavclient3 = "^3.14.6"
|
||||
boto3 = "^1.35.37"
|
||||
urllib3 = "<2"
|
||||
|
||||
0
vrobbler/apps/beers/api/__init__.py
Normal file
0
vrobbler/apps/beers/api/__init__.py
Normal file
18
vrobbler/apps/beers/api/serializers.py
Normal file
18
vrobbler/apps/beers/api/serializers.py
Normal file
@ -0,0 +1,18 @@
|
||||
from rest_framework import serializers
|
||||
from beers.models import Beer, BeerProducer, BeerStyle
|
||||
|
||||
|
||||
class BeerSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = Beer
|
||||
fields = "__all__"
|
||||
|
||||
class BeerProducerSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = BeerProducer
|
||||
fields = "__all__"
|
||||
|
||||
class BeerStyleSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = BeerStyle
|
||||
fields = "__all__"
|
||||
19
vrobbler/apps/beers/api/views.py
Normal file
19
vrobbler/apps/beers/api/views.py
Normal file
@ -0,0 +1,19 @@
|
||||
from rest_framework import permissions, viewsets
|
||||
from beers.api import serializers
|
||||
from beers import models
|
||||
|
||||
|
||||
class BeerViewSet(viewsets.ModelViewSet):
|
||||
queryset = models.Beer.objects.all().order_by("-created")
|
||||
serializer_class = serializers.BeerSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
|
||||
class BeerProducerViewSet(viewsets.ModelViewSet):
|
||||
queryset = models.BeerProducer.objects.all().order_by("-created")
|
||||
serializer_class = serializers.BeerProducerSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
|
||||
class BeerStyleViewSet(viewsets.ModelViewSet):
|
||||
queryset = models.BeerStyle.objects.all().order_by("-created")
|
||||
serializer_class = serializers.BeerStyleSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
22
vrobbler/apps/boardgames/api/serializers.py
Normal file
22
vrobbler/apps/boardgames/api/serializers.py
Normal file
@ -0,0 +1,22 @@
|
||||
from boardgames import models
|
||||
from rest_framework import serializers
|
||||
|
||||
class BoardGameDesignerSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = models.BoardGameDesigner
|
||||
fields = "__all__"
|
||||
|
||||
class BoardGamePublisherSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = models.BoardGamePublisher
|
||||
fields = "__all__"
|
||||
|
||||
class BoardGameLocationSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = models.BoardGameLocation
|
||||
fields = "__all__"
|
||||
|
||||
class BoardGameSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = models.BoardGame
|
||||
fields = "__all__"
|
||||
28
vrobbler/apps/boardgames/api/views.py
Normal file
28
vrobbler/apps/boardgames/api/views.py
Normal file
@ -0,0 +1,28 @@
|
||||
from rest_framework import permissions, viewsets
|
||||
|
||||
from boardgames.api import serializers
|
||||
from boardgames import models
|
||||
|
||||
|
||||
class BoardGameDesignerViewSet(viewsets.ModelViewSet):
|
||||
queryset = models.BoardGameDesigner.objects.all().order_by("-created")
|
||||
serializer_class = serializers.BoardGameDesignerSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
|
||||
|
||||
class BoardGamePublisherViewSet(viewsets.ModelViewSet):
|
||||
queryset = models.BoardGamePublisher.objects.all().order_by("-created")
|
||||
serializer_class = serializers.BoardGamePublisherSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
|
||||
|
||||
class BoardGameLocationViewSet(viewsets.ModelViewSet):
|
||||
queryset = models.BoardGameLocation.objects.all().order_by("-created")
|
||||
serializer_class = serializers.BoardGameLocationSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
|
||||
|
||||
class BoardGameViewSet(viewsets.ModelViewSet):
|
||||
queryset = models.BoardGame.objects.all().order_by("-created")
|
||||
serializer_class = serializers.BoardGameSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
@ -1,19 +1,16 @@
|
||||
from rest_framework import permissions, viewsets
|
||||
|
||||
from books.api.serializers import (
|
||||
AuthorSerializer,
|
||||
BookSerializer,
|
||||
)
|
||||
from books.models import Author, Book
|
||||
from books.api import serializers
|
||||
from books import models
|
||||
|
||||
|
||||
class AuthorViewSet(viewsets.ModelViewSet):
|
||||
queryset = Author.objects.all().order_by("-created")
|
||||
serializer_class = AuthorSerializer
|
||||
queryset = models.Author.objects.all().order_by("-created")
|
||||
serializer_class = serializers.AuthorSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
|
||||
|
||||
class BookViewSet(viewsets.ModelViewSet):
|
||||
queryset = Book.objects.all().order_by("-created")
|
||||
serializer_class = BookSerializer
|
||||
queryset = models.Book.objects.all().order_by("-created")
|
||||
serializer_class = serializers.BookSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
|
||||
@ -286,11 +286,11 @@ def build_scrobbles_from_book_map(
|
||||
)
|
||||
|
||||
# Adjust for Daylight Saving Time
|
||||
if timestamp.dst() == timedelta(
|
||||
0
|
||||
) or stop_timestamp.dst() == timedelta(0):
|
||||
timestamp = timestamp - timedelta(hours=1)
|
||||
stop_timestamp = stop_timestamp - timedelta(hours=1)
|
||||
#if timestamp.dst() == timedelta(
|
||||
# 0
|
||||
#) or stop_timestamp.dst() == timedelta(0):
|
||||
# timestamp = timestamp - timedelta(hours=1)
|
||||
# stop_timestamp = stop_timestamp - timedelta(hours=1)
|
||||
|
||||
scrobble = Scrobble.objects.filter(
|
||||
timestamp=timestamp,
|
||||
|
||||
0
vrobbler/apps/bricksets/api/__init__.py
Normal file
0
vrobbler/apps/bricksets/api/__init__.py
Normal file
8
vrobbler/apps/bricksets/api/serializers.py
Normal file
8
vrobbler/apps/bricksets/api/serializers.py
Normal file
@ -0,0 +1,8 @@
|
||||
from rest_framework import serializers
|
||||
from bricksets.models import BrickSet
|
||||
|
||||
|
||||
class BrickSetSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = BrickSet
|
||||
fields = "__all__"
|
||||
9
vrobbler/apps/bricksets/api/views.py
Normal file
9
vrobbler/apps/bricksets/api/views.py
Normal file
@ -0,0 +1,9 @@
|
||||
from rest_framework import permissions, viewsets
|
||||
from bricksets.api.serializers import BrickSetSerializer
|
||||
from bricksets.models import BrickSet
|
||||
|
||||
|
||||
class BrickSetViewSet(viewsets.ModelViewSet):
|
||||
queryset = BrickSet.objects.all().order_by("-created")
|
||||
serializer_class = BrickSetSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
0
vrobbler/apps/foods/api/__init__.py
Normal file
0
vrobbler/apps/foods/api/__init__.py
Normal file
14
vrobbler/apps/foods/api/serializers.py
Normal file
14
vrobbler/apps/foods/api/serializers.py
Normal file
@ -0,0 +1,14 @@
|
||||
from rest_framework import serializers
|
||||
from foods import models
|
||||
|
||||
|
||||
class FoodCategorySerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = models.FoodCategory
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class FoodSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = models.Food
|
||||
fields = "__all__"
|
||||
21
vrobbler/apps/foods/api/views.py
Normal file
21
vrobbler/apps/foods/api/views.py
Normal file
@ -0,0 +1,21 @@
|
||||
from rest_framework import permissions, viewsets
|
||||
from foods.api.serializers import (
|
||||
FoodSerializer,
|
||||
FoodCategorySerializer,
|
||||
)
|
||||
from foods.models import (
|
||||
FoodCategory,
|
||||
Food,
|
||||
)
|
||||
|
||||
|
||||
class FoodCategoryViewSet(viewsets.ModelViewSet):
|
||||
queryset = FoodCategory.objects.all().order_by("-created")
|
||||
serializer_class = FoodCategorySerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
|
||||
|
||||
class FoodViewSet(viewsets.ModelViewSet):
|
||||
queryset = Food.objects.all().order_by("-created")
|
||||
serializer_class = FoodSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
8
vrobbler/apps/lifeevents/api/serializers.py
Normal file
8
vrobbler/apps/lifeevents/api/serializers.py
Normal file
@ -0,0 +1,8 @@
|
||||
from lifeevents.models import LifeEvent
|
||||
from rest_framework import serializers
|
||||
|
||||
|
||||
class LifeEventSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = LifeEvent
|
||||
fields = "__all__"
|
||||
10
vrobbler/apps/lifeevents/api/views.py
Normal file
10
vrobbler/apps/lifeevents/api/views.py
Normal file
@ -0,0 +1,10 @@
|
||||
from rest_framework import permissions, viewsets
|
||||
|
||||
from lifeevents.api import serializers
|
||||
from lifeevents import models
|
||||
|
||||
|
||||
class LifeEventViewSet(viewsets.ModelViewSet):
|
||||
queryset = models.LifeEvent.objects.all().order_by("-created")
|
||||
serializer_class = serializers.LifeEventSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
8
vrobbler/apps/locations/api/serializers.py
Normal file
8
vrobbler/apps/locations/api/serializers.py
Normal file
@ -0,0 +1,8 @@
|
||||
from locations import models
|
||||
from rest_framework import serializers
|
||||
|
||||
|
||||
class GeoLocationSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = models.GeoLocation
|
||||
fields = "__all__"
|
||||
9
vrobbler/apps/locations/api/views.py
Normal file
9
vrobbler/apps/locations/api/views.py
Normal file
@ -0,0 +1,9 @@
|
||||
from rest_framework import permissions, viewsets
|
||||
|
||||
from locations.api import serializers
|
||||
from locations import models
|
||||
|
||||
class GeoLocationViewSet(viewsets.ModelViewSet):
|
||||
queryset = models.GeoLocation.objects.all().order_by("-created")
|
||||
serializer_class = serializers.GeoLocationSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
0
vrobbler/apps/moods/api/__init__.py
Normal file
0
vrobbler/apps/moods/api/__init__.py
Normal file
8
vrobbler/apps/moods/api/serializers.py
Normal file
8
vrobbler/apps/moods/api/serializers.py
Normal file
@ -0,0 +1,8 @@
|
||||
from rest_framework import serializers
|
||||
from moods.models import Mood
|
||||
|
||||
|
||||
class MoodSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = Mood
|
||||
fields = "__all__"
|
||||
9
vrobbler/apps/moods/api/views.py
Normal file
9
vrobbler/apps/moods/api/views.py
Normal file
@ -0,0 +1,9 @@
|
||||
from rest_framework import permissions, viewsets
|
||||
from moods.api.serializers import MoodSerializer
|
||||
from moods.models import Mood
|
||||
|
||||
|
||||
class MoodViewSet(viewsets.ModelViewSet):
|
||||
queryset = Mood.objects.all().order_by("-created")
|
||||
serializer_class = MoodSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
17
vrobbler/apps/podcasts/api/serializers.py
Normal file
17
vrobbler/apps/podcasts/api/serializers.py
Normal file
@ -0,0 +1,17 @@
|
||||
from podcasts import models
|
||||
from rest_framework import serializers
|
||||
|
||||
class ProducerSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = models.Producer
|
||||
fields = "__all__"
|
||||
|
||||
class PodcastEpisodeSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = models.PodcastEpisode
|
||||
fields = "__all__"
|
||||
|
||||
class PodcastSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = models.Podcast
|
||||
fields = "__all__"
|
||||
20
vrobbler/apps/podcasts/api/views.py
Normal file
20
vrobbler/apps/podcasts/api/views.py
Normal file
@ -0,0 +1,20 @@
|
||||
from rest_framework import permissions, viewsets
|
||||
|
||||
from podcasts.api import serializers
|
||||
from podcasts import models
|
||||
|
||||
|
||||
class ProducerViewSet(viewsets.ModelViewSet):
|
||||
queryset = models.Producer.objects.all().order_by("-created")
|
||||
serializer_class = serializers.ProducerSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
|
||||
class PodcastViewSet(viewsets.ModelViewSet):
|
||||
queryset = models.Podcast.objects.all().order_by("-created")
|
||||
serializer_class = serializers.PodcastSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
|
||||
class PodcastEpisodeViewSet(viewsets.ModelViewSet):
|
||||
queryset = models.PodcastEpisode.objects.all().order_by("-created")
|
||||
serializer_class = serializers.PodcastEpisodeSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
12
vrobbler/apps/puzzles/api/serializers.py
Normal file
12
vrobbler/apps/puzzles/api/serializers.py
Normal file
@ -0,0 +1,12 @@
|
||||
from puzzles import models
|
||||
from rest_framework import serializers
|
||||
|
||||
class PuzzleManufacturerSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = models.PuzzleManufacturer
|
||||
fields = "__all__"
|
||||
|
||||
class PuzzleSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = models.Puzzle
|
||||
fields = "__all__"
|
||||
15
vrobbler/apps/puzzles/api/views.py
Normal file
15
vrobbler/apps/puzzles/api/views.py
Normal file
@ -0,0 +1,15 @@
|
||||
from rest_framework import permissions, viewsets
|
||||
|
||||
from puzzles.api import serializers
|
||||
from puzzles import models
|
||||
|
||||
class PuzzleManufacturerViewSet(viewsets.ModelViewSet):
|
||||
queryset = models.PuzzleManufacturer.objects.all().order_by("-created")
|
||||
serializer_class = serializers.PuzzleManufacturerSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
|
||||
|
||||
class PuzzleViewSet(viewsets.ModelViewSet):
|
||||
queryset = models.Puzzle.objects.all().order_by("-created")
|
||||
serializer_class = serializers.PuzzleSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
@ -167,7 +167,7 @@ def web_scrobbler_scrobble_media(
|
||||
|
||||
|
||||
def manual_scrobble_video(
|
||||
video_id: str, user_id: int, action: Optional[str] = None
|
||||
video_id: str, user_id: int, source: str = "IMDb", action: Optional[str] = None
|
||||
):
|
||||
if "tt" in video_id:
|
||||
video = Video.get_from_imdb_id(video_id)
|
||||
@ -176,7 +176,6 @@ def manual_scrobble_video(
|
||||
video = Video.get_from_youtube_id(video_id)
|
||||
|
||||
# When manually scrobbling, try finding a source from the series
|
||||
source = "Vrobbler"
|
||||
if video.tv_series:
|
||||
source = video.tv_series.preferred_source
|
||||
scrobble_dict = {
|
||||
@ -205,7 +204,7 @@ def manual_scrobble_video(
|
||||
|
||||
|
||||
def manual_scrobble_event(
|
||||
thesportsdb_id: str, user_id: int, action: Optional[str] = None
|
||||
thesportsdb_id: str, user_id: int, source: str = "TheSportsDB", action: Optional[str] = None
|
||||
):
|
||||
data_dict = lookup_event_from_thesportsdb(thesportsdb_id)
|
||||
|
||||
@ -220,7 +219,7 @@ def manual_scrobble_event(
|
||||
|
||||
|
||||
def manual_scrobble_video_game(
|
||||
hltb_id: str, user_id: int, action: Optional[str] = None
|
||||
hltb_id: str, user_id: int, source: str = "HLTB", action: Optional[str] = None
|
||||
):
|
||||
game = VideoGame.objects.filter(hltb_id=hltb_id).first()
|
||||
if not game:
|
||||
@ -242,7 +241,7 @@ def manual_scrobble_video_game(
|
||||
"user_id": user_id,
|
||||
"timestamp": timezone.now(),
|
||||
"playback_position_seconds": 0,
|
||||
"source": "Vrobbler",
|
||||
"source": source,
|
||||
"long_play_complete": False,
|
||||
}
|
||||
|
||||
@ -260,10 +259,9 @@ def manual_scrobble_video_game(
|
||||
|
||||
|
||||
def manual_scrobble_book(
|
||||
title: str, user_id: int, action: Optional[str] = None
|
||||
title: str, user_id: int, source: str = "Google Books", action: Optional[str] = None
|
||||
):
|
||||
log = {}
|
||||
source = "Vrobbler"
|
||||
page = None
|
||||
url = ""
|
||||
|
||||
@ -328,7 +326,7 @@ def manual_scrobble_book(
|
||||
|
||||
|
||||
def manual_scrobble_board_game(
|
||||
bggeek_id: str, user_id: int, action: Optional[str] = None
|
||||
bggeek_id: str, user_id: int, source: str = "BGG", action: Optional[str] = None
|
||||
) -> Scrobble | None:
|
||||
boardgame = BoardGame.find_or_create(bggeek_id)
|
||||
|
||||
@ -340,7 +338,7 @@ def manual_scrobble_board_game(
|
||||
"user_id": user_id,
|
||||
"timestamp": timezone.now(),
|
||||
"playback_position_seconds": 0,
|
||||
"source": "Vrobbler",
|
||||
"source": source,
|
||||
}
|
||||
logger.info(
|
||||
"[vrobbler-scrobble] board game scrobble request received",
|
||||
@ -530,7 +528,7 @@ def email_scrobble_board_game(
|
||||
|
||||
|
||||
def manual_scrobble_from_url(
|
||||
url: str, user_id: int, action: Optional[str] = None
|
||||
url: str, user_id: int, source: str = "Vrobbler", action: Optional[str] = None
|
||||
) -> Scrobble:
|
||||
"""We have scrobblable media URLs, and then any other webpages that
|
||||
we want to scrobble as a media type in and of itself. This checks whether
|
||||
@ -564,7 +562,7 @@ def manual_scrobble_from_url(
|
||||
item_id = "tt" + str(item_id)
|
||||
|
||||
scrobble_fn = MANUAL_SCROBBLE_FNS[content_key]
|
||||
return eval(scrobble_fn)(item_id, user_id, action=action)
|
||||
return eval(scrobble_fn)(item_id, user_id, source=source, action=action)
|
||||
|
||||
|
||||
def todoist_scrobble_task_finish(
|
||||
@ -843,9 +841,10 @@ def emacs_scrobble_task(
|
||||
return scrobble
|
||||
|
||||
|
||||
def manual_scrobble_task(url: str, user_id: int, action: Optional[str] = None):
|
||||
def manual_scrobble_task(url: str, user_id: int, source: str = "Vrobbler", action: Optional[str] = None):
|
||||
source_id = re.findall(r"\d+", url)[0]
|
||||
|
||||
description = ""
|
||||
if "todoist" in url:
|
||||
source = "Todoist"
|
||||
title = "Generic Todoist task"
|
||||
@ -874,7 +873,7 @@ def manual_scrobble_task(url: str, user_id: int, action: Optional[str] = None):
|
||||
|
||||
|
||||
def manual_scrobble_webpage(
|
||||
url: str, user_id: int, action: Optional[str] = None
|
||||
url: str, user_id: int, source: str = "Bookmarklet", action: Optional[str] = None
|
||||
):
|
||||
webpage = WebPage.find_or_create({"url": url})
|
||||
|
||||
@ -882,7 +881,7 @@ def manual_scrobble_webpage(
|
||||
"user_id": user_id,
|
||||
"timestamp": timezone.now(),
|
||||
"playback_position_seconds": 0,
|
||||
"source": "Vrobbler",
|
||||
"source": source,
|
||||
}
|
||||
logger.info(
|
||||
"[vrobbler-scrobble] webpage scrobble request received",
|
||||
@ -1001,7 +1000,7 @@ def web_scrobbler_scrobble_video_or_song(
|
||||
|
||||
|
||||
def manual_scrobble_beer(
|
||||
untappd_id: str, user_id: int, action: Optional[str] = None
|
||||
untappd_id: str, user_id: int, source: str = "Untappd", action: Optional[str] = None
|
||||
):
|
||||
beer = Beer.find_or_create(untappd_id)
|
||||
|
||||
@ -1013,7 +1012,7 @@ def manual_scrobble_beer(
|
||||
"user_id": user_id,
|
||||
"timestamp": timezone.now(),
|
||||
"playback_position_seconds": 0,
|
||||
"source": "Vrobbler",
|
||||
"source": source,
|
||||
}
|
||||
logger.info(
|
||||
"[vrobbler-scrobble] beer scrobble request received",
|
||||
@ -1030,7 +1029,7 @@ def manual_scrobble_beer(
|
||||
|
||||
|
||||
def manual_scrobble_puzzle(
|
||||
ipdb_id: str, user_id: int, action: Optional[str] = None
|
||||
ipdb_id: str, user_id: int, source: str = "IPDb", action: Optional[str] = None
|
||||
):
|
||||
puzzle = Puzzle.find_or_create(ipdb_id)
|
||||
|
||||
@ -1042,7 +1041,7 @@ def manual_scrobble_puzzle(
|
||||
"user_id": user_id,
|
||||
"timestamp": timezone.now(),
|
||||
"playback_position_seconds": 0,
|
||||
"source": "Vrobbler",
|
||||
"source": source,
|
||||
}
|
||||
logger.info(
|
||||
"[vrobbler-scrobble] puzzle scrobble request received",
|
||||
@ -1059,7 +1058,7 @@ def manual_scrobble_puzzle(
|
||||
|
||||
|
||||
def manual_scrobble_brickset(
|
||||
brickset_id: str, user_id: int, action: Optional[str] = None
|
||||
brickset_id: str, user_id: int, source: str = "BrickSet", action: Optional[str] = None
|
||||
):
|
||||
brickset = BrickSet.find_or_create(brickset_id)
|
||||
|
||||
@ -1071,7 +1070,7 @@ def manual_scrobble_brickset(
|
||||
"user_id": user_id,
|
||||
"timestamp": timezone.now(),
|
||||
"playback_position_seconds": 0,
|
||||
"source": "Vrobbler",
|
||||
"source": source,
|
||||
"log": {"serial_scrobble_id": ""},
|
||||
}
|
||||
logger.info(
|
||||
|
||||
BIN
vrobbler/apps/scrobbles/static/images/youtube_logo.png
Normal file
BIN
vrobbler/apps/scrobbles/static/images/youtube_logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
@ -396,11 +396,12 @@ def get_daily_calories_for_user_by_day(user_id: int, date: date| str) -> int:
|
||||
|
||||
try:
|
||||
qs = base_scrobble_qs(user_id).filter(day=date)
|
||||
except AttibuteError as e:
|
||||
agg = qs.aggregate(total_calories=models.Sum("calories_int"))
|
||||
except AttributeError as e:
|
||||
logger.warning(f"Can't generate calorie total: {e}")
|
||||
agg = qs.aggregate(total_calories=models.Sum("calories_int"))
|
||||
agg = {}
|
||||
|
||||
return agg["total_calories"] or 0
|
||||
return agg.get("total_calories") or 0
|
||||
|
||||
def get_daily_calorie_dict_for_user(user_id: int) -> dict[date, int]:
|
||||
"""Return {day: total_calories} for all days with scrobbles, in one query."""
|
||||
|
||||
@ -127,8 +127,9 @@ class RecentScrobbleList(ListView):
|
||||
if user.is_authenticated:
|
||||
if scrobble_url := self.request.GET.get("scrobble_url", ""):
|
||||
action = self.request.GET.get("action", "")
|
||||
source = self.request.GET.get("source", "Bookmarklet")
|
||||
scrobble = manual_scrobble_from_url(
|
||||
scrobble_url, self.request.user.id, action
|
||||
scrobble_url, self.request.user.id, source, action
|
||||
)
|
||||
return HttpResponseRedirect(scrobble.redirect_url(user.id))
|
||||
return super().get(*args, **kwargs)
|
||||
|
||||
@ -244,7 +244,7 @@ class SportEvent(ScrobblableMixin):
|
||||
"player_two": player_two,
|
||||
"start": data_dict.get("Start"),
|
||||
"round": round,
|
||||
"run_time_seconds": data_dict.get("RunTime"),
|
||||
"base_run_time_seconds": data_dict.get("RunTime"),
|
||||
}
|
||||
event, _created = cls.objects.get_or_create(**event_dict)
|
||||
|
||||
|
||||
8
vrobbler/apps/tasks/api/serializers.py
Normal file
8
vrobbler/apps/tasks/api/serializers.py
Normal file
@ -0,0 +1,8 @@
|
||||
from tasks import models
|
||||
from rest_framework import serializers
|
||||
|
||||
|
||||
class TaskSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = models.Task
|
||||
fields = "__all__"
|
||||
10
vrobbler/apps/tasks/api/views.py
Normal file
10
vrobbler/apps/tasks/api/views.py
Normal file
@ -0,0 +1,10 @@
|
||||
from rest_framework import permissions, viewsets
|
||||
|
||||
from tasks.api import serializers
|
||||
from tasks import models
|
||||
|
||||
|
||||
class TaskViewSet(viewsets.ModelViewSet):
|
||||
queryset = models.Task.objects.all().order_by("-created")
|
||||
serializer_class = serializers.TaskSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
8
vrobbler/apps/trails/api/serializers.py
Normal file
8
vrobbler/apps/trails/api/serializers.py
Normal file
@ -0,0 +1,8 @@
|
||||
from trails import models
|
||||
from rest_framework import serializers
|
||||
|
||||
|
||||
class TrailSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = models.Trail
|
||||
fields = "__all__"
|
||||
11
vrobbler/apps/trails/api/views.py
Normal file
11
vrobbler/apps/trails/api/views.py
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
from rest_framework import permissions, viewsets
|
||||
|
||||
from trails.api import serializers
|
||||
from trails import models
|
||||
|
||||
|
||||
class TrailViewSet(viewsets.ModelViewSet):
|
||||
queryset = models.Trail.objects.all().order_by("-created")
|
||||
serializer_class = serializers.TrailSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
@ -1,10 +1,8 @@
|
||||
import logging
|
||||
|
||||
from imdb import Cinemagoer, helpers
|
||||
from cinemagoerng import web as imdb
|
||||
from videos.metadata import VideoMetadata, VideoType
|
||||
|
||||
imdb_client = Cinemagoer()
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ -27,11 +25,12 @@ def lookup_video_from_imdb(
|
||||
video_metadata = VideoMetadata(imdb_id=imdb_id)
|
||||
imdb_result: dict = {}
|
||||
|
||||
imdb_result = imdb_client.get_movie(name_or_id)
|
||||
imdb_result = imdb.get_title(name_or_id)
|
||||
logger.debug(f"Found result from IMDB: {imdb_result.title}")
|
||||
|
||||
if not imdb_result:
|
||||
imdb_result = {}
|
||||
imdb_results: list = imdb_client.search_movie(name_or_id)
|
||||
imdb_results: list = imdb.search_movie(name_or_id)
|
||||
if len(imdb_results) > 1:
|
||||
for result in imdb_results:
|
||||
if result["kind"] == kind:
|
||||
|
||||
14
vrobbler/apps/webpages/api/serializers.py
Normal file
14
vrobbler/apps/webpages/api/serializers.py
Normal file
@ -0,0 +1,14 @@
|
||||
from webpages.models import Domain, WebPage
|
||||
from rest_framework import serializers
|
||||
|
||||
|
||||
class DomainSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = Domain
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class WebPageSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = WebPage
|
||||
fields = "__all__"
|
||||
19
vrobbler/apps/webpages/api/views.py
Normal file
19
vrobbler/apps/webpages/api/views.py
Normal file
@ -0,0 +1,19 @@
|
||||
from rest_framework import permissions, viewsets
|
||||
|
||||
from webpages.api.serializers import (
|
||||
DomainSerializer,
|
||||
WebPageSerializer,
|
||||
)
|
||||
from webpages.models import Domain, WebPage
|
||||
|
||||
|
||||
class DomainViewSet(viewsets.ModelViewSet):
|
||||
queryset = Domain.objects.all().order_by("-created")
|
||||
serializer_class = DomainSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
|
||||
|
||||
class WebPageViewSet(viewsets.ModelViewSet):
|
||||
queryset = WebPage.objects.all().order_by("-created")
|
||||
serializer_class = WebPageSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
@ -66,9 +66,16 @@ dd {
|
||||
{% if object.overview %}<p><em>{{object.overview}}</em></p>{% endif %}
|
||||
{% if object.plot%}<p>{{object.plot|safe|linebreaks|truncatewords:160}}</p>{% endif %}
|
||||
<hr />
|
||||
{% if object.imdb_id %}
|
||||
<p style="float:right;">
|
||||
<a href="{{object.imdb_link}}"><img src="{% static "images/imdb_logo.png" %}" width=35></a>
|
||||
</p>
|
||||
{% endif %}
|
||||
{% if object.youtube_id %}
|
||||
<p style="float:right;">
|
||||
<a href="{{object.youtube_link}}"><img src="{% static "images/youtube_logo.png" %}" width=35></a>
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
<div class="deets">
|
||||
|
||||
@ -4,21 +4,35 @@ from oauth2_provider import urls as oauth2_urls
|
||||
from rest_framework import routers
|
||||
|
||||
import vrobbler.apps.scrobbles.views as scrobbles_views
|
||||
|
||||
from vrobbler.apps.boardgames import urls as boardgame_urls
|
||||
from vrobbler.apps.boardgames.api.views import BoardGameViewSet, BoardGameDesignerViewSet, BoardGamePublisherViewSet, BoardGameLocationViewSet
|
||||
|
||||
from vrobbler.apps.books import urls as book_urls
|
||||
from vrobbler.apps.books.api.views import AuthorViewSet, BookViewSet
|
||||
from vrobbler.apps.bricksets import urls as bricksets_urls
|
||||
|
||||
from vrobbler.apps.lifeevents import urls as lifeevents_urls
|
||||
from vrobbler.apps.lifeevents.api.views import LifeEventViewSet
|
||||
|
||||
from vrobbler.apps.locations import urls as locations_urls
|
||||
from vrobbler.apps.locations.api.views import GeoLocationViewSet
|
||||
|
||||
from vrobbler.apps.moods import urls as moods_urls
|
||||
from vrobbler.apps.moods.api.views import MoodViewSet
|
||||
|
||||
from vrobbler.apps.foods import urls as foods_urls
|
||||
from vrobbler.apps.foods.api.views import FoodViewSet, FoodCategoryViewSet
|
||||
|
||||
from vrobbler.apps.music import urls as music_urls
|
||||
from vrobbler.apps.music.api.views import (
|
||||
AlbumViewSet,
|
||||
ArtistViewSet,
|
||||
TrackViewSet,
|
||||
)
|
||||
|
||||
from vrobbler.apps.podcasts import urls as podcast_urls
|
||||
from vrobbler.apps.profiles.api.views import UserProfileViewSet, UserViewSet
|
||||
from vrobbler.apps.podcasts.api.views import ProducerViewSet, PodcastViewSet, PodcastEpisodeViewSet
|
||||
|
||||
from vrobbler.apps.scrobbles import urls as scrobble_urls
|
||||
from vrobbler.apps.scrobbles.api.views import (
|
||||
AudioScrobblerTSVImportViewSet,
|
||||
@ -26,6 +40,7 @@ from vrobbler.apps.scrobbles.api.views import (
|
||||
LastFmImportViewSet,
|
||||
ScrobbleViewSet,
|
||||
)
|
||||
|
||||
from vrobbler.apps.sports import urls as sports_urls
|
||||
from vrobbler.apps.sports.api.views import (
|
||||
LeagueViewSet,
|
||||
@ -36,15 +51,29 @@ from vrobbler.apps.sports.api.views import (
|
||||
TeamViewSet,
|
||||
)
|
||||
from vrobbler.apps.tasks import urls as tasks_urls
|
||||
from vrobbler.apps.tasks.api.views import TaskViewSet
|
||||
|
||||
from vrobbler.apps.profiles import urls as profiles_urls
|
||||
from vrobbler.apps.profiles.api.views import UserProfileViewSet, UserViewSet
|
||||
|
||||
from vrobbler.apps.trails import urls as trails_urls
|
||||
from vrobbler.apps.trails.api.views import TrailViewSet
|
||||
|
||||
from vrobbler.apps.beers import urls as beers_urls
|
||||
from vrobbler.apps.foods import urls as foods_urls
|
||||
from vrobbler.apps.beers.api.views import BeerViewSet, BeerProducerViewSet, BeerStyleViewSet
|
||||
|
||||
from vrobbler.apps.puzzles import urls as puzzles_urls
|
||||
from vrobbler.apps.puzzles.api.views import PuzzleViewSet, PuzzleManufacturerViewSet
|
||||
from vrobbler.apps.videogames import urls as videogame_urls
|
||||
|
||||
from vrobbler.apps.videos import urls as video_urls
|
||||
from vrobbler.apps.videos.api.views import SeriesViewSet, VideoViewSet
|
||||
|
||||
from vrobbler.apps.bricksets import urls as bricksets_urls
|
||||
from vrobbler.apps.bricksets.api.views import BrickSetViewSet
|
||||
|
||||
from vrobbler.apps.webpages import urls as webpages_urls
|
||||
from vrobbler.apps.webpages.api.views import DomainViewSet, WebPageViewSet
|
||||
|
||||
# from vrobbler.apps.modern_ui import urls as modern_ui_urls
|
||||
|
||||
@ -68,6 +97,26 @@ router.register(r"sport-events", SportEventViewSet)
|
||||
router.register(r"teams", TeamViewSet)
|
||||
router.register(r"users", UserViewSet)
|
||||
router.register(r"profiles", UserProfileViewSet)
|
||||
router.register(r"domains", DomainViewSet)
|
||||
router.register(r"webpages", WebPageViewSet)
|
||||
router.register(r"foods", FoodViewSet)
|
||||
router.register(r"moods", MoodViewSet)
|
||||
router.register(r"tasks", TaskViewSet)
|
||||
router.register(r"locations", GeoLocationViewSet)
|
||||
router.register(r"beers", BeerViewSet)
|
||||
router.register(r"beer-producers", BeerProducerViewSet)
|
||||
router.register(r"beer-styles", BeerStyleViewSet)
|
||||
router.register(r"boardgames", BoardGameViewSet)
|
||||
router.register(r"boardgame-designers", BoardGameDesignerViewSet)
|
||||
router.register(r"boardgame-publishers", BoardGamePublisherViewSet)
|
||||
router.register(r"boardgame-locations", BoardGameLocationViewSet)
|
||||
router.register(r"podcast-producers", ProducerViewSet)
|
||||
router.register(r"podcast-episodes", PodcastEpisodeViewSet)
|
||||
router.register(r"podcasts", PodcastViewSet)
|
||||
router.register(r"puzzle-manufacturers", PuzzleManufacturerViewSet)
|
||||
router.register(r"puzzles", PuzzleViewSet)
|
||||
router.register(r"bricksets", BrickSetViewSet)
|
||||
router.register(r"lifeevents", LifeEventViewSet)
|
||||
|
||||
urlpatterns = [
|
||||
path("api/v1/", include(router.urls)),
|
||||
|
||||
Reference in New Issue
Block a user