232

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?

2

21 Answers 21

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.

12
  • 37
    So essentially, you still have to download the whole video and crop it yourself
    – Antony
    Jun 17, 2016 at 0: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 7, 2017 at 14:41
  • 32
    @Antony ffmpeg will actually only download the part you specify.
    – akaihola
    Dec 21, 2018 at 20:29
  • 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, 2019 at 7: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 5, 2020 at 19:27
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

18
  • 1
    How does it differ from using --postprocessor-args directly in youtube-dl?
    – daGo
    Nov 2, 2019 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. Feb 3, 2020 at 7:20
  • 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? Jul 24, 2020 at 23:26
  • 1
    @LeftoverSalad Found one solution.
    – ynn
    Aug 18, 2020 at 9: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. Sep 8, 2020 at 22:59
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.

6
  • 12
    Could you explain, what it does, how it works?
    – peterh
    Sep 15, 2017 at 4: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. Sep 16, 2017 at 7:13
  • ffmpeg.zeranoe.com/builds for Windows. Jun 5, 2019 at 3: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 9, 2020 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). Jul 5, 2021 at 23:41
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.

4
  • 18
    but this will still require to download the whole video, then cut the desired part
    – Kasparov92
    Sep 15, 2018 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, 2018 at 9: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 9, 2019 at 11:29
  • 2
    This will not reliably work, as —postprocessor-args is applied multiple times in some cases. See github.com/ytdl-org/youtube-dl/issues/26863
    – antgiant
    Oct 17, 2020 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.

2
29

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.

3
  • 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. Jun 16, 2023 at 21:08
  • 2
    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, 2023 at 7:52
  • but why is the star only on the starting timestamp? "*6:02-6:22"
    – malhal
    13 hours ago
28

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

0
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.

1
  • 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 5, 2022 at 9: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.

6
  • 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. Sep 8, 2020 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 9, 2020 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 ? Sep 9, 2020 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, 2020 at 18:29
  • As with most solutions this downloads the entire video rather than just a portion of the video. Jul 5, 2021 at 15:53
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.

1
  • Yes, it seems to be the only possibility not to download all 12 hours of video.
    – Paul
    Oct 28, 2021 at 20:03
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.

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.

0
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.

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.

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!

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
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
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
}
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

}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .