fix: resolve path mismatch in destruct mode and prevent empty folder creation
All checks were successful
Docker Build / build (push) Successful in 13s
All checks were successful
Docker Build / build (push) Successful in 13s
This commit is contained in:
parent
45a1f0ae93
commit
88bc8229c9
1 changed files with 39 additions and 22 deletions
|
|
@ -805,23 +805,18 @@ def process_videos():
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log(f" ❌ Migration error for {sanitized_channel_name}: {e}")
|
log(f" ❌ Migration error for {sanitized_channel_name}: {e}")
|
||||||
|
|
||||||
# Folder Creation & Linking
|
# Folder Creation (Delay until link check)
|
||||||
channel_dir = target_root / sanitized_channel_name
|
channel_dir = target_root / sanitized_channel_name
|
||||||
sanitized_title = sanitize(meta["title"])
|
sanitized_title = sanitize(meta["title"])
|
||||||
folder_name = f"{meta['published']} - {sanitized_title}"
|
folder_name = f"{meta['published']} - {sanitized_title}"
|
||||||
video_dir = channel_dir / folder_name
|
video_dir = channel_dir / folder_name
|
||||||
|
|
||||||
# IMPORTANT: mkdir only when we are sure we have the file
|
|
||||||
# actual_file is video_file
|
|
||||||
|
|
||||||
channel_dir.mkdir(parents=True, exist_ok=True)
|
|
||||||
video_dir.mkdir(parents=True, exist_ok=True)
|
|
||||||
|
|
||||||
host_path_root = Path("/mnt/user/tubearchives/bp")
|
host_path_root = Path("/mnt/user/tubearchives/bp")
|
||||||
host_source_path = host_path_root / video_file.relative_to(SOURCE_DIR)
|
host_source_path = host_path_root / video_file.relative_to(SOURCE_DIR)
|
||||||
dest_file = video_dir / f"video{video_file.suffix}"
|
dest_file = video_dir / f"video{video_file.suffix}"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
link_success = False
|
||||||
if dest_file.exists():
|
if dest_file.exists():
|
||||||
if dest_file.is_symlink():
|
if dest_file.is_symlink():
|
||||||
current_target = Path(os.readlink(dest_file))
|
current_target = Path(os.readlink(dest_file))
|
||||||
|
|
@ -830,12 +825,18 @@ def process_videos():
|
||||||
os.symlink(host_source_path, dest_file)
|
os.symlink(host_source_path, dest_file)
|
||||||
log(f" [FIX] Relinked: {folder_name}")
|
log(f" [FIX] Relinked: {folder_name}")
|
||||||
new_links += 1
|
new_links += 1
|
||||||
|
link_success = True
|
||||||
else:
|
else:
|
||||||
verified_links += 1
|
verified_links += 1
|
||||||
|
link_success = True
|
||||||
else:
|
else:
|
||||||
|
# Create directories ONLY NOW
|
||||||
|
channel_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
video_dir.mkdir(parents=True, exist_ok=True)
|
||||||
os.symlink(host_source_path, dest_file)
|
os.symlink(host_source_path, dest_file)
|
||||||
log(f" [NEW] Linked: {folder_name}")
|
log(f" [NEW] Linked: {folder_name}")
|
||||||
new_links += 1
|
new_links += 1
|
||||||
|
link_success = True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log(f" ❌ Link error for {folder_name}: {e}")
|
log(f" ❌ Link error for {folder_name}: {e}")
|
||||||
|
|
||||||
|
|
@ -1151,31 +1152,47 @@ def api_recovery_delete_batch():
|
||||||
log(f"🔥 Batch Delete started. Items: {len(paths)}, Destruct: {destruct}")
|
log(f"🔥 Batch Delete started. Items: {len(paths)}, Destruct: {destruct}")
|
||||||
|
|
||||||
# Refresh metadata for destruct mode
|
# Refresh metadata for destruct mode
|
||||||
video_map = fetch_all_metadata() if destruct else {}
|
video_map = {}
|
||||||
|
if destruct:
|
||||||
|
# Optimization: only fetch if destruct is on
|
||||||
|
video_map = fetch_all_metadata()
|
||||||
|
|
||||||
for path in paths:
|
for path in paths:
|
||||||
try:
|
try:
|
||||||
# 1. Destruct Source if enabled
|
# 1. Destruct Source if enabled
|
||||||
|
p = Path(path)
|
||||||
if destruct:
|
if destruct:
|
||||||
source_deleted = False
|
source_deleted = False
|
||||||
for vid_id, meta in video_map.items():
|
# Try to find video_id from DB first (most reliable for library files)
|
||||||
if meta.get('path') == path or meta.get('filesystem_path') == path:
|
vid_id = None
|
||||||
source_path = meta.get('filesystem_path')
|
with get_db() as conn:
|
||||||
if source_path and os.path.exists(source_path):
|
row = conn.execute("SELECT video_id FROM videos WHERE symlink = ?", (path,)).fetchone()
|
||||||
|
if row:
|
||||||
|
vid_id = row['video_id']
|
||||||
|
|
||||||
|
# Fallback: Extraction from filename
|
||||||
|
if not vid_id:
|
||||||
|
vid_id = extract_id_from_filename(p.name)
|
||||||
|
|
||||||
|
if vid_id:
|
||||||
|
meta = video_map.get(vid_id)
|
||||||
|
if meta:
|
||||||
|
source_path_raw = meta.get('filesystem_path')
|
||||||
|
if source_path_raw:
|
||||||
|
source_path = Path(source_path_raw)
|
||||||
|
if source_path.exists():
|
||||||
try:
|
try:
|
||||||
os.remove(source_path)
|
source_path.unlink()
|
||||||
log(f"☢️ [DESTRUCT] Deleted source: {source_path}")
|
log(f"☢️ [DESTRUCT] Deleted source: {source_path}")
|
||||||
source_deleted = True
|
source_deleted = True
|
||||||
break
|
|
||||||
except Exception as se:
|
except Exception as se:
|
||||||
log(f"❌ [DESTRUCT] Failed to delete source {source_path}: {se}")
|
log(f"❌ [DESTRUCT] Failed to delete source {source_path}: {se}")
|
||||||
raise Exception(f"Source deletion failed: {se}")
|
raise Exception(f"Source deletion failed: {se}")
|
||||||
|
|
||||||
if not source_deleted:
|
if not source_deleted:
|
||||||
log(f"⚠️ [DESTRUCT] Source not found for: {path}")
|
log(f"⚠️ [DESTRUCT] Source file not found for: {path} (ID: {vid_id or 'unknown'})")
|
||||||
|
|
||||||
# 2. Delete Target
|
# 2. Delete Target
|
||||||
p = Path(path)
|
|
||||||
if p.exists():
|
if p.exists():
|
||||||
if p.is_dir():
|
if p.is_dir():
|
||||||
shutil.rmtree(p)
|
shutil.rmtree(p)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue