diff --git a/README.md b/README.md index 13f43b4..3ad12f3 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ You can then visit the frontend at `http://localhost:3000` and the swagger at `h * BLU * BTN * DarkPeers +* DigitalCore * FNP * GGn * HomieHelpDesk diff --git a/backend/migrations/0022_digitalcore_support.sql b/backend/migrations/0022_digitalcore_support.sql new file mode 100644 index 0000000..bd94a78 --- /dev/null +++ b/backend/migrations/0022_digitalcore_support.sql @@ -0,0 +1,2 @@ +INSERT INTO indexers (name, auth_data) VALUES +('DigitalCore', '{"cookies": {"value": "", "explanation": "1) Log in to this tracker. 2) Open up the DevTools. 3) Navigate to the Network tab. 4) Click on the Doc button (Chrome Browser) or HTML button (FireFox). 5) Refresh the page by pressing F5. 6) Click on the first row entry. 7) Select the Headers tab on the Right panel. 8) Find ''cookie:'' in the Request Headers section. 9) Copy the value and paste it here."}}'); diff --git a/backend/src/models/indexer.rs b/backend/src/models/indexer.rs index ae1433f..eaa18b5 100644 --- a/backend/src/models/indexer.rs +++ b/backend/src/models/indexer.rs @@ -10,10 +10,11 @@ use crate::{ services::user_stats::{ aither::AitherScraper, anime_bytes::AnimeBytesScraper, anthelion::AnthelionScraper, blutopia::BlutopiaScraper, broadcasthenet::BroadcasthenetScraper, - darkpeers::DarkPeersScraper, fear_no_peer::FearNoPeerScraper, - gazelle_games::GazelleGamesScraper, homiehelpdesk::HomieHelpDeskScraper, - ita_torrents::ItaTorrentsScraper, lst::LSTScraper, myanonamouse::MyAnonamouseScraper, - oldtoons::OldToonsScraper, only_encodes::OnlyEncodesScraper, orpheus::OrpheusScraper, + darkpeers::DarkPeersScraper, digitalcore::DigitalCoreScraper, + fear_no_peer::FearNoPeerScraper, gazelle_games::GazelleGamesScraper, + homiehelpdesk::HomieHelpDeskScraper, ita_torrents::ItaTorrentsScraper, lst::LSTScraper, + myanonamouse::MyAnonamouseScraper, oldtoons::OldToonsScraper, + only_encodes::OnlyEncodesScraper, orpheus::OrpheusScraper, phoenix_project::PhoenixProjectScraper, rastastugan::RastastuganScraper, redacted::RedactedScraper, reel_flix::ReelFlixScraper, seed_pool::SeedPoolScraper, upload_cx::UploadCXScraper, yoinked::YoinkedScraper, yu_scene::YuSceneScraper, @@ -157,6 +158,10 @@ impl Indexer { static HOMIE_HELP_DESK_SCRAPER: HomieHelpDeskScraper = HomieHelpDeskScraper; &HOMIE_HELP_DESK_SCRAPER } + "DigitalCore" => { + static DIGITAL_CORE_SCRAPER: DigitalCoreScraper = DigitalCoreScraper; + &DIGITAL_CORE_SCRAPER + } _ => { return Err(Error::CouldNotScrapeIndexer( "indexer has no scraper".into(), diff --git a/backend/src/services/user_stats/digitalcore.rs b/backend/src/services/user_stats/digitalcore.rs new file mode 100644 index 0000000..c746565 --- /dev/null +++ b/backend/src/services/user_stats/digitalcore.rs @@ -0,0 +1,113 @@ +use serde::Deserialize; + +use async_trait::async_trait; + +use crate::{ + error::{Error, Result}, + models::{ + indexer::{Indexer, Scraper}, + user_stats::UserProfileScraped, + }, +}; + +#[derive(Debug, Deserialize)] +struct DigitalCoreResponse { + bonuspoang: f64, + downloaded: i64, + downloaded_real: i64, + uploaded: i64, + uploaded_real: i64, + // leechbonus: f32, + #[serde(rename = "peersSeeder")] + peers_seeder: i32, + #[serde(rename = "peersLeecher")] + peers_leecher: i32, + warned: String, + #[serde(rename = "torrentComments")] + torrent_comments: i32, + donor: String, + #[serde(rename = "forumPosts")] + forum_posts: i32, + invitees: i32, +} + +impl From for UserProfileScraped { + fn from(wrapper: DigitalCoreResponse) -> Self { + let ratio = if wrapper.downloaded == 0 && wrapper.uploaded > 0 { + f32::MAX + } else { + wrapper.uploaded as f32 / wrapper.downloaded as f32 + }; + + UserProfileScraped { + uploaded: wrapper.uploaded, + downloaded: wrapper.downloaded, + ratio, + donor: Some(wrapper.donor.eq("yes")), + warned: Some(wrapper.warned.eq("yes")), + seeding: Some(wrapper.peers_seeder), + leeching: Some(wrapper.peers_leecher), + bonus_points: Some(wrapper.bonuspoang as i64), + uploaded_real: Some(wrapper.uploaded_real), + downloaded_real: Some(wrapper.downloaded_real), + torrent_comments: Some(wrapper.torrent_comments), + posts: Some(wrapper.forum_posts), + invited: Some(wrapper.invitees), + ..Default::default() + } + } +} + +pub struct DigitalCoreScraper; + +#[async_trait] +impl Scraper for DigitalCoreScraper { + async fn scrape( + &self, + indexer: Indexer, + client: &reqwest::Client, + ) -> Result { + let cookies = indexer + .auth_data + .get("cookies") + .ok_or("DigitalCore cookies not found.") + .map_err(|e| Error::CouldNotScrapeIndexer(e.into()))? + .get("value") + .ok_or("DigitalCore cookies not found.") + .map_err(|e| Error::CouldNotScrapeIndexer(e.into()))? + .as_str() + .unwrap(); + + if !cookies.contains("uid=") { + return Err(Error::CouldNotScrapeIndexer( + "Cannot find cookie for 'uid'.".to_string(), + )); + } + + if !cookies.contains("pass=") { + return Err(Error::CouldNotScrapeIndexer( + "Cannot find cookie for 'pass'.".to_string(), + )); + } + + let uid_cookie = cookies.split("uid=").collect::>()[1] + .split(";") + .collect::>()[0]; + + let res = client + .get(format!( + "https://digitalcore.club/api/v1/users/{}", + uid_cookie + )) + .header("Cookie", cookies) + .send() + .await + .map_err(|e| Error::CouldNotScrapeIndexer(e.to_string()))?; + + let body = res.text().await.unwrap(); + let response = serde_json::from_str::(&body) + .map_err(|e| Error::CouldNotScrapeIndexer(e.to_string()))?; + + Ok(response.into()) + } +} diff --git a/backend/src/services/user_stats/mod.rs b/backend/src/services/user_stats/mod.rs index 5b3db98..1ae27fd 100644 --- a/backend/src/services/user_stats/mod.rs +++ b/backend/src/services/user_stats/mod.rs @@ -5,6 +5,7 @@ pub mod blutopia; pub mod broadcasthenet; pub mod common; pub mod darkpeers; +pub mod digitalcore; pub mod fear_no_peer; pub mod gazelle_games; pub mod homiehelpdesk;