Repository: yt-dlp
Issue: [Feature request] Handle Long filenames in default template and temporary files
Labels: enhancement

<!--

######################################################################
  WARNING!
  IGNORING THE FOLLOWING TEMPLATE WILL RESULT IN ISSUE CLOSED AS INCOMPLETE
######################################################################

-->


## Checklist

<!--
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of yt-dlp:
- First of, make sure you are using the latest version of yt-dlp. Run `yt-dlp --version` and ensure your version is 2021.09.25. If it's not, see https://github.com/yt-dlp/yt-dlp on how to update. Issues with outdated version will be REJECTED.
- Make sure that all provided video/audio/playlist URLs (if any) are alive and playable in a browser.
- Make sure that all URLs and arguments with special characters are properly quoted or escaped as explained in https://github.com/yt-dlp/yt-dlp.
- Search the bugtracker for similar issues: https://github.com/yt-dlp/yt-dlp. DO NOT post duplicates.
- Read bugs section in FAQ: https://github.com/yt-dlp/yt-dlp
- Finally, put x into all relevant boxes like this [x] (Dont forget to delete the empty space)
-->

- [x] I'm reporting a bug unrelated to a specific site
- [x] I've verified that I'm running yt-dlp version **2021.09.25**
- [x] I've checked that all provided URLs are alive and playable in a browser
- [x] The provided URLs do not contain any DRM to the best of my knowledge
- [x] I've checked that all URLs and arguments with special characters are properly quoted or escaped
- [x] I've searched the bugtracker for similar bug reports including closed ones
- [x] I've read bugs section in FAQ


## Verbose log

<!--
Provide the complete verbose output of yt-dlp that clearly demonstrates the problem.
Add the `-v` flag to your command line you run yt-dlp with (`yt-dlp -v <your command line>`), copy the WHOLE output and insert it below. It should look similar to this:
 [debug] System config: []
 [debug] User config: []
 [debug] Command-line args: [u'-v', u'http://www.youtube.com/watch?v=BaW_jenozKc']
 [debug] Encodings: locale cp1251, fs mbcs, out cp866, pref cp1251
 [debug] yt-dlp version 2021.09.25
 [debug] Python version 2.7.11 - Windows-2003Server-5.2.3790-SP2
 [debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4
 [debug] Proxy map: {}
 <more lines>
-->

```
[debug] Command-line config: ['--verbose', 'https://twitter.com/NASA/status/1443572363757559808', '-o', 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx']
[debug] Encodings: locale cp1252, fs utf-8, out utf-8, pref cp1252
[debug] yt-dlp version 2021.09.25 (source)
[debug] Plugins: ['SamplePluginIE', 'SamplePluginPP']
[debug] Git HEAD: ad095c428
[debug] Python version 3.8.10 (CPython 64bit) - Windows-10-10.0.19043-SP0
[debug] exe versions: ffmpeg n4.4-80-gbf87bdd3f6-20210811, ffprobe n4.4-80-gbf87bdd3f6-20210811, phantomjs 2.1.1
[debug] Optional libraries: sqlite
[debug] Proxy map: {}
[debug] [twitter] Extracting URL: https://twitter.com/NASA/status/1443572363757559808
[twitter] 1443572363757559808: Downloading guest token
[twitter] 1443572363757559808: Downloading JSON metadata
[twitter] 1443572363757559808: Downloading m3u8 information
[debug] Formats sorted by: hasvid, ie_pref, lang, quality, res, fps, vcodec:vp9.2(10), acodec, filesize, fs_approx, tbr, vbr, abr, asr, proto, vext, aext, hasaud, source, id
[debug] Default format spec: bestvideo*+bestaudio/best
[info] 1443572363757559808: Downloading 1 format(s): hls-2176
[debug] Invoking downloader on "https://video.twimg.com/amplify_video/1443570535904935945/pl/1280x720/eB7trHC2QS5NrGUL.m3u8"
[hlsnative] Downloading m3u8 manifest
[hlsnative] Total fragments: 22
[download] Destination: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
[download]  40.9% of ~5.05MiB at  9.73MiB/s ETA 00:01 ERROR: unable to open for writing: [Errno 22] Invalid argument: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.part-Frag10.part'
Traceback (most recent call last):
  File "F:\source\repos\yt-dlp\yt_dlp\downloader\http.py", line 262, in download
    ctx.stream, ctx.tmpfilename = sanitize_open(
  File "F:\source\repos\yt-dlp\yt_dlp\utils.py", line 2068, in sanitize_open
    stream = open(encodeFilename(filename), open_mode)
OSError: [Errno 22] Invalid argument: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.part-Frag10.part'

ERROR: unable to download video data: [Errno 2] No such file or directory: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.part-Frag10'
Traceback (most recent call last):
  File "F:\source\repos\yt-dlp\yt_dlp\YoutubeDL.py", line 2758, in process_info
    success, real_download = self.dl(temp_filename, info_dict)
  File "F:\source\repos\yt-dlp\yt_dlp\YoutubeDL.py", line 2475, in dl
    return fd.download(name, new_info, subtitle)
  File "F:\source\repos\yt-dlp\yt_dlp\downloader\common.py", line 408, in download
    return self.real_download(filename, info_dict), True
  File "F:\source\repos\yt-dlp\yt_dlp\downloader\hls.py", line 350, in real_download
    return self.download_and_append_fragments(ctx, fragments, info_dict)
  File "F:\source\repos\yt-dlp\yt_dlp\downloader\fragment.py", line 478, in download_and_append_fragments
    frag_content, frag_index = download_fragment(fragment, ctx)
  File "F:\source\repos\yt-dlp\yt_dlp\downloader\fragment.py", line 418, in download_fragment
    success, frag_content = self._download_fragment(ctx, fragment['url'], info_dict, headers)
  File "F:\source\repos\yt-dlp\yt_dlp\downloader\fragment.py", line 132, in _download_fragment
    return True, self._read_fragment(ctx)
  File "F:\source\repos\yt-dlp\yt_dlp\downloader\fragment.py", line 135, in _read_fragment
    down, frag_sanitized = sanitize_open(ctx['fragment_filename_sanitized'], 'rb')
  File "F:\source\repos\yt-dlp\yt_dlp\utils.py", line 2068, in sanitize_open
    stream = open(encodeFilename(filename), open_mode)
FileNotFoundError: [Errno 2] No such file or directory: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.part-Frag10'

```
<!--
Do not remove the above ```
-->


## Description

<!--
Provide an explanation of your issue in an arbitrary form. Please make sure the description is worded well enough to be understood, see https://github.com/ytdl-org/youtube-dl#is-the-description-of-the-issue-itself-sufficient. Provide any additional information, suggested solution and as much context and examples as possible.
If work on your issue requires account credentials please provide them or explain how one can obtain them.
-->

The defaults can result in filenames that are too long and confusingly this can also occur in temporary files. The example here shows a 239 character filename fails when the `.part-Frag10` suffix causes the filename to exceed 255 characters.

The workaround is to explicitly specify an output template that will not become too long even when suffixes are added. The default `%(title)s [%(id)s].%(ext)s` and fallback `%(title)s-%(id)s.%(ext)s` can both exceed 255 characters, especially with videos in long tweets.

In the example provided the output template is explicitly set to a filename that will exactly exceed 255 characters on fragment 10 to better illustrate the issue. However, omitting template or explicitly using the default `%(title)s [%(id)s].%(ext)s` will still result in an immediate failure on fragment 1.

This is related to #1003 and would appear to be cross-platform issue (and depends on the filesystem for the target files rather than the OS or runtime).

Work published by NASA is in the public domain so there are no licensing concerns with testing using this URL.

There are various codepaths that expect to be able to add a suffix to a temporary file and the temporary filename is based on the destination filename. By adding an option to specify tempfile format such as `%(extractor)s-%(id)s.%(ext)s` and altering the default file template to set some high but sane limits this could be mitigated for most users and still allow advanced users to explicitly specify long filenames.