Compare commits

..

10 Commits
34 ... 35

41 changed files with 3087 additions and 2554 deletions

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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"

View File

View 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__"

View 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]

View 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__"

View 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]

View File

@ -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]

View File

@ -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,

View File

View 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__"

View 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]

View File

View 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__"

View 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]

View 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__"

View 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]

View 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__"

View 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]

View File

View 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__"

View 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]

View 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__"

View 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]

View 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__"

View 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]

View File

@ -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(

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -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."""

View File

@ -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)

View File

@ -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)

View 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__"

View 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]

View 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__"

View 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]

View File

@ -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:

View 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__"

View 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]

View File

@ -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">

View File

@ -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)),