Skip to content

Commit

Permalink
完成qbittorrent机器人实现
Browse files Browse the repository at this point in the history
  • Loading branch information
Chikage0o0 committed Oct 15, 2023
1 parent 87b2bba commit 838ace7
Show file tree
Hide file tree
Showing 15 changed files with 781 additions and 64 deletions.
26 changes: 26 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion matrix_bot/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ clap = { version = "4.4.6", features = ["derive", "env"] }
# Optional dependencies
yande_popular = { path = "../plugins/yande_popular", optional = true }
webhook = { path = "../plugins/webhook", optional = true }
qbittorrent = { path = "../plugins/qbittorrent", optional = true }

[features]
default = ["full"]
full = ["yande_popular", "webhook"]
full = ["yande_popular", "webhook", "qbittorrent"]
15 changes: 14 additions & 1 deletion matrix_bot/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use anyhow::Result;
use clap::Parser;
use matrix_bot_core::{
matrix::{self, client::Client},
sdk::SyncSettings,
matrix_sdk::config::SyncSettings,
};

#[derive(Parser, Debug)]
Expand Down Expand Up @@ -106,5 +106,18 @@ pub fn load_plugins(client: &Client, settings_folder: impl AsRef<Path>) -> Resul
});
});
};

#[cfg(feature = "qbittorrent")]
{
let client = client.clone();
let settings_folder = settings_folder.as_ref().to_path_buf();
tokio::spawn(async move {
qbittorrent::run(client, settings_folder)
.await
.unwrap_or_else(|e| {
log::error!("qbittorrent stop: {}", e);
});
});
};
Ok(())
}
4 changes: 1 addition & 3 deletions matrix_bot_core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
pub mod matrix;
pub mod sdk {
pub use matrix_sdk::config::SyncSettings;
}
pub use matrix_sdk;
2 changes: 1 addition & 1 deletion matrix_bot_core/src/matrix/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ impl Client {
let homeserver_url = Url::parse(homeserver_url).expect("Couldn't parse the homeserver URL");

std::fs::create_dir_all(&db_path)?;
std::fs::create_dir_all(&session_file.as_ref().parent().unwrap())?;
std::fs::create_dir_all(session_file.as_ref().parent().unwrap())?;

let mut client = matrix_sdk::Client::builder()
.homeserver_url(&homeserver_url)
Expand Down
48 changes: 35 additions & 13 deletions matrix_bot_core/src/matrix/room.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,16 @@ impl Room {

if let Some(room) = room {
Ok(Room(room))
} else if let Some(room) = client.get_invited_room(room_id.try_into()?) {
room.accept_invitation()
.await
.map_err(|e| anyhow!("Can't accept invitation:{e}"))?;
let room = client
.get_joined_room(room_id.try_into()?)
.ok_or(anyhow!("Can't find room {}", room_id))?;
Ok(Room(room))
} else {
if let Some(room) = client.get_invited_room(room_id.try_into()?) {
room.accept_invitation()
.await
.map_err(|e| anyhow!("Can't accept invitation:{e}"))?;
let room = client
.get_joined_room(room_id.try_into()?)
.ok_or(anyhow!("Can't find room {}", room_id))?;
Ok(Room(room))
} else {
Err(anyhow!("Can't find room {}", room_id))
}
Err(anyhow!("Can't find room {}", room_id))
}
}

Expand Down Expand Up @@ -95,18 +93,42 @@ impl Room {
Ok(())
}

pub async fn send_html(&self, msg: &str, html_msg: &str) -> Result<()> {
let msg = RoomMessageEventContent::text_html(msg, html_msg);

self.0.send(msg, None).await?;

Ok(())
}

pub async fn send_relates_html(&self, msg: &str, html_msg: &str, event_id: &str) -> Result<()> {
let msg = RoomMessageEventContent::text_html(msg, html_msg);

let event_id = OwnedEventId::try_from(event_id)?;
let timeline_event = self.0.event(&event_id).await?;
let event_content = timeline_event.event.deserialize_as::<RoomMessageEvent>()?;
let original_message = event_content.as_original().unwrap();
let msg = msg.make_reply_to(original_message);

self.0.send(msg, None).await?;

Ok(())
}

pub async fn send_relates_msg(
&self,
msg: &str,
event_id: &OwnedEventId,
event_id: &str,
is_markdown: bool,
) -> Result<()> {
let msg = if is_markdown {
RoomMessageEventContent::text_markdown(msg)
} else {
RoomMessageEventContent::text_plain(msg)
};
let timeline_event = self.0.event(event_id).await?;

let event_id = OwnedEventId::try_from(event_id)?;
let timeline_event = self.0.event(&event_id).await?;
let event_content = timeline_event.event.deserialize_as::<RoomMessageEvent>()?;
let original_message = event_content.as_original().unwrap();
let msg = msg.make_reply_to(original_message);
Expand Down
9 changes: 7 additions & 2 deletions plugins/qbittorrent/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,14 @@ matrix_bot_core = { path = "../../matrix_bot_core" }
log = "0.4.14"
toml = "0.8.2"
serde = { version = "1.0.188", features = ["derive"] }
tokio = { version = "1.33.0", default-features = false, features = [] }
tokio = { version = "1.33.0", default-features = false, features = ["macros"] }
qbit-rs = { version = "0.3.7" }
reqwest = { version = "0.11.6", features = ["blocking"] }
reqwest = { version = "0.11.6", features = ["blocking", "multipart", "json"] }
regex = "1.10.0"
once_cell = "1.8.0"
url = "2.4.1"
serde_json = "1.0.68"
walkdir = "2.4.0"

[dev-dependencies]
env_logger = "0.10.0"
59 changes: 55 additions & 4 deletions plugins/qbittorrent/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,67 @@
use std::{collections::HashMap, sync::OnceLock};

use anyhow::Result;
use matrix_bot_core::matrix::client::Client;
use matrix_bot_core::matrix::{client::Client, room::Room};
use qbit_rs::Qbit;
use setting::RoomSetting;

use crate::{
qbit::ops::{expire_torrents, upload_torrents},
setting::Setting,
};

mod matrix;
mod qbit;
mod setting;
mod upload;

static ROOM_MAP: OnceLock<HashMap<String, (Room, RoomSetting)>> = OnceLock::new();
static API: OnceLock<Qbit> = OnceLock::new();

#[allow(unused_variables)]
pub async fn run(client: Client, plugin_folder: impl AsRef<std::path::Path>) -> Result<()> {
log::info!("start yande_popular");

let setting = setting::get_or_init(plugin_folder)?;
let setting = Setting::get_or_init(plugin_folder)?;

#[cfg(target_os = "linux")]
let _child: std::process::Child;
#[cfg(target_os = "linux")]
if setting.use_internal_qbit {
let runtime_folder = PathBuf::from("data/plugins/qbittorrent/runtime");
let port = setting.qbit_url.split(":").last();
let port = port.unwrap_or("80").parse().unwrap_or(80);
_child = qbit::binary::run(&runtime_folder, port)?;
}

let room = setting.to_hashmap(&client).await?;
ROOM_MAP
.set(room)
.map_err(|_| anyhow::anyhow!("ROOM_MAP OnceLock double set"))?;

let api = qbit::ops::login(&setting.qbit_user, &setting.qbit_pass, &setting.qbit_url).await?;
API.set(api)
.map_err(|_| anyhow::anyhow!("API OnceLock double set"))?;

for (room, setting) in ROOM_MAP.get().unwrap().values() {
matrix::add_listener(room);
}

loop {
let (expire, upload) = qbit::ops::scan_torrent(API.get().unwrap()).await?;

expire_torrents(API.get().unwrap(), &expire)
.await
.unwrap_or_else(|e| {
log::error!("expire torrent failed: {}", e);
});


upload_torrents(API.get().unwrap(), &upload)
.await
.unwrap_or_else(|e| {
log::error!("upload torrent failed: {}", e);
});

Ok(())
tokio::time::sleep(std::time::Duration::from_secs(60)).await;
}
}
Loading

0 comments on commit 838ace7

Please sign in to comment.