[scrobbles] Blacken files and add local dev static
This commit is contained in:
@ -139,7 +139,6 @@ def build_book_map(rows) -> dict:
|
|||||||
book_id_map = {}
|
book_id_map = {}
|
||||||
|
|
||||||
for book_row in rows:
|
for book_row in rows:
|
||||||
|
|
||||||
if book_row[KoReaderBookColumn.TITLE.value] in BOOKS_TITLES_TO_IGNORE:
|
if book_row[KoReaderBookColumn.TITLE.value] in BOOKS_TITLES_TO_IGNORE:
|
||||||
logger.info(
|
logger.info(
|
||||||
"[build_book_map] Ignoring book title that is likely garbage",
|
"[build_book_map] Ignoring book title that is likely garbage",
|
||||||
@ -147,9 +146,7 @@ def build_book_map(rows) -> dict:
|
|||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
book = Book.objects.filter(
|
book = Book.objects.filter(
|
||||||
koreader_data_by_hash__icontains=book_row[
|
koreader_data_by_hash__icontains=book_row[KoReaderBookColumn.MD5.value]
|
||||||
KoReaderBookColumn.MD5.value
|
|
||||||
]
|
|
||||||
).first()
|
).first()
|
||||||
|
|
||||||
if not book:
|
if not book:
|
||||||
@ -203,15 +200,11 @@ def build_page_data(page_rows: list, book_map: dict, user_tz=None) -> dict:
|
|||||||
"end_ts": start_ts + duration,
|
"end_ts": start_ts + duration,
|
||||||
}
|
}
|
||||||
if book_ids_not_found:
|
if book_ids_not_found:
|
||||||
logger.info(
|
logger.info(f"Found pages for books not in file: {set(book_ids_not_found)}")
|
||||||
f"Found pages for books not in file: {set(book_ids_not_found)}"
|
|
||||||
)
|
|
||||||
return book_map
|
return book_map
|
||||||
|
|
||||||
|
|
||||||
def build_scrobbles_from_book_map(
|
def build_scrobbles_from_book_map(book_map: dict, user: "User") -> list["Scrobble"]:
|
||||||
book_map: dict, user: "User"
|
|
||||||
) -> list["Scrobble"]:
|
|
||||||
Scrobble = apps.get_model("scrobbles", "Scrobble")
|
Scrobble = apps.get_model("scrobbles", "Scrobble")
|
||||||
|
|
||||||
scrobbles_to_create = []
|
scrobbles_to_create = []
|
||||||
@ -241,9 +234,9 @@ def build_scrobbles_from_book_map(
|
|||||||
|
|
||||||
seconds_from_last_page = 0
|
seconds_from_last_page = 0
|
||||||
if prev_page_stats:
|
if prev_page_stats:
|
||||||
seconds_from_last_page = stats.get(
|
seconds_from_last_page = stats.get("end_ts") - prev_page_stats.get(
|
||||||
"end_ts"
|
"start_ts"
|
||||||
) - prev_page_stats.get("start_ts")
|
)
|
||||||
|
|
||||||
playback_position_seconds = playback_position_seconds + stats.get(
|
playback_position_seconds = playback_position_seconds + stats.get(
|
||||||
"duration"
|
"duration"
|
||||||
@ -252,9 +245,7 @@ def build_scrobbles_from_book_map(
|
|||||||
end_of_reading = pages_processed == total_pages_read
|
end_of_reading = pages_processed == total_pages_read
|
||||||
big_jump_to_this_page = (cur_page_number - last_page_number) > 10
|
big_jump_to_this_page = (cur_page_number - last_page_number) > 10
|
||||||
is_session_gap = seconds_from_last_page > SESSION_GAP_SECONDS
|
is_session_gap = seconds_from_last_page > SESSION_GAP_SECONDS
|
||||||
if (
|
if (is_session_gap and not big_jump_to_this_page) or end_of_reading:
|
||||||
is_session_gap and not big_jump_to_this_page
|
|
||||||
) or end_of_reading:
|
|
||||||
should_create_scrobble = True
|
should_create_scrobble = True
|
||||||
|
|
||||||
if should_create_scrobble:
|
if should_create_scrobble:
|
||||||
@ -286,9 +277,9 @@ def build_scrobbles_from_book_map(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Adjust for Daylight Saving Time
|
# Adjust for Daylight Saving Time
|
||||||
#if timestamp.dst() == timedelta(
|
# if timestamp.dst() == timedelta(
|
||||||
# 0
|
# 0
|
||||||
#) or stop_timestamp.dst() == timedelta(0):
|
# ) or stop_timestamp.dst() == timedelta(0):
|
||||||
# timestamp = timestamp - timedelta(hours=1)
|
# timestamp = timestamp - timedelta(hours=1)
|
||||||
# stop_timestamp = stop_timestamp - timedelta(hours=1)
|
# stop_timestamp = stop_timestamp - timedelta(hours=1)
|
||||||
|
|
||||||
@ -378,9 +369,7 @@ def process_koreader_sqlite_file(file_path, user_id) -> list:
|
|||||||
return new_scrobbles
|
return new_scrobbles
|
||||||
|
|
||||||
book_map = build_page_data(
|
book_map = build_page_data(
|
||||||
cur.execute(
|
cur.execute("SELECT * from page_stat_data ORDER BY id_book, start_time"),
|
||||||
"SELECT * from page_stat_data ORDER BY id_book, start_time"
|
|
||||||
),
|
|
||||||
book_map,
|
book_map,
|
||||||
tz,
|
tz,
|
||||||
)
|
)
|
||||||
|
|||||||
@ -58,9 +58,7 @@ logger = logging.getLogger(__name__)
|
|||||||
User = get_user_model()
|
User = get_user_model()
|
||||||
BNULL = {"blank": True, "null": True}
|
BNULL = {"blank": True, "null": True}
|
||||||
|
|
||||||
POINTS_FOR_MOVEMENT_HISTORY = int(
|
POINTS_FOR_MOVEMENT_HISTORY = int(getattr(settings, "POINTS_FOR_MOVEMENT_HISTORY", 3))
|
||||||
getattr(settings, "POINTS_FOR_MOVEMENT_HISTORY", 3)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class BaseFileImportMixin(TimeStampedModel):
|
class BaseFileImportMixin(TimeStampedModel):
|
||||||
@ -96,7 +94,6 @@ class BaseFileImportMixin(TimeStampedModel):
|
|||||||
from scrobbles.models import Scrobble
|
from scrobbles.models import Scrobble
|
||||||
|
|
||||||
if not self.process_log:
|
if not self.process_log:
|
||||||
|
|
||||||
logger.warning("No lines in process log found to undo")
|
logger.warning("No lines in process log found to undo")
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -104,9 +101,7 @@ class BaseFileImportMixin(TimeStampedModel):
|
|||||||
scrobble_id = line.split("\t")[0]
|
scrobble_id = line.split("\t")[0]
|
||||||
scrobble = Scrobble.objects.filter(id=scrobble_id).first()
|
scrobble = Scrobble.objects.filter(id=scrobble_id).first()
|
||||||
if not scrobble:
|
if not scrobble:
|
||||||
logger.warning(
|
logger.warning(f"Could not find scrobble {scrobble_id} to undo")
|
||||||
f"Could not find scrobble {scrobble_id} to undo"
|
|
||||||
)
|
|
||||||
continue
|
continue
|
||||||
logger.info(f"Removing scrobble {scrobble_id}")
|
logger.info(f"Removing scrobble {scrobble_id}")
|
||||||
if not dryrun:
|
if not dryrun:
|
||||||
@ -149,9 +144,7 @@ class BaseFileImportMixin(TimeStampedModel):
|
|||||||
return
|
return
|
||||||
|
|
||||||
for count, scrobble in enumerate(scrobbles):
|
for count, scrobble in enumerate(scrobbles):
|
||||||
scrobble_str = (
|
scrobble_str = f"{scrobble.id}\t{scrobble.timestamp}\t{scrobble.media_obj}"
|
||||||
f"{scrobble.id}\t{scrobble.timestamp}\t{scrobble.media_obj}"
|
|
||||||
)
|
|
||||||
log_line = f"{scrobble_str}"
|
log_line = f"{scrobble_str}"
|
||||||
if count > 0:
|
if count > 0:
|
||||||
log_line = "\n" + log_line
|
log_line = "\n" + log_line
|
||||||
@ -173,9 +166,7 @@ class KoReaderImport(BaseFileImportMixin):
|
|||||||
return "KOReader"
|
return "KOReader"
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse(
|
return reverse("scrobbles:koreader-import-detail", kwargs={"slug": self.uuid})
|
||||||
"scrobbles:koreader-import-detail", kwargs={"slug": self.uuid}
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_path(instance, filename):
|
def get_path(instance, filename):
|
||||||
extension = filename.split(".")[-1]
|
extension = filename.split(".")[-1]
|
||||||
@ -211,15 +202,11 @@ class KoReaderImport(BaseFileImportMixin):
|
|||||||
fix_profile_historic_timezones(self.user.profile)
|
fix_profile_historic_timezones(self.user.profile)
|
||||||
|
|
||||||
if self.processed_finished and not force:
|
if self.processed_finished and not force:
|
||||||
logger.info(
|
logger.info(f"{self} already processed on {self.processed_finished}")
|
||||||
f"{self} already processed on {self.processed_finished}"
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
self.mark_started()
|
self.mark_started()
|
||||||
scrobbles = process_koreader_sqlite_file(
|
scrobbles = process_koreader_sqlite_file(self.upload_file_path, self.user.id)
|
||||||
self.upload_file_path, self.user.id
|
|
||||||
)
|
|
||||||
self.record_log(scrobbles)
|
self.record_log(scrobbles)
|
||||||
self.mark_finished()
|
self.mark_finished()
|
||||||
|
|
||||||
@ -233,9 +220,7 @@ class AudioScrobblerTSVImport(BaseFileImportMixin):
|
|||||||
return "AudiosScrobbler"
|
return "AudiosScrobbler"
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse(
|
return reverse("scrobbles:tsv-import-detail", kwargs={"slug": self.uuid})
|
||||||
"scrobbles:tsv-import-detail", kwargs={"slug": self.uuid}
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_path(instance, filename):
|
def get_path(instance, filename):
|
||||||
extension = filename.split(".")[-1]
|
extension = filename.split(".")[-1]
|
||||||
@ -259,16 +244,12 @@ class AudioScrobblerTSVImport(BaseFileImportMixin):
|
|||||||
fix_profile_historic_timezones(self.user.profile)
|
fix_profile_historic_timezones(self.user.profile)
|
||||||
|
|
||||||
if self.processed_finished and not force:
|
if self.processed_finished and not force:
|
||||||
logger.info(
|
logger.info(f"{self} already processed on {self.processed_finished}")
|
||||||
f"{self} already processed on {self.processed_finished}"
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
self.mark_started()
|
self.mark_started()
|
||||||
|
|
||||||
scrobbles = import_audioscrobbler_tsv_file(
|
scrobbles = import_audioscrobbler_tsv_file(self.upload_file_path, self.user.id)
|
||||||
self.upload_file_path, self.user.id
|
|
||||||
)
|
|
||||||
self.record_log(scrobbles)
|
self.record_log(scrobbles)
|
||||||
self.mark_finished()
|
self.mark_finished()
|
||||||
|
|
||||||
@ -282,9 +263,7 @@ class LastFmImport(BaseFileImportMixin):
|
|||||||
return "LastFM"
|
return "LastFM"
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse(
|
return reverse("scrobbles:lastfm-import-detail", kwargs={"slug": self.uuid})
|
||||||
"scrobbles:lastfm-import-detail", kwargs={"slug": self.uuid}
|
|
||||||
)
|
|
||||||
|
|
||||||
def process(self, import_all=False):
|
def process(self, import_all=False):
|
||||||
"""Import scrobbles found on LastFM"""
|
"""Import scrobbles found on LastFM"""
|
||||||
@ -293,9 +272,7 @@ class LastFmImport(BaseFileImportMixin):
|
|||||||
fix_profile_historic_timezones(self.user.profile)
|
fix_profile_historic_timezones(self.user.profile)
|
||||||
|
|
||||||
if self.processed_finished:
|
if self.processed_finished:
|
||||||
logger.info(
|
logger.info(f"{self} already processed on {self.processed_finished}")
|
||||||
f"{self} already processed on {self.processed_finished}"
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
last_import = None
|
last_import = None
|
||||||
@ -333,9 +310,7 @@ class RetroarchImport(BaseFileImportMixin):
|
|||||||
return "Retroarch"
|
return "Retroarch"
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse(
|
return reverse("scrobbles:retroarch-import-detail", kwargs={"slug": self.uuid})
|
||||||
"scrobbles:retroarch-import-detail", kwargs={"slug": self.uuid}
|
|
||||||
)
|
|
||||||
|
|
||||||
def process(self, import_all=False, force=False):
|
def process(self, import_all=False, force=False):
|
||||||
"""Import scrobbles found on Retroarch"""
|
"""Import scrobbles found on Retroarch"""
|
||||||
@ -343,9 +318,7 @@ class RetroarchImport(BaseFileImportMixin):
|
|||||||
fix_profile_historic_timezones(self.user.profile)
|
fix_profile_historic_timezones(self.user.profile)
|
||||||
|
|
||||||
if self.processed_finished and not force:
|
if self.processed_finished and not force:
|
||||||
logger.info(
|
logger.info(f"{self} already processed on {self.processed_finished}")
|
||||||
f"{self} already processed on {self.processed_finished}"
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
if force:
|
if force:
|
||||||
@ -536,39 +509,25 @@ class Scrobble(TimeStampedModel):
|
|||||||
podcast_episode = models.ForeignKey(
|
podcast_episode = models.ForeignKey(
|
||||||
PodcastEpisode, on_delete=models.DO_NOTHING, **BNULL
|
PodcastEpisode, on_delete=models.DO_NOTHING, **BNULL
|
||||||
)
|
)
|
||||||
sport_event = models.ForeignKey(
|
sport_event = models.ForeignKey(SportEvent, on_delete=models.DO_NOTHING, **BNULL)
|
||||||
SportEvent, on_delete=models.DO_NOTHING, **BNULL
|
|
||||||
)
|
|
||||||
book = models.ForeignKey(Book, on_delete=models.DO_NOTHING, **BNULL)
|
book = models.ForeignKey(Book, on_delete=models.DO_NOTHING, **BNULL)
|
||||||
paper = models.ForeignKey(Paper, on_delete=models.DO_NOTHING, **BNULL)
|
paper = models.ForeignKey(Paper, on_delete=models.DO_NOTHING, **BNULL)
|
||||||
video_game = models.ForeignKey(
|
video_game = models.ForeignKey(VideoGame, on_delete=models.DO_NOTHING, **BNULL)
|
||||||
VideoGame, on_delete=models.DO_NOTHING, **BNULL
|
board_game = models.ForeignKey(BoardGame, on_delete=models.DO_NOTHING, **BNULL)
|
||||||
)
|
geo_location = models.ForeignKey(GeoLocation, on_delete=models.DO_NOTHING, **BNULL)
|
||||||
board_game = models.ForeignKey(
|
|
||||||
BoardGame, on_delete=models.DO_NOTHING, **BNULL
|
|
||||||
)
|
|
||||||
geo_location = models.ForeignKey(
|
|
||||||
GeoLocation, on_delete=models.DO_NOTHING, **BNULL
|
|
||||||
)
|
|
||||||
beer = models.ForeignKey(Beer, on_delete=models.DO_NOTHING, **BNULL)
|
beer = models.ForeignKey(Beer, on_delete=models.DO_NOTHING, **BNULL)
|
||||||
puzzle = models.ForeignKey(Puzzle, on_delete=models.DO_NOTHING, **BNULL)
|
puzzle = models.ForeignKey(Puzzle, on_delete=models.DO_NOTHING, **BNULL)
|
||||||
food = models.ForeignKey(Food, on_delete=models.DO_NOTHING, **BNULL)
|
food = models.ForeignKey(Food, on_delete=models.DO_NOTHING, **BNULL)
|
||||||
trail = models.ForeignKey(Trail, on_delete=models.DO_NOTHING, **BNULL)
|
trail = models.ForeignKey(Trail, on_delete=models.DO_NOTHING, **BNULL)
|
||||||
task = models.ForeignKey(Task, on_delete=models.DO_NOTHING, **BNULL)
|
task = models.ForeignKey(Task, on_delete=models.DO_NOTHING, **BNULL)
|
||||||
web_page = models.ForeignKey(WebPage, on_delete=models.DO_NOTHING, **BNULL)
|
web_page = models.ForeignKey(WebPage, on_delete=models.DO_NOTHING, **BNULL)
|
||||||
life_event = models.ForeignKey(
|
life_event = models.ForeignKey(LifeEvent, on_delete=models.DO_NOTHING, **BNULL)
|
||||||
LifeEvent, on_delete=models.DO_NOTHING, **BNULL
|
|
||||||
)
|
|
||||||
mood = models.ForeignKey(Mood, on_delete=models.DO_NOTHING, **BNULL)
|
mood = models.ForeignKey(Mood, on_delete=models.DO_NOTHING, **BNULL)
|
||||||
brick_set = models.ForeignKey(
|
brick_set = models.ForeignKey(BrickSet, on_delete=models.DO_NOTHING, **BNULL)
|
||||||
BrickSet, on_delete=models.DO_NOTHING, **BNULL
|
|
||||||
)
|
|
||||||
media_type = models.CharField(
|
media_type = models.CharField(
|
||||||
max_length=14, choices=MediaType.choices, default=MediaType.VIDEO
|
max_length=14, choices=MediaType.choices, default=MediaType.VIDEO
|
||||||
)
|
)
|
||||||
user = models.ForeignKey(
|
user = models.ForeignKey(User, blank=True, null=True, on_delete=models.DO_NOTHING)
|
||||||
User, blank=True, null=True, on_delete=models.DO_NOTHING
|
|
||||||
)
|
|
||||||
|
|
||||||
# Time keeping
|
# Time keeping
|
||||||
timestamp = models.DateTimeField(**BNULL)
|
timestamp = models.DateTimeField(**BNULL)
|
||||||
@ -596,9 +555,7 @@ class Scrobble(TimeStampedModel):
|
|||||||
upload_to="scrobbles/videogame_save_data/", **BNULL
|
upload_to="scrobbles/videogame_save_data/", **BNULL
|
||||||
)
|
)
|
||||||
gpx_file = models.FileField(upload_to="scrobbles/gpx_file/", **BNULL)
|
gpx_file = models.FileField(upload_to="scrobbles/gpx_file/", **BNULL)
|
||||||
screenshot = models.ImageField(
|
screenshot = models.ImageField(upload_to="scrobbles/videogame_screenshot/", **BNULL)
|
||||||
upload_to="scrobbles/videogame_screenshot/", **BNULL
|
|
||||||
)
|
|
||||||
screenshot_small = ImageSpecField(
|
screenshot_small = ImageSpecField(
|
||||||
source="screenshot",
|
source="screenshot",
|
||||||
processors=[ResizeToFit(100, 100)],
|
processors=[ResizeToFit(100, 100)],
|
||||||
@ -614,6 +571,16 @@ class Scrobble(TimeStampedModel):
|
|||||||
long_play_seconds = models.BigIntegerField(**BNULL)
|
long_play_seconds = models.BigIntegerField(**BNULL)
|
||||||
long_play_complete = models.BooleanField(**BNULL)
|
long_play_complete = models.BooleanField(**BNULL)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
indexes = [
|
||||||
|
models.Index(fields=["timestamp"]),
|
||||||
|
models.Index(fields=["media_type"]),
|
||||||
|
models.Index(fields=["source_id"]),
|
||||||
|
models.Index(
|
||||||
|
fields=["user", "in_progress", "played_to_completion", "is_paused"]
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def for_year(cls, user, year):
|
def for_year(cls, user, year):
|
||||||
return cls.objects.filter(timestamp__year=year, user=user).order_by(
|
return cls.objects.filter(timestamp__year=year, user=user).order_by(
|
||||||
@ -679,9 +646,7 @@ class Scrobble(TimeStampedModel):
|
|||||||
from scrobbles.models import Scrobble
|
from scrobbles.models import Scrobble
|
||||||
|
|
||||||
if self.logdata and self.logdata.serial_scrobble_id:
|
if self.logdata and self.logdata.serial_scrobble_id:
|
||||||
return Scrobble.objects.filter(
|
return Scrobble.objects.filter(id=self.logdata.serial_scrobble_id).first()
|
||||||
id=self.logdata.serial_scrobble_id
|
|
||||||
).first()
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def finish_url(self) -> str:
|
def finish_url(self) -> str:
|
||||||
@ -703,8 +668,12 @@ class Scrobble(TimeStampedModel):
|
|||||||
if self.media_obj:
|
if self.media_obj:
|
||||||
self.media_type = self.MediaType(self.media_obj.__class__.__name__)
|
self.media_type = self.MediaType(self.media_obj.__class__.__name__)
|
||||||
|
|
||||||
if (self.timestamp and self.stop_timestamp) and (not self.playback_position_seconds or self.playback_position_seconds <= 0):
|
if (self.timestamp and self.stop_timestamp) and (
|
||||||
self.playback_position_seconds = (self.stop_timestamp - self.timestamp).seconds
|
not self.playback_position_seconds or self.playback_position_seconds <= 0
|
||||||
|
):
|
||||||
|
self.playback_position_seconds = (
|
||||||
|
self.stop_timestamp - self.timestamp
|
||||||
|
).seconds
|
||||||
|
|
||||||
return super(Scrobble, self).save(*args, **kwargs)
|
return super(Scrobble, self).save(*args, **kwargs)
|
||||||
|
|
||||||
@ -715,9 +684,9 @@ class Scrobble(TimeStampedModel):
|
|||||||
return reverse("scrobbles:detail", kwargs={"uuid": self.uuid})
|
return reverse("scrobbles:detail", kwargs={"uuid": self.uuid})
|
||||||
|
|
||||||
def push_to_archivebox(self):
|
def push_to_archivebox(self):
|
||||||
pushable_media = hasattr(
|
pushable_media = hasattr(self.media_obj, "push_to_archivebox") and callable(
|
||||||
self.media_obj, "push_to_archivebox"
|
self.media_obj.push_to_archivebox
|
||||||
) and callable(self.media_obj.push_to_archivebox)
|
)
|
||||||
|
|
||||||
if pushable_media and self.user.profile.archivebox_url:
|
if pushable_media and self.user.profile.archivebox_url:
|
||||||
try:
|
try:
|
||||||
@ -781,10 +750,7 @@ class Scrobble(TimeStampedModel):
|
|||||||
logger.info(f"Redirecting to {self.media_obj.url}")
|
logger.info(f"Redirecting to {self.media_obj.url}")
|
||||||
redirect_url = self.media_obj.url
|
redirect_url = self.media_obj.url
|
||||||
|
|
||||||
if (
|
if self.media_type == self.MediaType.VIDEO and self.media_obj.youtube_id:
|
||||||
self.media_type == self.MediaType.VIDEO
|
|
||||||
and self.media_obj.youtube_id
|
|
||||||
):
|
|
||||||
redirect_url = self.media_obj.youtube_link
|
redirect_url = self.media_obj.youtube_link
|
||||||
|
|
||||||
return redirect_url
|
return redirect_url
|
||||||
@ -800,9 +766,7 @@ class Scrobble(TimeStampedModel):
|
|||||||
@property
|
@property
|
||||||
def local_stop_timestamp(self):
|
def local_stop_timestamp(self):
|
||||||
if self.stop_timestamp:
|
if self.stop_timestamp:
|
||||||
return timezone.localtime(
|
return timezone.localtime(self.stop_timestamp, timezone=self.tzinfo)
|
||||||
self.stop_timestamp, timezone=self.tzinfo
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def scrobble_media_key(self) -> str:
|
def scrobble_media_key(self) -> str:
|
||||||
@ -930,9 +894,7 @@ class Scrobble(TimeStampedModel):
|
|||||||
long_play_secs = 0
|
long_play_secs = 0
|
||||||
if self.previous and not self.previous.long_play_complete:
|
if self.previous and not self.previous.long_play_complete:
|
||||||
long_play_secs = self.previous.long_play_seconds or 0
|
long_play_secs = self.previous.long_play_seconds or 0
|
||||||
percent = int(
|
percent = int(((playback_seconds + long_play_secs) / run_time_secs) * 100)
|
||||||
((playback_seconds + long_play_secs) / run_time_secs) * 100
|
|
||||||
)
|
|
||||||
|
|
||||||
return percent
|
return percent
|
||||||
|
|
||||||
@ -977,9 +939,7 @@ class Scrobble(TimeStampedModel):
|
|||||||
expected_end = self.timestamp + datetime.timedelta(
|
expected_end = self.timestamp + datetime.timedelta(
|
||||||
seconds=self.media_obj.run_time_seconds
|
seconds=self.media_obj.run_time_seconds
|
||||||
)
|
)
|
||||||
expected_end_padded = expected_end + datetime.timedelta(
|
expected_end_padded = expected_end + datetime.timedelta(seconds=padding_seconds)
|
||||||
seconds=padding_seconds
|
|
||||||
)
|
|
||||||
# Take our start time, add our media length and an extra 30 min (1800s) is it still in the future? keep going
|
# Take our start time, add our media length and an extra 30 min (1800s) is it still in the future? keep going
|
||||||
is_in_progress = expected_end_padded > pendulum.now()
|
is_in_progress = expected_end_padded > pendulum.now()
|
||||||
logger.info(
|
logger.info(
|
||||||
@ -995,7 +955,10 @@ class Scrobble(TimeStampedModel):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def can_be_updated(self) -> bool:
|
def can_be_updated(self) -> bool:
|
||||||
if self.media_obj.__class__.__name__ in LONG_PLAY_MEDIA.values() and self.source != "readcomicsonline.ru":
|
if (
|
||||||
|
self.media_obj.__class__.__name__ in LONG_PLAY_MEDIA.values()
|
||||||
|
and self.source != "readcomicsonline.ru"
|
||||||
|
):
|
||||||
logger.info(
|
logger.info(
|
||||||
"[scrobbling] cannot be updated, long play media",
|
"[scrobbling] cannot be updated, long play media",
|
||||||
extra={
|
extra={
|
||||||
@ -1039,11 +1002,9 @@ class Scrobble(TimeStampedModel):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def by_date(cls, media_type: str = "Track"):
|
def by_date(cls, media_type: str = "Track"):
|
||||||
cls.objects.filter(media_type=media_type).values(
|
cls.objects.filter(media_type=media_type).values("timestamp__date").annotate(
|
||||||
"timestamp__date"
|
count=models.Count("id")
|
||||||
).annotate(count=models.Count("id")).values(
|
).values("timestamp__date", "count").order_by(
|
||||||
"timestamp__date", "count"
|
|
||||||
).order_by(
|
|
||||||
"-count",
|
"-count",
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1150,7 +1111,10 @@ class Scrobble(TimeStampedModel):
|
|||||||
if existing_by_source_id:
|
if existing_by_source_id:
|
||||||
logger.info(
|
logger.info(
|
||||||
"[create_or_update] found existing scrobble by source_id, updating",
|
"[create_or_update] found existing scrobble by source_id, updating",
|
||||||
extra={"scrobble_id": existing_by_source_id.id, "source_id": source_id},
|
extra={
|
||||||
|
"scrobble_id": existing_by_source_id.id,
|
||||||
|
"source_id": source_id,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
scrobble_data["playback_status"] = scrobble_data.pop("status", None)
|
scrobble_data["playback_status"] = scrobble_data.pop("status", None)
|
||||||
return existing_by_source_id.update(scrobble_data)
|
return existing_by_source_id.update(scrobble_data)
|
||||||
@ -1172,9 +1136,7 @@ class Scrobble(TimeStampedModel):
|
|||||||
logger.warning(
|
logger.warning(
|
||||||
f"[create_or_update] geoloc requires create_or_update_location"
|
f"[create_or_update] geoloc requires create_or_update_location"
|
||||||
)
|
)
|
||||||
scrobble = cls.create_or_update_location(
|
scrobble = cls.create_or_update_location(media, scrobble_data, user_id)
|
||||||
media, scrobble_data, user_id
|
|
||||||
)
|
|
||||||
return scrobble
|
return scrobble
|
||||||
|
|
||||||
if not skip_in_progress_check or read_log_page:
|
if not skip_in_progress_check or read_log_page:
|
||||||
@ -1187,9 +1149,7 @@ class Scrobble(TimeStampedModel):
|
|||||||
"scrobble_data": scrobble_data,
|
"scrobble_data": scrobble_data,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
scrobble_data["playback_status"] = scrobble_data.pop(
|
scrobble_data["playback_status"] = scrobble_data.pop("status", None)
|
||||||
"status", None
|
|
||||||
)
|
|
||||||
# If it's marked as stopped, send it through our update mechanism, which will complete it
|
# If it's marked as stopped, send it through our update mechanism, which will complete it
|
||||||
if scrobble and (
|
if scrobble and (
|
||||||
scrobble.can_be_updated
|
scrobble.can_be_updated
|
||||||
@ -1207,7 +1167,7 @@ class Scrobble(TimeStampedModel):
|
|||||||
page_list.append(
|
page_list.append(
|
||||||
BookPageLogData(
|
BookPageLogData(
|
||||||
page_number=read_log_page,
|
page_number=read_log_page,
|
||||||
start_ts=int(timezone.now().timestamp())
|
start_ts=int(timezone.now().timestamp()),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
scrobble.log["page_data"] = page_list
|
scrobble.log["page_data"] = page_list
|
||||||
@ -1220,7 +1180,14 @@ class Scrobble(TimeStampedModel):
|
|||||||
scrobble_data.pop("playback_status")
|
scrobble_data.pop("playback_status")
|
||||||
|
|
||||||
if read_log_page:
|
if read_log_page:
|
||||||
scrobble_data["log"] = BookLogData(page_data=[BookPageLogData(page_number=read_log_page, start_ts=int(timezone.now().timestamp()))])
|
scrobble_data["log"] = BookLogData(
|
||||||
|
page_data=[
|
||||||
|
BookPageLogData(
|
||||||
|
page_number=read_log_page,
|
||||||
|
start_ts=int(timezone.now().timestamp()),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
f"[scrobbling] creating new scrobble",
|
f"[scrobbling] creating new scrobble",
|
||||||
@ -1231,7 +1198,9 @@ class Scrobble(TimeStampedModel):
|
|||||||
"source": source,
|
"source": source,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if mtype == cls.MediaType.FOOD and not scrobble_data.get("log", {}).get("calories", None):
|
if mtype == cls.MediaType.FOOD and not scrobble_data.get("log", {}).get(
|
||||||
|
"calories", None
|
||||||
|
):
|
||||||
if media.calories:
|
if media.calories:
|
||||||
scrobble_data["log"] = FoodLogData(calories=media.calories)
|
scrobble_data["log"] = FoodLogData(calories=media.calories)
|
||||||
|
|
||||||
@ -1318,9 +1287,7 @@ class Scrobble(TimeStampedModel):
|
|||||||
if existing_locations := location.in_proximity(named=True):
|
if existing_locations := location.in_proximity(named=True):
|
||||||
existing_location = existing_locations.first()
|
existing_location = existing_locations.first()
|
||||||
ts = int(pendulum.now().timestamp())
|
ts = int(pendulum.now().timestamp())
|
||||||
scrobble.log[
|
scrobble.log[ts] = f"Location {location.id} too close to this scrobble"
|
||||||
ts
|
|
||||||
] = f"Location {location.id} too close to this scrobble"
|
|
||||||
scrobble.save(update_fields=["log"])
|
scrobble.save(update_fields=["log"])
|
||||||
logger.info(
|
logger.info(
|
||||||
f"[scrobbling] finished - found existing named location",
|
f"[scrobbling] finished - found existing named location",
|
||||||
@ -1499,9 +1466,7 @@ class Scrobble(TimeStampedModel):
|
|||||||
"""Returns true if our media is beyond our completion percent, unless
|
"""Returns true if our media is beyond our completion percent, unless
|
||||||
our type is geolocation in which case we always return false
|
our type is geolocation in which case we always return false
|
||||||
"""
|
"""
|
||||||
beyond_completion = (
|
beyond_completion = self.percent_played >= self.media_obj.COMPLETION_PERCENT
|
||||||
self.percent_played >= self.media_obj.COMPLETION_PERCENT
|
|
||||||
)
|
|
||||||
|
|
||||||
if self.media_type == "GeoLocation":
|
if self.media_type == "GeoLocation":
|
||||||
logger.info(
|
logger.info(
|
||||||
|
|||||||
@ -87,6 +87,7 @@ def mopidy_scrobble_media(post_data: dict, user_id: int) -> Scrobble:
|
|||||||
log = {
|
log = {
|
||||||
"mopidy_source": post_data.get("mopidy_uri", "").split(":")[0],
|
"mopidy_source": post_data.get("mopidy_uri", "").split(":")[0],
|
||||||
"raw_data": post_data,
|
"raw_data": post_data,
|
||||||
|
"album": post_data.get("album", ""),
|
||||||
}
|
}
|
||||||
except IndexError:
|
except IndexError:
|
||||||
pass
|
pass
|
||||||
@ -95,17 +96,14 @@ def mopidy_scrobble_media(post_data: dict, user_id: int) -> Scrobble:
|
|||||||
user_id,
|
user_id,
|
||||||
source="Mopidy",
|
source="Mopidy",
|
||||||
playback_position_seconds=int(
|
playback_position_seconds=int(
|
||||||
post_data.get(MOPIDY_POST_KEYS.get("PLAYBACK_POSITION_TICKS"), 1)
|
post_data.get(MOPIDY_POST_KEYS.get("PLAYBACK_POSITION_TICKS"), 1) / 1000
|
||||||
/ 1000
|
|
||||||
),
|
),
|
||||||
status=post_data.get(MOPIDY_POST_KEYS.get("STATUS"), ""),
|
status=post_data.get(MOPIDY_POST_KEYS.get("STATUS"), ""),
|
||||||
log=log,
|
log=log,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def jellyfin_scrobble_media(
|
def jellyfin_scrobble_media(post_data: dict, user_id: int) -> Optional[Scrobble]:
|
||||||
post_data: dict, user_id: int
|
|
||||||
) -> Optional[Scrobble]:
|
|
||||||
media_type = Scrobble.MediaType.VIDEO
|
media_type = Scrobble.MediaType.VIDEO
|
||||||
if post_data.pop("ItemType", "") in JELLYFIN_AUDIO_ITEM_TYPES:
|
if post_data.pop("ItemType", "") in JELLYFIN_AUDIO_ITEM_TYPES:
|
||||||
media_type = Scrobble.MediaType.TRACK
|
media_type = Scrobble.MediaType.TRACK
|
||||||
@ -123,13 +121,12 @@ def jellyfin_scrobble_media(
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
timestamp = parse(
|
timestamp = parse(post_data.get(JELLYFIN_POST_KEYS.get("TIMESTAMP"), "")).replace(
|
||||||
post_data.get(JELLYFIN_POST_KEYS.get("TIMESTAMP"), "")
|
tzinfo=pytz.utc
|
||||||
).replace(tzinfo=pytz.utc)
|
)
|
||||||
|
|
||||||
playback_position_seconds = int(
|
playback_position_seconds = int(
|
||||||
post_data.get(JELLYFIN_POST_KEYS.get("PLAYBACK_POSITION_TICKS"), 1)
|
post_data.get(JELLYFIN_POST_KEYS.get("PLAYBACK_POSITION_TICKS"), 1) / 10000000
|
||||||
/ 10000000
|
|
||||||
)
|
)
|
||||||
if media_type == Scrobble.MediaType.VIDEO:
|
if media_type == Scrobble.MediaType.VIDEO:
|
||||||
imdb_id = post_data.get("Provider_imdb", "")
|
imdb_id = post_data.get("Provider_imdb", "")
|
||||||
@ -139,9 +136,7 @@ def jellyfin_scrobble_media(
|
|||||||
title=post_data.get("Name", ""),
|
title=post_data.get("Name", ""),
|
||||||
artist_name=post_data.get("Artist", ""),
|
artist_name=post_data.get("Artist", ""),
|
||||||
album_name=post_data.get("Album", ""),
|
album_name=post_data.get("Album", ""),
|
||||||
run_time_seconds=convert_to_seconds(
|
run_time_seconds=convert_to_seconds(post_data.get("RunTime", 900000)),
|
||||||
post_data.get("RunTime", 900000)
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
# A hack because we don't worry about updating music ... we either finish it or we don't
|
# A hack because we don't worry about updating music ... we either finish it or we don't
|
||||||
playback_position_seconds = 0
|
playback_position_seconds = 0
|
||||||
@ -165,6 +160,7 @@ def jellyfin_scrobble_media(
|
|||||||
source_id=post_data.get(JELLYFIN_POST_KEYS.get("MEDIA_SOURCE_ID")),
|
source_id=post_data.get(JELLYFIN_POST_KEYS.get("MEDIA_SOURCE_ID")),
|
||||||
playback_position_seconds=playback_position_seconds,
|
playback_position_seconds=playback_position_seconds,
|
||||||
status=playback_status,
|
status=playback_status,
|
||||||
|
log={"album": post_data.get("Album", "")},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -301,9 +297,7 @@ def manual_scrobble_book(
|
|||||||
if not page:
|
if not page:
|
||||||
page = 1
|
page = 1
|
||||||
|
|
||||||
logger.info(
|
logger.info("[scrobblers] Book page included in scrobble, should update!")
|
||||||
"[scrobblers] Book page included in scrobble, should update!"
|
|
||||||
)
|
|
||||||
|
|
||||||
source = READCOMICSONLINE_URL.replace("https://", "")
|
source = READCOMICSONLINE_URL.replace("https://", "")
|
||||||
|
|
||||||
@ -420,9 +414,7 @@ def email_scrobble_board_game(
|
|||||||
if not location.name:
|
if not location.name:
|
||||||
location.name = location_dict.get("name")
|
location.name = location_dict.get("name")
|
||||||
update_fields.append("name")
|
update_fields.append("name")
|
||||||
geoloc = GeoLocation.objects.filter(
|
geoloc = GeoLocation.objects.filter(title__icontains=location.name).first()
|
||||||
title__icontains=location.name
|
|
||||||
).first()
|
|
||||||
if geoloc:
|
if geoloc:
|
||||||
location.geo_location = geoloc
|
location.geo_location = geoloc
|
||||||
update_fields.append("geo_location")
|
update_fields.append("geo_location")
|
||||||
@ -474,9 +466,7 @@ def email_scrobble_board_game(
|
|||||||
log_data.pop("expansion_ids")
|
log_data.pop("expansion_ids")
|
||||||
|
|
||||||
if play_dict.get("locationRefId", False):
|
if play_dict.get("locationRefId", False):
|
||||||
log_data["location_id"] = locations[
|
log_data["location_id"] = locations[play_dict.get("locationRefId")].id
|
||||||
play_dict.get("locationRefId")
|
|
||||||
].id
|
|
||||||
if play_dict.get("rounds", False):
|
if play_dict.get("rounds", False):
|
||||||
log_data["rounds"] = play_dict.get("rounds")
|
log_data["rounds"] = play_dict.get("rounds")
|
||||||
if play_dict.get("board", False):
|
if play_dict.get("board", False):
|
||||||
@ -499,9 +489,7 @@ def email_scrobble_board_game(
|
|||||||
timestamp = parse(play_dict.get("playDate"))
|
timestamp = parse(play_dict.get("playDate"))
|
||||||
if hour and minute:
|
if hour and minute:
|
||||||
logger.info(f"Scrobble playDate has manual start time {timestamp}")
|
logger.info(f"Scrobble playDate has manual start time {timestamp}")
|
||||||
timestamp = timestamp.replace(
|
timestamp = timestamp.replace(hour=hour, minute=minute, second=second or 0)
|
||||||
hour=hour, minute=minute, second=second or 0
|
|
||||||
)
|
|
||||||
logger.info(f"Update to {timestamp}")
|
logger.info(f"Update to {timestamp}")
|
||||||
|
|
||||||
profile = UserProfile.objects.filter(user_id=user_id).first()
|
profile = UserProfile.objects.filter(user_id=user_id).first()
|
||||||
@ -596,9 +584,7 @@ def manual_scrobble_from_url(
|
|||||||
scrobbler. Otherwise, return nothing."""
|
scrobbler. Otherwise, return nothing."""
|
||||||
|
|
||||||
if RecipeScraperService.is_recipe_url(url):
|
if RecipeScraperService.is_recipe_url(url):
|
||||||
return scrobble_from_recipe_website(
|
return scrobble_from_recipe_website(url, user_id, source=source, action=action)
|
||||||
url, user_id, source=source, action=action
|
|
||||||
)
|
|
||||||
|
|
||||||
content_key = ""
|
content_key = ""
|
||||||
domain = extract_domain(url)
|
domain = extract_domain(url)
|
||||||
@ -801,9 +787,7 @@ def emacs_scrobble_update_task(
|
|||||||
if not scrobble.log.get('notes"'):
|
if not scrobble.log.get('notes"'):
|
||||||
scrobble.log["notes"] = []
|
scrobble.log["notes"] = []
|
||||||
if note.get("timestamp") not in existing_note_ts:
|
if note.get("timestamp") not in existing_note_ts:
|
||||||
scrobble.log["notes"].append(
|
scrobble.log["notes"].append({note.get("timestamp"): note.get("content")})
|
||||||
{note.get("timestamp"): note.get("content")}
|
|
||||||
)
|
|
||||||
notes_updated = True
|
notes_updated = True
|
||||||
|
|
||||||
if notes_updated:
|
if notes_updated:
|
||||||
@ -829,9 +813,7 @@ def emacs_scrobble_task(
|
|||||||
user_context_list: list[str] = [],
|
user_context_list: list[str] = [],
|
||||||
) -> Scrobble | None:
|
) -> Scrobble | None:
|
||||||
orgmode_id = task_data.get("source_id")
|
orgmode_id = task_data.get("source_id")
|
||||||
title = get_title_from_labels(
|
title = get_title_from_labels(task_data.get("labels", []), user_context_list)
|
||||||
task_data.get("labels", []), user_context_list
|
|
||||||
)
|
|
||||||
|
|
||||||
task = Task.find_or_create(title)
|
task = Task.find_or_create(title)
|
||||||
|
|
||||||
@ -954,9 +936,7 @@ def manual_scrobble_webpage(
|
|||||||
):
|
):
|
||||||
|
|
||||||
if RecipeScraperService.is_recipe_url(url):
|
if RecipeScraperService.is_recipe_url(url):
|
||||||
return scrobble_from_recipe_website(
|
return scrobble_from_recipe_website(url, user_id, source=source, action=action)
|
||||||
url, user_id, source=source, action=action
|
|
||||||
)
|
|
||||||
|
|
||||||
webpage = WebPage.find_or_create({"url": url})
|
webpage = WebPage.find_or_create({"url": url})
|
||||||
|
|
||||||
|
|||||||
@ -155,25 +155,17 @@ class RecentScrobbleList(ListView):
|
|||||||
next_date = date + timedelta(weeks=+2)
|
next_date = date + timedelta(weeks=+2)
|
||||||
prev_date = date + timedelta(weeks=-1)
|
prev_date = date + timedelta(weeks=-1)
|
||||||
if date.isocalendar()[1] < today.isocalendar()[1]:
|
if date.isocalendar()[1] < today.isocalendar()[1]:
|
||||||
data[
|
data["next_link"] = f"?date={next_date.strftime('%Y-W%W')}"
|
||||||
"next_link"
|
|
||||||
] = f"?date={next_date.strftime('%Y-W%W')}"
|
|
||||||
data["prev_link"] = f"?date={prev_date.strftime('%Y-W%W')}"
|
data["prev_link"] = f"?date={prev_date.strftime('%Y-W%W')}"
|
||||||
data[
|
data["title"] = f"Week {date.strftime('%-W')} of {date.year}"
|
||||||
"title"
|
|
||||||
] = f"Week {date.strftime('%-W')} of {date.year}"
|
|
||||||
data = data | Scrobble.as_dict_by_type(
|
data = data | Scrobble.as_dict_by_type(
|
||||||
Scrobble.for_week(
|
Scrobble.for_week(user_id, date.year, date.isocalendar()[1])
|
||||||
user_id, date.year, date.isocalendar()[1]
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
elif date_str == "this_month" or date_str.count("-") == 1:
|
elif date_str == "this_month" or date_str.count("-") == 1:
|
||||||
next_date = date + relativedelta(months=1)
|
next_date = date + relativedelta(months=1)
|
||||||
prev_date = date + relativedelta(months=-1)
|
prev_date = date + relativedelta(months=-1)
|
||||||
if date.month < today.month:
|
if date.month < today.month:
|
||||||
data[
|
data["next_link"] = f"?date={next_date.strftime('%Y-%m')}"
|
||||||
"next_link"
|
|
||||||
] = f"?date={next_date.strftime('%Y-%m')}"
|
|
||||||
data["title"] = f"{date.strftime('%B %Y')}"
|
data["title"] = f"{date.strftime('%B %Y')}"
|
||||||
data["prev_link"] = f"?date={prev_date.strftime('%Y-%m')}"
|
data["prev_link"] = f"?date={prev_date.strftime('%Y-%m')}"
|
||||||
data = data | Scrobble.as_dict_by_type(
|
data = data | Scrobble.as_dict_by_type(
|
||||||
@ -182,24 +174,16 @@ class RecentScrobbleList(ListView):
|
|||||||
elif date_str == "today" or date_str.count("-") == 2:
|
elif date_str == "today" or date_str.count("-") == 2:
|
||||||
next_date = date + timedelta(days=1)
|
next_date = date + timedelta(days=1)
|
||||||
prev_date = date - timedelta(days=1)
|
prev_date = date - timedelta(days=1)
|
||||||
data[
|
data["prev_link"] = f"?date={prev_date.strftime('%Y-%m-%d')}"
|
||||||
"prev_link"
|
|
||||||
] = f"?date={prev_date.strftime('%Y-%m-%d')}"
|
|
||||||
if date < today:
|
if date < today:
|
||||||
data[
|
data["next_link"] = f"?date={next_date.strftime('%Y-%m-%d')}"
|
||||||
"next_link"
|
|
||||||
] = f"?date={next_date.strftime('%Y-%m-%d')}"
|
|
||||||
if date == today:
|
if date == today:
|
||||||
data["title"] = "Today"
|
data["title"] = "Today"
|
||||||
else:
|
else:
|
||||||
data["title"] = f"{date.strftime('%Y-%m-%d')}"
|
data["title"] = f"{date.strftime('%Y-%m-%d')}"
|
||||||
data[
|
data["today_link"] = f"?date={today.strftime('%Y-%m-%d')}"
|
||||||
"today_link"
|
|
||||||
] = f"?date={today.strftime('%Y-%m-%d')}"
|
|
||||||
data = data | Scrobble.as_dict_by_type(
|
data = data | Scrobble.as_dict_by_type(
|
||||||
Scrobble.for_day(
|
Scrobble.for_day(user_id, date.year, date.month, date.day)
|
||||||
user_id, date.year, date.month, date.day
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
elif date_str == "this_year" or date_str.count("-") == 0:
|
elif date_str == "this_year" or date_str.count("-") == 0:
|
||||||
next_date = date + relativedelta(years=+1)
|
next_date = date + relativedelta(years=+1)
|
||||||
@ -222,9 +206,7 @@ class RecentScrobbleList(ListView):
|
|||||||
data = data | Scrobble.as_dict_by_type(
|
data = data | Scrobble.as_dict_by_type(
|
||||||
Scrobble.for_day(user_id, date.year, date.month, date.day)
|
Scrobble.for_day(user_id, date.year, date.month, date.day)
|
||||||
)
|
)
|
||||||
data[
|
data["today_link"] = "" # f"?date={today.strftime('%Y-%m-%d')}"
|
||||||
"today_link"
|
|
||||||
] = "" # f"?date={today.strftime('%Y-%m-%d')}"
|
|
||||||
|
|
||||||
data["active_imports"] = AudioScrobblerTSVImport.objects.filter(
|
data["active_imports"] = AudioScrobblerTSVImport.objects.filter(
|
||||||
processing_started__isnull=False,
|
processing_started__isnull=False,
|
||||||
@ -232,7 +214,9 @@ class RecentScrobbleList(ListView):
|
|||||||
user=self.request.user,
|
user=self.request.user,
|
||||||
)
|
)
|
||||||
data["counts"] = [] # scrobble_counts(user)
|
data["counts"] = [] # scrobble_counts(user)
|
||||||
data["daily_calories"] = get_daily_calories_for_user_by_day(self.request.user.id, date)
|
data["daily_calories"] = get_daily_calories_for_user_by_day(
|
||||||
|
self.request.user.id, date
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
data["weekly_data"] = week_of_scrobbles()
|
data["weekly_data"] = week_of_scrobbles()
|
||||||
data["counts"] = scrobble_counts()
|
data["counts"] = scrobble_counts()
|
||||||
@ -251,9 +235,7 @@ class ScrobbleLongPlaysView(TemplateView):
|
|||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context_data = super().get_context_data(**kwargs)
|
context_data = super().get_context_data(**kwargs)
|
||||||
context_data["view"] = self.request.GET.get("view", "grid")
|
context_data["view"] = self.request.GET.get("view", "grid")
|
||||||
context_data["in_progress"] = get_long_plays_in_progress(
|
context_data["in_progress"] = get_long_plays_in_progress(self.request.user)
|
||||||
self.request.user
|
|
||||||
)
|
|
||||||
context_data["completed"] = get_long_plays_completed(self.request.user)
|
context_data["completed"] = get_long_plays_completed(self.request.user)
|
||||||
return context_data
|
return context_data
|
||||||
|
|
||||||
@ -330,9 +312,7 @@ class ManualScrobbleView(FormView):
|
|||||||
scrobble_fn = MANUAL_SCROBBLE_FNS[key]
|
scrobble_fn = MANUAL_SCROBBLE_FNS[key]
|
||||||
scrobble = eval(scrobble_fn)(item_id, self.request.user.id)
|
scrobble = eval(scrobble_fn)(item_id, self.request.user.id)
|
||||||
|
|
||||||
return HttpResponseRedirect(
|
return HttpResponseRedirect(scrobble.redirect_url(self.request.user.id))
|
||||||
scrobble.redirect_url(self.request.user.id)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class JsonableResponseMixin:
|
class JsonableResponseMixin:
|
||||||
@ -378,9 +358,7 @@ class AudioScrobblerImportCreateView(
|
|||||||
return HttpResponseRedirect(self.request.META.get("HTTP_REFERER"))
|
return HttpResponseRedirect(self.request.META.get("HTTP_REFERER"))
|
||||||
|
|
||||||
|
|
||||||
class KoReaderImportCreateView(
|
class KoReaderImportCreateView(LoginRequiredMixin, JsonableResponseMixin, CreateView):
|
||||||
LoginRequiredMixin, JsonableResponseMixin, CreateView
|
|
||||||
):
|
|
||||||
model = KoReaderImport
|
model = KoReaderImport
|
||||||
fields = ["sqlite_file"]
|
fields = ["sqlite_file"]
|
||||||
template_name = "scrobbles/upload_form.html"
|
template_name = "scrobbles/upload_form.html"
|
||||||
@ -439,9 +417,7 @@ def web_scrobbler_webhook(request):
|
|||||||
playing_state = "started"
|
playing_state = "started"
|
||||||
if request.POST.get("isPlaying") == "false":
|
if request.POST.get("isPlaying") == "false":
|
||||||
playing_state = "stopped"
|
playing_state = "stopped"
|
||||||
scrobble = web_scrobbler_scrobble_media(
|
scrobble = web_scrobbler_scrobble_media(youtube_id, user_id, status=playing_state)
|
||||||
youtube_id, user_id, status=playing_state
|
|
||||||
)
|
|
||||||
if not scrobble:
|
if not scrobble:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"[web_scrobbler_webhook] failed",
|
"[web_scrobbler_webhook] failed",
|
||||||
@ -566,18 +542,12 @@ def import_audioscrobbler_file(request):
|
|||||||
scrobbles_created = []
|
scrobbles_created = []
|
||||||
# tsv_file = request.FILES[0]
|
# tsv_file = request.FILES[0]
|
||||||
|
|
||||||
file_serializer = serializers.AudioScrobblerTSVImportSerializer(
|
file_serializer = serializers.AudioScrobblerTSVImportSerializer(data=request.data)
|
||||||
data=request.data
|
|
||||||
)
|
|
||||||
if file_serializer.is_valid():
|
if file_serializer.is_valid():
|
||||||
import_file = file_serializer.save()
|
import_file = file_serializer.save()
|
||||||
return Response(
|
return Response({"scrobble_ids": scrobbles_created}, status=status.HTTP_200_OK)
|
||||||
{"scrobble_ids": scrobbles_created}, status=status.HTTP_200_OK
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
return Response(
|
return Response(file_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||||
file_serializer.errors, status=status.HTTP_400_BAD_REQUEST
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@permission_classes([IsAuthenticated])
|
@permission_classes([IsAuthenticated])
|
||||||
@ -623,9 +593,9 @@ def scrobble_start(request, uuid):
|
|||||||
request, messages.ERROR, f"Media with uuid {uuid} not found."
|
request, messages.ERROR, f"Media with uuid {uuid} not found."
|
||||||
)
|
)
|
||||||
|
|
||||||
if (
|
if user.profile.redirect_to_webpage and (
|
||||||
user.profile.redirect_to_webpage
|
media_obj.__class__.__name__ == Scrobble.MediaType.WEBPAGE
|
||||||
and (media_obj.__class__.__name__ == Scrobble.MediaType.WEBPAGE or media_obj.__class__.__name__ == Scrobble.MediaType.BOOK)
|
or media_obj.__class__.__name__ == Scrobble.MediaType.BOOK
|
||||||
):
|
):
|
||||||
logger.info(f"Redirecting to {media_obj} detail page")
|
logger.info(f"Redirecting to {media_obj} detail page")
|
||||||
return HttpResponseRedirect(media_obj.url)
|
return HttpResponseRedirect(media_obj.url)
|
||||||
@ -754,9 +724,7 @@ class ChartRecordView(TemplateView):
|
|||||||
).order_by("rank")
|
).order_by("rank")
|
||||||
|
|
||||||
if charts.count() == 0:
|
if charts.count() == 0:
|
||||||
ChartRecord.build(
|
ChartRecord.build(user=self.request.user, model_str=media_type, **kwargs)
|
||||||
user=self.request.user, model_str=media_type, **kwargs
|
|
||||||
)
|
|
||||||
charts = ChartRecord.objects.filter(
|
charts = ChartRecord.objects.filter(
|
||||||
media_filter, user=self.request.user, **kwargs
|
media_filter, user=self.request.user, **kwargs
|
||||||
).order_by("rank")
|
).order_by("rank")
|
||||||
@ -788,9 +756,7 @@ class ChartRecordView(TemplateView):
|
|||||||
media_type = self.request.GET.get("media", "Track")
|
media_type = self.request.GET.get("media", "Track")
|
||||||
user = self.request.user
|
user = self.request.user
|
||||||
params = {}
|
params = {}
|
||||||
context_data["chart_type"] = self.request.GET.get(
|
context_data["chart_type"] = self.request.GET.get("chart_type", "maloja")
|
||||||
"chart_type", "maloja"
|
|
||||||
)
|
|
||||||
context_data["artist_charts"] = {}
|
context_data["artist_charts"] = {}
|
||||||
|
|
||||||
if not date:
|
if not date:
|
||||||
@ -855,9 +821,7 @@ class ChartRecordView(TemplateView):
|
|||||||
params["day"] = day
|
params["day"] = day
|
||||||
month_str = calendar.month_name[month]
|
month_str = calendar.month_name[month]
|
||||||
name = f"Chart for {month_str} {day}, {year}"
|
name = f"Chart for {month_str} {day}, {year}"
|
||||||
in_progress = (
|
in_progress = now.month == month and now.year == year and now.day == day
|
||||||
now.month == month and now.year == year and now.day == day
|
|
||||||
)
|
|
||||||
|
|
||||||
media_filter = self.get_media_filter("Track")
|
media_filter = self.get_media_filter("Track")
|
||||||
track_charts = ChartRecord.objects.filter(
|
track_charts = ChartRecord.objects.filter(
|
||||||
@ -869,17 +833,13 @@ class ChartRecordView(TemplateView):
|
|||||||
).order_by("rank")
|
).order_by("rank")
|
||||||
|
|
||||||
if track_charts.count() == 0 and not in_progress:
|
if track_charts.count() == 0 and not in_progress:
|
||||||
ChartRecord.build(
|
ChartRecord.build(user=self.request.user, model_str="Track", **params)
|
||||||
user=self.request.user, model_str="Track", **params
|
|
||||||
)
|
|
||||||
media_filter = self.get_media_filter("Track")
|
media_filter = self.get_media_filter("Track")
|
||||||
track_charts = ChartRecord.objects.filter(
|
track_charts = ChartRecord.objects.filter(
|
||||||
media_filter, user=self.request.user, **params
|
media_filter, user=self.request.user, **params
|
||||||
).order_by("rank")
|
).order_by("rank")
|
||||||
if artist_charts.count() == 0 and not in_progress:
|
if artist_charts.count() == 0 and not in_progress:
|
||||||
ChartRecord.build(
|
ChartRecord.build(user=self.request.user, model_str="Artist", **params)
|
||||||
user=self.request.user, model_str="Artist", **params
|
|
||||||
)
|
|
||||||
media_filter = self.get_media_filter("Artist")
|
media_filter = self.get_media_filter("Artist")
|
||||||
artist_charts = ChartRecord.objects.filter(
|
artist_charts = ChartRecord.objects.filter(
|
||||||
media_filter, user=self.request.user, **params
|
media_filter, user=self.request.user, **params
|
||||||
@ -900,38 +860,24 @@ class ScrobbleStatusView(LoginRequiredMixin, TemplateView):
|
|||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
data = super().get_context_data(**kwargs)
|
data = super().get_context_data(**kwargs)
|
||||||
user_scrobble_qs = Scrobble.objects.filter().order_by("-timestamp")
|
user_scrobble_qs = Scrobble.objects.filter().order_by("-timestamp")
|
||||||
progress_plays = user_scrobble_qs.filter(
|
progress_plays = user_scrobble_qs.filter(in_progress=True, is_paused=False)
|
||||||
in_progress=True, is_paused=False
|
|
||||||
)
|
|
||||||
|
|
||||||
data["listening"] = progress_plays.filter(
|
data["listening"] = progress_plays.filter(
|
||||||
Q(track__isnull=False) | Q(podcast_episode__isnull=False)
|
Q(track__isnull=False) | Q(podcast_episode__isnull=False)
|
||||||
).first()
|
).first()
|
||||||
data["watching"] = progress_plays.filter(video__isnull=False).first()
|
data["watching"] = progress_plays.filter(video__isnull=False).first()
|
||||||
data["going"] = progress_plays.filter(
|
data["going"] = progress_plays.filter(geo_location__isnull=False).first()
|
||||||
geo_location__isnull=False
|
data["playing"] = progress_plays.filter(board_game__isnull=False).first()
|
||||||
).first()
|
data["sporting"] = progress_plays.filter(sport_event__isnull=False).first()
|
||||||
data["playing"] = progress_plays.filter(
|
data["browsing"] = progress_plays.filter(web_page__isnull=False).first()
|
||||||
board_game__isnull=False
|
data["participating"] = progress_plays.filter(life_event__isnull=False).first()
|
||||||
).first()
|
|
||||||
data["sporting"] = progress_plays.filter(
|
|
||||||
sport_event__isnull=False
|
|
||||||
).first()
|
|
||||||
data["browsing"] = progress_plays.filter(
|
|
||||||
web_page__isnull=False
|
|
||||||
).first()
|
|
||||||
data["participating"] = progress_plays.filter(
|
|
||||||
life_event__isnull=False
|
|
||||||
).first()
|
|
||||||
data["working"] = progress_plays.filter(task__isnull=False).first()
|
data["working"] = progress_plays.filter(task__isnull=False).first()
|
||||||
|
|
||||||
long_plays = user_scrobble_qs.filter(
|
long_plays = user_scrobble_qs.filter(
|
||||||
long_play_complete=False, played_to_completion=True
|
long_play_complete=False, played_to_completion=True
|
||||||
)
|
)
|
||||||
data["reading"] = long_plays.filter(book__isnull=False).first()
|
data["reading"] = long_plays.filter(book__isnull=False).first()
|
||||||
data["sessioning"] = long_plays.filter(
|
data["sessioning"] = long_plays.filter(video_game__isnull=False).first()
|
||||||
video_game__isnull=False
|
|
||||||
).first()
|
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
@ -949,14 +895,16 @@ class ScrobbleDetailView(DetailView):
|
|||||||
|
|
||||||
log = self.object.log or {}
|
log = self.object.log or {}
|
||||||
initial_notes = log.get("notes", [])
|
initial_notes = log.get("notes", [])
|
||||||
if isinstance(initial_notes, list) and len(initial_notes) > 0 and isinstance(initial_notes[0], dict):
|
if (
|
||||||
|
isinstance(initial_notes, list)
|
||||||
|
and len(initial_notes) > 0
|
||||||
|
and isinstance(initial_notes[0], dict)
|
||||||
|
):
|
||||||
notes_str = note_list_to_str(notes)
|
notes_str = note_list_to_str(notes)
|
||||||
else:
|
else:
|
||||||
notes_str = "\n".join(initial_notes) if initial_notes else ""
|
notes_str = "\n".join(initial_notes) if initial_notes else ""
|
||||||
|
|
||||||
notes_str_fixed = notes_str.encode("utf-8").decode(
|
notes_str_fixed = notes_str.encode("utf-8").decode("unicode_escape")
|
||||||
"unicode_escape"
|
|
||||||
)
|
|
||||||
log["notes"] = notes_str_fixed
|
log["notes"] = notes_str_fixed
|
||||||
|
|
||||||
return FormClass(initial=log)
|
return FormClass(initial=log)
|
||||||
@ -975,9 +923,7 @@ class ScrobbleDetailView(DetailView):
|
|||||||
data[field_name] = original_value
|
data[field_name] = original_value
|
||||||
|
|
||||||
if data.get("with_people_ids", False):
|
if data.get("with_people_ids", False):
|
||||||
data["with_people_ids"] = [
|
data["with_people_ids"] = [p.id for p in data["with_people_ids"]]
|
||||||
p.id for p in data["with_people_ids"]
|
|
||||||
]
|
|
||||||
|
|
||||||
if data.get("platform_id", False):
|
if data.get("platform_id", False):
|
||||||
data["platform_id"] = data["platform_id"].id
|
data["platform_id"] = data["platform_id"].id
|
||||||
|
|||||||
@ -37,9 +37,7 @@ TESTING = len(sys.argv) > 1 and sys.argv[1] == "test"
|
|||||||
|
|
||||||
TAGGIT_CASE_INSENSITIVE = True
|
TAGGIT_CASE_INSENSITIVE = True
|
||||||
|
|
||||||
KEEP_DETAILED_SCROBBLE_LOGS = os.getenv(
|
KEEP_DETAILED_SCROBBLE_LOGS = os.getenv("VROBBLER_KEEP_DETAILED_SCROBBLE_LOGS", False)
|
||||||
"VROBBLER_KEEP_DETAILED_SCROBBLE_LOGS", False
|
|
||||||
)
|
|
||||||
|
|
||||||
# Key must be 16, 24 or 32 bytes long and will be converted to a byte stream
|
# Key must be 16, 24 or 32 bytes long and will be converted to a byte stream
|
||||||
ENCRYPTED_FIELD_KEY = os.getenv(
|
ENCRYPTED_FIELD_KEY = os.getenv(
|
||||||
@ -54,9 +52,7 @@ DELETE_STALE_SCROBBLES = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Used to dump data coming from srobbling sources, helpful for building new inputs
|
# Used to dump data coming from srobbling sources, helpful for building new inputs
|
||||||
DUMP_REQUEST_DATA = (
|
DUMP_REQUEST_DATA = os.getenv("VROBBLER_DUMP_REQUEST_DATA", "false").lower() in TRUTHY
|
||||||
os.getenv("VROBBLER_DUMP_REQUEST_DATA", "false").lower() in TRUTHY
|
|
||||||
)
|
|
||||||
|
|
||||||
USDA_API_KEY = os.getenv("VROBBLER_USDA_API_KEY")
|
USDA_API_KEY = os.getenv("VROBBLER_USDA_API_KEY")
|
||||||
THESPORTSDB_API_KEY = os.getenv("VROBBLER_THESPORTSDB_API_KEY", "2")
|
THESPORTSDB_API_KEY = os.getenv("VROBBLER_THESPORTSDB_API_KEY", "2")
|
||||||
@ -72,9 +68,7 @@ COMICVINE_API_KEY = os.getenv("VROBBLER_COMICVINE_API_KEY")
|
|||||||
BGG_ACCESS_TOKEN = os.getenv("VROBBLER_BGG_ACCESS_TOKEN", "")
|
BGG_ACCESS_TOKEN = os.getenv("VROBBLER_BGG_ACCESS_TOKEN", "")
|
||||||
GEOLOC_ACCURACY = os.getenv("VROBBLER_GEOLOC_ACCURACY", 3)
|
GEOLOC_ACCURACY = os.getenv("VROBBLER_GEOLOC_ACCURACY", 3)
|
||||||
GEOLOC_PROXIMITY = os.getenv("VROBBLER_GEOLOC_PROXIMITY", "0.0001")
|
GEOLOC_PROXIMITY = os.getenv("VROBBLER_GEOLOC_PROXIMITY", "0.0001")
|
||||||
POINTS_FOR_MOVEMENT_HISTORY = os.getenv(
|
POINTS_FOR_MOVEMENT_HISTORY = os.getenv("VROBBLER_POINTS_FOR_MOVEMENT_HISTORY", 3)
|
||||||
"VROBBLER_POINTS_FOR_MOVEMENT_HISTORY", 3
|
|
||||||
)
|
|
||||||
TODOIST_CLIENT_ID = os.getenv("VROBBLER_TODOIST_CLIENT_ID", "")
|
TODOIST_CLIENT_ID = os.getenv("VROBBLER_TODOIST_CLIENT_ID", "")
|
||||||
TODOIST_CLIENT_SECRET = os.getenv("VROBBLER_TODOIST_CLIENT_SECRET", "")
|
TODOIST_CLIENT_SECRET = os.getenv("VROBBLER_TODOIST_CLIENT_SECRET", "")
|
||||||
|
|
||||||
@ -97,9 +91,7 @@ DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
|||||||
TIME_ZONE = os.getenv("VROBBLER_TIME_ZONE", "America/New_York")
|
TIME_ZONE = os.getenv("VROBBLER_TIME_ZONE", "America/New_York")
|
||||||
|
|
||||||
ALLOWED_HOSTS = ["*"]
|
ALLOWED_HOSTS = ["*"]
|
||||||
CSRF_TRUSTED_ORIGINS = [
|
CSRF_TRUSTED_ORIGINS = [os.getenv("VROBBLER_TRUSTED_ORIGINS", "http://localhost:8000")]
|
||||||
os.getenv("VROBBLER_TRUSTED_ORIGINS", "http://localhost:8000")
|
|
||||||
]
|
|
||||||
X_FRAME_OPTIONS = "SAMEORIGIN"
|
X_FRAME_OPTIONS = "SAMEORIGIN"
|
||||||
|
|
||||||
REDIS_URL = os.getenv("VROBBLER_REDIS_URL", None)
|
REDIS_URL = os.getenv("VROBBLER_REDIS_URL", None)
|
||||||
@ -108,9 +100,7 @@ if REDIS_URL:
|
|||||||
else:
|
else:
|
||||||
print("Eagerly running all tasks")
|
print("Eagerly running all tasks")
|
||||||
|
|
||||||
CELERY_TASK_ALWAYS_EAGER = (
|
CELERY_TASK_ALWAYS_EAGER = os.getenv("VROBBLER_SKIP_CELERY", "false").lower() in TRUTHY
|
||||||
os.getenv("VROBBLER_SKIP_CELERY", "false").lower() in TRUTHY
|
|
||||||
)
|
|
||||||
CELERY_BROKER_URL = REDIS_URL if REDIS_URL else "memory://localhost/"
|
CELERY_BROKER_URL = REDIS_URL if REDIS_URL else "memory://localhost/"
|
||||||
CELERY_RESULT_BACKEND = "django-db"
|
CELERY_RESULT_BACKEND = "django-db"
|
||||||
CELERY_TIMEZONE = os.getenv("VROBBLER_TIME_ZONE", "America/New_York")
|
CELERY_TIMEZONE = os.getenv("VROBBLER_TIME_ZONE", "America/New_York")
|
||||||
@ -210,9 +200,7 @@ DATABASES = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if TESTING:
|
if TESTING:
|
||||||
DATABASES = {
|
DATABASES = {"default": dj_database_url.config(default="sqlite:///testdb.sqlite3")}
|
||||||
"default": dj_database_url.config(default="sqlite:///testdb.sqlite3")
|
|
||||||
}
|
|
||||||
|
|
||||||
db_str = ""
|
db_str = ""
|
||||||
if "sqlite" in DATABASES["default"]["ENGINE"]:
|
if "sqlite" in DATABASES["default"]["ENGINE"]:
|
||||||
@ -310,9 +298,7 @@ else:
|
|||||||
STATIC_ROOT = os.getenv(
|
STATIC_ROOT = os.getenv(
|
||||||
"VROBBLER_STATIC_ROOT", os.path.join(PROJECT_ROOT, "static")
|
"VROBBLER_STATIC_ROOT", os.path.join(PROJECT_ROOT, "static")
|
||||||
)
|
)
|
||||||
MEDIA_ROOT = os.getenv(
|
MEDIA_ROOT = os.getenv("VROBBLER_MEDIA_ROOT", os.path.join(PROJECT_ROOT, "media"))
|
||||||
"VROBBLER_MEDIA_ROOT", os.path.join(PROJECT_ROOT, "media")
|
|
||||||
)
|
|
||||||
STATIC_URL = os.getenv("VROBBLER_STATIC_URL", "/static/")
|
STATIC_URL = os.getenv("VROBBLER_STATIC_URL", "/static/")
|
||||||
MEDIA_URL = os.getenv("VROBBLER_MEDIA_URL", "/media/")
|
MEDIA_URL = os.getenv("VROBBLER_MEDIA_URL", "/media/")
|
||||||
|
|
||||||
@ -396,9 +382,7 @@ LOGGING = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_TO_CONSOLE = (
|
LOG_TO_CONSOLE = os.getenv("VROBBLER_LOG_TO_CONSOLE", "false").lower() in TRUTHY
|
||||||
os.getenv("VROBBLER_LOG_TO_CONSOLE", "false").lower() in TRUTHY
|
|
||||||
)
|
|
||||||
if LOG_TO_CONSOLE:
|
if LOG_TO_CONSOLE:
|
||||||
LOGGING["loggers"]["django"]["handlers"] = ["console"]
|
LOGGING["loggers"]["django"]["handlers"] = ["console"]
|
||||||
LOGGING["loggers"]["vrobbler"]["handlers"] = ["console"]
|
LOGGING["loggers"]["vrobbler"]["handlers"] = ["console"]
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
from django.conf import settings
|
||||||
|
from django.conf.urls.static import static
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.urls import include, path
|
from django.urls import include, path
|
||||||
from oauth2_provider import urls as oauth2_urls
|
from oauth2_provider import urls as oauth2_urls
|
||||||
@ -6,7 +8,12 @@ from rest_framework import routers
|
|||||||
import vrobbler.apps.scrobbles.views as scrobbles_views
|
import vrobbler.apps.scrobbles.views as scrobbles_views
|
||||||
|
|
||||||
from vrobbler.apps.boardgames import urls as boardgame_urls
|
from vrobbler.apps.boardgames import urls as boardgame_urls
|
||||||
from vrobbler.apps.boardgames.api.views import BoardGameViewSet, BoardGameDesignerViewSet, BoardGamePublisherViewSet, BoardGameLocationViewSet
|
from vrobbler.apps.boardgames.api.views import (
|
||||||
|
BoardGameViewSet,
|
||||||
|
BoardGameDesignerViewSet,
|
||||||
|
BoardGamePublisherViewSet,
|
||||||
|
BoardGameLocationViewSet,
|
||||||
|
)
|
||||||
|
|
||||||
from vrobbler.apps.books import urls as book_urls
|
from vrobbler.apps.books import urls as book_urls
|
||||||
from vrobbler.apps.books.api.views import AuthorViewSet, BookViewSet
|
from vrobbler.apps.books.api.views import AuthorViewSet, BookViewSet
|
||||||
@ -31,7 +38,11 @@ from vrobbler.apps.music.api.views import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from vrobbler.apps.podcasts import urls as podcast_urls
|
from vrobbler.apps.podcasts import urls as podcast_urls
|
||||||
from vrobbler.apps.podcasts.api.views import ProducerViewSet, PodcastViewSet, PodcastEpisodeViewSet
|
from vrobbler.apps.podcasts.api.views import (
|
||||||
|
ProducerViewSet,
|
||||||
|
PodcastViewSet,
|
||||||
|
PodcastEpisodeViewSet,
|
||||||
|
)
|
||||||
|
|
||||||
from vrobbler.apps.scrobbles import urls as scrobble_urls
|
from vrobbler.apps.scrobbles import urls as scrobble_urls
|
||||||
from vrobbler.apps.scrobbles.api.views import (
|
from vrobbler.apps.scrobbles.api.views import (
|
||||||
@ -60,14 +71,25 @@ from vrobbler.apps.trails import urls as trails_urls
|
|||||||
from vrobbler.apps.trails.api.views import TrailViewSet
|
from vrobbler.apps.trails.api.views import TrailViewSet
|
||||||
|
|
||||||
from vrobbler.apps.beers import urls as beers_urls
|
from vrobbler.apps.beers import urls as beers_urls
|
||||||
from vrobbler.apps.beers.api.views import BeerViewSet, BeerProducerViewSet, BeerStyleViewSet
|
from vrobbler.apps.beers.api.views import (
|
||||||
|
BeerViewSet,
|
||||||
|
BeerProducerViewSet,
|
||||||
|
BeerStyleViewSet,
|
||||||
|
)
|
||||||
|
|
||||||
from vrobbler.apps.puzzles import urls as puzzles_urls
|
from vrobbler.apps.puzzles import urls as puzzles_urls
|
||||||
from vrobbler.apps.puzzles.api.views import PuzzleViewSet, PuzzleManufacturerViewSet
|
from vrobbler.apps.puzzles.api.views import (
|
||||||
|
PuzzleViewSet,
|
||||||
|
PuzzleManufacturerViewSet,
|
||||||
|
)
|
||||||
from vrobbler.apps.videogames import urls as videogame_urls
|
from vrobbler.apps.videogames import urls as videogame_urls
|
||||||
|
|
||||||
from vrobbler.apps.videos import urls as video_urls
|
from vrobbler.apps.videos import urls as video_urls
|
||||||
from vrobbler.apps.videos.api.views import ChannelViewSet, SeriesViewSet, VideoViewSet
|
from vrobbler.apps.videos.api.views import (
|
||||||
|
ChannelViewSet,
|
||||||
|
SeriesViewSet,
|
||||||
|
VideoViewSet,
|
||||||
|
)
|
||||||
|
|
||||||
from vrobbler.apps.bricksets import urls as bricksets_urls
|
from vrobbler.apps.bricksets import urls as bricksets_urls
|
||||||
from vrobbler.apps.bricksets.api.views import BrickSetViewSet
|
from vrobbler.apps.bricksets.api.views import BrickSetViewSet
|
||||||
@ -149,3 +171,10 @@ urlpatterns = [
|
|||||||
"", scrobbles_views.RecentScrobbleList.as_view(), name="vrobbler-home"
|
"", scrobbles_views.RecentScrobbleList.as_view(), name="vrobbler-home"
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
if settings.DEBUG:
|
||||||
|
urlpatterns = urlpatterns + static(
|
||||||
|
settings.STATIC_URL, document_root=settings.STATIC_ROOT
|
||||||
|
)
|
||||||
|
urlpatterns = urlpatterns + static(
|
||||||
|
settings.MEDIA_URL, document_root=settings.MEDIA_ROOT
|
||||||
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user