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:
2026-06-26 13:27:37 +00:00
parent a35b2c6498
commit 3261a461cb

View File

@@ -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()