ytdl-org / youtube-dl

Command-line program to download videos from YouTube.com and other video sites

Home Page:http://ytdl-org.github.io/youtube-dl/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

External-downloader "ffmpeg" does not understand ffmpeg-location parameter

Murmur opened this issue · comments

YoutubeDownloader does not use ffmpeg-location path for an external-downloader argument I think? Full folder value did not work in an external args.

youtube-dl.exe --verbose ^
 --ffmpeg-location "c:/apps/ffmpeg" ^
 --format "(bestvideo[height<=1080][ext=mp4])+(bestaudio[asr=48000][ext=webm])" ^
 --external-downloader ffmpeg --external-downloader-args "-ss 00:00:00.00 -to 00:01:00.00" ^
 "https://www.youtube.com/watch?v=1JWEb2uKZ28" ^
 --merge-output-format mp4 -o "wildlife.mp4"

I had to put ffmpeg folder to PATH then external downloader worked.
set path=%path%;c:\apps\ffmpeg"

Feature Request If external download is ffmpeg then try to use ffmpeg-location folder.

ps: Or is there a downlod time limit parameter already without using an external ffmpeg trick?

I don't have a Windows test setup to hand but this has always worked before.

Setting --external-downloader ffmpeg --ffmpeg-location ./foo, where ./foo contains a (a link to) the ffmpeg binary leads to this downloader output:

...
[debug] ffmpeg command line: ./foo/ffmpeg -y -loglevel verbose -headers 'Accept-Lan
guage: en-us,en;q=0.5
...

Please post the text log of your failing command, with -v/--verbose.

I suppose "c:/dir1/dir2" is understood and shouldn't be "c:\\dir1\\dir2" or some such?

Exact error is Requested external downloader cannot be used: ignoring --external-downloader-args and app fallback to an internal downloader. It cannot use a duration limitter so 1h of video is downloaded and then must be trimmed post-process.

I tried a combination of ffmpeg-location values nothing helps.
External downloader works if I put ffmpeg folder to dos PATH variable set path=%path%;c:\apps\ffmpeg

--ffmpeg-location "c:/apps/ffmpeg"
--ffmpeg-location "c:\apps\ffmpeg"
--ffmpeg-location "c:\\apps\\ffmpeg"
--ffmpeg-location "c:/apps/ffmpeg/"
--ffmpeg-location "c:/apps/ffmpeg/ffmpeg.exe"
--external-downloader "c:/apps/ffmpeg.exe"
--external-downloader "c:\apps\ffmpeg.exe"
--external-downloader "c:/apps/ffmpeg"
--external-downloader "c:\apps\ffmpeg"

youtube-dl.exe --verbose ^
 --ffmpeg-location "c:/apps/ffmpeg" ^
 --external-downloader ffmpeg ^
 --external-downloader-args "-ss 00:00:00 -to 00:00:30" ^
 --format "(bestvideo[height<=1080][ext=mp4])+(bestaudio[asr=48000][ext=webm])" ^
 "https://www.youtube.com/watch?v=1JWEb2uKZ28" ^
 --merge-output-format mp4 -o test.mp4
[debug] System config: []
[debug] User config: []
[debug] Custom config: []
[debug] Command-line args: ['--verbose', '--external-downloader', 'ffmpeg', '--ffmpeg-location', 'c:/apps/ffmpeg', '--external-downloader-args', '-ss 00:00:00 -to 00:00:30', '--format', '(bestvideo[height<=1080][ext=mp4])+(bestaudio[asr=48000][ext=webm])', 'https://www.youtube.com/watch?v=1JWEb2uKZ28', '--merge-output-format', 'mp4', '-o', 'test.mp4']
[debug] Encodings: locale cp1252, fs mbcs, out cp437, pref cp1252
[debug] youtube-dl version 2024.02.23 [40bd5c181] (single file build)
[debug] ** This version was built from the latest master code at https://github.com/ytdl-org/youtube-dl.
[debug] Python 3.4.4 (CPython AMD64 32bit) - Windows-10-10.0.19041 - OpenSSL 1.0.2d 9 Jul 2015
[debug] exe versions: ffmpeg N-113115-gf01f31d39a, ffprobe N-113115-gf01f31d39a
[debug] Proxy map: {}
WARNING: Requested external downloader cannot be used: ignoring --external-downloader-args.
[debug] Invoking downloader on 'https://rr2---sn-xap5-uh2el.googlevideo.com/videoplayback....'
[dashsegments] Total fragments: 115
[download] Destination: test.f137.mp4
[download]   2.1% of ~1.12GiB at  7.70MiB/s ETA 02:26

I took a git clone sources to a local folder to debug what happens but am unable to run youtubeDL directly from the sources folder, how do I do it with a windows python3.exe?

cd into the cloned youtube-dl directory (that contains AUTHORS). Then use python3 -m youtube_dl as the yt-dl command.

The --ffmpeg-location is a valid pathname, or there would be a ffmpeg-location ... does not exist ... warning.

The ffmpeg in that location is found, or there would be a Cannot identify executable ... warning.

There is this fragment in the ffmpeg downloader class:

    @classmethod
    def available(cls, path=None):
        # TODO: Fix path for ffmpeg
        # Fixme: This may be wrong when --ffmpeg-location is used
        return FFmpegPostProcessor().available

Probably the comment author had in mind that the available is an instance method that is being called on the class, and so doesn't take account of initialisation that occurs at instance creation. You'd think there'd be a flake8 diagnostic for that. However the wrongness would be in the wrong direction: the static available value would be True but after trying to find the executable at instance creation the instance value might be False. This could happen if the program is invalid (but we know it's not) or if its version output can't be parsed.

Thanks, had to edit an adhoc python syslib folder, without it an error module not found in my environment. I can now debug this behaviour. For now I just downloaded few youtube files using set PATH fix.

Clone sources
  cd C:\apps\youtube-dl
  git clone --depth 1 https://github.com/ytdl-org/youtube-dl.git
  cd C:\apps\youtube-dl\youtube-dl
  c:\apps\python-3.10.7\python.exe -m site
Edit python syslib _pth text file:
  c:\apps\python-3.10.7\python310._pth
Add path to an adhoc project module.
  C:/apps/youtube-dl/youtube-dl
List new syslib values and run app directly from the git sources folder
  c:\apps\python-3.10.7\python.exe -m site
  "c:\apps\python-3.10.7\python.exe" -m youtube_dl --help

I guess the .pth setting is an alternative to setting the current directory.

@dirkf Indeed is as you said a problem with method static-class-instance scope. Hardcoding def available(cls): return True "fixed" this problem with an external ffmpeg downloader, original code returns false which is not expected.

def available(cls):

I made a quick fix possibly not breaking the internal logic, use a class attribute to remember ffmpeg variable and check for instance+class variable in available() function.

File ffmpeg.py:
class FFmpegPostProcessor(PostProcessor):
    cls_basename = None ## see _determine_executables() and available()
   ...clip...
	
   def _determine_executables(self):
        ...clip...at the end of function do this hack
        if FFmpegPostProcessor.cls_basename is None: 
            FFmpegPostProcessor.cls_basename = self.basename

    @property
    def available(self):
        return self.basename is not None or FFmpegPostProcessor.cls_basename is not None

Run from the sources folder

cd "C:\apps\youtube-dl\youtube-dl"
"c:\apps\python-3.10.7\python.exe" -m youtube_dl ^
 --verbose ^
 --ffmpeg-location "c:/apps/ffmpeg/" ^
 --external-downloader "ffmpeg" ^
 --external-downloader-args "-ss 00:00:00 -to 00:00:10" ^
 --format "(bestvideo[height<=1080][ext=mp4])+(bestaudio[asr=48000][ext=webm])" ^
 "https://www.youtube.com/watch?v=1JWEb2uKZ28" ^
 --merge-output-format mp4 -o "../test.mp4"

I think I understand the issue properly now.

Your case is failing with ed.can_download(info_dict) being falsy, which leads to the "Requested external downloader cannot be used: ..." warning. Then FFmpegFD is being selected as downloader because protocol.startswith('m3u8') and info_dict.get('is_live') is truthy (ie, regardless of the --extermnal-downloader) (all in downloader/__init__.py).

ed.can_download(info_dict) is falsy because its first subcondition ed.available() is falsy, which in turn is because the 'basenameof aFFmpegPostProcessorcreated without reference to the yt-dl instance isNone(since the yt-dl instance is how it finds out about--ffmpeg-location`).

Passing downloader=self.ydl to the constructor in FFmpegFD._call_downloader() instead of downloader=self (that is an actual bug, I think, caused by misunderstanding what downloader is supposed to mean, and still present in yt-dlp) should result in finding the executable but it's too late to recover the --external-downloader-args.

I think that combining this with your hack to hard-code the result of FFmpegFD.available() could give an adequate complete solution.