review: optionally queue save_media tasks after bulk actions
Adds SAVE_MEDIA_AFTER_BULK_ACTION (env: TUBESYNC_SAVE_MEDIA_AFTER_BULK_ACTION, default False). When enabled, each admin bulk action queues a save_media task per changed item so flags are re-evaluated without waiting for the next source edit or indexing run. When disabled (the default) behaviour is unchanged: re-evaluation happens on the next source edit/index pass. Requested by tcely in review.
This commit is contained in:
@@ -267,6 +267,7 @@ useful if you are manually installing TubeSync in some other environment. These
|
||||
| TUBESYNC_DIRECTORY_PREFIX | Enable `video` and `audio` directory prefixes in `/downloads` | True |
|
||||
| TUBESYNC_SHRINK_NEW | Filter unneeded information from newly retrieved metadata | True |
|
||||
| TUBESYNC_SHRINK_OLD | Filter unneeded information from metadata loaded from the database | True |
|
||||
| TUBESYNC_SAVE_MEDIA_AFTER_BULK_ACTION | Queue a `save_media` task per item changed by an admin bulk action, defaults to False | False |
|
||||
| GUNICORN_WORKERS | Number of `gunicorn` (web request) workers to spawn | 3 |
|
||||
| LISTEN_HOST | IP address for `gunicorn` to listen on | 127.0.0.1 |
|
||||
| LISTEN_PORT | Port number for `gunicorn` to listen on | 8080 |
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from django.conf import settings
|
||||
from django.contrib import admin
|
||||
from .models import (
|
||||
Source,
|
||||
@@ -6,6 +7,7 @@ from .models import (
|
||||
MetadataFormat,
|
||||
MediaServer
|
||||
)
|
||||
from .tasks import save_media
|
||||
|
||||
|
||||
@admin.register(Source)
|
||||
@@ -31,25 +33,42 @@ class MediaAdmin(admin.ModelAdmin):
|
||||
'enable_can_download', 'disable_can_download',
|
||||
)
|
||||
|
||||
def _queue_save_media_tasks(self, queryset):
|
||||
'''
|
||||
Optionally queue a `save_media` task per changed item, so flags
|
||||
are re-evaluated without waiting for the next source edit/index.
|
||||
Disabled by default: SAVE_MEDIA_AFTER_BULK_ACTION = True enables it.
|
||||
'''
|
||||
if not getattr(settings, 'SAVE_MEDIA_AFTER_BULK_ACTION', False):
|
||||
return
|
||||
save_media.map(
|
||||
str(media_uuid)
|
||||
for media_uuid in queryset.values_list('uuid', flat=True)
|
||||
)
|
||||
|
||||
@admin.action(description='Set "skip" for the selected media')
|
||||
def enable_skip(self, request, queryset):
|
||||
updated = queryset.update(skip=True, manual_skip=True)
|
||||
self._queue_save_media_tasks(queryset)
|
||||
self.message_user(request, f'Set "skip" on {updated} media item(s).')
|
||||
|
||||
@admin.action(description='Unset "skip" for the selected media')
|
||||
def disable_skip(self, request, queryset):
|
||||
updated = queryset.update(skip=False, manual_skip=False)
|
||||
self._queue_save_media_tasks(queryset)
|
||||
self.message_user(request, f'Unset "skip" on {updated} media item(s).')
|
||||
|
||||
@admin.action(description='Set "can download" for the selected media')
|
||||
def enable_can_download(self, request, queryset):
|
||||
updated = queryset.update(can_download=True)
|
||||
self._queue_save_media_tasks(queryset)
|
||||
self.message_user(
|
||||
request, f'Set "can download" on {updated} media item(s).')
|
||||
|
||||
@admin.action(description='Unset "can download" for the selected media')
|
||||
def disable_can_download(self, request, queryset):
|
||||
updated = queryset.update(can_download=False)
|
||||
self._queue_save_media_tasks(queryset)
|
||||
self.message_user(
|
||||
request, f'Unset "can download" on {updated} media item(s).')
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import logging
|
||||
from unittest.mock import patch
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.admin.sites import AdminSite
|
||||
from django.test import RequestFactory, TestCase
|
||||
from django.test import RequestFactory, TestCase, override_settings
|
||||
|
||||
from sync.admin import MediaAdmin
|
||||
from sync.models import Source, Media
|
||||
@@ -84,3 +85,26 @@ class MediaAdminBulkActionsTestCase(TestCase):
|
||||
'enable_can_download', 'disable_can_download',
|
||||
):
|
||||
self.assertIn(action, self.model_admin.actions)
|
||||
|
||||
def test_save_media_tasks_not_queued_by_default(self):
|
||||
queryset = Media.objects.filter(source=self.source)
|
||||
|
||||
with patch('sync.admin.save_media') as mock_save_media:
|
||||
self.model_admin.enable_skip(self.request, queryset)
|
||||
|
||||
mock_save_media.map.assert_not_called()
|
||||
|
||||
@override_settings(SAVE_MEDIA_AFTER_BULK_ACTION=True)
|
||||
def test_save_media_tasks_queued_when_enabled(self):
|
||||
queryset = Media.objects.filter(source=self.source)
|
||||
|
||||
with patch('sync.admin.save_media') as mock_save_media:
|
||||
self.model_admin.enable_skip(self.request, queryset)
|
||||
|
||||
mock_save_media.map.assert_called_once()
|
||||
queued = set(mock_save_media.map.call_args.args[0])
|
||||
expected = {
|
||||
str(media_uuid)
|
||||
for media_uuid in queryset.values_list('uuid', flat=True)
|
||||
}
|
||||
self.assertEqual(queued, expected)
|
||||
|
||||
@@ -108,6 +108,9 @@ SHRINK_OLD_MEDIA_METADATA = ( 'true' == SHRINK_OLD_MEDIA_METADATA_STR.strip().lo
|
||||
# TUBESYNC_RENAME_ALL_SOURCES: True or False
|
||||
RENAME_ALL_SOURCES_STR = getenv('TUBESYNC_RENAME_ALL_SOURCES', True)
|
||||
RENAME_ALL_SOURCES = ( 'true' == RENAME_ALL_SOURCES_STR.strip().lower() )
|
||||
# TUBESYNC_SAVE_MEDIA_AFTER_BULK_ACTION: True or False
|
||||
SAVE_MEDIA_AFTER_BULK_ACTION_STR = getenv('TUBESYNC_SAVE_MEDIA_AFTER_BULK_ACTION', False)
|
||||
SAVE_MEDIA_AFTER_BULK_ACTION = ( 'true' == SAVE_MEDIA_AFTER_BULK_ACTION_STR.strip().lower() )
|
||||
# TUBESYNC_RENAME_SOURCES: A comma-separated list of Source directories
|
||||
RENAME_SOURCES_STR = getenv('TUBESYNC_RENAME_SOURCES')
|
||||
RENAME_SOURCES = RENAME_SOURCES_STR.split(',') if RENAME_SOURCES_STR else list()
|
||||
|
||||
@@ -393,6 +393,12 @@ RENAME_ALL_SOURCES = True
|
||||
RENAME_SOURCES = list()
|
||||
|
||||
|
||||
# When True, admin bulk actions on Media queue a `save_media` task for each
|
||||
# changed item so flags are re-evaluated without waiting for the next source
|
||||
# edit or indexing run
|
||||
SAVE_MEDIA_AFTER_BULK_ACTION = False
|
||||
|
||||
|
||||
# An example for changing the ordering for audio tracks.
|
||||
#ENGLISH_LANGUAGE_CODE_ORDER = (
|
||||
# 'en-orig',
|
||||
|
||||
Reference in New Issue
Block a user