From f6b20c03e34431bf5d4cfbcd694b937b2f711af9 Mon Sep 17 00:00:00 2001 From: tcely Date: Fri, 2 May 2025 15:36:00 -0400 Subject: [PATCH 1/8] Add `NoThumbnailException` --- tubesync/common/errors.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tubesync/common/errors.py b/tubesync/common/errors.py index 87d8aa4d..67a00eba 100644 --- a/tubesync/common/errors.py +++ b/tubesync/common/errors.py @@ -1,3 +1,6 @@ +from django.http import Http404 + + class NoMediaException(Exception): ''' Raised when a source returns no media to be indexed. Could be an invalid @@ -22,6 +25,13 @@ class NoMetadataException(Exception): pass +class NoThumbnailException(Http404): + ''' + Raised when a thumbnail was not found at the remote URL. + ''' + pass + + class DownloadFailedException(Exception): ''' Raised when a downloaded media file is expected to be present, but doesn't From 3a0c4c8fb15a4deefac2f16027f851510ea6141e Mon Sep 17 00:00:00 2001 From: tcely Date: Fri, 2 May 2025 16:12:25 -0400 Subject: [PATCH 2/8] Raise when `status_code` is not 200: OK --- tubesync/sync/utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tubesync/sync/utils.py b/tubesync/sync/utils.py index 917a9531..b67fedc8 100644 --- a/tubesync/sync/utils.py +++ b/tubesync/sync/utils.py @@ -65,6 +65,8 @@ def get_remote_image(url, force_rgb=True): '(KHTML, like Gecko) Chrome/69.0.3497.64 Safari/537.36') } r = requests.get(url, headers=headers, stream=True, timeout=60) + if 200 != r.status_code: + r.raise_for_status() r.raw.decode_content = True i = Image.open(r.raw) if force_rgb: From add6454c336be23f869a2617fd02d94d5b20a17c Mon Sep 17 00:00:00 2001 From: tcely Date: Fri, 2 May 2025 16:20:48 -0400 Subject: [PATCH 3/8] Use `NoThumbnailException` from thumbnail task --- tubesync/sync/tasks.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tubesync/sync/tasks.py b/tubesync/sync/tasks.py index 5e727e6d..3c70c0ef 100644 --- a/tubesync/sync/tasks.py +++ b/tubesync/sync/tasks.py @@ -8,6 +8,7 @@ import os import json import math import random +import requests import time import uuid from io import BytesIO @@ -29,7 +30,8 @@ from background_task.exceptions import InvalidTaskError from background_task.models import Task, CompletedTask from common.logger import log from common.errors import ( NoFormatException, NoMediaException, - NoMetadataException, DownloadFailedException, ) + NoMetadataException, NoThumbnailException, + DownloadFailedException, ) from common.utils import ( django_queryset_generator as qs_gen, remove_enclosed, ) from .choices import Val, TaskQueue @@ -548,7 +550,10 @@ def download_media_thumbnail(media_id, url): return width = getattr(settings, 'MEDIA_THUMBNAIL_WIDTH', 430) height = getattr(settings, 'MEDIA_THUMBNAIL_HEIGHT', 240) - i = get_remote_image(url) + try: + i = get_remote_image(url) + except requests.HTTPError as e: + raise NoThumbnailException(url) from e if (i.width > width) and (i.height > height): log.info(f'Resizing {i.width}x{i.height} thumbnail to ' f'{width}x{height}: {url}') From d6b60f41c9fe266d0d169bf168af695a4254ae75 Mon Sep 17 00:00:00 2001 From: tcely Date: Fri, 2 May 2025 16:52:20 -0400 Subject: [PATCH 4/8] End the task for HTTP 404 response status --- tubesync/sync/tasks.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tubesync/sync/tasks.py b/tubesync/sync/tasks.py index 3c70c0ef..744373da 100644 --- a/tubesync/sync/tasks.py +++ b/tubesync/sync/tasks.py @@ -551,9 +551,14 @@ def download_media_thumbnail(media_id, url): width = getattr(settings, 'MEDIA_THUMBNAIL_WIDTH', 430) height = getattr(settings, 'MEDIA_THUMBNAIL_HEIGHT', 240) try: - i = get_remote_image(url) - except requests.HTTPError as e: - raise NoThumbnailException(url) from e + try: + i = get_remote_image(url) + except requests.HTTPError as re: + if 404 != re.response.status_code: + raise + raise NoThumbnailException(re.response.reason) from re + except NoThumbnailException as e: + raise InvalidTaskError(str(e.__cause__)) from e if (i.width > width) and (i.height > height): log.info(f'Resizing {i.width}x{i.height} thumbnail to ' f'{width}x{height}: {url}') From a7fdd02d47a462aac003a5de3ebd331d0d56c20f Mon Sep 17 00:00:00 2001 From: tcely Date: Fri, 2 May 2025 17:09:23 -0400 Subject: [PATCH 5/8] A standard `Exception` is fine --- tubesync/common/errors.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tubesync/common/errors.py b/tubesync/common/errors.py index 67a00eba..9ff44a48 100644 --- a/tubesync/common/errors.py +++ b/tubesync/common/errors.py @@ -1,6 +1,3 @@ -from django.http import Http404 - - class NoMediaException(Exception): ''' Raised when a source returns no media to be indexed. Could be an invalid @@ -25,7 +22,7 @@ class NoMetadataException(Exception): pass -class NoThumbnailException(Http404): +class NoThumbnailException(Exception): ''' Raised when a thumbnail was not found at the remote URL. ''' From 46d2e3c8e70243cef3134845e7857ff627034a5e Mon Sep 17 00:00:00 2001 From: tcely Date: Fri, 2 May 2025 17:14:07 -0400 Subject: [PATCH 6/8] `raise_for_status` checks `status_code` itself --- tubesync/sync/utils.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tubesync/sync/utils.py b/tubesync/sync/utils.py index b67fedc8..5bc90d25 100644 --- a/tubesync/sync/utils.py +++ b/tubesync/sync/utils.py @@ -65,8 +65,7 @@ def get_remote_image(url, force_rgb=True): '(KHTML, like Gecko) Chrome/69.0.3497.64 Safari/537.36') } r = requests.get(url, headers=headers, stream=True, timeout=60) - if 200 != r.status_code: - r.raise_for_status() + r.raise_for_status() r.raw.decode_content = True i = Image.open(r.raw) if force_rgb: From 71b57dd477896cfc23082d5025de6f5ee50b1fa6 Mon Sep 17 00:00:00 2001 From: tcely Date: Fri, 2 May 2025 21:03:09 -0400 Subject: [PATCH 7/8] Schedule thumbnail tasks for new media --- tubesync/sync/tasks.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tubesync/sync/tasks.py b/tubesync/sync/tasks.py index 744373da..304b38e6 100644 --- a/tubesync/sync/tasks.py +++ b/tubesync/sync/tasks.py @@ -354,8 +354,21 @@ def index_source_task(source_id): ) if new_media_instance: log.info(f'Indexed new media: {source} / {media}') + log.info(f'Scheduling tasks to download thumbnail for: {media.key}') + thumbnail_fmt = 'https://i.ytimg.com/vi/{}/{}default.jpg' + vn_fmt = _('Downloading {} thumbnail for: "{}": {}' + for prefix in ('hq', 'sd', 'maxres',): + thumbnail_url = thumbnail_fmt.format( + media.key, + prefix, + ) + download_media_thumbnail( + str(media.pk), + thumbnail_url, + verbose_name=vn_fmt.format(prefix, media.key, media.name), + ) log.info(f'Scheduling task to download metadata for: {media.url}') - verbose_name = _('Downloading metadata for: {}: "{}"') + verbose_name = _('Downloading metadata for: "{}": {}') download_media_metadata( str(media.pk), verbose_name=verbose_name.format(media.key, media.name), From efc59420516d480264ecda37afe155e08f12ba1a Mon Sep 17 00:00:00 2001 From: tcely Date: Fri, 2 May 2025 21:05:16 -0400 Subject: [PATCH 8/8] fixup: closing parenthesis --- tubesync/sync/tasks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tubesync/sync/tasks.py b/tubesync/sync/tasks.py index 304b38e6..2e6b1433 100644 --- a/tubesync/sync/tasks.py +++ b/tubesync/sync/tasks.py @@ -356,7 +356,7 @@ def index_source_task(source_id): log.info(f'Indexed new media: {source} / {media}') log.info(f'Scheduling tasks to download thumbnail for: {media.key}') thumbnail_fmt = 'https://i.ytimg.com/vi/{}/{}default.jpg' - vn_fmt = _('Downloading {} thumbnail for: "{}": {}' + vn_fmt = _('Downloading {} thumbnail for: "{}": {}') for prefix in ('hq', 'sd', 'maxres',): thumbnail_url = thumbnail_fmt.format( media.key,