added aria2 websocket + fetching magnet links

and ascii text on startup
This commit is contained in:
2025-11-16 01:13:05 +01:00
parent c68a120f95
commit aa1359bc97
3 changed files with 977 additions and 22 deletions
Generated
+873 -13
View File
File diff suppressed because it is too large Load Diff
+3
View File
@@ -4,8 +4,11 @@ version = "0.1.0"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
aria2-ws = "0.5.1"
dialoguer = { version = "0.12.0", features = ["fuzzy-select"] } dialoguer = { version = "0.12.0", features = ["fuzzy-select"] }
futures = "0.3.31"
reqwest = { version = "0.12", features = ["json"] } reqwest = { version = "0.12", features = ["json"] }
select = "0.6.1"
serde = "1.0.228" serde = "1.0.228"
serde_json = "1.0.145" serde_json = "1.0.145"
tokio = { version = "1", features = ["full"] } tokio = { version = "1", features = ["full"] }
+101 -9
View File
@@ -1,21 +1,46 @@
use aria2_ws::{Callbacks, Client, TaskOptions};
use dialoguer::FuzzySelect; use dialoguer::FuzzySelect;
use futures::FutureExt;
use select::document::Document;
use select::predicate::Name;
use serde::Deserialize; use serde::Deserialize;
use serde_json::Value; use serde_json::{json, Value};
use std::io; use std::io;
use std::process::Command;
use std::sync::Arc;
use tokio::{spawn, sync::Semaphore};
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
struct Software { struct Software {
author: String, //author: String,
id: i64,
title: String, title: String,
url: String, url: String,
} }
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> { async fn main() -> Result<(), Box<dyn std::error::Error>> {
let ascii = r#"
_________ _____ __ _____
/ _____/ _____/ ____\/ |___ _ _______ _______ ____ / \ _____ ____ _____ ____ ___________
\_____ \ / _ \ __\\ __\ \/ \/ /\__ \\_ __ \_/ __ \ / \ / \\__ \ / \\__ \ / ___\_/ __ \_ __ \
/ ( <_> ) | | | \ / / __ \| | \/\ ___/ / Y \/ __ \| | \/ __ \_/ /_/ > ___/| | \/
/_______ /\____/|__| |__| \/\_/ (____ /__| \___ > \____|__ (____ /___| (____ /\___ / \___ >__|
\/ \/ \/ \/ \/ \/ \//_____/ \/
"#;
println!("{ascii}");
let server_url = "https://api.michijackson.xyz/search/".to_owned(); let server_url = "https://api.michijackson.xyz/search/".to_owned();
let mut input = String::new(); let mut input = String::new();
let _command = Command::new("/usr/bin/aria2c")
.arg("--enable-rpc")
.arg("--disable-ipv6")
.arg("--rpc-listen-all")
.arg("--rpc-listen-port=6800")
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.spawn();
eprint!("Search: "); eprint!("Search: ");
io::stdin() io::stdin()
.read_line(&mut input) .read_line(&mut input)
@@ -23,9 +48,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let res = reqwest::get(server_url + &input).await?; let res = reqwest::get(server_url + &input).await?;
println!("Status: {}", res.status()); println!("Status: {}", res.status());
let text = res.text().await?;
let body = res.text().await?; let v: Value = serde_json::from_str(&text)?;
let v: Value = serde_json::from_str(&body)?;
let data = &v["data"]; let data = &v["data"];
let items: Vec<Software> = let items: Vec<Software> =
@@ -39,10 +64,77 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
.interact() .interact()
.unwrap(); .unwrap();
println!("You selected: {}", items[selection].title); let html_res = reqwest::get(&items[selection].url).await?;
println!("Author: {}", items[selection].author); let html_text = html_res.text().await?;
println!("ID: {}", items[selection].id); let doc = Document::from(html_text.as_str());
println!("URL: {}", items[selection].url); let links = doc
.find(Name("a"))
.filter_map(|n| n.attr("href"))
.collect::<Vec<_>>();
let mut magnet: Option<&str> = None;
for link in links {
if link.starts_with("magnet:") {
println!("magnet link: {link:?}");
magnet = Some(link);
}
}
aria2_ws(magnet.unwrap()).await;
Ok(()) Ok(())
} }
async fn aria2_ws(items: &str) {
let client = Client::connect("ws://127.0.0.1:6800/jsonrpc", None)
.await
.unwrap();
let options = TaskOptions {
split: Some(2),
extra_options: json!({"max-download-limit": "200K"})
.as_object()
.unwrap()
.clone(),
..Default::default()
};
let semaphore = Arc::new(Semaphore::new(0));
client
.add_uri(
vec![items.to_string()],
Some(options.clone()),
None,
Some(Callbacks {
on_download_complete: Some({
let s = semaphore.clone();
async move {
s.add_permits(1);
println!("Task 1 completed!");
}
.boxed()
}),
on_error: Some({
let s = semaphore.clone();
async move {
s.add_permits(1);
println!("Task 1 error!");
}
.boxed()
}),
}),
)
.await
.unwrap();
let mut not = client.subscribe_notifications();
spawn(async move {
while let Ok(msg) = not.recv().await {
println!("Received notification {:?}", &msg);
}
});
let _ = semaphore.acquire_many(2).await.unwrap();
client.shutdown().await.unwrap();
}