Merge e75487efae into 5429200fba
This commit is contained in:
commit
b607722fe1
1 changed files with 57 additions and 1 deletions
58
app/ytdl.py
58
app/ytdl.py
|
|
@ -1389,13 +1389,69 @@ class DownloadQueue:
|
||||||
dl = self.done.get(id)
|
dl = self.done.get(id)
|
||||||
try:
|
try:
|
||||||
dldirectory, _ = self.__calc_download_path(dl.info.download_type, dl.info.folder)
|
dldirectory, _ = self.__calc_download_path(dl.info.download_type, dl.info.folder)
|
||||||
os.remove(os.path.join(dldirectory, dl.info.filename))
|
self.__remove_download_and_sidecars(dldirectory, dl.info.filename)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.warning(f'deleting file for download {id} failed with error message {e!r}')
|
log.warning(f'deleting file for download {id} failed with error message {e!r}')
|
||||||
self.done.delete(id)
|
self.done.delete(id)
|
||||||
await self.notifier.cleared(id)
|
await self.notifier.cleared(id)
|
||||||
return {'status': 'ok'}
|
return {'status': 'ok'}
|
||||||
|
|
||||||
|
def __remove_download_and_sidecars(self, bucket_root, rel_filename):
|
||||||
|
"""When DELETE_FILE_ON_TRASHCAN is enabled, the trash button should
|
||||||
|
leave the bucket the way it found it: no orphan thumbnail / subtitle
|
||||||
|
/ info.json files, no empty `<uploader>/` directories left behind.
|
||||||
|
|
||||||
|
Removes:
|
||||||
|
1. the main file the download record references
|
||||||
|
2. every same-stem sidecar in the same directory
|
||||||
|
(writethumbnail's .jpg/.webp, writesubtitles' .vtt/.srt,
|
||||||
|
writeinfojson's .info.json, writedescription's .description,
|
||||||
|
anything else yt-dlp writes per video)
|
||||||
|
3. any directories from the file's parent up to (but not including)
|
||||||
|
the bucket root, while they're empty after the removals above
|
||||||
|
|
||||||
|
Never touches the bucket root itself (e.g. /downloads/helmut), and
|
||||||
|
os.rmdir() is non-destructive — it raises if the directory still
|
||||||
|
contains anything, which is exactly the desired behaviour."""
|
||||||
|
main_path = os.path.join(bucket_root, rel_filename)
|
||||||
|
main_dir = os.path.dirname(main_path)
|
||||||
|
main_stem, _ = os.path.splitext(os.path.basename(main_path))
|
||||||
|
# Sidecar prefix matches the main file and anything yt-dlp wrote
|
||||||
|
# alongside it (e.g. "Title [id].jpg", "Title [id].en.vtt",
|
||||||
|
# "Title [id].info.json"). The trailing dot avoids matching a
|
||||||
|
# sibling whose name starts with the same stem but continues
|
||||||
|
# with other characters (e.g. "Title [id] (alt cut).mp4").
|
||||||
|
sidecar_prefix = main_stem + '.'
|
||||||
|
if os.path.isdir(main_dir):
|
||||||
|
for entry in os.listdir(main_dir):
|
||||||
|
if not entry.startswith(sidecar_prefix):
|
||||||
|
continue
|
||||||
|
entry_path = os.path.join(main_dir, entry)
|
||||||
|
if not os.path.isfile(entry_path):
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
os.remove(entry_path)
|
||||||
|
except OSError as e:
|
||||||
|
log.warning(f'failed to remove sidecar {entry_path}: {e!r}')
|
||||||
|
|
||||||
|
# Prune empty parent directories up to (but not including)
|
||||||
|
# bucket_root. Walk on realpath()ed paths so a symlinked layout
|
||||||
|
# can't trick us into climbing above the bucket.
|
||||||
|
try:
|
||||||
|
bucket_real = os.path.realpath(bucket_root)
|
||||||
|
cur = os.path.realpath(main_dir)
|
||||||
|
while cur != bucket_real and cur.startswith(bucket_real + os.sep):
|
||||||
|
try:
|
||||||
|
os.rmdir(cur)
|
||||||
|
except OSError:
|
||||||
|
# Directory is non-empty (or a permission issue) —
|
||||||
|
# in either case stop climbing, that's the signal
|
||||||
|
# to leave it alone.
|
||||||
|
break
|
||||||
|
cur = os.path.dirname(cur)
|
||||||
|
except Exception as e:
|
||||||
|
log.warning(f'failed to prune empty parents below {bucket_root}: {e!r}')
|
||||||
|
|
||||||
def get(self):
|
def get(self):
|
||||||
return (list((k, v.info) for k, v in self.queue.items()) +
|
return (list((k, v.info) for k, v in self.queue.items()) +
|
||||||
list((k, v.info) for k, v in self.pending.items()),
|
list((k, v.info) for k, v in self.pending.items()),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue