231

I am using Ubuntu, and the youtube-dl command is working absolutely fine.

However, now I want to download only a portion a video that is too long. So I want to download only a few minutes of that video, e.g. from minute 13 to minute 17.

Is there any way to do that?

AdminBee
  • 22,803
user3181614
  • 2,411
  • Related: https://askubuntu.com/questions/970629/how-to-download-a-portion-of-a-video-with-youtube-dl-or-something-else – Ciro Santilli OurBigBook.com Feb 25 '21 at 10:05
  • youtube-dl does not know anything about video coding and video-frames... so you will need to download everything and cut it with a program which has video editing capabilities – schnedan Aug 22 '21 at 10:38

21 Answers21

175

I don't believe youtube-dl alone will do what you want. However you can combine it with a command line utility like ffmpeg.

First acquire the actual URL using youtube-dl:

youtube-dl -g "https://www.youtube.com/watch?v=V_f2QkBdbRI"

Copy the output of the command and paste it as part of the -i parameter of the next command:

ffmpeg -ss 00:00:15.00 -i "OUTPUT-OF-FIRST URL" -t 00:00:10.00 -c copy out.mp4

The -ss parameter in this position states to discard all input up until 15 seconds into the video. The -t option states to capture for 10 seconds. The rest of the command tells it to store as an mp4.

ffmpeg is a popular tool and should be in any of the popular OS repositories/package managers.

Johnnie
  • 2,531
  • 37
    So essentially, you still have to download the whole video and crop it yourself – Antony Jun 17 '16 at 00:08
  • 38
    You can use the -to option instead of -t if you want to specify the time for ending the video slice.

    ffmpeg -i "OUTPUT-OF-FIRST URL" -ss 00:13:00.00 -to 00:17:00.00 -c copy out.mp4

    – Capstone Apr 07 '17 at 14:41
  • 32
    @Antony ffmpeg will actually only download the part you specify. – akaihola Dec 21 '18 at 20:29
  • It didn't saved audio for a video in my case unlike @godofgrunts answer. – daGo Nov 02 '19 at 13:26
  • 9
    @Antony As long as you put the -ss parameter before the -i parameter, then it will start downloading from the time you specified with -ss. However, if you place -ss after the -i parameter, then ffmpeg will download from the very beginning of the video and start encoding from where -ss specifies. See my edit of Johnnie's answer for more info. – programmar Dec 15 '19 at 07:35
  • 3
    using the link provided by youtube-dl with the -g option will always return 403 forbidden for me. Using youtube-dl alone to download the video, will always work like a charm. – Fabián Aug 05 '20 at 19:27
  • 1
    @Roy That requires downloading the entire video first. – Geremia Feb 17 '21 at 00:15
  • @Geremia I am new to this. Do you know how I can do this with Python? – Kashish Arora Feb 19 '21 at 04:52
  • I struggle to copy this link and add -f parameter, if need only video with -f 248 for example. – Peter.k May 30 '21 at 16:28
  • I'd like to use this answer, but I prefer using the youtube name (eg "c:\myvideos%%(title)s-%%(id)s.%%(ext)s ) -- how would you use this with your answer? A line I tried to use but failed with an error message of mixed argument design: %program% -f %option% "%youtubelink%" "%option2%" ffmpeg -ss %startTime% -i "OUTPUT-OF-FIRST URL" -t %endTime% -o "%MYDLDIR%%EXTS%" – ejbytes Sep 07 '21 at 19:32
  • This downloads no video. Only audio is downloaded. – Mehdi Haghgoo Feb 15 '22 at 10:39
  • 2
    Audio is not captured – Crasher May 23 '22 at 16:07
105

Adding to Johnnie's answer:

Use youtube-dl --youtube-skip-dash-manifest -g "URL" to get the video and audio streams.

Now use:

ffmpeg -ss 12:15 -i "1st-URL" -ss 12:15 -i "2nd-URL" -t 5:15 -map 0:v -map 1:a -c:v libx264 -c:a aac output.mkv

You'll need to use the -ss option for each stream. I also recommend doing it about 30 seconds earlier and then using another -ss 30 to avoid losing any key frames. Here's a real example using one of my youtube videos.

Video

youtube-dl --youtube-skip-dash-manifest -g https://www.youtube.com/watch?v=gESHIrvIQQo

Output:

https://r3---sn-mv-cvne.googlevideo.com/videoplayback/id/80448722bbc8410a/itag/298/source/youtube/requiressl/yes/mn/sn-mv-cvne/ei/BgifWfmmL4iE8wSlv47oCA/mm/31/pl/23/mv/m/ms/au/initcwndbps/11447500/ratebypass/yes/mime/video%2Fmp4/otfp/1/gir/yes/clen/5231968228/lmt/1502479662079137/dur/18575.164/key/dg_yt0/signature/4FFB9B0B7E1703B31F5D07DAD579B55F17EF7BAA.0CB63905C89DD4D33F90CF3AAD728F1ECDFCB9B3/mt/1503594423/ip/206.34.122.70/ipbits/0/expire/1503616102/sparams/ip,ipbits,expire,id,itag,source,requiressl,mn,ei,mm,pl,mv,ms,initcwndbps,ratebypass,mime,otfp,gir,clen,lmt,dur/
https://r3---sn-mv-cvne.googlevideo.com/videoplayback/id/80448722bbc8410a/itag/140/source/youtube/requiressl/yes/mn/sn-mv-cvne/ei/BgifWfmmL4iE8wSlv47oCA/mm/31/pl/23/mv/m/ms/au/initcwndbps/11447500/ratebypass/yes/mime/audio%2Fmp4/otfp/1/gir/yes/clen/295235970/lmt/1502480001536214/dur/18575.243/key/dg_yt0/signature/4CD42047D1D5C714377350905C1CC5CBA37C0009.6EED1FC92D17A096235C32E48F4B15DEF7DD99B0/mt/1503594423/ip/206.34.122.70/ipbits/0/expire/1503616102/sparams/ip,ipbits,expire,id,itag,source,requiressl,mn,ei,mm,pl,mv,ms,initcwndbps,ratebypass,mime,otfp,gir,clen,lmt,dur/

I wanted to cut from 43:00 to 50:10 so I'm going to do -ss 42:30 (giving me a few seconds to catch a good keyframe) on both inputs and then do a -ss 30 after the inputs to start at 43:00.

I'll then use map to map the video 0:v and audio 1:a (0 means first input, which is the video and 1 means the second input, which is the audio) and then choose my encoding options.

# The first URL
video_url="https://r3---sn-mv-cvne.googlevideo.com/videoplayback/id/80448722bbc8410a/itag/298/source/youtube/requiressl/yes/pl/23/ei/5wCfWY6dBeOj8gSSxZaACQ/mv/m/initcwndbps/5055000/ms/au/mm/31/mn/sn-mv-cvne/ratebypass/yes/mime/video%2Fmp4/otfp/1/gir/yes/clen/5231968228/lmt/1502479662079137/dur/18575.164/key/dg_yt0/beids/%5B9466591%5D/mt/1503592562/signature/8CCFBF5CAB97341D0CB1F34E85AB6EE20FC7A03E.7679F39A8603CF41A95F10232E2A921EB0774101/ip/206.34.122.70/ipbits/0/expire/1503614279/sparams/ip,ipbits,expire,id,itag,source,requiressl,pl,ei,mv,initcwndbps,ms,mm,mn,ratebypass,mime,otfp,gir,clen,lmt,dur/"
# The second URL
audio_url="https://r3---sn-mv-cvne.googlevideo.com/videoplayback/id/80448722bbc8410a/itag/140/source/youtube/requiressl/yes/pl/23/ei/5wCfWY6dBeOj8gSSxZaACQ/mv/m/initcwndbps/5055000/ms/au/mm/31/mn/sn-mv-cvne/ratebypass/yes/mime/audio%2Fmp4/otfp/1/gir/yes/clen/295235970/lmt/1502480001536214/dur/18575.243/key/dg_yt0/beids/%5B9466591%5D/mt/1503592562/signature/4AACC8E27F9036D36D4D623A771A9F2BAC4674BA.7E4F4FB4DC023E3FE491A991F0F9F2329648DE9D/ip/206.34.122.70/ipbits/0/expire/1503614279/sparams/ip,ipbits,expire,id,itag,source,requiressl,pl,ei,mv,initcwndbps,ms,mm,mn,ratebypass,mime,otfp,gir,clen,lmt,dur/"
ffmpeg -ss 42:30 -i "$video_url" -ss 42:30 -i "$audio_url" -map 0:v -map 1:a -ss 30 -t 7:10 -c:v libx264 -c:a aac gog-vs-triv.mkv

Credit to Jakub Vrána for the --youtube-skip-dash-manifest solution.


EDIT: I do this so often I've created a script that I will include here. I've moved from youtube-dl to yt-dlp for reasons that aren't super important for this post, but you can replace yt-dlp with youtube-dl if you want to continue using it.

clip-youtube.sh

#!/bin/bash
#Arguments: URL, Time stamp -5 seconds, length of clip, video file name

readarray -t urls <<< "$(yt-dlp --youtube-skip-dash-manifest -g "$1")" ffmpeg -ss $2 -i "${urls[0]}" -ss $2 -i "${urls[1]}" -ss 5 -map 0:v -map 1:a -c:v libx264 -c:a aac -t $3 $4

Example usage:

./clip-youtube.sh "https://www.youtube.com/watch?v=aqz-KE-bpKQ" 3:05 11 squashed.mp4

Chris Davies
  • 116,213
  • 16
  • 160
  • 287
godofgrunts
  • 1,163
  • 1
    How does it differ from using --postprocessor-args directly in youtube-dl? – daGo Nov 02 '19 at 13:15
  • 11
    @daGo - I believe youtube-dl --postprocessor-args will download the whole video and then edit it down to the selected range, whereas this answer uses youtube-dl just to get some special URLs. ffmpeg then uses those URLs to download only the required range. So if you want to extract 2 minutes from a 2 hour lecture video, this answer will save you a lot of downloading. – Nick Chammas Feb 03 '20 at 07:20
  • The end of my audio file is getting clipped by several seconds so there is just silence. – StevieD Apr 14 '20 at 15:16
  • 3
    This works with most YT videos, but I am trying this with a 9 hour video that was previously streamed live (and now completed) and I get "Invalid data found when processing input". The main difference is that the output of youtube-dl -g is different. With most videos it has the struct. "https://r3---sn-mv-cvne.googlevideo.com/videoplayback/id/8..." but for this video it has the struct. "https://manifest.googlevideo.com/api/manifest/dash/expire/15956..." (truncated for space). Ideas on how to make this work? – Leftover Salad Jul 24 '20 at 23:26
  • @LeftoverSalad I have exactly the same issue. Have you found any solutions? – ynn Aug 17 '20 at 14:41
  • @ynn nope :/ I ended up downloading the whole thing and editing afterwards – Leftover Salad Aug 17 '20 at 23:29
  • 1
    @LeftoverSalad Found one solution. – ynn Aug 18 '20 at 09:01
  • 1
    the last -ss 30 works very well for me: without it, I get 5 seconds too much on a 10 seconds video portion (and the audio starts before at minus 5 seconds, it was very strange), and with -ss 30 or even -ss 5 I get a 10.022 seconds portion. I tried with this URL: https://www.youtube.com/watch?v=fOe7ip5nNgQ to get a portion from 00:00:30.00 to 00:00:40.00. – ewen-goisot Sep 08 '20 at 22:59
  • @LeftoverSalad @ynn I've edited the answer to this solution to fix the manifest issue. You basically need to add --youtube-skip-dash-manifest in the original youtube-dl command. – godofgrunts Nov 20 '20 at 16:21
  • For a video that comes in many formats/resolutions (1080p, 1440p, 2160p), which one will be downloaded this way? And is there a way to chose it? – Overflowh Dec 29 '20 at 17:41
  • @Overflowh Yeah. If you use -F like youtube-dl -F https://www.youtube.com/watch?v=gESHIrvIQQo you'll get a list of formats. Then you use the number in the format column with -f (note the lowercase) in the rest of the commands.

    Like youtube-dl --youtube-skip-dash-manifest -g -f 302 https://www.youtube.com/watch?v=gESHIrvIQQo for the video URL and then youtube-dl --youtube-skip-dash-manifest -g -f 251 https://www.youtube.com/watch?v=gESHIrvIQQo for the audio.

    – godofgrunts Mar 17 '21 at 13:05
  • This only seems to work when using the -t option - -to doesn't seem possible to use, which is a shame cause I'd rather pass the timestamp I need directly instead of calculating how many minutes and seconds of the video I need. Any idea whether this is possible to do using your solution? – Hashim Aziz Jul 05 '21 at 22:08
  • @HashimAziz I don't think so since we have to skip the manifest in order for this solution to work. – godofgrunts Jul 08 '21 at 14:57
  • 1
    @godofgrunts It turned out to be a case of positioning them before the inputs, I posted my own question and answer here: https://superuser.com/questions/1661048/how-to-download-a-portion-of-a-youtube-video. – Hashim Aziz Jul 08 '21 at 15:11
  • Heres the script without re-encoding + with ending timestamps rather than duration – Tom Huntington Apr 20 '23 at 07:50
  • Re-encoding isn't necessary. Can't you just do: ffmpeg -ss $2 -i "${urls[0]}" -ss $2 -i "${urls[1]}" -ss 5 -c:v copy -c:a copy -t $3 $4? – Geremia Aug 07 '23 at 04:03
  • This doesn't work at all for me. yt-dlp --youtube-skip-dash-manifest -g only returns one URL; what is the second URL we're supposed to have? – ghostly_s Feb 16 '24 at 02:38
  • I see, this script is only for Youtube videos, which is not what the question asked. I guess Youtube serves the audio in a separate file? I got it working for other sites by changing the command to ffmpeg -ss $2 -i "${urls[0]}" -c:v libx264 -c:a aac -t $3 $4 – ghostly_s Feb 16 '24 at 03:12
51
ffmpeg $(youtube-dl -g 'https://www.youtube.com/watch?v=oHg5SJYRHA0' | sed 's/^/-ss 00:05 -i /') -t 01:00 -c copy out.mkv

Edit the URL and the -ss, -t times to use this command. It creates the arguments, using both video and audio URLs, similar to this answer by @godofgrunts. No quotes are used for $() because this produces two separate arguments for ffmpeg.

  • 12
    Could you explain, what it does, how it works? – peterh Sep 15 '17 at 04:49
  • 9
    It's just a more terse version of @godofgrunts answer, using sed to save some time manually grabbing the URLs and copying/pasting in the start times (-ss 00:05).

    @godofgrunts has some extra flags -map 0:v -map 1:a -c:v libx264 -c:a aac that might improve quality.

    I also like to add youtube-dl -f bestvideo+bestaudio to be sure I'm getting the highest quality version.

    – Steve Goranson Sep 16 '17 at 07:13
  • https://ffmpeg.zeranoe.com/builds/ for Windows. – Wolfpack'08 Jun 05 '19 at 03:29
  • The "extra flags" deal with the two streams (video and audio) which I think you are mishandling - IIUC they have nothing to do with improving quality (well, having sound is probably a mark of improved quality :-) ) The answer by @godofgrunts below seems to be correct. – NickD Dec 09 '20 at 22:23
  • 1
    @NickD That's the apparent case, but I found that audio and video work fine even without -map, so it's possible @godofgrunt's -map is redundant for some reason - I have a feeling that reason is that it's the default mapping (and therefore automatically applied). – Hashim Aziz Jul 05 '21 at 23:41
  • The time is not exact with this solution (it starts at the last keyframe before 0:05) and the sound is out of sync (video and audio streams have different start point but they are merged since the beginning so it is both out of sync and the sound is missing at the end of the video).

    What I ended up doing is downloading the streams separately:

    youtube-dl -k --external-downloader ffmpeg --external-downloader-args '-ss 5 -t 60' oHg5SJYRHA0

    And then merging the streams from the end:

    ffmpeg -sseof -60 -i video.webm -sseof -60 audio.mp4 -map 0:v:0 -map 1:a:0 out.mkv

    – Jakub Vrána Sep 26 '21 at 17:24
49

youtube-dl supports passing arguments to the underlying postprocessor (tested with version 2017.08.27.1):

youtube-dl -x --postprocessor-args "-ss 00:13:00.00 -t 00:04:00.00" https://youtu.be/...

This is basically the same as doing the postprocessing with ffmpeg yourself after downloading the file first.

  • 18
    but this will still require to download the whole video, then cut the desired part – Kasparov92 Sep 15 '18 at 10:52
  • I am getting unable to obtain file audio codec with ffprobe error. Can you please help me with that. I am using CentOS 7 – Hassaan Nov 22 '18 at 09:40
  • 12
    Note that the -x flag downloads the audio only. Omit it from the command if you want both audio and video. :) – grooveplex Jan 09 '19 at 11:29
  • 2
    This will not reliably work, as —postprocessor-args is applied multiple times in some cases. See https://github.com/ytdl-org/youtube-dl/issues/26863 – antgiant Oct 17 '20 at 13:05
30

Use the --postprocessor-args parameter to pass the audio/video output to ffmpeg to be edited (the processor). The postprocessor needs to be ffmpeg installed.

--postprocessor-args takes 3 arguments & values (for example, theres is more, check manual page of ffmpeg):

  • -ss HH:MM:SS : start time to take
  • -to HH:MM:SS : end time
  • -t HH:MM:SS : time length to take

Examples:

  • Start encoding at 15 seconds and stop at 1 minutes 20 seconds
    $ youtube-dl --postprocessor-args "-ss 0:0:15 -to 0:1:20" '[video_URL]'
    
  • Start encoding at 15 seconds and take only the next 3 minutes 5 seconds
    $ youtube-dl --postprocessor-args "-ss 0:0:15 -t 0:3:5" '[video_URL]'
    

PS: youtube-dl will download the entire media before processing it, and remove it after.

0xc0de
  • 305
niainaLens
  • 409
  • 4
  • 3
  • 2
    This will not reliably work, as —postprocessor-args is applied multiple times in some cases. See https://github.com/ytdl-org/youtube-dl/issues/26863 – antgiant Oct 17 '20 at 13:07
  • As noted for the much older answer mentioning the same option, this will still require downloading the whole video. – Dan Dascalescu Mar 31 '23 at 20:46
28

This feature request is not yet implemented in youtube-dl. See #622 issue and many duplicates of it on github.

ks1322
  • 1,656
28

Native Way (YT-DLP)

yt-dlp, the spiritual successor to youtube-dl, supports this w/ ffmpeg installed.

It will ONLY download the section of video you specify, good for low bandwidth or long videos!


Fastest

It accepts timestamps or seconds:

yt-dlp.exe --download-sections "*6:02-6:22"

It will only download the section specified (to the nearest keyframe).


Exact Key Frame

If you need exact start / stop times (albeit slower):

yt-dlp.exe --download-sections "*1:22:22-inf" --force-keyframes-at-cuts

inf means to the end of the video.


Sections

Download a section titled "03. Symphony No. 6, Op. 68 (Pastoral): III. Allegro":

yt-dlp.exe --download-sections "03.*"


Multiple Sections

Download multiple sections:

yt-dlp.exe --download-sections "03.*" --download-sections "05.*" -o "%(title)s-%(section_title)s.%(ext)s"


A Note About Speed

This method downloads and transcodes pretty slow.

It may be faster to just download the whole video and chop up w/ ffmpeg.

I would definitely use this method for very long videos or very short segments.

  • This actually worked in a few seconds for a 2-hour-long video, seemingly even merging high-res “video only” with audio. Of course, one needs to prepend the video's URL to the commands given in this answer. – Nicolai Weitkemper Jun 16 '23 at 21:08
  • 1
    Note that the * at the beginning means "this is a timestamp, not a chapter name". It's displayed wrongly when you access it via man yt-dlp so maybe confusing – phil294 Jul 21 '23 at 07:52
14

This doesn't completely answer OP's question but there is way to download a stream from beginning to a specific duration without having to download the complete stream. Since YouTube provides resume support, we could request for partial content using the Range header.

We first fetch the stream URLs:

$ youtube-dl -g https://www.youtube.com/watch?v=yysk8s2vih8
https://r1---sn-npoeenee.googlevideo.com/videoplayback?source=youtu...
https://r1---sn-npoeenee.googlevideo.com/videoplayback?source=youtu...

This should output two URLs (each for video and audio streams).

Now send a head request to the first URL (which links to the video stream) to fetch the total content length of this stream:

$ curl "1st-URL" -sI | grep Content-Length
Content-Length: 64380504

Now, we divide this total content length by total seconds in video (the YouTube video has a duration of 4 min and 7 secs which is 247 seconds.) to approximately get the content length of 1 second:

64380504 / 247 ≈ 260650

We multiply this value with (number of seconds we want to fetch from the beginning + 1)

(we add one to also roughly account for extra space taken by metadata which is placed at the beginning of the stream)

For example to fetch approximately the first 10 seconds, you will need to fetch the first 260650 * 11 = 2867150 bytes, so we make a request with the Range header:

$ curl "1st-URL" -H "Range: bytes=0-2867150" -o ten_secs.mp4

This should only download the first 10 secs. The downloaded file should be able to play but best let FFmpeg fix the incorrect metadata:

$ ffmpeg -i ten_secs.mp4 -c copy corrected_ten_secs.mp4

We can also download only the initial part of the audio (2nd-URL) in a similar fashion (content-length would differ but total seconds would remain same).

Downloading any middle portion from the video should also be possible in this way but is going probably way much trickier because YouTube places the metadata at the beginning of the stream (in the first few bytes) and without it being present in the downloaded media, the stream won't play at all.

EDIT: This will only work on websites with resume support, say YouTube. It won't work for other websites.

ritiek
  • 251
  • About that trickier part, do you have any solution like getting the first metadata bytes, and merge it with a specific range, I tried it but there's an issue – Momo Apr 05 '22 at 09:56
7

For all the lazy guys who don't want to use more than one command, do the following:

youtube-dl https://www.youtube.com/watch?v=MJD39Aja1Is --external-downloader ffmpeg --external-downloader-args "-ss 00:00:10.00 -t 00:01:00.00"

You can now combine the options of youtube-dl.exe and ffmpeg like choosing the format, removing the video and cutting the audio file etc. (maybe cutting the video file and than converting to an audio file, whatever happens first)

youtube-dl -f 251 https://www.youtube.com/watch?v=MJD39Aja1Is -x --external-downloader ffmpeg --external-downloader-args "-ss 00:00:10.00 -t 00:01:00.00"

Note: on HLS videos such as on Twitch, you will also need to add --hls-prefer-ffmpeg for this to work.

xpt
  • 1,530
Yuki
  • 71
  • your command does not work on GNU/Linux: we use youtube-dl instead of youtube-dl.exe. And ffmpeg told me Invalid duration specification for ss: 00.00.10.00, it should be -ss 00:00:30.00 with colons instead of periods except for the last one. – ewen-goisot Sep 08 '20 at 21:33
  • 1
    @ewin-goisot I am sorry, this happened because i didn't copy-pasted the whole command after testing it. Now it should work. the problem was the time definition. it has to be 00:00:00.00 2 times double point, than only 1 point. like hh:mm:ss.ms – Yuki Sep 09 '20 at 13:56
  • with 00:00:00.0, it works better, I can download a portion of the video. I still have an issue (with your command and most of other ones) : it downloads 5 or 10 seconds too much. The solution is given on @godofgrunts ' s answer: -ss 42:30 -i "$video_url" -ss 42:30 -i "$audio_url" -map 0:v -map 1:a -ss 30 starting 30 seconds before the portion start and adding a -ss 30 at the end. So I need to use several times the -ss option on the same command. Is there a way to do the same with --external-downloader-args ? – ewen-goisot Sep 09 '20 at 16:21
  • ah sorry, i am not that familiar with mixing different streams. but if you want to take just the best audio and video material of the same video, than you can do it with youtube-dl instead – Yuki Sep 10 '20 at 18:29
  • As with most solutions this downloads the entire video rather than just a portion of the video. – Hashim Aziz Jul 05 '21 at 15:53
  • @HashimAziz - not from my testing. I was able to download a Rumble.com video using the above method and it only downloaded the small portion I specified, not the whole 3hr broadcast. Phew! – Simon East Apr 18 '22 at 05:33
4

You can download from the start up to a point without downloading the whole thing and editing. That's half of what this question asks:

interrupt the download with ^C

  • I've only tried this with mp4
  • won't work with separate video and audio, you need a format with both. By default ytdl often gets separate video and audio, then merges them. Use -F to see the formats available, and choose an mp4 that has both. e.g. -f18 or -f22 are usually there.
  • you'll have to estimate from percentage downloaded (which isn't linear; the compression rate varies over time).

Yes. It's a hack.

Further question: if you do want the separate video and audio formats, could you download part of each separately (using ^c as here), and then merge them manually? I don't think it willl work for some formats.

hyperpallium
  • 171
  • 6
4

yt-dlp - a fork of youtube-dl has --download-sections flag:

    --download-sections REGEX                         Download only chapters whose title matches the given regular
                                                      expression. Time ranges prefixed by a "*" can also be used in
                                                      place of chapters to download the specified range. Needs ffmpeg.
                                                      This option can be used multiple times to download multiple
                                                      sections, e.g. --download-sections "*10:15-inf" --download-
                                                      sections "intro"

For example, download 10 seconds from 07:35 to 07:45:

yt-dlp --download-sections "*07:35-07:45" https://www.youtube.com/watch?v=vidid

And based on speed it looks like it's not done in post.

rfg
  • 143
2

This is to add to all the answers that involve --postprocessor-args.

I have a work around to the problem pointed out by @antgiant, that --postprocessor-args is applied to each post processor, outlined here (https://github.com/ytdl-org/youtube-dl/issues/26863). This could cause your arguments to be applied more than once resulting in unexpected behaviours, such as cutting your video shorter than it should.

I would make a comment to the original answers but I don't have enough reputation for that. To work around this you must set up youtube-dl to use a default config file, and specify all post processes you'd like to apply to the video/audio but one other post processes to use in the command line with --postprocessor-args. The goal is that there is only one post process for --postprocessor-args in the command line, so that it is only applied once.

For example, my config file specifies the --ffmpeg-location, --audio-format, and --audio-quality. So that in the command line, I would only use -x.

youtube-dl -x --postprocessor-args "-ss 00:57.50" "URL"

Of course, this would work with any post process in the command line, so long as there is only one, and that the rest is hidden in the config file. To make a config file simply make a folder in your %appdata% called youtube-dl and create a config.txt there with all your parameters.

This is my first post at Unix & Linux Stack Exchange, please don't hesitate to point out any mistakes.

1

I made a script implementing @godofgrunts answer here

#!/bin/bash
#taken from https://unix.stackexchange.com/a/388148/48971

if [ $# -lt 4 ]; then
        echo "Usage: $0 <youtube's URL> <HH:mm:ss from time> <HH:mm:ss to time> <output_file_name>"
        echo "e.g.:"
        echo "$0 https://www.youtube.com/watch?v=T1n5gXIPyws 00:00:25 00:00:42 intro.mp4"
        exit 1
fi

echo "processing..."

from=$(date "+%s" -d "UTC 01/01/1970 $2")
to=$(date "+%s" -d "UTC 01/01/1970 $3")

from_pre=$(($from - 30))

if [ $from_pre -lt 0 ]
then
        from_pre=0
fi

from_pre_command_print=$(date -u "+%T" -d @$from_pre)
from_command_print=$(date -u "+%T" -d @$(($from - $from_pre)))$(grep -o "\..*" <<< $2)
to_command_print=$(date -u "+%T" -d @$(($to - $from_pre)))$(grep -o "\..*" <<< $3)

command="ffmpeg "

for uri in $(youtube-dl -g $1)
do
        command+="-ss $from_pre_command_print -i $uri "
done

command+="-ss $from_command_print -to $to_command_print $4"
echo "downloading with the following command:"
echo "$command" 
$command

I also uploaded it to Gitlab's snippets

1

I made a flask app that can to what you want. I know the post is old, but the problem persists.

You can find it here

It can parse text for YouTube links as well. You just supply e.g.:

YouTube.com/blahblah start-1:20

This will download a video from 0-1:22 (slightly differences can arise because of keyframes). It can also download whole videos, just omit the time interval in that case.

AdminBee
  • 22,803
1

To add on to @hyperpallium answer: OP did not mention the video he was downloading had to be from YouTube.

YouTube is ridiculously restrictive with their videos, they split the audio and video streams into different files, and they track you/sell your data; therefore, one could have difficulties with the method of downloading it partly then hitting Ctrl+C.

With youtube-dl version 2020.11.17 in Microsoft Windows version 10.0.17134.1304 I downloaded part of a video from archive.org:

E:\cs>youtube-dl --abort-on-unavailable-fragment https://archive.org/download/beastars-season-1-1080p/%5BHCS%5D%20Beastars%20-%2003%20%5B1080p%5D.mkv
[generic] [HCS] Beastars - 03 [1080p]: Requesting header
[redirect] Following redirect to https://ia601504.us.archive.org/14/items/beastars-season-1-1080p/%5BHCS%5D%20Beastars%20-%2003%20%5B1080p%5D.mkv
[generic] [HCS] Beastars - 03 [1080p]: Requesting header
WARNING: Falling back on generic information extractor.
[generic] [HCS] Beastars - 03 [1080p]: Downloading webpage
WARNING: URL could be a direct video link, returning it as such.
[download] Destination: [HCS] Beastars - 03 [1080p]-[HCS] Beastars - 03 [1080p].mkv
[download]   2.3% of 513.77MiB at 839.68KiB/s ETA 10:12
ERROR: Interrupted by user

E:\cs>ren "[HCS] Beastars - 03 [1080p]-[HCS] Beastars - 03 [1080p].mkv.part" "[HCS] Beastars - 03 [1080p]-[HCS] Beastars - 03 [1080p].mkv"

E:\cs>ffmpeg -i "[HCS] Beastars - 03 [1080p]-[HCS] Beastars - 03 [1080p].mkv" "[HCS] Beastars - 03 [1080p].mp4" ffmpeg version N-91990-g49c67e79ca Copyright (c) 2000-2018 the FFmpeg developers built with gcc 8.2.1 (GCC) 20180813 [stdout text] Stream #0:1(jpn): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 128 kb/s (default) Metadata: encoder : Lavc58.30.100 aac [matroska,webm @ 0000020c8f28a2c0] Read errorme=00:00:33.96 bitrate=2099.5kbits/s speed=0.0185x frame= 823 fps=0.3 q=-1.0 Lsize= 9677kB time=00:00:34.56 bitrate=2293.8kbits/s speed=0.0147x video:9134kB audio:519kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.248960% [libx264 @ 0000020c8f3423c0] frame I:25 Avg QP:14.71 size: 56865 [stdout]

E:\cs>youtube-dl -v [debug] System config: [] [debug] User config: [] [debug] Custom config: [] [debug] Command-line args: ['-v'] [debug] Encodings: locale cp1252, fs mbcs, out cp437, pref cp1252 [debug] youtube-dl version 2020.11.17 [debug] Python version 3.4.4 (CPython) - Windows-10-10.0.17134 [debug] exe versions: ffmpeg 3.4, ffprobe N-91990-g49c67e79ca [debug] Proxy map: {} Usage: youtube-dl [OPTIONS] URL [URL...]

The MKV file I ended up with was "00:22:57" in "total duration", but it ended after 34 seconds. The MP4 video I ended up with was was 00:00:34 seconds in total duration, ended after 34 seconds, and the video and audio played completely fine/as intended.

Full cmd.exe log is here

So in summary, run

youtube-dl --abort-on-unavailable-fragment [URL to video file]

(option --abort-on-unavailable-fragment might be important as you end up interrupting the download with Ctrl+C), let it download for a bit, then press Ctrl+C.

Optional: rename the [file].mkv.part file to [file].mkv. Converting the MKV to MP4 is probably optional too.

AdminBee
  • 22,803
Rublacava
  • 131
1

-o - sends the YouTube video to stdout which is piped into ffmpeg using |. -i - inputs the video from stdin being piped from the youtube-dl command. -ss is the start time of the clip and -to is the end time of the clip. `

youtube-dl -o - "https://youtu.be/dQw4w9WgXcQ" | ffmpeg -i - -ss 00:00:15 -to 00:01:30 -c copy FileNameOfYouTubeVideoDownload.mp4

Hope this helps!

cdb
  • 11
1

For zsh, just copy and paste this function in your .zshrc and be happy :)

For more info, check my dotfiles

# function that uses youtube-dl along with ffmpeg to capture a portion of a yt video
# $1 - youtube URL
# $2 - start position in hh:mm:ss.msms format (ms=miliseconds)
# $3 - final position in hh:mm:ss.msms format (ms=miliseconds)
# $4 - output file name (optional)
# $5 - output video codec type (optional, for instance: libx264)
# $6 - output audio codec type (optional, for instance: aac)
function youtubedl_snippet()(
  local url_streams=$(youtube-dl -f best --get-url $1)
  local output_name=$(youtube-dl --get-title $1)

ffmpeg -ss $2 -to $3 -i $url_streams -c:v copy -c:a copy ${4:-"$output_name.mp4"} )

PS: If it get forbidden access. In this, just try once again.

0

Someone made a batch script (for Windows) that downloads the file and extracts the desired portion:

@ECHO off

:Input
ECHO.
SET url=
ECHO Enter Youtube-url:
SET /P url=
IF "%url%" EQU "" GOTO End
IF "%url: =%" NEQ "%url%" GOTO Input
ECHO Enter start time (in seconds, or in hh:mm:ss[.xxx] form):
SET /P start=
ECHO Enter duration (in seconds, or in hh:mm:ss[.xxx] form):
SET /P dur=
ECHO.
FOR /F "delims==" %%A IN ('youtube-dl.exe --no-warnings --get-filename "%url%"') DO SET filename=%%A
FOR /F %%B IN ('youtube-dl.exe -g "%url%"') DO (
ffmpeg.exe -hide_banner -ss "%start%" -i "%%B" -c copy -t "%dur%" "%filename%"
)
GOTO Input

:End
Stephen Kitt
  • 434,908
0

Here a clean batch script that will do the job nicely, it should be easy to port this to linux as well. ffmpeg.exe and youtube-dl.exe should be somewhere in %PATH%, or just add the full path to the both commands in the script.

@echo off
rem
rem Download a part of youtube video
rem
rem Parameters :
rem 
rem "%1" = quality, "-f18", "-f22", ...
rem "%2" = youtube video "url"
rem "%3" = starttime "HH:MM:SS"
rem "%4" = duration "HH:MM:SS" (to capture 1 minute 00:01:00)
rem "%5" = outputfile "my-part.mp4"

youtube-dl "%1" -g "%2" > urls.tmp rem read the first line of the file "urls.tmp" in the variable "url" set /p url=< urls.tmp ffmpeg -ss "%3" -i "%url%" -t "%4" -c copy "%5" del urls.tmp

In linux you can use this command:

ffmpeg -ss "starttime" -i $(youtube-dl "url" "quality" -g) -t "duration" -c copy "output-file.mp4"

Cheers

0

Well, working solution:

ffmpeg -ss 00:01:00 -to 00:02:00 -i "$(youtube-dl -f best --get-url 'https://www.youtube.com/watch?v=dc7I-i7sPrg')" -c:v copy -c:a copy kiosk.mp4

but -f best returns 720p (one-file: video+audio) and this is not a Jedi path, so there is an alternative solution for max (default) quality:

ffmpeg `youtube-dl --get-url "$url" | xargs printf -- "-ss $start -to $finish"' -i %s\n'` -map 0:v -map 1:a -c copy $outname

Also, you can put -f video+audio before pipe to xargs (check possible variants with youtube-dl -F) in the second command. For example:

  • -f 137+140 - same as default
  • -f 397+249 - 480p with lowest audio qty.

zsh easy function-wrapper:

function youtube-dl-part {                                          
   readonly start=${1:?"Start must be specified"}
   readonly finish=${2:?"Finish must be specified"}
   readonly url=${3:?"Url must be specified"}
   readonly outname=${4:?"Outname must be specified"}
   ffmpeg `youtube-dl --get-url "$url" | xargs printf -- "-ss $start -to $finish"' -i %s\n'` -map 0:v -map 1:a -c copy $outname
}
unklem
  • 1
0

Here is a simple command line solution.

Paste the below function into your .bashrc file and call it with the command clip as follows
clip {youtube_video_url} {start_hh:mm:ss} {end_hh:mm:ss} {out_clip.mp4}

The function also has a basic help file to show you how to use it. Just type clip at the command line.

It is straight forward to use and will save a lot of time messing about the next time you need to clip something from a youtube video.

Hope this helps!

function clip () {

download a section of a youtube video without downloading the whole video

reference

https://unix.stackexchange.com/a/392350/46470

echo help statement if 4 parameters are not entered

or $1 or $2 are not entered in the correct format

if [ -z "$1 " ] || [ -z "$2" ] || [ -z "$3" ] || [ -z "$4" ]; then

$1 $2 $3 $4

echo echo " Produce a clip from youtube using"
echo echo " 1 clip URL" echo " 2 start time, hh:mm:ss" echo " 3 end time, hh:mm:ss" echo " 4 out_file_name.mp4" echo " "
echo " eg "
echo echo " clip https://www.youtube.com/watch?v=6mPxcljRRzE 00:01:56 00:02:15 out_clip.mp4" echo " " echo echo

else

change to your download directory or it will work in the directory you are in

cd /home/$USER/videos

url_z="$1" start_time_z="$2" end_time_z="$3" out_file_name="$4"

eg

$1 url_z="https://www.youtube.com/watch?v=6mPxcljRRzE"

$2 start_time_z=00:01:56

$3 end_time_z=00:02:15

duration_z=00:00:19

$4 out_file_name=out_clip.mp4

collect duration in seconds between times the two times to

calculate our ffmpeg "-to" duration from the $start_time and $end_time

reference

https://unix.stackexchange.com/a/167156/46470

start_time_z=00:01:56

end_time_z=00:02:15

beginning_seconds=$(date --date="$start_time_z" +%s); ending_seconds=$(date --date="$end_time_z" +%s); duration_z=$((ending_seconds-beginning_seconds))

echo the culculated duration in seconds

#echo $duration_z

duration_z=19

get the necessary information from youtube. See the reference link above

video_url_z="youtube-dl -g $url_z"

command

ffmpeg $($video_url_z | sed "s/^/-ss $start_time_z -i /") -to $duration_z -c copy $out_file_name

fi

}

Kes
  • 859