Spaces:
Running
Running
File size: 5,589 Bytes
6c3a31d 5f400f8 529b973 6c3a31d 5f400f8 6c3a31d 5f400f8 6c3a31d 5f400f8 529b973 5f400f8 529b973 5f400f8 6c3a31d 5f400f8 6c3a31d 529b973 5f400f8 6c3a31d 5f400f8 6c3a31d 5f400f8 6c3a31d 5f400f8 6c3a31d 5f400f8 6c3a31d 5f400f8 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | """Saved formats (auto and manual): the pieces shared by the menus, the handlers and the pipeline.
A format is a named bundle of a naming template, a caption, a thumbnail, the six metadata titles and the Keep
Audio / Keep Subtitle lists. Every other setting (mode, file type, remove words, target channel) still comes
from the user's normal settings. The caption never does: a format that was given none sends the new
file name in bold.
There are two kinds, twelve of each. An **auto** format renames every file the user sends (the one in use is chosen from
the /start menu); a **manual** format is chosen with /rename and renames one file. The user's default metadata is a preset:
a format can copy it ("Apply default metadata"), and an auto format that has no metadata of its own uses it while it is On.
"""
from __future__ import annotations
import copy
from typing import Any, Dict, Optional, Tuple
from .db import DEFAULT_CAPTION, DEFAULT_FORMAT, DEFAULT_KIND, DEFAULT_SETTINGS, Database
NAME_MAX = 30
KIND_LABELS = {"auto": "Auto", "manual": "Manual"}
KIND_ICONS = {"auto": "🤖", "manual": "✋"}
# format field -> the kind settings_ops.apply_setting() understands
FIELD_KINDS: Dict[str, str] = {
"template": "template", "caption": "caption",
"title": "mt_title", "author": "mt_author", "artist": "mt_artist",
"audio": "mt_audio", "subtitle": "mt_subtitle", "video": "mt_video",
"keep_audio": "keep_audio", "keep_subtitle": "keep_subtitle",
}
_EDITABLE = ("template", "caption", "meta", "keep_audio", "keep_subtitle")
def other_kind(kind: str) -> str:
return "manual" if kind == "auto" else "auto"
def validate_name(text: Optional[str]) -> Tuple[bool, str]:
"""``(True, cleaned name)`` or ``(False, html error)``."""
name = " ".join((text or "").split())
if not name:
return False, "❌ Send a name for the format."
if len(name) > NAME_MAX:
return False, f"❌ That name is too long ({NAME_MAX} characters max)."
return True, name
def has_metadata(fmt: Dict[str, Any]) -> bool:
return any(fmt["meta"].values()) or bool(fmt["keep_audio"] or fmt["keep_subtitle"])
def has_default_metadata(settings: Dict[str, Any]) -> bool:
"""Has the user set any default metadata (a title or the like, or a Keep Audio / Keep Subtitle list)?"""
return any(settings["meta"].values()) or bool(settings["keep_audio"] or settings["keep_subtitle"])
def default_metadata_changes(settings: Dict[str, Any]) -> Dict[str, Any]:
"""What ``Database.update_format`` takes to make a format's metadata the user's default metadata."""
return dict(meta=dict(settings["meta"]), keep_audio=list(settings["keep_audio"]), keep_subtitle=list(settings["keep_subtitle"]))
def default_auto_format() -> Dict[str, Any]:
"""What renames the files of a user who has no auto format: the built-in template and caption, no thumbnail, no metadata."""
out = copy.deepcopy(DEFAULT_FORMAT)
out.update(kind="auto", id=0, name="", has_thumb=False)
return out
def apply_format(settings: Dict[str, Any], fmt: Optional[Dict[str, Any]]) -> Dict[str, Any]:
"""The user's settings with the format's template, caption, metadata and keep lists laid over them.
``fmt`` is ``None`` for an auto rename of a user who has no auto format: the built-in defaults.
Metadata is on whenever the format sets anything, whatever the Metadata switch says: the format carries its own
metadata. A manual format with none leaves the file alone (no ffmpeg pass). An auto format with none leaves the user's
default metadata in charge: it applies while its switch is On, as it always did for auto renames.
"""
fmt = fmt or default_auto_format()
out = copy.deepcopy(settings)
out["template"] = fmt["template"]
out["caption"] = fmt.get("caption") or DEFAULT_CAPTION # never a caption from anywhere else
if has_metadata(fmt) or fmt.get("kind", DEFAULT_KIND) == "manual":
out["meta"] = dict(fmt["meta"])
out["keep_audio"] = list(fmt["keep_audio"])
out["keep_subtitle"] = list(fmt["keep_subtitle"])
out["metadata_on"] = has_metadata(fmt)
return out
def _as_settings(fmt: Dict[str, Any]) -> Dict[str, Any]:
"""A format shaped like the user's settings, which is what ``apply_setting`` reads."""
out = copy.deepcopy(DEFAULT_SETTINGS)
out.update(
template=fmt["template"], caption=fmt["caption"], keep_audio=list(fmt["keep_audio"]),
keep_subtitle=list(fmt["keep_subtitle"]), metadata_on=True,
)
out["meta"] = dict(fmt["meta"])
return out
class FormatSettings:
"""Edits one saved format through the two methods ``apply_setting`` uses on ``Database``.
That keeps a single copy of every validation rule and message for the user's settings and the formats.
Metadata is always "on" here, so the "metadata is off" notes never show for a format.
"""
def __init__(self, db: Database, fid: int):
self.db = db
self.fid = fid
async def get_settings(self, uid: int) -> Dict[str, Any]:
fmt = await self.db.get_format(uid, self.fid)
if fmt is None:
raise LookupError("that format no longer exists")
return _as_settings(fmt)
async def update_settings(self, uid: int, **changes: Any) -> Dict[str, Any]:
wanted = {k: v for k, v in changes.items() if k in _EDITABLE}
if wanted and await self.db.update_format(uid, self.fid, **wanted) is None:
raise LookupError("that format no longer exists")
return await self.get_settings(uid)
|