Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

is it possible to download only desired time interval? #4821

Closed
lapaci opened this issue Jan 30, 2015 · 47 comments
Closed

is it possible to download only desired time interval? #4821

lapaci opened this issue Jan 30, 2015 · 47 comments
Labels

Comments

@lapaci
Copy link

lapaci commented Jan 30, 2015

I want to download small part of a video which is 2 hours long and 1080p. How can i do that with youtube-dl?

@phihag
Copy link
Contributor

phihag commented Jan 30, 2015

At the moment, there is no such functionality. This is quite complicated internally, because we need to find a table of which times correspond to which byte intervals, interpret that table, download the partial file (that's actually the easy part), and then reassemble the whole shebang so that the headers are valid.

@Reino17
Copy link

Reino17 commented Jan 30, 2015

You could try to let youtube-dl only generate the url and then feed that url to ffmpeg.
Something like this:

SET /P url=
FOR /F %%A IN ('youtube-dl.exe -g %url%') DO (
ffmpeg.exe -ss 00:41:55 -i "%%A" -c copy -t 00:03:00 output.mp4
)

@mannemvamsi
Copy link

Thank You.. !!

@nixxquality
Copy link

+1

Long Twitch videos can sometimes be upwards of 5 GiB or more, and if you just want watch a small part of them, you have to wait a long time to be able to even watch that.

@AlexanderMatveev
Copy link

@corone17 This command downloads a full video to /tmp files or somewhere, loads it for cutting OR it naturally retrieves a part of remote file?

@AlexanderMatveev
Copy link

@corone17 This didn't work with long video: http://www.youtube.com/watch?v=eyU3bRy2x44 :-(

@Reino17
Copy link

Reino17 commented Apr 29, 2015

@alexmatveev I didn't actually test it 3 months ago, so you could try and run the following as a batch-file:

@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

If you make sure youtube-dl.exe and ffmpeg.exe are in the same directory, then this will work fine for your 3hour fireplace video :p.
Youtube-dl.exe will generate the direct videolink. This link will be the input for ffmpeg, which will then only download the section you specify.

@jaimeMF
Copy link
Collaborator

jaimeMF commented Sep 2, 2015

Closing as a duplicate of #622.

@sergiy-talashko
Copy link

@Reino17 Could you please write a shell script? (for linux users)

@Reino17
Copy link

Reino17 commented Apr 6, 2017

I'm sorry, but I'm not a Linux user. I have very little experience with Linux's shell script.

@sergiy-talashko
Copy link

@Reino17 Ok, still thanks

@andreikobe
Copy link

i finally made an account because I'm desperate for a clipconverter dot cc alternative because they've recently made impossible restrictions to what they could download. Really hope you find a way :(

@KeithCu
Copy link

KeithCu commented Jan 31, 2018

I know this is a somewhat difficult feature, but it is a great one to add. Right now, I want to grab a 2 minute clip from a 3 gig video file! I'd love to be able to give you the -ss and -t flags like ffmpeg.

@josephomorrow
Copy link

youtube-dl does have a --postprocessor-args command-line parameter. Example:

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

where -ss indicates start position (13 minutes in) and -t indicates new length (4 minutes) of output video. Just tried it with a 47-minute video that had about 4 hours of nothing on the end of it. I used --postprocessor-args "-t 00:47:00.0" and it worked fine.

@teocci
Copy link

teocci commented May 3, 2018

I know that this question is long but you can do it using this command:

ffmpeg -ss 3:59:10 -i $(youtube-dl -f 22 -g 'https://www.youtube.com/watch?v=mMZriSvaVP8') \
-t 3:06:00

You need to have the ffmpeg installed.

@andreikobe
Copy link

Yes, but that would mean I will have to download what could be a 1 gb file to get a few seconds

@josephomorrow
Copy link

I was primarily giving a command-line-friendly solution. If your download speed is too slow, then what alternative would you suggest for downloading a smaller chunk of the original?

@noureddin
Copy link

teocci's command works perfectly and doesn't download the entire video; I just tried it.

Inspired by it and Reino17's script, I hacked together a non-interactive Bash function that downloads a range of any youtube-dl downloadable video, provided you have ffmpeg.

You can put it in you ~/.bashrc. It should also work in Zsh.

download-clip() {
    # $1: url or Youtube video id
    # $2: starting time, in seconds, or in hh:mm:ss[.xxx] form
    # $3: duration, in seconds, or in hh:mm:ss[.xxx] form
    # $4: format, as accepted by youtube-dl (default: best)
    # other args are passed directly to youtube-dl; eg, -r 40K
    local fmt=${4:-best}
    local url="$(youtube-dl --get-url "$1" -f $fmt ${@:5})" 
    local filename="$(youtube-dl --get-filename "$1" ${@:5})"
    ffmpeg -loglevel warning -hide_banner \
        -ss $2 -i "$url" -c copy -t $3 "$filename"
    printf "Saved to: %s\n" "$filename"
    # based on Reino17's and teocci's comments in https://github.com/rg3/youtube-dl/issues/4821
}

A few catches:

  • No download progress bar.

  • If a video has a higher resolution in a video-only format, which youtube-dl downloads by default, than the format labeled "(best)", you'll get a "HTTP error 400 Bad Request". Thus, I made it by default download the best single audio+video file. You can easily change it as it's a function argument.
    See this comment also.

@Reino17
Copy link

Reino17 commented May 4, 2018

Very nice.
Lately I've become more and more familiar with Bash (although I'm still a Windows user), but some things are still new to me.
Does ${4:-best} mean: default to "-best" if the 4th parameter is empty?
What does ${@:5} exactly do/mean (the @ in particular)?
You know the $url-assignment can be simplified by doing $(youtube-dl -gf $fmt ${@:5} "$1")?
Also note Usage: youtube-dl.exe [OPTIONS] URL [URL...] that options (officially) need to go before the url.

@noureddin
Copy link

Thanks, Reino17.

${4:-best} returns the value of $4 if it has a value, otherwise (if it's unset or null) the value after the :- is used, ie, best.
This is one of the Parameter Expansions listed in man bash. ;)

$@ is an array holding all the parameters passed to the function; ie, it's equivalent to $1 $2 $3 ....
${@:5} returns $@ without the first four elements.

I preferred --get-url over -g mainly to be consistent with --get-filename, and also to be more readable, because it's not an option I use every day. But I've already used the short option -f. So I guess you're right.

I also forgot to add the format option to the get-filename command, because it can change the extension.

As I can't find a documentation for the urls-options order except what you mentioned, I will change the code to put the urls at the end. Thanks.

I also added the -stats option to ffmpeg to show the progress bar of the encoding. (It shows after some time; I guess it downloads the relevant segment first.)

For quieter output, you can remove -stats, and change -loglevel warning to -loglevel quiet.

download-clip() {
    # $1: url or Youtube video id
    # $2: starting time, in seconds, or in hh:mm:ss[.xxx] form
    # $3: duration, in seconds, or in hh:mm:ss[.xxx] form
    # $4: format, as accepted by youtube-dl (default: best)
    # other args are passed directly to youtube-dl; eg, -r 40K
    local fmt=${4:-best}
    local url="$(youtube-dl -g -f $fmt ${@:5} "$1")"
    local filename="$(youtube-dl --get-filename -f $fmt ${@:5} "$1")"
    ffmpeg -loglevel warning -hide_banner -stats \
        -ss $2 -i "$url" -c copy -t $3 "$filename"
    printf "Saved to: %s\n" "$filename"
    # based on Reino17's and teocci's comments in https://github.com/rg3/youtube-dl/issues/4821
}

@KeithCu
Copy link

KeithCu commented May 10, 2018

That's a great step. Do you think you could convert it to Python and submit it as a patch?

@noureddin
Copy link

I am not familiar enough with youtube-dl source code to be able to make a patch, but I will try.

In the mean time, there are some other discussions about this feature, mainly: #8851, and #622.
And johnhawkinson suggested a good idea in #12347, but it doesn't seem to work in all cases.

@satnatantas
Copy link

@noureddin do you know a way of doing same but with support for resuming?

@noureddin
Copy link

@satnatantas, if ffmpeg can resume a paused transcoding, it can be done. But unfortunately I couldn't find a way to do that reliably; the best way I was able to find is to pause using ctrl-z and then resume using fg. I will be interested if you find a better way. :)

@estathop
Copy link

any progress ?

@AdityaGujrati
Copy link

At the moment, there is no such functionality. This is quite complicated internally, because we need to find a table of which times correspond to which byte intervals, interpret that table, download the partial file (that's actually the easy part), and then reassemble the whole shebang so that the headers are valid.

its 2020 now 5 year passed since that comment. Is that feature available now to trim the youtube video and dounload the specific parts.Please reply ASAP

@LesFerch
Copy link

LesFerch commented Feb 20, 2021

I made the following batch file to make it easier for me to download all or part of video, select desired streams, and extract/convert audio. Hopefully, others will find it helpful as well.

@Echo Off
REM Requires YouTube-DL.exe and FFMPEG.exe
REM This script provides an easy way to select specific video and/or audio streams and
REM download all or part of your selection. For stream, you can enter a single number or two
REM numbers joined with a plus sign (no spaces). For example, 137+140, will copy video from
REM stream 137 and audio from stream 140. By default, it selects bestvideo+bestaudio.
REM Using ffmpeg to download part of a video will only save time when downloading a very small chunk.
REM You can convert to MP3 using this script, but please note you cannot add quality. If you select
REM MP3 and 320K, it will just reencode the original 129K stream and make a bigger file.
REM For audio only, usually the best option is to select stream 140 (M4A-AAC) and leave it as is.

Set URL=
Set Stream=bestvideo+bestaudio
Set Start=
Set Stop=
Set AF=
Set AQ=
Set Audio=
Set Mode=0

Echo.
Set /P URL="Enter video URL: "
If "%URL%"=="" Goto End

YouTube-DL -F "%URL%"

Echo.
Set /P Stream="Enter stream number(s) (n or n+n or Enter for bestvideo+bestaudio): "
Set /P start="Enter start time (in seconds or hh:mm:ss or Enter for 0): "
If Not "%Start%"=="" Set Start=-ss %Start%
Set /P Stop="Enter stop time (in seconds hh:mm:ss or Enter for end): "
If Not "%Stop%"=="" Set Stop=-to %Stop%
If "%Start%%Stop%"=="" Goto Audio
Set /P Mode="Enter 2 to download using ffmpeg (Enter to use YouTube-DL only): "
If Not %Mode%==2 Set Mode=1
:Audio
Set /P AF="Enter format to convert audio (e.g. mp3, or Enter to keep original): "
If "%AF%"=="" Goto Process
Set Audio=-x --audio-format %AF%
Set /P AQ="Enter audio convert quality (e.g. 192K or Enter for default): "
If Not "%AQ%"=="" Set Audio=%Audio% --audio-quality %AQ%

:Process
If %Mode%==0 YouTube-DL -f %stream% %Audio% "%URL%"
If %Mode%==1 YouTube-DL -f %stream% %Audio% --postprocessor-args "%Start% %Stop%" "%URL%"
If %Mode%==2 YouTube-DL -f %stream% %Audio% --external-downloader ffmpeg --external-downloader-args "%Start% %Stop%" "%URL%"

:End

@AtomicNess123
Copy link

Does this download only the part of the video?

@LesFerch
Copy link

LesFerch commented Sep 22, 2021 via email

@rhysperry111
Copy link

Just for anyone reading this issue who wants a quick way to do it on Linux, you can use

youtube-dl -g VIDEO_URL | xargs -I{} ffmpeg -ss START_TIME -i "{}" -c copy -t FINISH_TIME OUTPUT_NAME

@AlexanderMatveev
Copy link

Just for anyone reading this issue who wants a quick way to do it on Linux, you can use


youtube-dl -g VIDEO_URL | xargs -I{} ffmpeg -ss START_TIME -i "{}" -c copy -t FINISH_TIME OUTPUT_NAME

This downloads full video and then crops it. A little off topic.

@rhysperry111
Copy link

rhysperry111 commented Feb 18, 2022

This downloads full video and then crops it. A little off topic.

No it doesn't... try it yourself if you don't believe me. It's the same solution that @Reino17 provided, but adapted for linux

@AtomicNess123
Copy link

Just for anyone reading this issue who wants a quick way to do it on Linux, you can use

youtube-dl -g VIDEO_URL | xargs -I{} ffmpeg -ss START_TIME -i "{}" -c copy -t FINISH_TIME OUTPUT_NAME

Thanks! What would be the format of time? START_TIME = 2:30 (for 2 minutes 30 seconds)?

@rhysperry111
Copy link

rhysperry111 commented Feb 18, 2022

Thanks! What would be the format of time? START_TIME = 2:30 (for 2 minutes 30 seconds)?

You can read the ffmpeg docs to see other ways of specifying time, but hh:mm:ss works (00:02:30)

@AlexanderMatveev
Copy link

This downloads full video and then crops it. A little off topic.

No it doesn't... try it yourself if you don't believe me. It's the same solution that @Reino17 provided, but adapted for linux

My doubt is caused by the fact that youtube-dl doesn't get the start timestamp. This means that the video will download from the beginning. In any case, the above command does not work:

youtube-dl -g https://www.youtube.com/watch?v=L_LUpnjgPso | xargs -I{} ffmpeg -ss 01:02:00 -c copy -t 01:01:00 t.mp4
Output file #0 does not contain any stream

@rhysperry111
Copy link

youtube-dl -g https://www.youtube.com/watch?v=L_LUpnjgPso | xargs -I{} ffmpeg -ss 01:02:00 -c copy -t 01:01:00 t.mp4

That isn't what I wrote though... Also, you'll need to make sure youtube-dl doesn't automatically select separate formats for audio and video

@AlexanderMatveev
Copy link

youtube-dl -g https://www.youtube.com/watch?v=L_LUpnjgPso | xargs -I{} ffmpeg -ss 01:02:00 -c copy -t 01:01:00 t.mp4

That isn't what I wrote though... Also, you'll need to make sure youtube-dl doesn't automatically select separate formats for audio and video

My bad, I copied wrong line from my bash history, so here is correct one:

youtube-dl -g https://www.youtube.com/watch?v=L_LUpnjgPso | xargs -I{} ffmpeg -ss 01:02:00 -i "{}" -c copy -t 01:01:00 1.mp4

I just thought that one of the commands might work differently on Mac and Linux. It doesn't seem to have this error under Linux, but it looks like the video is downloading from the start. I'll continue to try with other videos.

@AtomicNess123
Copy link

youtube-dl -g https://www.youtube.com/watch?v=L_LUpnjgPso | xargs -I{} ffmpeg -ss 01:02:00 -i "{}" -c copy -t 01:01:00 1.mp4

When I run this I get

{}: No such file or directory

@josch
Copy link

josch commented Jul 25, 2022

Don't forget to put quotes around your {} because otherwise your shell will interpret them as special characters.

Since there seems to be some confusion here about how this works and because some people assume that this will download the whole video first and only split afterwards, let me explain how this works.

The -g option is short for --get-url: https://manpages.debian.org/bullseye/youtube-dl/youtube-dl.1.en.html#g, Running youtube-dl with it lets youtube-dl output a list of URLs, one per line. Each url can either be the URL to a video or the URL to an m3u or similar. So in case of downloading from twitch, just running youtube-dl -g without the xargs part will output a list of (but usually one) links to m3u files. These files are then all fed into ffmpeg and ffmpeg is then the one that actually follows the url and does the actual downloading. In case of twitch an m3u looks like this:

0#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:12
#ID3-EQUIV-TDTG:2022-07-25T00:24:04
#EXT-X-PLAYLIST-TYPE:EVENT
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-TWITCH-ELAPSED-SECS:0.000
#EXT-X-TWITCH-TOTAL-SECS:46439.425
#EXTINF:11.912,
0.ts
#EXTINF:11.912,
1.ts
#EXTINF:11.912,
2.ts
#EXTINF:11.912,
3.ts
#EXTINF:11.912,
4.ts
#EXTINF:11.912,
5.ts
#EXTINF:11.912,

The EXTINF entries tell ffmpeg how long each of the *.ts files is so if you also pass the -ss option to ffmpeg, then ffmpeg can pick out and download exactly those videos that it needs and ignore the rest. You will see this from the ffmpeg output which will not start downloading with 0.ts but will only start after some offset.

@AtomicNess123
Copy link

Don't forget to put quotes around your {} because otherwise your shell will interpret them as special characters.

youtube-dl -g https://www.youtube.com/watch?v=L_LUpnjgPso | xargs -I"{}" ffmpeg -ss 01:02:00 -i "{}" -c copy -t 01:01:00 1.mp4

With quotes around {} does not work either, same message {}: No such file or directory

@josch
Copy link

josch commented Jul 26, 2022

@AtomicNess123 what's your operating system and your version of xargs?

@AtomicNess123
Copy link

MacOS Catalina 10.15.7
$FreeBSD: src/usr.bin/xargs/strnsubst.c,v 1.7 2004/10/18 15:40:47 cperciva Exp $
$FreeBSD: src/usr.bin/xargs/xargs.c,v 1.57 2005/02/27 02:01:31 gad Exp $

@josch
Copy link

josch commented Jul 26, 2022

@AtomicNess123 it seems that some versions of freebsd xargs do not have the -I option. Compare:

https://www.freebsd.org/cgi/man.cgi?query=xargs&manpath=FreeBSD+4.0-RELEASE
https://www.freebsd.org/cgi/man.cgi?query=xargs&manpath=FreeBSD+14.0-current

Maybe you can fix your problem by getting a more modern version of xargs.

@AtomicNess123
Copy link

I have been trying to find how to update xargs on my MAC, unsucessfully.

@josch
Copy link

josch commented Jul 30, 2022

@AtomicNess123 depending on what you want to download, maybe you don't need xargs at all. Try running the first part, the youtube-dl -g part and see what it outputs. If it's just a single line, then you can feed that directly into ffmpeg without xargs. For example if I want to download parts of https://www.twitch.tv/videos/1541264505 then I run:

 youtube-dl -g https://www.twitch.tv/videos/1541264505

Which (in my case) outputs:

https://d1ymi26ma8va5x.cloudfront.net/a5a005f82fc0c7a2bda8_taketv_39656269816_1658662201/chunked/index-dvr.m3u8

I can then plug that into ffmpeg directly instead of the {} like this:

ffmpeg -ss 08:47:06 -i "https://d1ymi26ma8va5x.cloudfront.net/a5a005f82fc0c7a2bda8_taketv_39656269816_1658662201/chunked/index-dvr.m3u8" -c copy out.mp4

@mestrini
Copy link

mestrini commented Jun 18, 2023

Just for anyone reading this issue who wants a quick way to do it on Linux, you can use

youtube-dl -g VIDEO_URL | xargs -I{} ffmpeg -ss START_TIME -i "{}" -c copy -t FINISH_TIME OUTPUT_NAME

This worked out almost perfectly, except for the "FINISH_TIME" that should be "DURATION" since the flag "-t" is being used. Maybe that's why @AlexanderMatveev was assuming the video was being downloaded in full as he was telling the program to download more than one hour of video.

The other issue I have is not getting audio from the stream selected by youtube-dl. Investigating now either how to merge or how the select a stream with audio

Thanks @rhysperry111

EDIT:
Managed to extract just the portion I wanted and from the stream I wanted. :D

This is how I did it:
1 - Run youtube-dl -F VIDEO_URL to get the list of different streams provided by youtube

2023-06-18_17-13

2 - Then run the original code but add -f STREAM_ID after the VIDEO_URL, like so youtube-dl -g VIDEO_URL -f STREAM_ID | xargs -I{} ffmpeg -ss START_TIME -i "{}" -c copy -t DURATION OUTPUT_NAME

@dirkf
Copy link
Contributor

dirkf commented Jun 19, 2023

A cross-platform yt-dl solution involving --external-downloader ffmpeg --external-downloader-args ..., with no xargs, was shown in #4821 (comment), but the placement of the ffmpeg arguments supplied in --external-downloader-args ... may be incorrect (relative to the -i ... argument(s)). yt-dlp has additional syntax to control this which might eventually be back-ported.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests