⫶☰ Table of contents

Angel Blessing Cards App

Screenshot

angel blessing cards screenshot

Download

Fetch youtube playlist

Fetch a youtube playlist and download the thumbnails.

For the youtube v3 api there is a nice crate. Put the config.playlist_id and the config.api_key in the config.toml.

use anyhow::Result;
use clap::Parser;
use futures::future::try_join_all;
use serde::{Deserialize, Serialize};

use youtube::{GoogleAPIRequest, YouTubeDataV3Client, initialize_client};

mod config;
use crate::config::read_config_from_toml;

#[derive(Parser)]
struct Cli {
    output_path: std::path::PathBuf,
}

#[derive(Serialize, Deserialize, Debug)]
struct AngelVideo {
    title: String,
    thumbnail: String,
    position: usize,
    video: String,
}

#[derive(Serialize, Deserialize, Debug)]
struct AngelVideos {
    videos: Vec<AngelVideo>,
}

#[tokio::main]
async fn main() -> Result<()> {
    // Get the config.api.playlist_id and the config.api.key
    let args = Cli::parse();
    let config = read_config_from_toml("config.toml").expect("config.toml error");

    // Initialize the HTTP client
    let client = initialize_client()?;
    // Create YouTube client
    let mut youtube_client =
        YouTubeDataV3Client::new("youtube.googleapis.com".to_string(), client).await;

    // Get playlist information
    let playlist = youtube_client
        .list_playlist_items(config.api.playlist_id, None, None)
        .with_key(&config.api.key)
        .send()
        .await?;

    // Download thumbnails concurrently
    let videos: Vec<AngelVideo> = try_join_all(playlist.items.iter().map(|v| async move {
        let url = v.snippet.thumbnails.default.as_ref().unwrap().url.clone();
        let video_id = v.snippet.resource_id.video_id.clone();
        let thumbnail = format!("{}.jpg", video_id);
        // Download image
        let bytes = reqwest::get(url).await?.bytes().await?;
        // Write file
        tokio::fs::write(&thumbnail, &bytes).await?;
        Ok::<AngelVideo, anyhow::Error>(AngelVideo {
            title: v.snippet.title.to_string(),
            thumbnail,
            position: v.snippet.position as usize,
            video: video_id,
        })
    }))
    .await?;
    let a = AngelVideos { videos };

    let json = serde_json::to_string_pretty(&a)?;
    std::fs::write(args.output_path, json).expect("Unable to write file");
    Ok(())
}

Convert images in parallel to webp