v4.1: BiliBili Live filename auto-rename
- Add a '✨ Rename' button and live preview to the Output Settings section - Convert BiliBili Live recording stems of the form '[YYYY-MM-DD HH-MM-SS][streamer][title]' into 'YYYY年MM月DD日【直播回放】title' - Preview shows the converted result and enables/disables the button based on whether the current name matches the pattern - On auto-fill, keep the raw stem (no '_concat' suffix) so the pattern can match; strip a trailing '_concat' before matching as well Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -316,7 +316,7 @@ class App(_BaseClass): # type: ignore[valid-type]
|
|||||||
|
|
||||||
# Name row
|
# Name row
|
||||||
r1 = ctk.CTkFrame(body, fg_color="transparent")
|
r1 = ctk.CTkFrame(body, fg_color="transparent")
|
||||||
r1.pack(fill="x", pady=(0, 8))
|
r1.pack(fill="x", pady=(0, 4))
|
||||||
ctk.CTkLabel(r1, text="File name:", width=96, anchor="w").pack(side="left")
|
ctk.CTkLabel(r1, text="File name:", width=96, anchor="w").pack(side="left")
|
||||||
ctk.CTkEntry(r1, textvariable=self.out_name_var).pack(side="left", fill="x", expand=True)
|
ctk.CTkEntry(r1, textvariable=self.out_name_var).pack(side="left", fill="x", expand=True)
|
||||||
ctk.CTkOptionMenu(
|
ctk.CTkOptionMenu(
|
||||||
@@ -324,6 +324,24 @@ class App(_BaseClass): # type: ignore[valid-type]
|
|||||||
variable=self.out_ext_var, width=84
|
variable=self.out_ext_var, width=84
|
||||||
).pack(side="left", padx=(8, 0))
|
).pack(side="left", padx=(8, 0))
|
||||||
|
|
||||||
|
# Auto-rename button — converts BiliBili Live filename to readable format
|
||||||
|
self.rename_btn = ctk.CTkButton(
|
||||||
|
r1, text="✨ Rename", width=110,
|
||||||
|
fg_color=("#EDE9FE", "#3B1F6E"),
|
||||||
|
text_color=("#5B21B6", "#C4B5FD"),
|
||||||
|
hover_color=("#DDD6FE", "#4C2889"),
|
||||||
|
command=self._apply_bililive_rename
|
||||||
|
)
|
||||||
|
self.rename_btn.pack(side="left", padx=(8, 0))
|
||||||
|
|
||||||
|
# Preview label: shows what the rename will produce before applying
|
||||||
|
self.rename_preview_lbl = ctk.CTkLabel(
|
||||||
|
body, text="",
|
||||||
|
font=ctk.CTkFont(size=11), text_color=("#7C3AED", "#A78BFA"),
|
||||||
|
anchor="w"
|
||||||
|
)
|
||||||
|
self.rename_preview_lbl.pack(fill="x", pady=(0, 4))
|
||||||
|
|
||||||
# Directory row
|
# Directory row
|
||||||
r2 = ctk.CTkFrame(body, fg_color="transparent")
|
r2 = ctk.CTkFrame(body, fg_color="transparent")
|
||||||
r2.pack(fill="x")
|
r2.pack(fill="x")
|
||||||
@@ -504,8 +522,61 @@ class App(_BaseClass): # type: ignore[valid-type]
|
|||||||
self.out_path_lbl.configure(
|
self.out_path_lbl.configure(
|
||||||
text=f"Output path: {out}" if out else "Output path: —"
|
text=f"Output path: {out}" if out else "Output path: —"
|
||||||
)
|
)
|
||||||
|
self._refresh_rename_preview()
|
||||||
self._refresh_start()
|
self._refresh_start()
|
||||||
|
|
||||||
|
def _refresh_rename_preview(self):
|
||||||
|
"""Show a live preview of what the rename button will produce."""
|
||||||
|
if not hasattr(self, "rename_preview_lbl"):
|
||||||
|
return
|
||||||
|
current = self.out_name_var.get().strip()
|
||||||
|
renamed = self._bililive_rename(current)
|
||||||
|
if renamed and renamed != current:
|
||||||
|
self.rename_preview_lbl.configure(
|
||||||
|
text=f" → {renamed}"
|
||||||
|
)
|
||||||
|
self.rename_btn.configure(state="normal")
|
||||||
|
else:
|
||||||
|
self.rename_preview_lbl.configure(text="")
|
||||||
|
# Only disable if the name cannot be converted
|
||||||
|
self.rename_btn.configure(state="disabled" if not renamed else "normal")
|
||||||
|
|
||||||
|
|
||||||
|
# ══════════════════════════════════════════════════════════════════════════
|
||||||
|
# BiliBili Live filename auto-rename
|
||||||
|
# ══════════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
# Pattern: [2025-06-28 20-31-15][纳豆nado][title content]
|
||||||
|
_BILILIVE_RE = re.compile(
|
||||||
|
r"^\[(\d{4})-(\d{2})-(\d{2}) \d{2}-\d{2}-\d{2}\]\[[^\]]*\]\[(.+)\]$"
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _bililive_rename(stem: str) -> str:
|
||||||
|
"""
|
||||||
|
Convert a BiliBili Live recording stem to a readable name.
|
||||||
|
Input: [2026-03-14 22-46-37][纳豆nado][【点歌专场】今晚九点来捏]
|
||||||
|
Output: 2026年03月14日【直播回放】【点歌专场】今晚九点来捏
|
||||||
|
Returns the converted string, or "" if the stem does not match.
|
||||||
|
"""
|
||||||
|
# Strip any trailing _concat suffix before matching
|
||||||
|
test = stem.removesuffix("_concat").strip()
|
||||||
|
m = App._BILILIVE_RE.match(test)
|
||||||
|
if not m:
|
||||||
|
return ""
|
||||||
|
year, month, day, title = m.groups()
|
||||||
|
return f"{year}年{month}月{day}日【直播回放】{title}"
|
||||||
|
|
||||||
|
def _apply_bililive_rename(self):
|
||||||
|
"""Apply the rename conversion to the current output name."""
|
||||||
|
current = self.out_name_var.get().strip()
|
||||||
|
renamed = self._bililive_rename(current)
|
||||||
|
if not renamed:
|
||||||
|
return
|
||||||
|
self.out_name_var.set(renamed)
|
||||||
|
self.rename_preview_lbl.configure(text=" ✓ Renamed!")
|
||||||
|
self.rename_btn.configure(state="disabled")
|
||||||
|
|
||||||
def _refresh_start(self):
|
def _refresh_start(self):
|
||||||
if not hasattr(self, "start_btn"):
|
if not hasattr(self, "start_btn"):
|
||||||
return # UI not fully built yet
|
return # UI not fully built yet
|
||||||
@@ -572,7 +643,8 @@ class App(_BaseClass): # type: ignore[valid-type]
|
|||||||
if not self.out_dir_var.get().strip():
|
if not self.out_dir_var.get().strip():
|
||||||
self.out_dir_var.set(str(Path(self.items[0]["path"]).parent))
|
self.out_dir_var.set(str(Path(self.items[0]["path"]).parent))
|
||||||
if self.out_name_var.get() in ("", "output_concat"):
|
if self.out_name_var.get() in ("", "output_concat"):
|
||||||
self.out_name_var.set(Path(self.items[0]["path"]).stem + "_concat")
|
# Keep the raw BiliBili stem so the rename pattern can match it
|
||||||
|
self.out_name_var.set(Path(self.items[0]["path"]).stem)
|
||||||
|
|
||||||
self._rebuild_list()
|
self._rebuild_list()
|
||||||
self._update_count()
|
self._update_count()
|
||||||
|
|||||||
Reference in New Issue
Block a user