X454BCZLRPB4JH42LSQZXR3GTPMVVVK2ZUYWLHGUMLB3I6TGXKHAC
pub trait FeedQuality {
fn level() -> u8 {
0
}
}
#[derive(Debug)]
pub enum Twitter {
/// Editable handle
Handle(String),
/// Immutable snowflake id
Snowflake(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 video
fn 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 Mail
fn 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 Mail
fn 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: broken
fn 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=1235
art "oglaf" (url)"oglaf.com" {
patreon "oglaf" null 0
facebook null
twitter "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 artists
Whose lives are on a brink.
And wherever they are,
We won't forget
*/
/* Most account handles can have
- (text) name
- (numeric) ID, eg snowflake
IDs 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=100066857361008
alias "swb"
(ended)date "2018-02-11"
title
}