diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 9edc7225..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.8', '3.9', '3.10', '3.11', '3.12'] + python-version: ['3.10', '3.11', '3.12', '3.13'] steps: - uses: actions/checkout@v4 - name: Install Python ${{ matrix.python-version }} @@ -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 manage.py test --verbosity=2 + run: cd tubesync && python3 -B -W default manage.py test --verbosity=2 containerise: if: ${{ !cancelled() && 'success' == needs.info.result }} 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 = "*" 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 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() diff --git a/tubesync/sync/forms.py b/tubesync/sync/forms.py index 39b1b606..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( @@ -12,7 +18,8 @@ class ValidateSourceForm(forms.Form): ) source_url = forms.URLField( label=_('Source URL'), - required=True + required=True, + **_assume_scheme, ) diff --git a/tubesync/sync/management/commands/fix-mariadb.py b/tubesync/sync/management/commands/fix-mariadb.py index c3f2287a..9b21d2df 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 @@ -220,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', ) 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 diff --git a/tubesync/tubesync/settings.py b/tubesync/tubesync/settings.py index 391a209d..7f5922ae 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 @@ -7,7 +8,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 = [] @@ -99,7 +100,10 @@ AUTH_PASSWORD_VALIDATORS = [ LANGUAGE_CODE = 'en-us' TIME_ZONE = getenv('TZ', 'UTC') USE_I18N = True -USE_L10N = True +# 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