From 01a44f74cf2ba585066e521b6319e03f2c16884b Mon Sep 17 00:00:00 2001 From: tcely Date: Tue, 13 May 2025 04:52:10 -0400 Subject: [PATCH 01/15] Unpin Django --- Pipfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pipfile b/Pipfile index 2976db2e..bf53b4bf 100644 --- a/Pipfile +++ b/Pipfile @@ -7,7 +7,7 @@ verify_ssl = true autopep8 = "*" [packages] -django = "<5.2" +django = "*" django-sass-processor = {extras = ["management-command"], version = "*"} pillow = "*" whitenoise = "*" From 25af3e340732dc234f2f97c319a2c947ce319342 Mon Sep 17 00:00:00 2001 From: tcely Date: Tue, 13 May 2025 05:24:22 -0400 Subject: [PATCH 02/15] Bump version --- tubesync/tubesync/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tubesync/tubesync/settings.py b/tubesync/tubesync/settings.py index 391a209d..68bca98b 100644 --- a/tubesync/tubesync/settings.py +++ b/tubesync/tubesync/settings.py @@ -7,7 +7,7 @@ CONFIG_BASE_DIR = BASE_DIR DOWNLOADS_BASE_DIR = BASE_DIR -VERSION = '0.15.1' +VERSION = '0.15.2' SECRET_KEY = '' DEBUG = False ALLOWED_HOSTS = [] From aa27e1c22b6db95ce85bc105b1aec353a3b9f3e5 Mon Sep 17 00:00:00 2001 From: tcely Date: Wed, 14 May 2025 10:09:09 -0400 Subject: [PATCH 03/15] Adjust Python versions --- .github/workflows/ci.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 9edc7225..e3fee696 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -84,7 +84,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] + python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] steps: - uses: actions/checkout@v4 - name: Install Python ${{ matrix.python-version }} @@ -102,7 +102,7 @@ jobs: cp -v -a -t "${Python3_ROOT_DIR}"/lib/python3.*/site-packages/background_task/ patches/background_task/* cp -v -a -t "${Python3_ROOT_DIR}"/lib/python3.*/site-packages/yt_dlp/ patches/yt_dlp/* - name: Run Django tests - run: cd tubesync && python3 manage.py test --verbosity=2 + run: cd tubesync && python3 -W error manage.py test --verbosity=2 containerise: if: ${{ !cancelled() && 'success' == needs.info.result }} From 6c10a1da5b6ac7809a897b633c4dd61b908e021c Mon Sep 17 00:00:00 2001 From: tcely Date: Wed, 14 May 2025 10:38:16 -0400 Subject: [PATCH 04/15] Check the Django version before using a removed setting --- tubesync/tubesync/settings.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tubesync/tubesync/settings.py b/tubesync/tubesync/settings.py index 68bca98b..06853cbf 100644 --- a/tubesync/tubesync/settings.py +++ b/tubesync/tubesync/settings.py @@ -1,3 +1,4 @@ +from django import VERSION as DJANGO_VERSION from pathlib import Path from common.utils import getenv @@ -99,7 +100,9 @@ AUTH_PASSWORD_VALIDATORS = [ LANGUAGE_CODE = 'en-us' TIME_ZONE = getenv('TZ', 'UTC') USE_I18N = True -USE_L10N = True +# Removed in Django 5.0 +if DJANGO_VERSION[0:3] < (5, 0, 0): + USE_L10N = True USE_TZ = True From 406ba8a8cd0728840860bb67e1a9e85ebb268ddd Mon Sep 17 00:00:00 2001 From: tcely Date: Wed, 14 May 2025 10:47:32 -0400 Subject: [PATCH 05/15] Set `USE_L10N` to `True` only before Django 4 --- tubesync/tubesync/settings.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tubesync/tubesync/settings.py b/tubesync/tubesync/settings.py index 06853cbf..7f5922ae 100644 --- a/tubesync/tubesync/settings.py +++ b/tubesync/tubesync/settings.py @@ -100,8 +100,9 @@ AUTH_PASSWORD_VALIDATORS = [ LANGUAGE_CODE = 'en-us' TIME_ZONE = getenv('TZ', 'UTC') USE_I18N = True -# Removed in Django 5.0 -if DJANGO_VERSION[0:3] < (5, 0, 0): +# Removed in Django 5.0, set to True by default in Django 4.0 +# https://docs.djangoproject.com/en/4.1/releases/4.0/#localization +if DJANGO_VERSION[0:3] < (4, 0, 0): USE_L10N = True USE_TZ = True From 49340701830bd4fa7b5005f5167c5e4549ae38c6 Mon Sep 17 00:00:00 2001 From: tcely Date: Wed, 14 May 2025 10:58:42 -0400 Subject: [PATCH 06/15] Explicitly pass `assume_scheme` --- tubesync/sync/forms.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tubesync/sync/forms.py b/tubesync/sync/forms.py index 39b1b606..655b93be 100644 --- a/tubesync/sync/forms.py +++ b/tubesync/sync/forms.py @@ -12,7 +12,8 @@ class ValidateSourceForm(forms.Form): ) source_url = forms.URLField( label=_('Source URL'), - required=True + required=True, + assume_scheme='http', # Silence RemovedInDjango60Warning ) From b6466c9b0eb4bf818e04bafad5de92ad2a5c7dc9 Mon Sep 17 00:00:00 2001 From: tcely Date: Wed, 14 May 2025 11:12:58 -0400 Subject: [PATCH 07/15] Always use the UTC time zone --- tubesync/common/timestamp.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tubesync/common/timestamp.py b/tubesync/common/timestamp.py index df7b2f13..d8b69178 100644 --- a/tubesync/common/timestamp.py +++ b/tubesync/common/timestamp.py @@ -1,8 +1,8 @@ import datetime -posix_epoch = datetime.datetime.utcfromtimestamp(0) utc_tz = datetime.timezone.utc +posix_epoch = datetime.datetime.fromtimestamp(0, utc_tz) def add_epoch(seconds): @@ -13,10 +13,9 @@ def add_epoch(seconds): def subtract_epoch(arg_dt, /): assert isinstance(arg_dt, datetime.datetime) - epoch = posix_epoch.astimezone(utc_tz) utc_dt = arg_dt.astimezone(utc_tz) - return utc_dt - epoch + return utc_dt - posix_epoch def datetime_to_timestamp(arg_dt, /, *, integer=True): timestamp = subtract_epoch(arg_dt).total_seconds() From 0cf25a1bc8491ad58e4a4e9204e2267f025b37fa Mon Sep 17 00:00:00 2001 From: tcely Date: Wed, 14 May 2025 11:29:05 -0400 Subject: [PATCH 08/15] `assume_scheme` was added in Django 5 --- tubesync/sync/forms.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tubesync/sync/forms.py b/tubesync/sync/forms.py index 655b93be..e46b740f 100644 --- a/tubesync/sync/forms.py +++ b/tubesync/sync/forms.py @@ -1,8 +1,14 @@ -from django import forms +from django import forms, VERSION as DJANGO_VERSION from django.utils.translation import gettext_lazy as _ +if DJANGO_VERSION[0:3] < (5, 0, 0): + _assume_scheme = dict() +else: + # Silence RemovedInDjango60Warning + _assume_scheme = dict(assume_scheme='http') + class ValidateSourceForm(forms.Form): source_type = forms.CharField( @@ -13,7 +19,7 @@ class ValidateSourceForm(forms.Form): source_url = forms.URLField( label=_('Source URL'), required=True, - assume_scheme='http', # Silence RemovedInDjango60Warning + **_assume_scheme, ) From b901f6f08c925d1ebb5a09bd68721ce3ba0e8aba Mon Sep 17 00:00:00 2001 From: tcely Date: Wed, 14 May 2025 11:39:45 -0400 Subject: [PATCH 09/15] Run `collectstatic` before `test` --- .github/workflows/ci.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index e3fee696..27240f3e 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -101,8 +101,9 @@ jobs: cp -v -p tubesync/tubesync/local_settings.py.example tubesync/tubesync/local_settings.py cp -v -a -t "${Python3_ROOT_DIR}"/lib/python3.*/site-packages/background_task/ patches/background_task/* cp -v -a -t "${Python3_ROOT_DIR}"/lib/python3.*/site-packages/yt_dlp/ patches/yt_dlp/* + cd tubesync && python3 -B manage.py collectstatic --no-input --link - name: Run Django tests - run: cd tubesync && python3 -W error manage.py test --verbosity=2 + run: cd tubesync && python3 -W default manage.py test --verbosity=2 containerise: if: ${{ !cancelled() && 'success' == needs.info.result }} From b99cb61cdb47758e9fa9579214092f032f1f651d Mon Sep 17 00:00:00 2001 From: tcely Date: Wed, 14 May 2025 11:58:29 -0400 Subject: [PATCH 10/15] Don't write `.pyc` files --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 27240f3e..f2a341b8 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -103,7 +103,7 @@ jobs: cp -v -a -t "${Python3_ROOT_DIR}"/lib/python3.*/site-packages/yt_dlp/ patches/yt_dlp/* cd tubesync && python3 -B manage.py collectstatic --no-input --link - name: Run Django tests - run: cd tubesync && python3 -W default manage.py test --verbosity=2 + run: cd tubesync && python3 -B -W default manage.py test --verbosity=2 containerise: if: ${{ !cancelled() && 'success' == needs.info.result }} From 06591a002075dfebe4b8e8a188ca08880a37ba6e Mon Sep 17 00:00:00 2001 From: tcely Date: Wed, 14 May 2025 12:46:57 -0400 Subject: [PATCH 11/15] Remove `Path.is_relative_to` patch for Python `3.8` --- tubesync/sync/signals.py | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/tubesync/sync/signals.py b/tubesync/sync/signals.py index 62f104bb..790ce1c2 100644 --- a/tubesync/sync/signals.py +++ b/tubesync/sync/signals.py @@ -22,20 +22,6 @@ from .filtering import filter_media from .choices import Val, YouTube_SourceType -def is_relative_to(self, *other): - """Return True if the path is relative to another path or False. - """ - try: - self.relative_to(*other) - return True - except ValueError: - return False - -# patch Path for Python 3.8 -if not hasattr(Path, 'is_relative_to'): - Path.is_relative_to = is_relative_to - - @receiver(pre_save, sender=Source) def source_pre_save(sender, instance, **kwargs): # Triggered before a source is saved, if the schedule has been updated recreate From 1c078322ef44e97a61136e044291870cadad6881 Mon Sep 17 00:00:00 2001 From: tcely Date: Wed, 14 May 2025 12:49:48 -0400 Subject: [PATCH 12/15] Remove Python `3.9` as unsupported --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index f2a341b8..b7de46be 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -84,7 +84,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] + python-version: ['3.10', '3.11', '3.12', '3.13'] steps: - uses: actions/checkout@v4 - name: Install Python ${{ matrix.python-version }} From 1142fb6844b55ff84c397a044992564b6ecb42ee Mon Sep 17 00:00:00 2001 From: tcely Date: Wed, 14 May 2025 13:04:58 -0400 Subject: [PATCH 13/15] Update README.md --- README.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 502abf3a..2ea83c54 100644 --- a/README.md +++ b/README.md @@ -146,7 +146,7 @@ services: ## Optional authentication -Available in `v1.0` (or `:latest`)and later. If you want to enable a basic username and +Available in `v1.0` (or `:latest`) and later. If you want to enable a basic username and password to be required to access the TubeSync dashboard you can set them with the following environment variables: @@ -188,6 +188,14 @@ $ docker pull ghcr.io/meeb/tubesync:v[number] Back-end updates such as database migrations should be automatic. +> [!IMPORTANT] +> `MariaDB` was not automatically upgraded for `UUID` column types. +> To see what changes are needed, you can run: +> ```bash +> docker exec -it tubesync python3 /app/manage.py fix-mariadb --dry-run --uuid-columns +> ``` +> Removing the `--dry-run` will attempt to execute those statements using the configured database connection. + # Moving, backing up, etc. @@ -349,7 +357,7 @@ and you can probably break things by playing in the admin. If you still want to it you can run: ```bash -$ docker exec -ti tubesync python3 /app/manage.py createsuperuser +$ docker exec -it tubesync python3 /app/manage.py createsuperuser ``` And follow the instructions to create an initial Django superuser, once created, you @@ -415,7 +423,7 @@ following this rough guide, you are on your own and should be knowledgeable abou installing and running WSGI-based Python web applications before attempting this. 1. Clone or download this repo -2. Make sure you're running a modern version of Python (>=3.9) and have Pipenv +2. Make sure you're running a modern version of Python (>=3.10) and have Pipenv installed 3. Set up the environment with `pipenv install` 4. Copy `tubesync/tubesync/local_settings.py.example` to From be1617979f44d8703176a111dc4c22cec6543ae9 Mon Sep 17 00:00:00 2001 From: tcely Date: Thu, 15 May 2025 04:09:14 -0400 Subject: [PATCH 14/15] Use `db.connection.ensure_connection()` --- tubesync/sync/management/commands/fix-mariadb.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tubesync/sync/management/commands/fix-mariadb.py b/tubesync/sync/management/commands/fix-mariadb.py index c3f2287a..58ad2202 100644 --- a/tubesync/sync/management/commands/fix-mariadb.py +++ b/tubesync/sync/management/commands/fix-mariadb.py @@ -24,6 +24,7 @@ def SQLTable(arg_table): needle = arg_table if needle.startswith('new__'): needle = arg_table[len('new__'):] + db.connection.ensure_connection() valid_table_name = ( needle in new_tables and arg_table in db_tables(include_views=False) @@ -122,6 +123,7 @@ class Command(BaseCommand): + f': {db.connection.vendor}' ) + db.connection.ensure_connection() db_is_mariadb = ( hasattr(db.connection, 'mysql_is_mariadb') and db.connection.is_usable() and From add42bd87c3f90d08750ad3d02ad12e0d261ecce Mon Sep 17 00:00:00 2001 From: tcely Date: Thu, 15 May 2025 04:43:59 -0400 Subject: [PATCH 15/15] Use a migration that gives the output we search for --- tubesync/sync/management/commands/fix-mariadb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tubesync/sync/management/commands/fix-mariadb.py b/tubesync/sync/management/commands/fix-mariadb.py index 58ad2202..9b21d2df 100644 --- a/tubesync/sync/management/commands/fix-mariadb.py +++ b/tubesync/sync/management/commands/fix-mariadb.py @@ -222,7 +222,7 @@ class Command(BaseCommand): at_31, err_31, out_31 = check_migration_status( '0031_metadata_metadataformat' ) at_31s, err_31s, out_31s = check_migration_status( '0031_squashed_metadata_metadataformat' ) after_31, err_31a, out_31a = check_migration_status( - '0030_alter_source_source_vcodec', + '0031_metadata_metadataformat', needle='Undo Rename table for metadata to sync_media_metadata', )