From 77503b38b9f23710980eb70310e07778d24a1d14 Mon Sep 17 00:00:00 2001 From: Markos Gogoulos Date: Mon, 26 May 2025 09:52:44 +0300 Subject: [PATCH] fix black --- cms/settings.py | 1 - files/admin.py | 3 +- files/forms.py | 11 +--- files/helpers.py | 50 +++++++------------ files/methods.py | 23 ++------- ...0008_alter_media_state_videotrimrequest.py | 1 - files/models.py | 3 +- files/tasks.py | 50 ++++++------------- files/views.py | 16 ++---- 9 files changed, 48 insertions(+), 110 deletions(-) diff --git a/cms/settings.py b/cms/settings.py index c5f99811..b291843e 100644 --- a/cms/settings.py +++ b/cms/settings.py @@ -548,4 +548,3 @@ if GLOBAL_LOGIN_REQUIRED: r'/accounts/confirm-email/.*/$', # r'/api/v[0-9]+/', ] - diff --git a/files/admin.py b/files/admin.py index 86b20a06..e346ab4e 100644 --- a/files/admin.py +++ b/files/admin.py @@ -13,9 +13,9 @@ from .models import ( Encoding, Language, Media, - VideoTrimRequest, Subtitle, Tag, + VideoTrimRequest, ) @@ -199,6 +199,7 @@ class LanguageAdmin(admin.ModelAdmin): class SubtitleAdmin(admin.ModelAdmin): pass + class VideoTrimRequestAdmin(admin.ModelAdmin): pass diff --git a/files/forms.py b/files/forms.py index 5fb31687..b48704ff 100644 --- a/files/forms.py +++ b/files/forms.py @@ -5,7 +5,7 @@ from django import forms from django.conf import settings from .methods import get_next_state, is_mediacms_editor -from .models import Category, Media, MEDIA_STATES, Subtitle +from .models import MEDIA_STATES, Category, Media, Subtitle class CustomField(Field): @@ -92,12 +92,7 @@ class MediaMetadataForm(forms.ModelForm): class MediaPublishForm(forms.ModelForm): - confirm_state = forms.BooleanField( - required=False, - initial=False, - label="Acknowledge sharing status", - help_text="" - ) + confirm_state = forms.BooleanField(required=False, initial=False, label="Acknowledge sharing status", help_text="") class Meta: model = Media @@ -129,7 +124,6 @@ class MediaPublishForm(forms.ModelForm): valid_states.append(self.instance.state) self.fields["state"].choices = [(state, dict(MEDIA_STATES).get(state, state)) for state in valid_states] - if getattr(settings, 'USE_RBAC', False) and 'category' in self.fields: if is_mediacms_editor(user): pass @@ -187,7 +181,6 @@ class MediaPublishForm(forms.ModelForm): layout_items.insert(state_index + 1, CustomField('confirm_state')) self.helper.layout = Layout(*layout_items) - if not cleaned_data.get('confirm_state'): error_message = f"I understand that although media state is {state}, the media is also shared with users that have access to the following categories: {', '.join(rbac_categories)}" self.add_error('confirm_state', error_message) diff --git a/files/helpers.py b/files/helpers.py index 12f3b1f8..6fa0004a 100644 --- a/files/helpers.py +++ b/files/helpers.py @@ -822,6 +822,7 @@ def seconds_to_timestamp(seconds): return f"{hours:02d}:{minutes:02d}:{seconds_int:02d}.{milliseconds:03d}" + def get_trim_timestamps(media_file_path, timestamps_list, run_ffprobe=False): """Process a list of timestamps to align start times with I-frames for better video trimming @@ -866,12 +867,17 @@ def get_trim_timestamps(media_file_path, timestamps_list, run_ffprobe=False): # Create ffprobe command to find nearest I-frame cmd = [ settings.FFPROBE_COMMAND, - "-v", "error", - "-select_streams", "v:0", - "-show_entries", "frame=pts_time,pict_type", - "-of", "csv=p=0", - "-read_intervals", f"{search_start}%{startTime}", - media_file_path + "-v", + "error", + "-select_streams", + "v:0", + "-show_entries", + "frame=pts_time,pict_type", + "-of", + "csv=p=0", + "-read_intervals", + f"{search_start}%{startTime}", + media_file_path, ] cmd = [str(s) for s in cmd] logger.info(f"trim cmd: {cmd}") @@ -887,12 +893,9 @@ def get_trim_timestamps(media_file_path, timestamps_list, run_ffprobe=False): adjusted_startTime = seconds_to_timestamp(float(i_frames[-1])) if not i_frames: - adjusted_startTime = startTime + adjusted_startTime = startTime - timestamps_results.append({ - 'startTime': adjusted_startTime, - 'endTime': endTime - }) + timestamps_results.append({'startTime': adjusted_startTime, 'endTime': endTime}) return timestamps_results @@ -926,18 +929,9 @@ def trim_video_method(media_file_path, timestamps_list): # For multiple timestamps, we need to create segment files segment_file = output_file if len(timestamps_list) == 1 else os.path.join(temp_dir, f"segment_{i}.mp4") - cmd = [ - settings.FFMPEG_COMMAND, - "-y", - "-ss", str(item['startTime']), - "-i", media_file_path, - "-t", str(duration), - "-c", "copy", - "-avoid_negative_ts", "1", - segment_file - ] + cmd = [settings.FFMPEG_COMMAND, "-y", "-ss", str(item['startTime']), "-i", media_file_path, "-t", str(duration), "-c", "copy", "-avoid_negative_ts", "1", segment_file] - result = run_command(cmd) + result = run_command(cmd) # noqa if os.path.exists(segment_file) and os.path.getsize(segment_file) > 0: if len(timestamps_list) > 1: @@ -953,17 +947,9 @@ def trim_video_method(media_file_path, timestamps_list): with open(concat_list_path, "w") as f: for segment in segment_files: f.write(f"file '{segment}'\n") - concat_cmd = [ - settings.FFMPEG_COMMAND, - "-y", - "-f", "concat", - "-safe", "0", - "-i", concat_list_path, - "-c", "copy", - output_file - ] + concat_cmd = [settings.FFMPEG_COMMAND, "-y", "-f", "concat", "-safe", "0", "-i", concat_list_path, "-c", "copy", output_file] - concat_result = run_command(concat_cmd) + concat_result = run_command(concat_cmd) # noqa if not os.path.exists(output_file) or os.path.getsize(output_file) == 0: return False diff --git a/files/methods.py b/files/methods.py index cb80aef3..9696244c 100644 --- a/files/methods.py +++ b/files/methods.py @@ -5,8 +5,8 @@ import itertools import logging import random import re -from datetime import datetime import subprocess +from datetime import datetime from django.conf import settings from django.core.cache import cache @@ -448,25 +448,18 @@ def copy_video(original_media, copy_encodings=True, title_suffix="(Trimmed)"): listable=original_media.listable, add_date=timezone.now(), video_height=original_media.video_height, - media_info=original_media.media_info + media_info=original_media.media_info, ) models.Media.objects.bulk_create([new_media]) # avoids calling signals since signals will call media_init and we don't want that - if copy_encodings: for encoding in original_media.encodings.filter(chunk=False, status="success"): if encoding.media_file: with open(encoding.media_file.path, "rb") as f: myfile = File(f) new_encoding = models.Encoding( - media_file=myfile, - media=new_media, - profile=encoding.profile, - status="success", - progress=100, - chunk=False, - logs=f"Copied from encoding {encoding.id}" + media_file=myfile, media=new_media, profile=encoding.profile, status="success", progress=100, chunk=False, logs=f"Copied from encoding {encoding.id}" ) models.Encoding.objects.bulk_create([new_encoding]) # avoids calling signals as this is still not ready @@ -483,13 +476,11 @@ def copy_video(original_media, copy_encodings=True, title_suffix="(Trimmed)"): thumbnail_name = helpers.get_file_name(original_media.thumbnail.path) new_media.thumbnail.save(thumbnail_name, File(f)) - if original_media.poster: with open(original_media.poster.path, 'rb') as f: poster_name = helpers.get_file_name(original_media.poster.path) new_media.poster.save(poster_name, File(f)) - return new_media @@ -510,13 +501,7 @@ def create_video_trim_request(media, data): elif data.get('saveAsCopy'): video_action = "save_new" - video_trim_request = models.VideoTrimRequest.objects.create( - media=media, - status="initial", - video_action=video_action, - media_trim_style='no_encoding', - timestamps=data.get('segments', {}) - ) + video_trim_request = models.VideoTrimRequest.objects.create(media=media, status="initial", video_action=video_action, media_trim_style='no_encoding', timestamps=data.get('segments', {})) return video_trim_request diff --git a/files/migrations/0008_alter_media_state_videotrimrequest.py b/files/migrations/0008_alter_media_state_videotrimrequest.py index 1a15f8fd..cdd906e6 100644 --- a/files/migrations/0008_alter_media_state_videotrimrequest.py +++ b/files/migrations/0008_alter_media_state_videotrimrequest.py @@ -5,7 +5,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ ('files', '0007_alter_media_state_videochapterdata'), ] diff --git a/files/models.py b/files/models.py index fae9445d..9c4d8510 100644 --- a/files/models.py +++ b/files/models.py @@ -84,7 +84,6 @@ ENCODE_EXTENSIONS_KEYS = [extension for extension, name in ENCODE_EXTENSIONS] ENCODE_RESOLUTIONS_KEYS = [resolution for resolution, name in ENCODE_RESOLUTIONS] - def generate_uid(): return get_random_string(length=16) @@ -651,6 +650,7 @@ class Media(models.Model): if encoding and encoding.status == "success" and encoding.profile.codec == "h264" and action == "add" and not encoding.chunk: from . import tasks + tasks.create_hls.delay(self.friendly_token) # TODO: ideally would ensure this is run only at the end when the last encoding is done... @@ -692,7 +692,6 @@ class Media(models.Model): # showing the original file return helpers.url_from_path(self.media_file.path) - @property def trim_video_path(self): if self.media_type not in ["video"]: diff --git a/files/tasks.py b/files/tasks.py index 7529bfd3..45f8bc0f 100644 --- a/files/tasks.py +++ b/files/tasks.py @@ -2,13 +2,11 @@ import json import os import re import shutil -import subprocess import tempfile from datetime import datetime, timedelta from celery import Task from celery import shared_task as task -from celery.exceptions import SoftTimeLimitExceeded from celery.signals import task_revoked # from celery.task.control import revoke @@ -16,8 +14,9 @@ from celery.utils.log import get_task_logger from django.conf import settings from django.core.cache import cache from django.core.files import File -from django.db.models import Q from django.db import DatabaseError +from django.db.models import Q + from actions.models import USER_MEDIA_ACTIONS, MediaAction from users.models import User @@ -36,7 +35,13 @@ from .helpers import ( run_command, trim_video_method, ) -from .methods import list_tasks, notify_users, pre_save_action, copy_video, kill_ffmpeg_process +from .methods import ( + copy_video, + kill_ffmpeg_process, + list_tasks, + notify_users, + pre_save_action, +) from .models import ( Category, EncodeProfile, @@ -45,7 +50,7 @@ from .models import ( Rating, Tag, VideoChapterData, - VideoTrimRequest + VideoTrimRequest, ) logger = get_task_logger(__name__) @@ -87,12 +92,11 @@ def handle_pending_running_encodings(media): return deleted - def pre_trim_video_actions(media): # the reason for this function is to perform tasks before trimming a video # avoid re-running unnecessary encodings (or chunkize_media, which is the first step for them) - # if the video is already completed + # if the video is already completed # however if it is a new video (user uploded the video and starts trimming # before the video is processed), this is necessary, so encode has to be called to give it a chance to encode @@ -106,13 +110,7 @@ def pre_trim_video_actions(media): # are still not finished. profiles = EncodeProfile.objects.filter(active=True, extension='mp4', resolution__lte=media.video_height) - media_encodings = EncodeProfile.objects.filter( - encoding__in=media.encodings.filter( - status="success", - chunk=False - ), - extension='mp4' - ).distinct() + media_encodings = EncodeProfile.objects.filter(encoding__in=media.encodings.filter(status="success", chunk=False), extension='mp4').distinct() picked = [] for profile in profiles: @@ -121,7 +119,6 @@ def pre_trim_video_actions(media): else: picked.append(profile) - if picked: # by calling encode will re-encode all. The logic is explained above... logger.info(f"Encoding media {media.friendly_token} will have to be performed for all profiles") @@ -129,6 +126,7 @@ def pre_trim_video_actions(media): return True + @task(name="chunkize_media", bind=True, queue="short_tasks", soft_time_limit=60 * 30 * 4) def chunkize_media(self, friendly_token, profiles, force=True): """Break media in chunks and start encoding tasks""" @@ -417,7 +415,6 @@ def encode_media( raise except Exception as e: - try: # output is empty, fail message is on the exception output = e.message @@ -496,11 +493,7 @@ def produce_sprite_from_video(friendly_token): with open(output_name, "rb") as f: myfile = File(f) # SOS: avoid race condition, since this runs for a long time and will replace any other media changes on the meanwhile!!! - media.sprites.save( - content=myfile, - name=get_file_name(media.media_file.path) + "sprites.jpg", - save=False - ) + media.sprites.save(content=myfile, name=get_file_name(media.media_file.path) + "sprites.jpg", save=False) media.save(update_fields=["sprites"]) except Exception as e: @@ -877,8 +870,6 @@ def task_sent_handler(sender=None, headers=None, body=None, **kwargs): return True - - @task(name="remove_media_file", base=Task, queue="long_tasks") def remove_media_file(media_file=None): rm_file(media_file) @@ -1006,9 +997,7 @@ def video_trim_task(self, trim_request_id): else: proceed_with_single_file = False - if proceed_with_single_file: - if trim_request.video_action == "save_new" or trim_request.video_action == "create_segments" and len(timestamps_encodings) == 1: new_media = copy_video(original_media, copy_encodings=True) @@ -1042,16 +1031,10 @@ def video_trim_task(self, trim_request_id): # file on different times. target_media = copy_video(original_media, title_suffix=f"(Trimmed) {i}", copy_encodings=True) - video_trim_request = VideoTrimRequest.objects.create( - media=target_media, - status="running", - video_action="create_segments", - media_trim_style='no_encoding', - timestamps=[timestamp] - ) + video_trim_request = VideoTrimRequest.objects.create(media=target_media, status="running", video_action="create_segments", media_trim_style='no_encoding', timestamps=[timestamp]) # noqa original_trim_result = trim_video_method(target_media.media_file.path, [timestamp]) - deleted_encodings = handle_pending_running_encodings(target_media) + deleted_encodings = handle_pending_running_encodings(target_media) # noqa # the following could be un-necessary, read commend in pre_trim_video_actions to see why encodings = target_media.encodings.filter(status="success", profile__extension='mp4', chunk=False) for encoding in encodings: @@ -1063,7 +1046,6 @@ def video_trim_task(self, trim_request_id): pre_trim_video_actions(target_media) post_trim_action.delay(target_media.friendly_token) - # set as completed the initial trim_request trim_request.status = "success" trim_request.save(update_fields=["status"]) diff --git a/files/views.py b/files/views.py index 3555580a..8566b0f0 100644 --- a/files/views.py +++ b/files/views.py @@ -1,6 +1,6 @@ import json from datetime import datetime, timedelta -from . import helpers + from allauth.socialaccount.models import SocialApp from django.conf import settings from django.contrib import messages @@ -38,6 +38,7 @@ from cms.version import VERSION from identity_providers.models import LoginOption from users.models import User +from . import helpers from .forms import ( ContactForm, EditSubtitleForm, @@ -393,10 +394,7 @@ def trim_video(request, friendly_token): if not (request.user == media.user or is_mediacms_editor(request.user)): return HttpResponseRedirect("/") - existing_requests = VideoTrimRequest.objects.filter( - media=media, - status__in=["initial", "running"] - ).exists() + existing_requests = VideoTrimRequest.objects.filter(media=media, status__in=["initial", "running"]).exists() if existing_requests: return JsonResponse({"success": False, "error": "A trim request is already in progress for this video"}, status=400) @@ -407,7 +405,7 @@ def trim_video(request, friendly_token): video_trim_task.delay(video_trim_request.id) ret = {"success": True, "request_id": video_trim_request.id} return JsonResponse(ret, safe=False, status=200) - except Exception as e: + except Exception as e: # noqa ret = {"success": False, "error": "Incorrect request data"} return JsonResponse(ret, safe=False, status=400) @@ -435,12 +433,8 @@ def edit_video(request): messages.add_message(request, messages.INFO, "Video Trimmer is not enabled") return HttpResponseRedirect(media.get_absolute_url()) - # Check if there's a running trim request - running_trim_request = VideoTrimRequest.objects.filter( - media=media, - status__in=["initial", "running"] - ).exists() + running_trim_request = VideoTrimRequest.objects.filter(media=media, status__in=["initial", "running"]).exists() if running_trim_request: messages.add_message(request, messages.INFO, "Video trim request is already running")