Skip to content

Commit

Permalink
Release Updates v0.1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
clitic committed Jun 22, 2022
1 parent 29cc4e4 commit 0f11d6b
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 50 deletions.
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,20 @@ Dependencies

Visit [releases](https://github.com/clitic/vsd/releases) for prebuilt binaries. You just need to copy that binary to any path specified in your `PATH` environment variable.

### On x86_64 Linux

```bash
INSTALL_PATH=/usr/local/bin curl https://github.com/clitic/vsd/releases/download/v0.1.0/vsd-v0.1.0-x86_64-unknown-linux-musl.tar.gz -o vsd-v0.1.0.tar.gz && tar -xzf vsd-v0.1.0.tar.gz -C $INSTALL_PATH/ && chmod +x $INSTALL_PATH/vsd && rm vsd-v0.1.0.tar.gz
```

### On Termux

Android builds are compiled with **android-ndk-r22b** and targets **API Level 30** it means binary is only supported by **Android 11** and above.

```bash
curl https://github.com/clitic/vsd/releases/download/v0.1.0/vsd-v0.1.0-aarch64-linux-android.tar.gz -o vsd-v0.1.0.tar.gz && tar -xzf vsd-v0.1.0.tar.gz -C $PREFIX/bin/ && chmod +x $PREFIX/bin/vsd && rm vsd-v0.1.0.tar.gz
```

## Usage

For quick testing purposes you may use [https://test-streams.mux.dev](https://test-streams.mux.dev) as direct input. These streams are used by [hls.js](https://github.com/video-dev/hls.js) for testing purposes.
Expand Down Expand Up @@ -134,7 +148,7 @@ CLIENT OPTIONS:
Custom headers for requests. This option can be used multiple times
--proxy-address <PROXY_ADDRESS>
Custom http or https proxy address for requests
Set http or https proxy address for requests
--user-agent <USER_AGENT>
Update and set custom user agent for requests [default: "Mozilla/5.0 (Windows NT 10.0;
Expand Down
2 changes: 1 addition & 1 deletion src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ pub struct Args {
)]
pub user_agent: String,

/// Custom http or https proxy address for requests.
/// Set http or https proxy address for requests.
#[clap(long, validator = proxy_address_validator, help_heading = "CLIENT OPTIONS")]
pub proxy_address: Option<String>,

Expand Down
70 changes: 33 additions & 37 deletions src/chrome.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,23 @@ use headless_chrome::protocol::network::methods::RequestPattern;
use headless_chrome::{Browser, LaunchOptionsBuilder};
use kdam::term::Colorizer;

pub fn message(headless: bool) {
println!("Some websites use window size to check wheter to show quality switch button or not. \
For such websites open chrome in full-screen mode and then right-click and select inspect. \
Now resize the window as required.\n\
{}\n\
Chrome will launch {} a window.\n\
Terminate this program using {}\n",
"Sometimes request interception doesn't works in such condition try re running the command."
.colorize("#FFA500"),
if headless {
"without"
} else {
"with"
}, "CTRL+C".colorize("bold red")
);
}

fn filepath(url: &str, ext: &str) -> String {
let path = if let Some(output) = url
.split("?")
Expand All @@ -14,7 +31,11 @@ fn filepath(url: &str, ext: &str) -> String {
.split("/")
.find(|x| x.ends_with(&format!(".{}", ext)))
{
crate::utils::replace_ext(output, ext)
if output.ends_with(&format!(".ts.{}", ext)) {
output.trim_end_matches(&format!(".{}", ext)).to_owned()
} else {
crate::utils::replace_ext(output, "ts")
}
} else {
match ext {
"m3u8" => "playlist.m3u8".to_owned(),
Expand Down Expand Up @@ -42,7 +63,7 @@ fn filepath(url: &str, ext: &str) -> String {
path
}

pub fn capture(url: String, headless: bool) -> Result<()> {
pub fn capture(url: &str, headless: bool) -> Result<()> {
let browser = Browser::new(
LaunchOptionsBuilder::default()
.headless(headless)
Expand All @@ -54,40 +75,36 @@ pub fn capture(url: String, headless: bool) -> Result<()> {
let tab = browser
.wait_for_initial_tab()
.map_err(|e| anyhow!(e.to_string()))?;
tab.navigate_to(url.as_str())
tab.navigate_to(url)
.map_err(|e| anyhow!(e.to_string()))?;

let count = std::sync::atomic::AtomicU8::new(1);

tab.enable_request_interception(
&[RequestPattern {
url_pattern: None,
resource_type: Some("XHR"),
interception_stage: None,
}],
Box::new(|_transport, _session_id, intercepted| {
Box::new(move |_transport, _session_id, intercepted| {
if intercepted.request.url.contains(".m3u") || intercepted.request.url.contains(".mpd")
{
println!("• {}", intercepted.request.url);
let i = count.load(std::sync::atomic::Ordering::SeqCst);
println!("{}) {}", i, intercepted.request.url);
count.store(i + 1, std::sync::atomic::Ordering::SeqCst);
}

RequestInterceptionDecision::Continue
}),
)
.map_err(|e| anyhow!(e.to_string()))?;

println!(
"{}\n\
Some websites use window size to check wheter to show quality switch button or not. \
For such websites open chrome in full-screen mode and then right-click and select inspect. \
Now resize the window as required.",
"Sometimes request interception may not work in such conditions try re running the command."
.colorize("cyan")
);
std::thread::sleep(std::time::Duration::from_secs(60 * 3));
Ok(())
}

pub fn collect(
url: String,
url: &str,
headless: bool,
downloader: &crate::downloader::Downloader,
) -> Result<()> {
Expand All @@ -102,7 +119,7 @@ pub fn collect(
let tab = browser
.wait_for_initial_tab()
.map_err(|e| anyhow!(e.to_string()))?;
tab.navigate_to(url.as_str())
tab.navigate_to(url)
.map_err(|e| anyhow!(e.to_string()))?;

let (sender, receiver) = std::sync::mpsc::channel();
Expand Down Expand Up @@ -130,29 +147,12 @@ pub fn collect(
)
.map_err(|e| anyhow!(e.to_string()))?;

println!(
"{}\n\
Some websites use window size to check wheter to show quality switch button or not. \
For such websites open chrome in full-screen mode and then right-click and select inspect. \
Now resize the window as required.",
"Sometimes request interception may not work in such conditions try re running the command."
.colorize("cyan")
);

if url.starts_with("https://www.iq.com/play") {
println!(
"Collection method available for {}\nUsing {} method for collection.",
"https://www.iq.com/play".colorize("bold green"),
"CUSTOM".colorize("cyan")
);
println!("Using {} method for collection.", "CUSTOM".colorize("cyan"));
} else {
println!("Using {} method for collection.", "COMMAN".colorize("cyan"))
}

println!(
"Terminate this program using {}",
"CTRL+C".colorize("bold red")
);
while let Ok(xhr_url) = receiver.recv() {
if xhr_url.contains(".m3u") {
let file = filepath(&xhr_url, "m3u8");
Expand Down Expand Up @@ -190,10 +190,6 @@ pub fn collect(
}

fn iqiyi(url: &str, xhr_url: &str, downloader: &crate::downloader::Downloader) -> Result<()> {
// if !url.starts_with("https://www.iq.com/play") {
// bail!("Only https://www.iq.com/play links are supported.")
// }

let re = regex::Regex::new(r"[a-zA-Z0-9-]*\?").unwrap();
let name = re
.captures_iter(&url)
Expand Down
25 changes: 14 additions & 11 deletions src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,8 @@ impl DownloadState {
let args = crate::args::parse();

if args.capture {
println!(
"Launching chrome in headless={} mode for 3 minutes.",
args.headless
);
crate::chrome::capture(args.input, args.headless)?;
crate::chrome::message(args.headless);
crate::chrome::capture(&args.input, args.headless)?;
std::process::exit(0);
}

Expand All @@ -37,8 +34,8 @@ impl DownloadState {
.context("Couldn't create reqwest client.")?;

if args.collect {
println!("Launching chrome in headless={} mode.", args.headless);
crate::chrome::collect(args.input.clone(), args.headless, &downloader)?;
crate::chrome::message(args.headless);
crate::chrome::collect(&args.input, args.headless, &downloader)?;
}

if let Some(output) = &args.output {
Expand Down Expand Up @@ -85,7 +82,11 @@ impl DownloadState {
.split("/")
.find(|x| x.ends_with(".m3u8"))
{
replace_ext(output, "ts")
if output.ends_with(".ts.m3u8") {
output.trim_end_matches(".m3u8").to_owned()
} else {
replace_ext(output, "ts")
}
} else {
"merged.ts".to_owned()
};
Expand Down Expand Up @@ -124,9 +125,9 @@ impl DownloadState {
{} If m3u8 url is not captured then rerun the command or use {} flag \
and then run the command with saved .m3u8 as {} file with {} flag. \
Sometimes baseurl is not needed so it can be skipped.\n\n\
First command will save .m3u8 (suppose playlist.m3u8)\n\
First command will save .m3u8 (suppose master.m3u8)\n\
$ vsd {} --collect\n\
$ vsd playlist.m3u8 --baseurl {}",
$ vsd master.m3u8 --baseurl https://streaming.site/video_001/",
"TRY THIS:".colorize("yellow"),
"--capture".colorize("bold green"),
"INPUT".colorize("bold green"),
Expand All @@ -136,7 +137,6 @@ impl DownloadState {
"INPUT".colorize("bold green"),
"--baseurl".colorize("bold green"),
self.args.input,
self.args.input,
),
1 => {
self.args.input = links[0].clone();
Expand Down Expand Up @@ -341,6 +341,9 @@ impl DownloadState {
segments: &Vec<m3u8_rs::MediaSegment>,
mut tempfile: String,
) -> Result<()> {
// Check to ensure baseurl is required or not.
self.get_url(&segments[0].uri)?;

if let Some(output) = &self.args.output {
if output.ends_with(".ts") {
tempfile = output.clone();
Expand Down

0 comments on commit 0f11d6b

Please sign in to comment.