Fix parse_artist_title (ANS.* bug) + unify station naming na FOLX SLO
PROBLEMS: 1. parse_artist_title je uporabljal Path(s).stem za stripping ext-a, kar je pri YT title 'ANS.NAVEZA - SREČA OPOTEČA' vrnilo 'ANS' (Path smatra '.NAVEZA - SREČA OPOTEČA' kot extension). Posledica: parser failed → ACR fallback → 'Folx' kot artist na 15+ jobih. 2. tv_station je imel dva imena: 'FOLX SLOVENIJA' (frontend default) in 'FOLX SLO' (qnet match output) — UI tabi niso seštevali pravilno. FIXES: - parse_artist_title: ext stripping samo za znane ekstenzije (.mp4, .mp3, .m4a, .webm, .mkv, .avi, .mov, .wav, .flac, .aac, .opus, .ogg, .wmv, .mxf), NE za naključne pike v YT title. - Vsi defaultni 'FOLX SLOVENIJA' → 'FOLX SLO' v Pydantic modelih + templates + filter tabi. - Nextcloud mapping STATION_TO_NEXTCLOUD_FOLDER ostane nespremenjen (FOLX SLO → mapa 'FOLX SLOVENIJA', kjer pač zaplane). BACKFILL (že apliciran prek scripte): - 15 jobov z parsed_artist='Folx' popravljenih na pravi izvajalec iz youtube_title (ANS.NAVEZA, ANS.BITENC, ANS. ROKA ŽLINDRE, ipd.). - 86 jobov tv_station 'FOLX SLOVENIJA' → 'FOLX SLO'.
This commit is contained in:
parent
cd872d8bea
commit
576cc807b5
24
app/main.py
24
app/main.py
@ -333,8 +333,18 @@ def parse_artist_title(filename_or_title):
|
|||||||
if not filename_or_title:
|
if not filename_or_title:
|
||||||
return (None, None)
|
return (None, None)
|
||||||
|
|
||||||
# Odstrani extension
|
# Odstrani extension SAMO če je dejansko file extension (kratko, brez presledka).
|
||||||
name = Path(filename_or_title).stem if "." in filename_or_title else filename_or_title
|
# Path("ANS.NAVEZA - SREČA OPOTEČA").stem vrne "ANS" — narobe za YT title.
|
||||||
|
# Pravilno: samo če je string brez presledkov ali se konča na običajno ext.
|
||||||
|
_COMMON_EXT = {".mp4", ".mp3", ".m4a", ".webm", ".mkv", ".avi", ".mov",
|
||||||
|
".wav", ".flac", ".aac", ".opus", ".ogg", ".wmv", ".mxf"}
|
||||||
|
name = filename_or_title
|
||||||
|
if "." in name:
|
||||||
|
# Vzemi zadnjo piko in preveri ali je to znana ext
|
||||||
|
last_dot = name.rfind(".")
|
||||||
|
ext = name[last_dot:].lower()
|
||||||
|
if ext in _COMMON_EXT and last_dot > 0:
|
||||||
|
name = name[:last_dot]
|
||||||
|
|
||||||
# Odstrani noise patterns
|
# Odstrani noise patterns
|
||||||
for pat in _NOISE_PATTERNS:
|
for pat in _NOISE_PATTERNS:
|
||||||
@ -1032,7 +1042,7 @@ def process_job(job_id):
|
|||||||
if final_job.get("auto_upload_to_nextcloud") and _nextcloud_configured():
|
if final_job.get("auto_upload_to_nextcloud") and _nextcloud_configured():
|
||||||
update_job(job_id, nextcloud_status="uploading", nextcloud_error=None)
|
update_job(job_id, nextcloud_status="uploading", nextcloud_error=None)
|
||||||
download_name = build_download_filename(final_job)
|
download_name = build_download_filename(final_job)
|
||||||
tv_station = final_job.get("tv_station", "FOLX SLOVENIJA")
|
tv_station = final_job.get("tv_station", "FOLX SLO")
|
||||||
nc_folder = _nextcloud_folder_for_station(tv_station)
|
nc_folder = _nextcloud_folder_for_station(tv_station)
|
||||||
target_subdir = f"folxspeed/REELS/{nc_folder}"
|
target_subdir = f"folxspeed/REELS/{nc_folder}"
|
||||||
print(f"☁️ Avto-upload v Nextcloud: /{target_subdir}/{download_name}", flush=True)
|
print(f"☁️ Avto-upload v Nextcloud: /{target_subdir}/{download_name}", flush=True)
|
||||||
@ -1300,7 +1310,7 @@ class YouTubeJobIn(BaseModel):
|
|||||||
subtitle_style: str = "reels"
|
subtitle_style: str = "reels"
|
||||||
whisper_model: str = "large-v3"
|
whisper_model: str = "large-v3"
|
||||||
quality: str = "medium"
|
quality: str = "medium"
|
||||||
tv_station: str = "FOLX SLOVENIJA" # za Nextcloud target mapo
|
tv_station: str = "FOLX SLO" # za Nextcloud target mapo
|
||||||
|
|
||||||
|
|
||||||
class StartJobIn(BaseModel):
|
class StartJobIn(BaseModel):
|
||||||
@ -1325,7 +1335,7 @@ class StartJobIn(BaseModel):
|
|||||||
# Batch tracking za multi-upload (Telegram summary)
|
# Batch tracking za multi-upload (Telegram summary)
|
||||||
batch_id: Optional[str] = None
|
batch_id: Optional[str] = None
|
||||||
# TV postaja — določa Nextcloud target mapo
|
# TV postaja — določa Nextcloud target mapo
|
||||||
tv_station: str = "FOLX SLOVENIJA"
|
tv_station: str = "FOLX SLO"
|
||||||
|
|
||||||
|
|
||||||
# ────────────────────────────────────────────────────────────────
|
# ────────────────────────────────────────────────────────────────
|
||||||
@ -1333,7 +1343,7 @@ class StartJobIn(BaseModel):
|
|||||||
# ────────────────────────────────────────────────────────────────
|
# ────────────────────────────────────────────────────────────────
|
||||||
class DedupCheckRequest(BaseModel):
|
class DedupCheckRequest(BaseModel):
|
||||||
filenames: list[str]
|
filenames: list[str]
|
||||||
tv_station: str = "FOLX SLOVENIJA"
|
tv_station: str = "FOLX SLO"
|
||||||
|
|
||||||
|
|
||||||
@app.post("/api/dedup/check")
|
@app.post("/api/dedup/check")
|
||||||
@ -2308,7 +2318,7 @@ async def upload_nextcloud(job_id: str, user: str = Depends(check_auth)):
|
|||||||
download_name = build_download_filename(job)
|
download_name = build_download_filename(job)
|
||||||
|
|
||||||
# TV postaja določa target mapo (mapping Qnet -> Nextcloud folder)
|
# TV postaja določa target mapo (mapping Qnet -> Nextcloud folder)
|
||||||
tv_station = job.get("tv_station", "FOLX SLOVENIJA")
|
tv_station = job.get("tv_station", "FOLX SLO")
|
||||||
nc_folder = _nextcloud_folder_for_station(tv_station)
|
nc_folder = _nextcloud_folder_for_station(tv_station)
|
||||||
target_subdir = f"folxspeed/REELS/{nc_folder}"
|
target_subdir = f"folxspeed/REELS/{nc_folder}"
|
||||||
|
|
||||||
|
|||||||
@ -351,13 +351,13 @@
|
|||||||
<!-- TV postaja: določa Nextcloud target mapo -->
|
<!-- TV postaja: določa Nextcloud target mapo -->
|
||||||
<label style="margin-top:8px;">📺 TV postaja (določa kam gre na Nextcloud)</label>
|
<label style="margin-top:8px;">📺 TV postaja (določa kam gre na Nextcloud)</label>
|
||||||
<div class="tv-station-tabs" style="display:flex; flex-wrap:wrap; gap:6px; margin-bottom:14px;">
|
<div class="tv-station-tabs" style="display:flex; flex-wrap:wrap; gap:6px; margin-bottom:14px;">
|
||||||
<button type="button" class="tv-tab active" data-station="FOLX SLOVENIJA" style="padding:6px 12px; border:1px solid var(--accent); background:var(--accent); color:#fff; border-radius:4px; cursor:pointer; font-size:13px;">FOLX SLOVENIJA</button>
|
<button type="button" class="tv-tab active" data-station="FOLX SLO" style="padding:6px 12px; border:1px solid var(--accent); background:var(--accent); color:#fff; border-radius:4px; cursor:pointer; font-size:13px;">FOLX SLO</button>
|
||||||
<button type="button" class="tv-tab" data-station="FOLX DE" style="padding:6px 12px; border:1px solid #444; background:transparent; color:#ccc; border-radius:4px; cursor:pointer; font-size:13px;">FOLX DE</button>
|
<button type="button" class="tv-tab" data-station="FOLX DE" style="padding:6px 12px; border:1px solid #444; background:transparent; color:#ccc; border-radius:4px; cursor:pointer; font-size:13px;">FOLX DE</button>
|
||||||
<button type="button" class="tv-tab" data-station="ONE DE" style="padding:6px 12px; border:1px solid #444; background:transparent; color:#ccc; border-radius:4px; cursor:pointer; font-size:13px;">ONE DE</button>
|
<button type="button" class="tv-tab" data-station="ONE DE" style="padding:6px 12px; border:1px solid #444; background:transparent; color:#ccc; border-radius:4px; cursor:pointer; font-size:13px;">ONE DE</button>
|
||||||
<button type="button" class="tv-tab" data-station="ZWEI MUSIC" style="padding:6px 12px; border:1px solid #444; background:transparent; color:#ccc; border-radius:4px; cursor:pointer; font-size:13px;">ZWEI MUSIC</button>
|
<button type="button" class="tv-tab" data-station="ZWEI MUSIC" style="padding:6px 12px; border:1px solid #444; background:transparent; color:#ccc; border-radius:4px; cursor:pointer; font-size:13px;">ZWEI MUSIC</button>
|
||||||
<button type="button" class="tv-tab" data-station="ADRIA" style="padding:6px 12px; border:1px solid #444; background:transparent; color:#ccc; border-radius:4px; cursor:pointer; font-size:13px;">ADRIA</button>
|
<button type="button" class="tv-tab" data-station="ADRIA" style="padding:6px 12px; border:1px solid #444; background:transparent; color:#ccc; border-radius:4px; cursor:pointer; font-size:13px;">ADRIA</button>
|
||||||
</div>
|
</div>
|
||||||
<input type="hidden" id="tv-station-input" value="FOLX SLOVENIJA">
|
<input type="hidden" id="tv-station-input" value="FOLX SLO">
|
||||||
|
|
||||||
<!-- Skriti settings — vsi defaulti zapečeni za reels workflow -->
|
<!-- Skriti settings — vsi defaulti zapečeni za reels workflow -->
|
||||||
<input type="hidden" id="mode" value="track">
|
<input type="hidden" id="mode" value="track">
|
||||||
@ -428,8 +428,8 @@
|
|||||||
<button type="button" class="station-filter-tab active" data-station="" style="padding:5px 11px; border:1px solid var(--accent); background:var(--accent); color:#fff; border-radius:4px; cursor:pointer; font-size:12px;">
|
<button type="button" class="station-filter-tab active" data-station="" style="padding:5px 11px; border:1px solid var(--accent); background:var(--accent); color:#fff; border-radius:4px; cursor:pointer; font-size:12px;">
|
||||||
Vse <span class="cnt" data-cnt-all>0</span>
|
Vse <span class="cnt" data-cnt-all>0</span>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="station-filter-tab" data-station="FOLX SLOVENIJA" style="padding:5px 11px; border:1px solid #444; background:transparent; color:#ccc; border-radius:4px; cursor:pointer; font-size:12px;">
|
<button type="button" class="station-filter-tab" data-station="FOLX SLO" style="padding:5px 11px; border:1px solid #444; background:transparent; color:#ccc; border-radius:4px; cursor:pointer; font-size:12px;">
|
||||||
FOLX SLOVENIJA <span class="cnt" data-cnt="FOLX SLOVENIJA">0</span>
|
FOLX SLO <span class="cnt" data-cnt="FOLX SLO">0</span>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="station-filter-tab" data-station="FOLX DE" style="padding:5px 11px; border:1px solid #444; background:transparent; color:#ccc; border-radius:4px; cursor:pointer; font-size:12px;">
|
<button type="button" class="station-filter-tab" data-station="FOLX DE" style="padding:5px 11px; border:1px solid #444; background:transparent; color:#ccc; border-radius:4px; cursor:pointer; font-size:12px;">
|
||||||
FOLX DE <span class="cnt" data-cnt="FOLX DE">0</span>
|
FOLX DE <span class="cnt" data-cnt="FOLX DE">0</span>
|
||||||
@ -536,7 +536,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const filenames = newItems.map(i => i.file.name);
|
const filenames = newItems.map(i => i.file.name);
|
||||||
const tvStation = $("#tv-station-input").value || "FOLX SLOVENIJA";
|
const tvStation = $("#tv-station-input").value || "FOLX SLO";
|
||||||
|
|
||||||
// Vzporedno: dedup check + Qnet match (oba endpointa, neodvisna)
|
// Vzporedno: dedup check + Qnet match (oba endpointa, neodvisna)
|
||||||
const [dedupRes, qnetRes] = await Promise.all([
|
const [dedupRes, qnetRes] = await Promise.all([
|
||||||
@ -681,7 +681,7 @@
|
|||||||
quality: $("#quality").value,
|
quality: $("#quality").value,
|
||||||
no_subs: $("#no-subs").checked,
|
no_subs: $("#no-subs").checked,
|
||||||
llm_provider: $("#llm-provider").value,
|
llm_provider: $("#llm-provider").value,
|
||||||
tv_station: $("#tv-station-input").value || "FOLX SLOVENIJA",
|
tv_station: $("#tv-station-input").value || "FOLX SLO",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1271,7 +1271,7 @@
|
|||||||
actions.push(`<button class="small ghost" data-action="delete" data-id="${job.id}">✕</button>`);
|
actions.push(`<button class="small ghost" data-action="delete" data-id="${job.id}">✕</button>`);
|
||||||
|
|
||||||
// TV station label (brez emoji)
|
// TV station label (brez emoji)
|
||||||
const tvStation = job.tv_station || "FOLX SLOVENIJA";
|
const tvStation = job.tv_station || "FOLX SLO";
|
||||||
const tvBadge = `<span style="font-size:10px; padding:2px 6px; background:rgba(255,107,107,0.15); border:1px solid rgba(255,107,107,0.4); border-radius:3px; color:#ff8c8c; font-weight:600; white-space:nowrap;">${escapeHtml(tvStation)}</span>`;
|
const tvBadge = `<span style="font-size:10px; padding:2px 6px; background:rgba(255,107,107,0.15); border:1px solid rgba(255,107,107,0.4); border-radius:3px; color:#ff8c8c; font-weight:600; white-space:nowrap;">${escapeHtml(tvStation)}</span>`;
|
||||||
|
|
||||||
el.innerHTML = `
|
el.innerHTML = `
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user