Skip to content

Commit

Permalink
05.03.2024
Browse files Browse the repository at this point in the history
* VideoFormat mime_type property more stable with new crate `mime`
* Some crates updated with new versions
Mithronn committed Mar 5, 2024
1 parent 32232d4 commit 3fde023
Showing 7 changed files with 119 additions and 136 deletions.
37 changes: 19 additions & 18 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rusty_ytdl"
version = "0.6.6"
version = "0.6.7"
authors = ["Mithronn"]
edition = "2021"
description = "A Rust library for Youtube video searcher and downloader"
@@ -21,35 +21,36 @@ members = [".", "cli"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
reqwest = { version = "0.11.18", features = [
reqwest = { version = "0.11.24", features = [
"cookies",
"gzip",
], default-features = false }
scraper = "0.16.0"
serde = "1.0.158"
serde_json = "1.0.94"
scraper = "0.19.0"
serde = "1.0.197"
serde_json = "1.0.114"
serde_qs = "0.12.0"
regex = "1.7.2"
url = "2.3.1"
urlencoding = "2.1.2"
thiserror = "1.0.40"
regex = "1.10.3"
url = "2.5.0"
urlencoding = "2.1.3"
thiserror = "1.0.57"
derive_more = "0.99.17"
derivative = "2.2.0"
once_cell = "1.17.1"
tokio = { version = "1.26.0", default-features = false, features = ["sync"] }
once_cell = "1.19.0"
tokio = { version = "1.36.0", default-features = false, features = ["sync"] }
rand = "0.8.5"
reqwest-middleware = "0.2.2"
reqwest-retry = "0.3.0"
m3u8-rs = "5.0.3"
async-trait = "0.1.68"
aes = "0.8.2"
reqwest-middleware = "0.2.4"
reqwest-retry = "0.4.0"
m3u8-rs = "6.0.0"
async-trait = "0.1.77"
aes = "0.8.4"
cbc = { version = "0.1.2", features = ["std"] }
hex = "0.4.3"
unicode-segmentation = "1.10.1"
unicode-segmentation = "1.11.0"
boa_engine = "0.17.3"
mime = "0.3.17"

[dev-dependencies]
tokio = { version = "1.26.0", features = ["full"] }
tokio = { version = "1.36.0", features = ["full"] }

[features]
default = ["search", "live", "default-tls"]
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -158,5 +158,5 @@ Or add the following to your `Cargo.toml` file:

```toml
[dependencies]
rusty_ytdl = "0.6.6"
rusty_ytdl = "0.6.7"
```
2 changes: 1 addition & 1 deletion cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -30,7 +30,7 @@ tokio = { version = "1.28.2", features = [
"io-std",
] }
log = "0.4.20"
rusty_ytdl = { path = "..", version = "0.6.6" }
rusty_ytdl = { path = "..", version = "0.6.7" }
colored = { version = "2.0.0" }
indicatif = "0.17.4"
fern = { version = "0.6.2", features = ["colored"] }
6 changes: 3 additions & 3 deletions cli/src/utils/result_serializer.rs
Original file line number Diff line number Diff line change
@@ -85,18 +85,18 @@ impl Serialize for FormatSerializer {
approx_duration_ms, url
}
OutputLevel::GENERAL | OutputLevel::VERBOSE => {
codecs

}

OutputLevel::VIDEO_TRACK => {
height, width, quality_label, fps, video_codec
height, width, quality_label, fps
}
OutputLevel::VIDEO_TRACK | OutputLevel::VERBOSE => {
color_info, high_replication,
}

OutputLevel::AUDIO_TRACK => {
audio_quality, bitrate, audio_sample_rate, audio_channels, loudness_db, audio_codec, high_replication
audio_quality, bitrate, audio_sample_rate, audio_channels, loudness_db, high_replication
}
OutputLevel::AUDIO_TRACK | OutputLevel::VERBOSE => {
average_bitrate
6 changes: 3 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -19,9 +19,9 @@ pub mod search;

pub use info::Video;
pub use structs::{
Author, Chapter, ColorInfo, DownloadOptions, Embed, RangeObject, RelatedVideo, RequestOptions,
StoryBoard, Thumbnail, VideoDetails, VideoError, VideoFormat, VideoInfo, VideoOptions,
VideoQuality, VideoSearchOptions,
Author, Chapter, ColorInfo, DownloadOptions, Embed, MimeType, RangeObject, RelatedVideo,
RequestOptions, StoryBoard, Thumbnail, VideoDetails, VideoError, VideoFormat, VideoInfo,
VideoOptions, VideoQuality, VideoSearchOptions,
};
pub use utils::{choose_format, get_random_v6_ip, get_video_id};
// export to access proxy feature
93 changes: 85 additions & 8 deletions src/structs.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
use serde::{Deserialize, Serialize};
use mime::Mime;
use serde::{
de::{Error, Unexpected},
Deserialize, Deserializer, Serialize, Serializer,
};
use std::{
ops::{Bound, RangeBounds},
str::FromStr,
sync::Arc,
};

@@ -262,7 +267,7 @@ pub struct VideoFormat {
pub itag: u64,
/// Video format mime type
#[serde(rename = "mimeType")]
pub mime_type: String,
pub mime_type: MimeType,
pub bitrate: u64,
/// Video format width
pub width: Option<u64>, // VIDEO & DASH MPD ONLY
@@ -308,12 +313,6 @@ pub struct VideoFormat {
/// Video format has audio or not
#[serde(rename = "hasAudio")]
pub has_audio: bool,
pub container: Option<String>,
pub codecs: Option<String>,
#[serde(rename = "videoCodec")]
pub video_codec: Option<String>,
#[serde(rename = "audioCodec")]
pub audio_codec: Option<String>,
/// Video is live or not
#[serde(rename = "isLive")]
pub is_live: bool,
@@ -573,3 +572,81 @@ impl StringUtils for str {
self.substr(start, len)
}
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MimeType {
pub mime: Mime,
/// Mime container
pub container: String,
/**
* Mime codec parameters
**Mime type:** [`mime::AUDIO`] or [`mime::VIDEO`] => contains 1 element and its audio/video codec
**Mime type:** [`mime::VIDEO`] => if contains 2 element, first is video and second is audio codec
*/
pub codecs: Vec<String>,
/// Video codec parameter
pub video_codec: Option<String>,
/// Audio codec parameter
pub audio_codec: Option<String>,
}

impl Serialize for MimeType {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let s = format!(
r#"{}/{}; codecs="{}""#,
self.mime.type_(),
self.mime.subtype(),
self.codecs.join(", "),
);

s.serialize(serializer)
}
}

impl<'de> Deserialize<'de> for MimeType {
fn deserialize<D>(deserializer: D) -> Result<MimeType, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;

let mime: Mime = Mime::from_str(&s).map_err(|_| {
D::Error::invalid_value(
Unexpected::Str(&s),
&r#"valid mime type format must be `(\w+/\w+);\scodecs="([a-zA-Z-0-9.,\s]*)"`"#,
)
})?;

let codecs: Vec<String> = mime
.get_param("codecs")
.map(|x| x.as_str().split(", ").map(|x| x.to_string()).collect())
.unwrap_or_default();

let container: String = mime.subtype().to_string();

let video_codec = if mime.type_() == mime::VIDEO {
codecs.first().cloned()
} else {
None
};

let audio_codec = if mime.type_() == mime::AUDIO {
codecs.first().cloned()
} else {
codecs.get(1).cloned()
};

Ok(MimeType {
mime,
container,
codecs,
video_codec,
audio_codec,
})
}
}
109 changes: 7 additions & 102 deletions src/utils.rs
Original file line number Diff line number Diff line change
@@ -142,97 +142,6 @@ pub fn add_format_meta(format: &mut serde_json::Map<String, serde_json::Value>)
format.insert("hasAudio".to_owned(), serde_json::Value::Bool(false));
}

if format.contains_key("mimeType") {
let container_value_arr = format
.get("mimeType")
.and_then(|x| x.as_str())
.unwrap_or("")
.split(';')
.collect::<Vec<&str>>()
.first()
.unwrap_or(&"")
.split('/')
.collect::<Vec<&str>>();

let container_value = container_value_arr.get(1).unwrap_or(&"");

if !container_value.is_empty() {
format.insert("container".to_owned(), serde_json::json!(container_value));
} else {
format.insert("container".to_owned(), serde_json::json!(null));
}

let codecs_value = between(
format
.get("mimeType")
.and_then(|x| x.as_str())
.unwrap_or(""),
r#"codecs=""#,
r#"""#,
);

if !codecs_value.is_empty() {
format.insert("codecs".to_string(), serde_json::json!(codecs_value));
} else {
format.insert("codecs".to_string(), serde_json::json!(null));
}
} else {
format.insert("container".to_owned(), serde_json::json!(null));
format.insert("codecs".to_string(), serde_json::json!(null));
}

if format
.get("hasVideo")
.and_then(|x| x.as_bool())
.unwrap_or(false)
&& format.get("codecs").map(|x| !x.is_null()).unwrap_or(false)
{
let video_codec_value = format
.get("codecs")
.and_then(|x| x.as_str())
.unwrap_or("")
.split(", ")
.collect::<Vec<&str>>()[0];

if !video_codec_value.is_empty() {
format.insert(
"videoCodec".to_string(),
serde_json::json!(video_codec_value),
);
} else {
format.insert("videoCodec".to_string(), serde_json::json!(null));
}
} else {
format.insert("videoCodec".to_string(), serde_json::json!(null));
}

if format
.get("hasAudio")
.and_then(|x| x.as_bool())
.unwrap_or(false)
&& format.get("codecs").map(|x| !x.is_null()).unwrap_or(false)
{
let audio_codec_value_arr = format
.get("codecs")
.and_then(|x| x.as_str())
.unwrap_or("")
.split(", ")
.collect::<Vec<&str>>();

let audio_codec_value = audio_codec_value_arr.last().unwrap_or(&"");

if !audio_codec_value.is_empty() {
format.insert(
"audioCodec".to_string(),
serde_json::json!(audio_codec_value),
);
} else {
format.insert("audioCodec".to_string(), serde_json::json!(null));
}
} else {
format.insert("audioCodec".to_string(), serde_json::json!(null));
}

let regex_is_live = Regex::new(r"\bsource[/=]yt_live_broadcast\b").unwrap();
let regex_is_hls = Regex::new(r"/manifest/hls_(variant|playlist)/").unwrap();
let regex_is_dashmpd = Regex::new(r"/manifest/dash/").unwrap();
@@ -413,10 +322,7 @@ pub fn sort_formats_by_video(a: &VideoFormat, b: &VideoFormat) -> std::cmp::Orde
|form: &VideoFormat| {
let index = VIDEO_ENCODING_RANKS
.iter()
.position(|enc| {
form.codecs.is_some()
&& form.codecs.clone().unwrap_or("".to_string()).contains(enc)
})
.position(|enc| form.mime_type.codecs.join(", ").contains(enc))
.map(|x| x as i32)
.unwrap_or(-1);

@@ -437,10 +343,7 @@ pub fn sort_formats_by_audio(a: &VideoFormat, b: &VideoFormat) -> std::cmp::Orde
|form: &VideoFormat| {
let index = AUDIO_ENCODING_RANKS
.iter()
.position(|enc| {
form.codecs.is_some()
&& form.codecs.clone().unwrap_or("".to_string()).contains(enc)
})
.position(|enc| form.mime_type.codecs.join(", ").contains(enc))
.map(|x| x as i32)
.unwrap_or(-1);

@@ -488,7 +391,7 @@ pub fn sort_formats(a: &VideoFormat, b: &VideoFormat) -> std::cmp::Ordering {
|form: &VideoFormat| {
let index = VIDEO_ENCODING_RANKS
.iter()
.position(|enc| form.codecs.clone().unwrap_or("".to_string()).contains(enc))
.position(|enc| form.mime_type.codecs.join(", ").contains(enc))
.map(|x| x as i32)
.unwrap_or(-1);

@@ -498,7 +401,7 @@ pub fn sort_formats(a: &VideoFormat, b: &VideoFormat) -> std::cmp::Ordering {
|form: &VideoFormat| {
let index = AUDIO_ENCODING_RANKS
.iter()
.position(|enc| form.codecs.clone().unwrap_or("".to_string()).contains(enc))
.position(|enc| form.mime_type.codecs.join(", ").contains(enc))
.map(|x| x as i32)
.unwrap_or(-1);

@@ -1598,7 +1501,9 @@ pub fn cut_after_js(mixed_json: &str) -> Option<String> {
{
is_escaped_object = None;
continue;
} else if !is_escaped && is_escaped_object.is_none() {
}

if !is_escaped && is_escaped_object.is_none() {
for escaped in ESCAPING_SEQUENZES.iter() {
if value != escaped.start.as_str() {
continue;

0 comments on commit 3fde023

Please sign in to comment.