v2
This commit is contained in:
Generated
+2023
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "letterboxd-sync"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
reqwest = { version = "0.12", features = ["blocking", "rustls-tls"] }
|
||||
scraper = "0.24"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
@@ -0,0 +1,69 @@
|
||||
use reqwest::blocking::Client;
|
||||
use scraper::{Html, Selector};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fs;
|
||||
|
||||
const BASE: &str = "https://letterboxd.com";
|
||||
const LIST: &str = "https://letterboxd.com/mimuuu/list/2026/by/reverse/";
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct FilmJson {
|
||||
name: String,
|
||||
released: Released,
|
||||
directors: Vec<Person>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Released {
|
||||
year: u16,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Person {
|
||||
name: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct Film {
|
||||
title: String,
|
||||
year: u16,
|
||||
director: String,
|
||||
url: String,
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let client = Client::builder().user_agent("Mozilla/5.0").build()?;
|
||||
|
||||
// One request: list page (only to discover the 5 film endpoints)
|
||||
let html = client.get(LIST).send()?.text()?;
|
||||
let doc = Html::parse_document(&html);
|
||||
let selector = Selector::parse("li.posteritem div.react-component")?;
|
||||
|
||||
let mut films = Vec::new();
|
||||
|
||||
for node in doc.select(&selector).take(5) {
|
||||
let details = node.value().attr("data-details-endpoint").unwrap();
|
||||
|
||||
let slug = node.value().attr("data-item-link").unwrap();
|
||||
|
||||
// One request per film: JSON metadata
|
||||
let film: FilmJson = client.get(format!("{BASE}{details}")).send()?.json()?;
|
||||
|
||||
films.push(Film {
|
||||
title: film.name,
|
||||
year: film.released.year,
|
||||
director: film
|
||||
.directors
|
||||
.first()
|
||||
.map(|d| d.name.clone())
|
||||
.unwrap_or_default(),
|
||||
url: format!("{BASE}{slug}"),
|
||||
});
|
||||
}
|
||||
|
||||
fs::create_dir_all("data")?;
|
||||
fs::write("data/films.json", serde_json::to_string_pretty(&films)?)?;
|
||||
|
||||
println!("Saved {} films", films.len());
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc_fingerprint":13028192105755907156,"outputs":{"7971740275564407648":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/home/mimu/.rustup/toolchains/stable-x86_64-unknown-linux-gnu\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n","stderr":""},"17747080675513052775":{"success":true,"status":"","code":0,"stdout":"rustc 1.94.1 (e408947bf 2026-03-25)\nbinary: rustc\ncommit-hash: e408947bfd200af42db322daf0fadfe7e26d3bd1\ncommit-date: 2026-03-25\nhost: x86_64-unknown-linux-gnu\nrelease: 1.94.1\nLLVM version: 21.1.8\n","stderr":""}},"successes":{}}
|
||||
@@ -0,0 +1,3 @@
|
||||
Signature: 8a477f597d28d172789f06886806bc55
|
||||
# This file is a cache directory tag created by cargo.
|
||||
# For information about cache directory tags see https://bford.info/cachedir/
|
||||
Reference in New Issue
Block a user