Yet Another Youtube Down Loader

⌈⌋ ⎇ branch:  yaydl


Check-in [f6dd0520b6]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:yaydl 0.3.2: Won't panic with VOE.sx embed only streams anymore.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk | release-0.3.2
Files: files | file ages | folders
SHA3-256: f6dd0520b6d90bf12b3c7810524e8773e35eda4f5103472bc4fa5092912f68bf
User & Date: Cthulhux 2021-02-24 21:53:48
Context
2021-03-24
22:03
yaydl 0.4.0: I was asked to add at least one porn site - I added WatchMDH.to. Also, updated dependencies. check-in: 29e17c7c41 user: Cthulhux tags: trunk, release-0.4.0
2021-02-24
21:53
yaydl 0.3.2: Won't panic with VOE.sx embed only streams anymore. check-in: f6dd0520b6 user: Cthulhux tags: trunk, release-0.3.2
2021-01-30
23:37
tag check-in: 4fd8bf5fdc user: Cthulhux tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to Cargo.toml.

1
2
3
4
5
6
7
8
9
10
11
[package]
name = "yaydl"
description = "yet another youtube (and more) down loader"
version = "0.3.1"
authors = ["Cthulhux <git@tuxproject.de>"]
edition = "2018"
license = "CDDL-1.0"
repository = "https://code.rosaelefanten.org/yaydl"
categories = ["command-line-utilities"]
keywords = ["youtube", "vimeo", "voe"]




|







1
2
3
4
5
6
7
8
9
10
11
[package]
name = "yaydl"
description = "yet another youtube (and more) down loader"
version = "0.3.2"
authors = ["Cthulhux <git@tuxproject.de>"]
edition = "2018"
license = "CDDL-1.0"
repository = "https://code.rosaelefanten.org/yaydl"
categories = ["command-line-utilities"]
keywords = ["youtube", "vimeo", "voe"]

Changes to src/handlers/voe.rs.

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 */

// Yet Another Youtube Down Loader
// - VOE handler -

use crate::definitions::SiteDefinition;

use anyhow::Result;
use regex::Regex;
use scraper::{Html, Selector};

static mut VIDEO_INFO: String = String::new();

unsafe fn get_video_info(url: &str) -> Result<Html> {
    if VIDEO_INFO.is_empty() {







|







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 */

// Yet Another Youtube Down Loader
// - VOE handler -

use crate::definitions::SiteDefinition;

use anyhow::{anyhow, Result};
use regex::Regex;
use scraper::{Html, Selector};

static mut VIDEO_INFO: String = String::new();

unsafe fn get_video_info(url: &str) -> Result<Html> {
    if VIDEO_INFO.is_empty() {
47
48
49
50
51
52
53
54
55
56



57
58
59
60
61
62
63
    }

    fn find_video_title<'a>(&'a self, url: &'a str) -> Result<String> {
        unsafe {
            let video_info = get_video_info(url)?;

            let h1_selector = Selector::parse("h1.mt-1").unwrap();
            let text = video_info.select(&h1_selector).next().unwrap();

            let result = text.text().collect();




            Ok(result)
        }
    }

    fn find_video_direct_url<'a>(&'a self, url: &'a str, _onlyaudio: bool) -> Result<String> {
        unsafe {







|

|
>
>
>







47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
    }

    fn find_video_title<'a>(&'a self, url: &'a str) -> Result<String> {
        unsafe {
            let video_info = get_video_info(url)?;

            let h1_selector = Selector::parse("h1.mt-1").unwrap();
            let text = video_info.select(&h1_selector).next();

            let result = match text {
                Some(txt) => txt.text().collect(),
                None => return Err(anyhow!("Erroneous video site - maybe embed-only?")),
            };

            Ok(result)
        }
    }

    fn find_video_direct_url<'a>(&'a self, url: &'a str, _onlyaudio: bool) -> Result<String> {
        unsafe {

Changes to src/handlers/youtube.rs.

132
133
134
135
136
137
138
139

140
141
142
143
144
145
146

                // If audio: Try to download the best audio quality.
                // If video: Try to download the best combination.
                if (onlyaudio && itag["mimeType"].to_string().contains("audio/")
                    || !onlyaudio && itag["mimeType"].to_string().contains("video/"))
                    && (!onlyaudio || itag["quality"] != json!(null))
                    && itag["audioQuality"] != json!(null)
                    && (onlyaudio && this_vq.is_empty() || !onlyaudio && last_vq.is_empty() && !this_vq.is_empty())

                    || is_better_quality
                {
                    VIDEO_MIME = itag["mimeType"].to_string();
                    // Now here are two options: Either the URL is written directly in the itag
                    // or YouTube hides it in a "signatureCipher" which we need to decode first.
                    if itag["signatureCipher"] != json!(null) && itag["url"] == json!(null) {
                        // Sigh.







|
>







132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147

                // If audio: Try to download the best audio quality.
                // If video: Try to download the best combination.
                if (onlyaudio && itag["mimeType"].to_string().contains("audio/")
                    || !onlyaudio && itag["mimeType"].to_string().contains("video/"))
                    && (!onlyaudio || itag["quality"] != json!(null))
                    && itag["audioQuality"] != json!(null)
                    && (onlyaudio && this_vq.is_empty()
                        || !onlyaudio && last_vq.is_empty() && !this_vq.is_empty())
                    || is_better_quality
                {
                    VIDEO_MIME = itag["mimeType"].to_string();
                    // Now here are two options: Either the URL is written directly in the itag
                    // or YouTube hides it in a "signatureCipher" which we need to decode first.
                    if itag["signatureCipher"] != json!(null) && itag["url"] == json!(null) {
                        // Sigh.

Changes to src/main.rs.

73
74
75
76
77
78
79
80


81
82
83
84
85
86
87

    let file = Path::new(filename);

    if file.exists() {
        // Continue the file:
        let size = file.metadata()?.len() - 1;
        // Override the range:
        request = ureq::get(url.as_str()).set("Range", &format!("bytes={}-", size)).to_owned();


        pb.inc(size);
    }

    let resp = request.call();
    let mut source = DownloadProgress {
        progress_bar: pb,
        inner: resp.into_reader(),







|
>
>







73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89

    let file = Path::new(filename);

    if file.exists() {
        // Continue the file:
        let size = file.metadata()?.len() - 1;
        // Override the range:
        request = ureq::get(url.as_str())
            .set("Range", &format!("bytes={}-", size))
            .to_owned();
        pb.inc(size);
    }

    let resp = request.call();
    let mut source = DownloadProgress {
        progress_bar: pb,
        inner: resp.into_reader(),
151
152
153
154
155
156
157
158




159
160

161
162
163
164
165
166
167
168
169
170
171
172
173
174
175

176
177
178
179
180
181
182
183
            if !video_exists {
                println!("The video could not be found. Invalid link?");
            } else {
                if args.is_present("verbose") {
                    println!("The requested video was found. Processing...");
                }

                let vt = handler.find_video_title(in_url)?;





                // Usually, we already find errors here.

                if vt.is_empty() {
                    println!("The video title could not be extracted. Invalid link?");
                } else {
                    if args.is_present("verbose") {
                        println!("Title: {}", vt);
                    }

                    let url =
                        handler.find_video_direct_url(in_url, args.is_present("onlyaudio"))?;
                    let ext =
                        handler.find_video_file_extension(in_url, args.is_present("onlyaudio"))?;

                    // Now let's download it:
                    let mut targetfile = format!(
                        "{}.{}",

                        vt.trim().replace(&['|', '\'', '\"', ':', '\'', '\\', '/'][..], r#""#),
                        ext
                    );

                    if let Some(in_targetfile) = args.value_of("outputfile") {
                        targetfile = in_targetfile.to_string();
                    }








|
>
>
>
>


>















>
|







153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
            if !video_exists {
                println!("The video could not be found. Invalid link?");
            } else {
                if args.is_present("verbose") {
                    println!("The requested video was found. Processing...");
                }

                let video_title = handler.find_video_title(in_url);
                let vt = match video_title {
                    Err(_e) => "".to_string(),
                    Ok(title) => title,
                };

                // Usually, we already find errors here.

                if vt.is_empty() {
                    println!("The video title could not be extracted. Invalid link?");
                } else {
                    if args.is_present("verbose") {
                        println!("Title: {}", vt);
                    }

                    let url =
                        handler.find_video_direct_url(in_url, args.is_present("onlyaudio"))?;
                    let ext =
                        handler.find_video_file_extension(in_url, args.is_present("onlyaudio"))?;

                    // Now let's download it:
                    let mut targetfile = format!(
                        "{}.{}",
                        vt.trim()
                            .replace(&['|', '\'', '\"', ':', '\'', '\\', '/'][..], r#""#),
                        ext
                    );

                    if let Some(in_targetfile) = args.value_of("outputfile") {
                        targetfile = in_targetfile.to_string();
                    }