X454BCZLRPB4JH42LSQZXR3GTPMVVVK2ZUYWLHGUMLB3I6TGXKHAC pub trait FeedQuality {fn level() -> u8 {0}}#[derive(Debug)]pub enum Twitter {/// Editable handleHandle(String),/// Immutable snowflake idSnowflake(u64),}impl ToString for Twitter {fn to_string(&self) -> String {match self {Twitter::Handle(name) => format!("https://x.com/{name}"),Twitter::Snowflake(id) => format!("https://x.com/i/user/{id}"),}}}impl FeedQuality for Twitter {/// Needs nitter instances. Images: doesn't show thumbnails of 2nd videofn level() -> u8 {return 1;}}pub struct Kofi(String);impl ToString for Kofi {fn to_string(&self) -> String {format!("https://ko-fi.com/{}", self.0)}}impl FeedQuality for Kofi {/// Images: only 1 in mail. Needs piping via Mailfn level() -> u8 {return 3;}}pub struct Patreon(String);impl ToString for Patreon {fn to_string(&self) -> String {format!("https://patreon.com/{}", self.0)}}impl FeedQuality for Patreon {/// Images: only 1 in mail. Needs piping via Mailfn level() -> u8 {return 3;}}pub struct FacebookPage(String);impl ToString for FacebookPage {fn to_string(&self) -> String {format!("https://facebook.com/{}", self.0)}}impl FeedQuality for FacebookPage {/// Images: ok, supports multiple. Needs `decode html = disable` in feedme. video: brokenfn level() -> u8 {return 7;}}
use super::*;#[test]fn decode_fb() -> miette::Result<()> {let input = r#"facebook name="abc"facebook name=null id=1234"#;assert_eq!(vec![Facebook {account: Account {name: Some("abc".into()),id: None}},Facebook {account: Account {id: Some(1234),name: None}}],knuffel::parse::<Vec<Facebook>>("", input).unwrap());Ok(())}#[test]fn where_am_i() -> miette::Result<()> {let input = r#"hdhoang "hdhoang.space" {pat name="hdhoang"fb name="hdh0000"twt name="2125" id=21_25} "#;assert_eq!(knuffel::parse::<Vec<Art>>("", input)?,vec![Art {handle: "hdhoang".into(),web: Some("hdhoang.space".into()),link_list: None,pat: Some(Patreon {per_month: 0,account: Account {name: Some("hdhoang".into()),id: None}}),fb: Some(Facebook {account: Account {name: Some("hdh0000".into()),id: None}}),twt: Some(Twitter {account: Account {name: Some("2125".into()),id: Some(2125)}})}]);Ok(())}
fn main() {println!("Hello, world!");
use artlist::*;fn main() -> miette::Result<()> {let accounts = knuffel::parse::<Vec<Art>>("example.kdl",r#"/-twitter name="abcde"/-twitter id=1235art "oglaf" (url)"oglaf.com" {patreon "oglaf" null 0facebook nulltwitter "Oglaf"}"#,)?;dbg! {accounts};Ok(())
mod feeds;
#[derive(Debug, knuffel::Decode)]#[cfg_attr(test, derive(PartialEq))]pub struct Art {/// prominent web handle#[knuffel(node_name)]handle: Name,/// official website, if any#[knuffel(argument, default)]web: Option<Website>,/// linktr.ee, carrd.co, ... and the like#[knuffel(property, default)]link_list: Option<Website>,#[knuffel(child)]pat: Option<Patreon>,#[knuffel(child)]kofi: Option<Kofi>,#[knuffel(child)]fb: Option<Facebook>,#[knuffel(child)]twt: Option<Twitter>,}pub type Name = String;pub type Id = u64;pub type Website = String;/// name-or-id common pattern#[derive(Debug, Default, knuffel::Decode)]#[cfg_attr(test, derive(PartialEq))]pub struct Account {#[knuffel(property)]name: Option<Name>,#[knuffel(property, default)]id: Option<Id>,}/// patreon profile, and monthly support amount#[derive(Debug, knuffel::Decode)]#[cfg_attr(test, derive(PartialEq))]pub struct Patreon {#[knuffel(property, default)]per_month: u8,#[knuffel(flatten(property))]account: Account,}/// ko-fi profile, and monthly support amount#[derive(Debug, knuffel::Decode)]#[cfg_attr(test, derive(PartialEq))]pub struct Kofi {#[knuffel(property, default)]per_month: u8,#[knuffel(flatten(property))]account: Account,}/// fb profile#[derive(Debug, knuffel::Decode)]#[cfg_attr(test, derive(PartialEq))]pub struct Facebook {#[knuffel(flatten(property))]account: Account,}impl ToString for Facebook {fn to_string(&self) -> String {self.account.id.map(|n| format!("https://facebook.com/profile?id={n}")).or(self.account.name.clone()).map(|n| format!("https://fb.me/{n}")).expect("both snowflake and username are missing")}}/// twt/X profile#[derive(Debug, knuffel::Decode)]#[cfg_attr(test, derive(PartialEq))]pub struct Twitter {#[knuffel(flatten(property))]account: Account,}impl ToString for Twitter {fn to_string(&self) -> String {self.account.id.map(|n| format!("https://x.com/i/user/{n}")).or(self.account.name.clone()).map(|n| format!("https://x.com/{n}")).expect("both snowflake and username are missing")}}#[cfg(test)]mod tests;
document {info {title "Artist list schema" lang="en"license "CC0"}}
# -*- mode: conf-space -*-
/* These are the artistsWhose lives are on a brink.And wherever they are,We won't forget*//* Most account handles can have- (text) name- (numeric) ID, eg snowflakeIDs are allocated once, and are innate.DNS and bsky handles are textual, innate IDs.*/perry-bible-fellowship"909sickle" "https://909sickle.net/about" \{twitter name="909sickle"fb id=100066857361008alias "swb"(ended)date "2018-02-11"title}