from django.contrib import admin from .models import MediaAsset, TranscodeJob, TranscodePreset @admin.register(MediaAsset) class MediaAssetAdmin(admin.ModelAdmin): list_display = [ "filename", "status", "duration_display", "resolution", "created_at", ] list_filter = ["status", "video_codec", "audio_codec"] search_fields = ["filename", "file_path", "comments"] readonly_fields = ["id", "created_at", "updated_at", "properties"] fieldsets = [ (None, {"fields": ["id", "filename", "file_path", "status", "error_message"]}), ( "Media Info", { "fields": [ "file_size", "duration", "video_codec", "audio_codec", "width", "height", "framerate", "bitrate", ] }, ), ("Annotations", {"fields": ["comments", "tags"]}), ( "Metadata", { "classes": ["collapse"], "fields": ["properties", "created_at", "updated_at"], }, ), ] def duration_display(self, obj): if obj.duration: mins, secs = divmod(int(obj.duration), 60) hours, mins = divmod(mins, 60) if hours: return f"{hours}:{mins:02d}:{secs:02d}" return f"{mins}:{secs:02d}" return "-" duration_display.short_description = "Duration" def resolution(self, obj): if obj.width and obj.height: return f"{obj.width}x{obj.height}" return "-" @admin.register(TranscodePreset) class TranscodePresetAdmin(admin.ModelAdmin): list_display = ["name", "container", "video_codec", "audio_codec", "is_builtin"] list_filter = ["is_builtin", "container", "video_codec"] search_fields = ["name", "description"] readonly_fields = ["id", "created_at", "updated_at"] fieldsets = [ (None, {"fields": ["id", "name", "description", "is_builtin"]}), ("Output", {"fields": ["container"]}), ( "Video", { "fields": [ "video_codec", "video_bitrate", "video_crf", "video_preset", "resolution", "framerate", ] }, ), ( "Audio", { "fields": [ "audio_codec", "audio_bitrate", "audio_channels", "audio_samplerate", ] }, ), ( "Advanced", { "classes": ["collapse"], "fields": ["extra_args", "created_at", "updated_at"], }, ), ] @admin.register(TranscodeJob) class TranscodeJobAdmin(admin.ModelAdmin): list_display = [ "id_short", "source_asset_id_short", "status", "progress_display", "created_at", ] list_filter = ["status"] search_fields = ["output_filename"] readonly_fields = [ "id", "created_at", "started_at", "completed_at", "progress", "current_frame", "current_time", "speed", "celery_task_id", "preset_snapshot", ] fieldsets = [ (None, {"fields": ["id", "source_asset_id", "status", "error_message"]}), ( "Configuration", { "fields": [ "preset_id", "preset_snapshot", "trim_start", "trim_end", "priority", ] }, ), ("Output", {"fields": ["output_filename", "output_path", "output_asset_id"]}), ( "Progress", {"fields": ["progress", "current_frame", "current_time", "speed"]}, ), ( "Worker", { "classes": ["collapse"], "fields": [ "celery_task_id", "created_at", "started_at", "completed_at", ], }, ), ] def id_short(self, obj): return str(obj.id)[:8] id_short.short_description = "ID" def source_asset_id_short(self, obj): return str(obj.source_asset_id)[:8] if obj.source_asset_id else "-" source_asset_id_short.short_description = "Source" def progress_display(self, obj): return f"{obj.progress:.1f}%" progress_display.short_description = "Progress"