Yet Another Youtube Down Loader

⌈⌋ ⎇ branch:  yaydl


Check-in [5568ac57ba]

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

Overview
Comment:yaydl 0.3.0: Added VOE.sx support, updated regex, added file name trimming.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk | release-0.3.0
Files: files | file ages | folders
SHA3-256: 5568ac57baeaebf14ab626760f0447ecb64af270943cc808f1b67a6f99328a2f
User & Date: Cthulhux 2021-01-06 18:55:00
Context
2021-01-08
10:29
Added Cargo.lock, tagged 0.3.0 check-in: e8e964ae11 user: Cthulhux tags: trunk
2021-01-06
18:55
yaydl 0.3.0: Added VOE.sx support, updated regex, added file name trimming. check-in: 5568ac57ba user: Cthulhux tags: trunk, release-0.3.0
2020-11-19
15:48
Style check-in: 607bb4dcad 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
12
13
14
15
16
17
18

19
20
21
22
23
24
25
[package]
name = "yaydl"
description = "yet another youtube (and more) down loader"
version = "0.2.6"
authors = ["Cthulhux <git@tuxproject.de>"]
edition = "2018"
license = "CDDL-1.0"
repository = "https://code.rosaelefanten.org/yaydl"
categories = ["command-line-utilities"]
keywords = ["youtube", "vimeo"]

[dependencies]
anyhow = "1.0"
clap = "3.0.0-beta.2"
indicatif = "0.15.0"
inventory = "0.1.9"
qstring = "0.7.2"
regex = "1.4.1"

serde_json = "1.0"
ureq = { version = "1.5", default_features = false, features = ["native-tls"] }
url = "2.2.0"
urlencoding = "1.1.1"

[profile.release]
lto = true



|





|







|
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[package]
name = "yaydl"
description = "yet another youtube (and more) down loader"
version = "0.3.0"
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"]

[dependencies]
anyhow = "1.0"
clap = "3.0.0-beta.2"
indicatif = "0.15.0"
inventory = "0.1.9"
qstring = "0.7.2"
regex = "1.4.2"
scraper = "0.12.0"
serde_json = "1.0"
ureq = { version = "1.5", default_features = false, features = ["native-tls"] }
url = "2.2.0"
urlencoding = "1.1.1"

[profile.release]
lto = true

Changes to README.md.

17
18
19
20
21
22
23

24
25
26
27
28
29
30
* Could convert the resulting file to something else (requires `ffmpeg`).
* Comes as a single binary (once compiled) - take it everywhere on your thumbdrive, no Python cruft required.

## Currently supported sites

* YouTube.com
* Vimeo.com


There is an easy way to add more supported sites, see below for details.

## Non-features

The list of features is deliberately kept short:








>







17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
* Could convert the resulting file to something else (requires `ffmpeg`).
* Comes as a single binary (once compiled) - take it everywhere on your thumbdrive, no Python cruft required.

## Currently supported sites

* YouTube.com
* Vimeo.com
* VOE.sx

There is an easy way to add more supported sites, see below for details.

## Non-features

The list of features is deliberately kept short:

Changes to src/handlers.rs.

13
14
15
16
17
18
19

20
21
22
 * distribution.
 */

// Yet Another Youtube Down Loader
// - handlers.rs file -

mod vimeo;

mod youtube;

// Add your own modules here.







>



13
14
15
16
17
18
19
20
21
22
23
 * distribution.
 */

// Yet Another Youtube Down Loader
// - handlers.rs file -

mod vimeo;
mod voe;
mod youtube;

// Add your own modules here.

Added src/handlers/voe.rs.

























































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/*
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * See the file LICENSE in this distribution for details.
 * A copy of the CDDL is also available via the Internet at
 * http://www.opensource.org/licenses/cddl1.txt
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the contents of the LICENSE file from this
 * distribution.
 */

// 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() {
        // We need to fetch the video information first.
        // It will contain the whole body for now.
        let req = ureq::get(&url).call();
        let body = req.into_string()?;

        VIDEO_INFO = body;
    }

    // Return it:
    let d = Html::parse_document(&VIDEO_INFO);
    Ok(d)
}

// Implement the site definition:
struct VoeHandler;
impl SiteDefinition for VoeHandler {
    fn can_handle_url<'a>(&'a self, url: &'a str) -> bool {
        Regex::new(r"(?:\.)?voe.sx/.+").unwrap().is_match(url)
    }

    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 {
            let _video_info = get_video_info(url)?;
            let url_re = Regex::new("sources: ..src: '(?P<URL>.+?)'").unwrap();
            let url_search = url_re.captures(&VIDEO_INFO).unwrap();
            let video_url = url_search.name("URL").map_or("", |u| u.as_str());

            Ok(video_url.to_string())
        }
    }

    fn does_video_exist<'a>(&'a self, url: &'a str) -> Result<bool> {
        unsafe {
            let _video_info = get_video_info(url);
            Ok(!VIDEO_INFO.is_empty())
        }
    }

    fn display_name<'a>(&'a self) -> String {
        "Voe".to_string()
    }

    fn find_video_file_extension<'a>(&'a self, _url: &'a str, _onlyaudio: bool) -> Result<String> {
        Ok("mp4".to_string())
    }
}

// Push the site definition to the list of known handlers:
inventory::submit! {
    &VoeHandler as &dyn SiteDefinition
}

Changes to src/main.rs.

169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
                        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.replace(&['|', '\'', '\"', ':', '\'', '\\', '/'][..], r#""#),
                        ext
                    );

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








|







169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
                        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();
                    }