Repository: yt-dlp
Issue: Provide an option to cleanup temporary files before exiting, or moving on to the next video
Labels: enhancement,triage,core:downloader

### DO NOT REMOVE OR SKIP THE ISSUE TEMPLATE

- [X] I understand that I will be **blocked** if I *intentionally* remove or skip any mandatory\* field

### Checklist

- [X] I'm requesting a feature unrelated to a specific site
- [X] I've looked through the [README](https://github.com/yt-dlp/yt-dlp#readme)
- [X] I've verified that I have **updated yt-dlp to nightly or master** ([update instructions](https://github.com/yt-dlp/yt-dlp#update-channels))
- [X] I've searched [known issues](https://github.com/yt-dlp/yt-dlp/issues/3766) and the [bugtracker](https://github.com/yt-dlp/yt-dlp/issues?q=) for similar issues **including closed ones**. DO NOT post duplicates
- [X] I've read the [guidelines for opening an issue](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#opening-an-issue)

### Provide a description that is worded well enough to be understood

There's currently a problem with temporarily files lingering around, partially because the default `--continue` option relies on this behavior, therefore there's no cleanup, even `--no-continue` just results in ignoring the files, with no option available to clean the temporary directory.

Splitting off from #2532 which already describes a good case where the temporary files left around are not expected to be used ever again, I have another case where the files even get in the way of normal operation.

My setup opportunistically uses tmpfs to avoid unnecessary disk I/O, giving the temporary (-P "temp:") directory a quite limited size with no room to spare. When downloading is interrupted, the temporary data is left lingering around, resulting in subsequent downloads no longer fitting into the temporary directory, making the rest of the playlist also fail depending on how much space was left.

This problem can be commonly observed with Twitch as some VODs have missing pieces, resulting in an archiving setup with `--abort-on-unavailable-fragments` failing on the affected video.
Example command leaving behind temporary files:
`yt-dlp --abort-on-unavailable-fragments -vU https://www.twitch.tv/videos/1870517085` (attached output too)
Avoided the "decoration" with `--no-continue`, `--no-keep-video` (it's the default anyway), and other options as despite the "spirit" of having an explicit temporary directory and indicating no desire of keeping files for later, there's nothing stopping the littering.

I've already had containerization taking care of leftover files on exit, and as an extra workaround `--exec before_dl:"clean.sh"` seems to help where `clean.sh` cleans the temporary directory.
Beware: Early attempts like `--exec before_dl:"rm -rf /tmp/yt-dlp"` didn't work, because the "temp" directory needs to exist, and `--exec` also stuffs an extra parameter to the end which seems to be impossible to avoid if templating is just undesired. A helper script ended up being much simpler.

This also presents the opportunity of exposing the hidden _no_ytdl_file option which benefits mostly HDDs. If the user can signal no desire for later continuation, there's also no need to keep on dumping the current state to the disk.
For large videos not fitting into tmpfs, I'm using a patch getting rid of the ytdl file, and pushing fragment files into tmpfs, resulting in significantly more efficient disk I/O as a result of having a single write stream during the downloading part.

### Provide verbose output that clearly demonstrates the problem

- [X] Run **your** yt-dlp command with **-vU** flag added (`yt-dlp -vU <your command line>`)
- [ ] If using API, add `'verbose': True` to `YoutubeDL` params instead
- [X] Copy the WHOLE output (starting with `[debug] Command-line config`) and insert it below

### Complete Verbose Output

```shell
[debug] Command-line config: ['--abort-on-unavailable-fragments', '-vU', 'https://www.twitch.tv/videos/1870517085']
[debug] Encodings: locale utf-8, fs utf-8, pref utf-8, out utf-8, error utf-8, screen utf-8
[debug] yt-dlp version stable@2024.11.18 from yt-dlp/yt-dlp [7ea278792] (zip)
[debug] Lazy loading extractors is disabled
[debug] Python 3.12.3 (CPython x86_64 64bit) - Linux-6.8.0-47-generic-x86_64-with-glibc2.39 (OpenSSL 3.0.13 30 Jan 2024, glibc 2.39)
[debug] exe versions: ffmpeg 6.1.1 (setts), ffprobe 6.1.1
[debug] Optional libraries: sqlite3-3.45.1
[debug] Proxy map: {}
[debug] Request Handlers: urllib
[debug] Loaded 1837 extractors
[debug] Fetching release info: https://api.github.com/repos/yt-dlp/yt-dlp/releases/latest
Latest version: stable@2024.11.18 from yt-dlp/yt-dlp
yt-dlp is up to date (stable@2024.11.18 from yt-dlp/yt-dlp)
[twitch:vod] Extracting URL: https://www.twitch.tv/videos/1870517085
[twitch:vod] 1870517085: Downloading stream metadata GraphQL
[twitch:vod] 1870517085: Downloading video access token GraphQL
[twitch:vod] 1870517085: Downloading m3u8 information
[twitch:vod] 1870517085: Downloading storyboard metadata JSON
[debug] Formats sorted by: hasvid, ie_pref, lang, quality, res, fps, hdr:12(7), vcodec, channels, acodec, size, br, asr, proto, vext, aext, hasaud, source, id
[debug] Default format spec: bestvideo*+bestaudio/best
[info] v1870517085: Downloading 1 format(s): 1080p60
[debug] Invoking hlsnative downloader on "https://dgeft87wbj63p.cloudfront.net/ae1b0881cb83a24fdfa0_sodapoppin_67689483633_2831051625/chunked/highlight-1870517085.m3u8"
[hlsnative] Downloading m3u8 manifest
[hlsnative] Total fragments: 2574
[download] Destination: Highlight 07⧸05⧸23： im in the UK bruv ｜ !contest ｜ @StarforgeSystems ｜ @MadMushroomGG ｜ sodaPride [v1870517085].mp4
[download]  87.9% of ~  22.23GiB at    7.80MiB/s ETA 06:03 (frag 2264/2574)[download] Got error: HTTP Error 403: Forbidden. Retrying fragment 2265 (1/10)...
[download] Got error: HTTP Error 403: Forbidden. Retrying fragment 2265 (2/10)...
[download] Got error: HTTP Error 403: Forbidden. Retrying fragment 2265 (3/10)...
[download] Got error: HTTP Error 403: Forbidden. Retrying fragment 2265 (4/10)...
[download] Got error: HTTP Error 403: Forbidden. Retrying fragment 2265 (5/10)...
[download] Got error: HTTP Error 403: Forbidden. Retrying fragment 2265 (6/10)...
[download] Got error: HTTP Error 403: Forbidden. Retrying fragment 2265 (7/10)...
[download] Got error: HTTP Error 403: Forbidden. Retrying fragment 2265 (8/10)...
[download] Got error: HTTP Error 403: Forbidden. Retrying fragment 2265 (9/10)...
[download] Got error: HTTP Error 403: Forbidden. Retrying fragment 2265 (10/10)...
[download] Got error: HTTP Error 403: Forbidden. Giving up after 10 retries
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "/root/bin/yt-dlp/__main__.py", line 17, in <module>
    yt_dlp.main()
  File "/root/bin/yt-dlp/yt_dlp/__init__.py", line 1093, in main
    _exit(*variadic(_real_main(argv)))
  File "/root/bin/yt-dlp/yt_dlp/__init__.py", line 1083, in _real_main
    return ydl.download(all_urls)
  File "/root/bin/yt-dlp/yt_dlp/YoutubeDL.py", line 3604, in download
    self.__download_wrapper(self.extract_info)(
  File "/root/bin/yt-dlp/yt_dlp/YoutubeDL.py", line 3577, in wrapper
    res = func(*args, **kwargs)
  File "/root/bin/yt-dlp/yt_dlp/YoutubeDL.py", line 1613, in extract_info
    return self.__extract_info(url, self.get_info_extractor(key), download, extra_info, process)
  File "/root/bin/yt-dlp/yt_dlp/YoutubeDL.py", line 1624, in wrapper
    return func(self, *args, **kwargs)
  File "/root/bin/yt-dlp/yt_dlp/YoutubeDL.py", line 1780, in __extract_info
    return self.process_ie_result(ie_result, download, extra_info)
  File "/root/bin/yt-dlp/yt_dlp/YoutubeDL.py", line 1839, in process_ie_result
    ie_result = self.process_video_result(ie_result, download=download)
  File "/root/bin/yt-dlp/yt_dlp/YoutubeDL.py", line 3010, in process_video_result
    self.process_info(new_info)
  File "/root/bin/yt-dlp/yt_dlp/YoutubeDL.py", line 177, in wrapper
    return func(self, *args, **kwargs)
  File "/root/bin/yt-dlp/yt_dlp/YoutubeDL.py", line 3478, in process_info
    success, real_download = self.dl(temp_filename, info_dict)
  File "/root/bin/yt-dlp/yt_dlp/YoutubeDL.py", line 3198, in dl
    return fd.download(name, new_info, subtitle)
  File "/root/bin/yt-dlp/yt_dlp/downloader/common.py", line 464, in download
    ret = self.real_download(filename, info_dict)
  File "/root/bin/yt-dlp/yt_dlp/downloader/hls.py", line 381, in real_download
    return self.download_and_append_fragments(ctx, fragments, info_dict)
  File "/root/bin/yt-dlp/yt_dlp/downloader/fragment.py", line 513, in download_and_append_fragments
    download_fragment(fragment, ctx)
  File "/root/bin/yt-dlp/yt_dlp/downloader/fragment.py", line 459, in download_fragment
    for retry in RetryManager(self.params.get('fragment_retries'), error_callback):
  File "/root/bin/yt-dlp/yt_dlp/utils/_utils.py", line 5251, in __iter__
    self.error_callback(self.error, self.attempt, self.retries)
  File "/root/bin/yt-dlp/yt_dlp/downloader/fragment.py", line 456, in error_callback
    self.report_retry(err, count, retries, frag_index, fatal)
  File "/root/bin/yt-dlp/yt_dlp/downloader/common.py", line 410, in report_retry
    RetryManager.report_retry(
  File "/root/bin/yt-dlp/yt_dlp/utils/_utils.py", line 5258, in report_retry
    return error(f'{e}. Giving up after {count - 1} retries') if count > 1 else error(str(e))
  File "/root/bin/yt-dlp/yt_dlp/downloader/common.py", line 413, in <lambda>
    error=IDENTITY if not fatal else lambda e: self.report_error(f'\r[download] Got error: {e}'),
  File "/root/bin/yt-dlp/yt_dlp/YoutubeDL.py", line 1090, in report_error
    self.trouble(f'{self._format_err("ERROR:", self.Styles.ERROR)} {message}', *args, **kwargs)
  File "/root/bin/yt-dlp/yt_dlp/YoutubeDL.py", line 1018, in trouble
    tb_data = traceback.format_list(traceback.extract_stack())

ERROR: fragment 2265 not found, unable to continue
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "/root/bin/yt-dlp/__main__.py", line 17, in <module>
    yt_dlp.main()
  File "/root/bin/yt-dlp/yt_dlp/__init__.py", line 1093, in main
    _exit(*variadic(_real_main(argv)))
  File "/root/bin/yt-dlp/yt_dlp/__init__.py", line 1083, in _real_main
    return ydl.download(all_urls)
  File "/root/bin/yt-dlp/yt_dlp/YoutubeDL.py", line 3604, in download
    self.__download_wrapper(self.extract_info)(
  File "/root/bin/yt-dlp/yt_dlp/YoutubeDL.py", line 3577, in wrapper
    res = func(*args, **kwargs)
  File "/root/bin/yt-dlp/yt_dlp/YoutubeDL.py", line 1613, in extract_info
    return self.__extract_info(url, self.get_info_extractor(key), download, extra_info, process)
  File "/root/bin/yt-dlp/yt_dlp/YoutubeDL.py", line 1624, in wrapper
    return func(self, *args, **kwargs)
  File "/root/bin/yt-dlp/yt_dlp/YoutubeDL.py", line 1780, in __extract_info
    return self.process_ie_result(ie_result, download, extra_info)
  File "/root/bin/yt-dlp/yt_dlp/YoutubeDL.py", line 1839, in process_ie_result
    ie_result = self.process_video_result(ie_result, download=download)
  File "/root/bin/yt-dlp/yt_dlp/YoutubeDL.py", line 3010, in process_video_result
    self.process_info(new_info)
  File "/root/bin/yt-dlp/yt_dlp/YoutubeDL.py", line 177, in wrapper
    return func(self, *args, **kwargs)
  File "/root/bin/yt-dlp/yt_dlp/YoutubeDL.py", line 3478, in process_info
    success, real_download = self.dl(temp_filename, info_dict)
  File "/root/bin/yt-dlp/yt_dlp/YoutubeDL.py", line 3198, in dl
    return fd.download(name, new_info, subtitle)
  File "/root/bin/yt-dlp/yt_dlp/downloader/common.py", line 464, in download
    ret = self.real_download(filename, info_dict)
  File "/root/bin/yt-dlp/yt_dlp/downloader/hls.py", line 381, in real_download
    return self.download_and_append_fragments(ctx, fragments, info_dict)
  File "/root/bin/yt-dlp/yt_dlp/downloader/fragment.py", line 514, in download_and_append_fragments
    result = append_fragment(
  File "/root/bin/yt-dlp/yt_dlp/downloader/fragment.py", line 479, in append_fragment
    self.report_error(f'fragment {frag_index} not found, unable to continue')
  File "/root/bin/yt-dlp/yt_dlp/YoutubeDL.py", line 1090, in report_error
    self.trouble(f'{self._format_err("ERROR:", self.Styles.ERROR)} {message}', *args, **kwargs)
  File "/root/bin/yt-dlp/yt_dlp/YoutubeDL.py", line 1018, in trouble
    tb_data = traceback.format_list(traceback.extract_stack())
```
```