mirror of
https://github.com/nadimkobeissi/mkbsd.git
synced 2025-06-08 07:37:19 -04:00
Merge 0749148a7d
into 82e50c64f0
This commit is contained in:
commit
b3dcf41c94
5 changed files with 1554 additions and 26 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,2 +1,3 @@
|
||||||
.DS_Store
|
.DS_Store
|
||||||
downloads
|
downloads
|
||||||
|
MKBSD/target
|
||||||
|
|
1349
MKBSD/Cargo.lock
generated
Normal file
1349
MKBSD/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
12
MKBSD/Cargo.toml
Normal file
12
MKBSD/Cargo.toml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
[package]
|
||||||
|
name = "MKBSD"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
reqwest = { version = "0.12.7", features = ["json", "blocking"] }
|
||||||
|
tokio = { version = "1.40", features = ["full"] }
|
||||||
|
url = "2.5.2"
|
||||||
|
serde = { version = "1.0.210", features = ["derive"] }
|
||||||
|
serde_json = "1.0.128"
|
||||||
|
futures = "0.3.30"
|
124
MKBSD/src/main.rs
Normal file
124
MKBSD/src/main.rs
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
// Licensed under the WTFPL License
|
||||||
|
|
||||||
|
use futures::future::join_all;
|
||||||
|
use reqwest::Client;
|
||||||
|
use serde_json::Value;
|
||||||
|
use std::fs::{self, File};
|
||||||
|
use std::io::Write;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::time::Duration;
|
||||||
|
use tokio::time::sleep;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
const URL: &str = "https://storage.googleapis.com/panels-api/data/20240916/media-1a-i-p~s";
|
||||||
|
const DOWNLOAD_DIR: &str = "downloads";
|
||||||
|
|
||||||
|
async fn download_image(
|
||||||
|
client: &Client,
|
||||||
|
image_url: &str,
|
||||||
|
file_path: &Path,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let response = client.get(image_url).send().await?;
|
||||||
|
|
||||||
|
if !response.status().is_success() {
|
||||||
|
return Err(format!("Failed to download image: {}", response.status()).into());
|
||||||
|
}
|
||||||
|
|
||||||
|
let content = response.bytes().await?;
|
||||||
|
let mut file = File::create(file_path)?;
|
||||||
|
file.write_all(&content)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn main_task() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let client = Client::new();
|
||||||
|
|
||||||
|
// Fetch the JSON data
|
||||||
|
let response = client.get(URL).send().await?;
|
||||||
|
if !response.status().is_success() {
|
||||||
|
return Err(format!("⛔ Failed to fetch JSON file: {}", response.status()).into());
|
||||||
|
}
|
||||||
|
|
||||||
|
let json_data: Value = response.json().await?;
|
||||||
|
let data = json_data
|
||||||
|
.get("data")
|
||||||
|
.ok_or("⛔ JSON does not have a 'data' property at its root.")?;
|
||||||
|
|
||||||
|
// Create download directory if it doesn't exist
|
||||||
|
let download_dir = Path::new(DOWNLOAD_DIR);
|
||||||
|
if !download_dir.exists() {
|
||||||
|
fs::create_dir_all(download_dir)?;
|
||||||
|
println!("📁 Created directory: {:?}", download_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut file_index = 1;
|
||||||
|
let mut download_tasks = vec![];
|
||||||
|
|
||||||
|
for (_key, subproperty) in data.as_object().unwrap().iter() {
|
||||||
|
if let Some(subproperty) = subproperty.as_object() {
|
||||||
|
if let Some(image_url) = subproperty.get("dhd").and_then(|v| v.as_str()) {
|
||||||
|
println!("🔍 Found image URL!");
|
||||||
|
|
||||||
|
// Parse URL to get the file extension
|
||||||
|
let parsed_url = Url::parse(image_url)?;
|
||||||
|
let ext = Path::new(parsed_url.path())
|
||||||
|
.extension()
|
||||||
|
.and_then(|e| e.to_str())
|
||||||
|
.unwrap_or("jpg");
|
||||||
|
|
||||||
|
let filename = format!("{}.{ext}", file_index);
|
||||||
|
let file_path = download_dir.join(filename);
|
||||||
|
|
||||||
|
let client_clone = client.clone();
|
||||||
|
let image_url_clone = image_url.to_string();
|
||||||
|
let file_path_clone = file_path.clone();
|
||||||
|
|
||||||
|
// Spawn a new task for each download
|
||||||
|
let download_task = tokio::spawn(async move {
|
||||||
|
if let Err(e) =
|
||||||
|
download_image(&client_clone, &image_url_clone, &file_path_clone).await
|
||||||
|
{
|
||||||
|
eprintln!("Error downloading {}: {}", image_url_clone, e);
|
||||||
|
} else {
|
||||||
|
println!("🖼️ Saved image to {:?}", file_path_clone);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
download_tasks.push(download_task);
|
||||||
|
file_index += 1;
|
||||||
|
sleep(Duration::from_millis(250)).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for all download tasks to complete
|
||||||
|
join_all(download_tasks).await;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ascii_art() {
|
||||||
|
println!(
|
||||||
|
r#"
|
||||||
|
/$$ /$$ /$$ /$$ /$$$$$$$ /$$$$$$ /$$$$$$$
|
||||||
|
| $$$ /$$$| $$ /$$/| $$__ $$ /$$__ $$| $$__ $$
|
||||||
|
| $$$$ /$$$$| $$ /$$/ | $$ \ $$| $$ \__/| $$ \ $$
|
||||||
|
| $$ $$/$$ $$| $$$$$/ | $$$$$$$ | $$$$$$ | $$ | $$
|
||||||
|
| $$ $$$| $$| $$ $$ | $$__ $$ \____ $$| $$ | $$
|
||||||
|
| $$\ $ | $$| $$\ $$ | $$ \ $$ /$$ \ $$| $$ | $$
|
||||||
|
| $$ \/ | $$| $$ \ $$| $$$$$$$/| $$$$$$/| $$$$$$$/
|
||||||
|
|__/ |__/|__/ \__/|_______/ \______/ |_______/
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
println!("🤑 Starting downloads from your favorite sellout grifter's wallpaper app...");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
ascii_art();
|
||||||
|
sleep(Duration::from_secs(5)).await;
|
||||||
|
if let Err(e) = main_task().await {
|
||||||
|
eprintln!("Error: {}", e);
|
||||||
|
}
|
||||||
|
}
|
44
README.md
44
README.md
|
@ -13,7 +13,7 @@ _Because selling out is bad_
|
||||||
|
|
||||||
## How to use
|
## How to use
|
||||||
|
|
||||||
MKBSD comes in two variants! Node.js and Python.
|
MKBSD comes in three variants! Node.js, Python, and Rust.
|
||||||
|
|
||||||
### Running in Node.js
|
### Running in Node.js
|
||||||
|
|
||||||
|
@ -30,6 +30,48 @@ MKBSD comes in two variants! Node.js and Python.
|
||||||
4. Wait a little.
|
4. Wait a little.
|
||||||
5. All wallpapers are now in a newly created `downloads` subfolder.
|
5. All wallpapers are now in a newly created `downloads` subfolder.
|
||||||
|
|
||||||
|
### Running in Rust
|
||||||
|
|
||||||
|
1. **Install Rust and Cargo**
|
||||||
|
- If you haven't already, install Rust and Cargo by following the instructions at [rustup.rs](https://rustup.rs/).
|
||||||
|
|
||||||
|
2. **Navigate to the Rust Implementation Directory**
|
||||||
|
- Open your terminal or command prompt.
|
||||||
|
- Navigate to the directory containing the Rust implementation.
|
||||||
|
```bash
|
||||||
|
cd MKBSD
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Build the Project**
|
||||||
|
- Run the following command to build the project in release mode:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo build --release
|
||||||
|
```
|
||||||
|
|
||||||
|
- This will create an optimized executable in the `target/release` directory.
|
||||||
|
|
||||||
|
4. **Run the Executable**
|
||||||
|
- After building, run the executable:
|
||||||
|
|
||||||
|
- On Linux/macOS:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./target/release/mkbsd
|
||||||
|
```
|
||||||
|
|
||||||
|
- On Windows:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
.\target\release\mkbsd.exe
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **Wait for the Process to Complete**
|
||||||
|
- The program will start downloading wallpapers. Wait until it finishes.
|
||||||
|
|
||||||
|
6. **Find Your Wallpapers**
|
||||||
|
- All wallpapers are now in a newly created `downloads` subfolder.
|
||||||
|
|
||||||
## FAQ
|
## FAQ
|
||||||
|
|
||||||
### Q: What's the story behind this?
|
### Q: What's the story behind this?
|
||||||
|
|
Loading…
Add table
Reference in a new issue