From 3d91521510483b326d23c9ac8224abd0c9c24013 Mon Sep 17 00:00:00 2001 From: syui Date: Sat, 13 Apr 2024 02:05:05 +0900 Subject: [PATCH] add bot custom feed --- .config/ai/scpt | 2 +- README.md | 23 +- at/feed-generator/env | 10 + at/feed-generator/readme.md | 26 ++ at/feed-generator/src/algos/cmd.ts | 43 +++ at/feed-generator/src/algos/index.ts | 14 + at/feed-generator/src/subscription.ts | 50 +++ src/bot.rs | 448 +++++++++++++++++++++++++- src/data.rs | 3 + src/delete_record.rs | 33 ++ src/feed_get.rs | 33 ++ src/main.rs | 53 +++ 12 files changed, 725 insertions(+), 13 deletions(-) create mode 100644 at/feed-generator/env create mode 100644 at/feed-generator/readme.md create mode 100644 at/feed-generator/src/algos/cmd.ts create mode 100644 at/feed-generator/src/algos/index.ts create mode 100644 at/feed-generator/src/subscription.ts create mode 100644 src/delete_record.rs create mode 100644 src/feed_get.rs diff --git a/.config/ai/scpt b/.config/ai/scpt index b16ed58..70595e1 160000 --- a/.config/ai/scpt +++ b/.config/ai/scpt @@ -1 +1 @@ -Subproject commit b16ed585525aa279c1caeae606b8e49cc6589c7a +Subproject commit 70595e19511e7970ecdbe5fe556eef9380a9fbdf diff --git a/README.md b/README.md index ef5dcdf..da289b5 100644 --- a/README.md +++ b/README.md @@ -63,15 +63,19 @@ $ ai bot |command|sub|type|link|auth| |---|---|---|---|---| -|@yui.syui.ai did||mention, reply| [plc.directory](https://plc.directory)/$did/log |user| -|@yui.syui.ai card|r, s, b|mention, reply| [card.syui.ai](https://card.syui.ai) |user| -|@yui.syui.ai ten|start, d, p, coin|mention, reply| [card.syui.ai](https://card.syui.ai) |user| -|@yui.syui.ai fav|{cid}|mention, reply| [card.syui.ai](https://card.syui.ai) |user| -|@yui.syui.ai egg|{password}|mention, reply| [card.syui.ai](https://card.syui.ai) |user| -|@yui.syui.ai 捠い||mention, reply| [yui.syui.ai](https://yui.syui.ai) |user| -|@yui.syui.ai nyan|🍬|mention, reply| [yui.syui.ai](https://yui.syui.ai) |user| -|@yui.syui.ai diffusers|{keyword}|mention, reply| [huggingface.co/diffusers](https://huggingface.co/docs/diffusers/index) |user| -|@yui.syui.ai sh|{command}|mention, reply| [archlinux.org](https://wiki.archlinux.org/title/Systemd-nspawn) |admin| +|/did||mention, reply| [plc.directory](https://plc.directory)/$did/log |user| +|/card|r, s, b|mention, reply| [card.syui.ai](https://card.syui.ai) |user| +|/ten|start, close, d, p|mention, reply| [card.syui.ai](https://card.syui.ai) |user| +|/fav|{cid}|mention, reply| [card.syui.ai](https://card.syui.ai) |user| +|/egg|{password}|mention, reply| [card.syui.ai](https://card.syui.ai) |user| +|/nyan|🍬|mention, reply| [yui.syui.ai](https://yui.syui.ai) |user| +|/diffusers|{keyword}|mention, reply| [huggingface.co/diffusers](https://huggingface.co/docs/diffusers/index) |user| +|/sh|{command}|mention, reply| [archlinux.org](https://wiki.archlinux.org/title/Systemd-nspawn) |admin| +|/捠い||mention, reply| [yui.syui.ai](https://yui.syui.ai) |user| + +```sh +@yui.syui.ai /did +``` ### test @@ -88,7 +92,6 @@ $ cargo install --force cargo-make $ cargo make build ``` - ### docker > .env diff --git a/at/feed-generator/env b/at/feed-generator/env new file mode 100644 index 0000000..7b86bb4 --- /dev/null +++ b/at/feed-generator/env @@ -0,0 +1,10 @@ +FEEDGEN_PORT=3000 +FEEDGEN_LISTENHOST="0.0.0.0" +FEEDGEN_SQLITE_LOCATION="/data/db.sqlite" +FEEDGEN_SUBSCRIPTION_ENDPOINT="wss://bgs.syu.is" +FEEDGEN_PUBLISHER_DID="did:web:feed.syu.is" +FEEDGEN_HOSTNAME="feed.syu.is" + +FEEDGEN_SUBSCRIPTION_RECONNECT_DELAY=3000 +FEEDGEN_PUBLISHER_DID=did:plc:4hqjfn7m6n5hno3doamuhgef +FEEDGEN_SUBSCRIPTION_ENDPOINT="wss://bsky.network" diff --git a/at/feed-generator/readme.md b/at/feed-generator/readme.md new file mode 100644 index 0000000..a1102cc --- /dev/null +++ b/at/feed-generator/readme.md @@ -0,0 +1,26 @@ +# custom feed + +- at://did:plc:4hqjfn7m6n5hno3doamuhgef/app.bsky.feed.generator/cmd +- [bsky.app](https://bsky.app/profile/did:plc:4hqjfn7m6n5hno3doamuhgef/feed/cmd) +- [app.bsky.feed.getFeedSkeleton](https://feed.syu.is/xrpc/app.bsky.feed.getFeedSkeleton?feed=at://did:plc:4hqjfn7m6n5hno3doamuhgef/app.bsky.feed.generator/cmd) + +```sh +did=did:plc:4hqjfn7m6n5hno3doamuhgef +col=app.bsky.feed.generator +cid=cmd +uri=at://$did/$col/$cid + +echo $uri +``` + +## bsky-feed + +```sh +$ git clone https://github.com/bluesky-social/feed-generator +``` + +```sh +docker compose build feed-generator +docker build -t publish_feed -f Dockerfile.feed . +docker run publish_feed +``` diff --git a/at/feed-generator/src/algos/cmd.ts b/at/feed-generator/src/algos/cmd.ts new file mode 100644 index 0000000..bac1f4a --- /dev/null +++ b/at/feed-generator/src/algos/cmd.ts @@ -0,0 +1,43 @@ +import { InvalidRequestError } from '@atproto/xrpc-server' +import { QueryParams } from '../lexicon/types/app/bsky/feed/getFeedSkeleton' +import { AppContext } from '../config' + +// max 15 chars +export const shortname = 'cmd' + +export const handler = async (ctx: AppContext, params: QueryParams) => { + let builder = ctx.db + .selectFrom('post') + .selectAll() + .orderBy('indexedAt', 'desc') + .orderBy('cid', 'desc') + .limit(params.limit) + + if (params.cursor) { + const [indexedAt, cid] = params.cursor.split('::') + if (!indexedAt || !cid) { + throw new InvalidRequestError('malformed cursor') + } + const timeStr = new Date(parseInt(indexedAt, 10)).toISOString() + builder = builder + .where('post.indexedAt', '<', timeStr) + .orWhere((qb) => qb.where('post.indexedAt', '=', timeStr)) + .where('post.cid', '<', cid) + } + const res = await builder.execute() + + const feed = res.map((row) => ({ + post: row.uri, + })) + + let cursor: string | undefined + const last = res.at(-1) + if (last) { + cursor = `${new Date(last.indexedAt).getTime()}::${last.cid}` + } + + return { + cursor, + feed, + } +} diff --git a/at/feed-generator/src/algos/index.ts b/at/feed-generator/src/algos/index.ts new file mode 100644 index 0000000..4490a2d --- /dev/null +++ b/at/feed-generator/src/algos/index.ts @@ -0,0 +1,14 @@ +import { AppContext } from '../config' +import { + QueryParams, + OutputSchema as AlgoOutput, +} from '../lexicon/types/app/bsky/feed/getFeedSkeleton' +import * as cmd from './cmd' + +type AlgoHandler = (ctx: AppContext, params: QueryParams) => Promise + +const algos: Record = { + [cmd.shortname]: cmd.handler, +} + +export default algos diff --git a/at/feed-generator/src/subscription.ts b/at/feed-generator/src/subscription.ts new file mode 100644 index 0000000..e02d09e --- /dev/null +++ b/at/feed-generator/src/subscription.ts @@ -0,0 +1,50 @@ +import { + OutputSchema as RepoEvent, + isCommit, +} from './lexicon/types/com/atproto/sync/subscribeRepos' +import { FirehoseSubscriptionBase, getOpsByType } from './util/subscription' + +export class FirehoseSubscription extends FirehoseSubscriptionBase { + async handleEvent(evt: RepoEvent) { + if (!isCommit(evt)) return + const ops = await getOpsByType(evt) + + // This logs the text of every post off the firehose. + // Just for fun :) + // Delete before actually using + for (const post of ops.posts.creates) { + console.log(post.record.text) + } + + const postsToDelete = ops.posts.deletes.map((del) => del.uri) + const postsToCreate = ops.posts.creates + .filter((create) => { + return create.record.text.match('^/[a-z]') || create.record.text.match('^@ai ') || create.record.text.match('/ai ') || create.record.text.match('^ai '); + //return create.record.text.toLowerCase().includes('alf') + }) + .map((create) => { + // map alf-related posts to a db row + return { + uri: create.uri, + cid: create.cid, + replyParent: create.record?.reply?.parent.uri ?? null, + replyRoot: create.record?.reply?.root.uri ?? null, + indexedAt: new Date().toISOString(), + } + }) + + if (postsToDelete.length > 0) { + await this.db + .deleteFrom('post') + .where('uri', 'in', postsToDelete) + .execute() + } + if (postsToCreate.length > 0) { + await this.db + .insertInto('post') + .values(postsToCreate) + .onConflict((oc) => oc.doNothing()) + .execute() + } + } +} diff --git a/src/bot.rs b/src/bot.rs index 354fd15..0e1e19e 100644 --- a/src/bot.rs +++ b/src/bot.rs @@ -7,6 +7,7 @@ use crate::openai; use crate::refresh; use crate::reply; use crate::reply_link; +use crate::feed_get; use crate::data::c_char; use crate::data::data_scpt; @@ -14,6 +15,7 @@ use crate::data::data_toml; use crate::data::log_file; use crate::data::w_cid; use crate::data::Notify; +use crate::data::Timeline; pub fn c_bot(c: &Context) { let h = async { @@ -108,7 +110,7 @@ pub fn c_bot(c: &Context) { || check_cid_run == false && { reason == "mention" || reason == "reply" } { w_cid(cid.to_string(), log_file(&"n2"), true); - if com == "did" { + if com == "did" || com == "/did" { let link = "https://plc.directory/".to_owned() + &did + &"/log"; let s = 0; let e = link.chars().count(); @@ -421,7 +423,7 @@ pub fn c_bot(c: &Context) { .await; println!("{}", str_rep); w_cid(cid.to_string(), log_file(&"n1"), true); - } else if com == "mitractl" && handle == &admin { + } else if { com == "mitractl" || com == "/mitractl" } && handle == &admin { println!("admin:{}", admin); let output = Command::new(data_scpt(&"ai")) .arg(&"atproto").arg(&"mitra") @@ -508,3 +510,445 @@ pub fn c_bot(c: &Context) { let res = tokio::runtime::Runtime::new().unwrap().block_on(h); return res; } + +pub fn c_bot_feed(c: &Context) { + let mut feed = "at://did:plc:4hqjfn7m6n5hno3doamuhgef/app.bsky.feed.generator/cmd".to_string(); + if c.string_flag("feed").is_ok() { + feed = c.string_flag("feed").unwrap(); + } + let h = async { + let mut notify = feed_get::get_request(feed).await; + if notify == "err" { + refresh(c); + notify = feed_get::get_request("at://did:plc:4hqjfn7m6n5hno3doamuhgef/app.bsky.feed.generator/cmd".to_string()).await; + } + let timeline: Timeline = serde_json::from_str(¬ify).unwrap(); + let n = timeline.feed; + let host = data_toml(&"host"); + let length = &n.len(); + let su = 0..*length; + for i in su { + let handle = &n[i].post.author.handle; + let did = &n[i].post.author.did; + let cid = &n[i].post.cid; + let uri = &n[i].post.uri; + let _time = &n[i].post.indexedAt; + let cid_root = cid; + let uri_root = uri; + let check_cid = w_cid(cid.to_string(), log_file(&"n1"), false); + let check_cid_run = w_cid(cid.to_string(), log_file(&"n2"), false); + + let mut text = ""; + if !n[i].post.record.text.is_none() { + text = &n[i].post.record.text.as_ref().unwrap(); + } + let vec: Vec<&str> = text.split_whitespace().collect(); + let handlev: Vec<&str> = handle.split('.').collect(); + let mut handlev = handlev[0].trim().to_string(); + let mut ten_p = "false"; + + let mut link = "https://card.syui.ai/".to_owned() + &handlev; + let s = 0; + let mut e = link.chars().count(); + + let com = vec[0].trim().to_string(); + let mut prompt = "".to_string(); + let mut prompt_sub = "".to_string(); + let mut prompt_chat = "".to_string(); + + if com == "@ai" || com == "/ai" { + prompt_chat = vec[1..].join(" "); + } else { + prompt = vec[1..].join(" "); + if vec.len() > 1 { + prompt_sub = vec[2..].join(" "); + } + } + + if prompt.is_empty() == false || com.is_empty() == false { + println!("{}", handle); + println!( + "cid:{}\nuri:{}\ncid_root:{}\nuri_root:{}\nhost:{}", + cid, uri, cid_root, uri_root, host + ); + println!("prompt_sub:{}", prompt_sub); + } + + let mut admin = "".to_string(); + if c.string_flag("admin").is_ok() { + admin = c.string_flag("admin").unwrap(); + } + + if check_cid == false + || check_cid_run == false + { + w_cid(cid.to_string(), log_file(&"n2"), true); + if com == "did" || com == "/did" { + let link = "https://plc.directory/".to_owned() + &did + &"/log"; + let s = 0; + let e = link.chars().count(); + let d = "\n".to_owned() + &did.to_string(); + let text_limit = c_char(d); + if text_limit.len() > 3 { + let str_rep = reply_link::post_request( + text_limit.to_string(), + link.to_string(), + s, + e.try_into().unwrap(), + cid.to_string(), + uri.to_string(), + cid_root.to_string(), + uri_root.to_string(), + ) + .await; + w_cid(cid.to_string(), log_file(&"n1"), true); + println!("{}", str_rep); + } + } else if com == "help" || com == "/help" { + let link = "https://git.syui.ai/ai/bot/wiki/help".to_string(); + let s = 0; + let e = link.chars().count(); + let str_rep = reply_link::post_request( + "\n".to_string(), + link.to_string(), + s, + e.try_into().unwrap(), + cid.to_string(), + uri.to_string(), + cid_root.to_string(), + uri_root.to_string(), + ) + .await; + w_cid(cid.to_string(), log_file(&"n1"), true); + println!("{}", str_rep); + } else if { com == "diffusers" || com == "/diffusers" } && handle == &admin{ + let _output = Command::new(data_scpt(&"ai")) + .arg(&"atproto").arg(&"diffusers") + .arg(&handle) + .arg(&did) + .arg(&cid) + .arg(&uri) + .arg(&cid_root) + .arg(&uri_root) + .arg(&host) + .arg(&prompt) + .arg(&prompt_sub) + .output() + .expect("zsh"); + w_cid(cid.to_string(), log_file(&"n1"), true); + } else if com.contains("/捠") == true + || com.contains("/うらăȘい") == true + || com.contains("/うらăȘっお") == true + { + let _output = Command::new(data_scpt(&"ai")) + .arg(&"atproto").arg(&"fortune") + .arg(&handle) + .arg(&did) + .arg(&cid) + .arg(&uri) + .arg(&cid_root) + .arg(&uri_root) + .arg(&host) + .arg(&prompt) + .arg(&prompt_sub) + .output() + .expect("zsh"); + w_cid(cid.to_string(), log_file(&"n1"), true); + } else if com == "card" || com == "/card" { + let output = Command::new(data_scpt(&"ai")) + .arg(&"atproto").arg(&"card") + .arg(&handle) + .arg(&did) + .arg(&cid) + .arg(&uri) + .arg(&cid_root) + .arg(&uri_root) + .arg(&host) + .arg(&prompt) + .arg(&prompt_sub) + .output() + .expect("zsh"); + let d = String::from_utf8_lossy(&output.stdout); + let dd = "\n".to_owned() + &d.to_string(); + let text_limit = c_char(dd); + if text_limit.len() > 3 { + //handlev = handle.replace(".", "-").to_string(); + handlev = d.lines().collect::>()[0].to_string(); + link = "https://card.syui.ai/".to_owned() + &handlev; + e = link.chars().count(); + let str_rep = reply_link::post_request( + text_limit.to_string(), + link.to_string(), + s, + e.try_into().unwrap(), + cid.to_string(), + uri.to_string(), + cid_root.to_string(), + uri_root.to_string(), + ) + .await; + println!("{}", str_rep); + w_cid(cid.to_string(), log_file(&"n1"), true); + } + } else if com == "fav" || com == "/fav" { + let output = Command::new(data_scpt(&"ai")) + .arg(&"atproto").arg(&"fav") + .arg(&handle) + .arg(&did) + .arg(&cid) + .arg(&uri) + .arg(&cid_root) + .arg(&uri_root) + .arg(&host) + .arg(&prompt) + .arg(&prompt_sub) + .output() + .expect("zsh"); + let d = String::from_utf8_lossy(&output.stdout); + let dd = "\n".to_owned() + &d.to_string(); + let text_limit = c_char(dd); + if text_limit.len() > 3 { + handlev = d.lines().collect::>()[0].to_string(); + link = "https://card.syui.ai/".to_owned() + &handlev; + e = link.chars().count(); + let str_rep = reply_link::post_request( + text_limit.to_string(), + link.to_string(), + s, + e.try_into().unwrap(), + cid.to_string(), + uri.to_string(), + cid_root.to_string(), + uri_root.to_string(), + ) + .await; + println!("{}", str_rep); + w_cid(cid.to_string(), log_file(&"n1"), true); + } + } else if com == "egg" || com == "/egg" { + let output = Command::new(data_scpt(&"ai")) + .arg(&"atproto").arg(&"egg") + .arg(&handle) + .arg(&did) + .arg(&cid) + .arg(&uri) + .arg(&cid_root) + .arg(&uri_root) + .arg(&host) + .arg(&prompt) + .arg(&prompt_sub) + .output() + .expect("zsh"); + let d = String::from_utf8_lossy(&output.stdout); + let dd = "\n".to_owned() + &d.to_string(); + let text_limit = c_char(dd); + if text_limit.len() > 3 { + handlev = d.lines().collect::>()[0].to_string(); + link = "https://card.syui.ai/".to_owned() + &handlev; + e = link.chars().count(); + let str_rep = reply_link::post_request( + text_limit.to_string(), + link.to_string(), + s, + e.try_into().unwrap(), + cid.to_string(), + uri.to_string(), + cid_root.to_string(), + uri_root.to_string(), + ) + .await; + println!("{}", str_rep); + w_cid(cid.to_string(), log_file(&"n1"), true); + } + } else if com == "nyan" || com == "/nyan" { + let output = Command::new(data_scpt(&"ai")) + .arg(&"atproto").arg(&"nyan") + .arg(&handle) + .arg(&did) + .arg(&cid) + .arg(&uri) + .arg(&cid_root) + .arg(&uri_root) + .arg(&host) + .arg(&prompt) + .arg(&prompt_sub) + .output() + .expect("zsh"); + let d = String::from_utf8_lossy(&output.stdout); + let dd = "\n".to_owned() + &d.to_string(); + let text_limit = c_char(dd); + println!("{}", text_limit); + if text_limit.len() > 3 { + let str_rep = reply::post_request( + text_limit.to_string(), + cid.to_string(), + uri.to_string(), + cid_root.to_string(), + uri_root.to_string(), + ) + .await; + println!("{}", str_rep); + w_cid(cid.to_string(), log_file(&"n1"), true); + } + } else if com == "ten" || com == "/ten" { + let output = Command::new(data_scpt(&"ai")) + .arg(&"atproto").arg(&"ten") + .arg(&handle) + .arg(&did) + .arg(&cid) + .arg(&uri) + .arg(&cid_root) + .arg(&uri_root) + .arg(&host) + .arg(&prompt) + .arg(&prompt_sub) + .output() + .expect("zsh"); + let d = String::from_utf8_lossy(&output.stdout); + let dd = "\n".to_owned() + &d.to_string(); + let text_limit = c_char(dd); + handlev = d.lines().collect::>()[0].to_string(); + let ten_l = d.lines().collect::>().len(); + println!("handlev {}", handlev); + println!("ten_l {}", ten_l); + if ten_l == 3 { + ten_p = d.lines().collect::>()[1]; + println!("ten_p {}", ten_p); + } + if ten_p != "true" { + link = "https://card.syui.ai/".to_owned() + &handlev; + e = link.chars().count(); + let str_rep = reply_link::post_request( + text_limit.to_string(), + link.to_string(), + s, + e.try_into().unwrap(), + cid.to_string(), + uri.to_string(), + cid_root.to_string(), + uri_root.to_string(), + ) + .await; + println!("{}", str_rep); + } + w_cid(cid.to_string(), log_file(&"n1"), true); + } else if com == "coin" || com == "/coin" { + let output = Command::new(data_scpt(&"ai")) + .arg(&"atproto").arg(&"coin") + .arg(&handle) + .arg(&did) + .arg(&cid) + .arg(&uri) + .arg(&cid_root) + .arg(&uri_root) + .arg(&host) + .arg(&prompt) + .arg(&prompt_sub) + .output() + .expect("zsh"); + let d = String::from_utf8_lossy(&output.stdout); + let dd = "\n".to_owned() + &d.to_string(); + let text_limit = c_char(dd); + handlev = d.lines().collect::>()[0].to_string(); + link = "https://card.syui.ai/".to_owned() + &handlev; + println!("{}", e); + e = link.chars().count(); + if text_limit.len() > 3 { + let str_rep = reply_link::post_request( + text_limit.to_string(), + link.to_string(), + s, + e.try_into().unwrap(), + cid.to_string(), + uri.to_string(), + cid_root.to_string(), + uri_root.to_string(), + ) + .await; + println!("{}", str_rep); + w_cid(cid.to_string(), log_file(&"n1"), true); + } + } else if { com == "sh" || com == "/sh" } && handle == &admin { + println!("admin:{}", admin); + let output = Command::new(data_scpt(&"ai")) + .arg(&"atproto").arg(&"sh") + .arg(&handle) + .arg(&did) + .arg(&cid) + .arg(&uri) + .arg(&cid_root) + .arg(&uri_root) + .arg(&host) + .arg(&prompt) + .arg(&prompt_sub) + .output() + .expect("zsh"); + let d = String::from_utf8_lossy(&output.stdout); + let d = d.to_string(); + let text_limit = c_char(d); + let str_rep = reply::post_request( + text_limit.to_string(), + cid.to_string(), + uri.to_string(), + cid_root.to_string(), + uri_root.to_string(), + ) + .await; + println!("{}", str_rep); + w_cid(cid.to_string(), log_file(&"n1"), true); + } else if { com == "mitractl" || com == "/mitractl" } && handle == &admin { + println!("admin:{}", admin); + let output = Command::new(data_scpt(&"ai")) + .arg(&"atproto").arg(&"mitra") + .arg(&handle) + .arg(&did) + .arg(&cid) + .arg(&uri) + .arg(&cid_root) + .arg(&uri_root) + .arg(&host) + .arg(&prompt) + .arg(&prompt_sub) + .output() + .expect("zsh"); + let d = String::from_utf8_lossy(&output.stdout); + let d = "\n".to_owned() + &d.to_string(); + let text_limit = c_char(d); + link = "https://m.syu.is".to_string(); + e = link.chars().count(); + if text_limit.len() > 3 { + let str_rep = reply_link::post_request( + text_limit.to_string(), + link.to_string(), + s, + e.try_into().unwrap(), + cid.to_string(), + uri.to_string(), + cid_root.to_string(), + uri_root.to_string(), + ) + .await; + println!("{}", str_rep); + w_cid(cid.to_string(), log_file(&"n1"), true); + } + } else if com == "@ai" || com == "/ai" { + let str_openai = openai::post_request(prompt_chat.to_string()).await; + let text_limit = c_char(str_openai); + let str_rep = reply::post_request( + text_limit.to_string(), + cid.to_string(), + uri.to_string(), + cid_root.to_string(), + uri_root.to_string(), + ) + .await; + println!("{}", str_rep); + w_cid(cid.to_string(), log_file(&"n1"), true); + } + println!("---"); + } + } + }; + let res = tokio::runtime::Runtime::new().unwrap().block_on(h); + return res; +} diff --git a/src/data.rs b/src/data.rs index 3f569e6..540a36d 100644 --- a/src/data.rs +++ b/src/data.rs @@ -123,6 +123,7 @@ pub struct BaseUrl { pub follow: String, pub follows: String, pub followers: String, + pub feed_get: String, } pub fn url(s: &str) -> String { @@ -148,6 +149,7 @@ pub fn url(s: &str) -> String { session_refresh: "com.atproto.server.refreshSession".to_string(), session_get: "com.atproto.server.getSession".to_string(), timeline_get: "app.bsky.feed.getTimeline".to_string(), + feed_get: "app.bsky.feed.getFeed".to_string(), timeline_author: "app.bsky.feed.getAuthorFeed".to_string(), like: "app.bsky.feed.like".to_string(), repost: "app.bsky.feed.repost".to_string(), @@ -187,6 +189,7 @@ pub fn url(s: &str) -> String { "follow" => t.to_string() + &baseurl.follow, "follows" => t.to_string() + &baseurl.follows, "followers" => t.to_string() + &baseurl.followers, + "feed_get" => t.to_string() + &baseurl.feed_get, _ => s, } } diff --git a/src/delete_record.rs b/src/delete_record.rs new file mode 100644 index 0000000..1f61212 --- /dev/null +++ b/src/delete_record.rs @@ -0,0 +1,33 @@ +extern crate reqwest; +use crate::data_toml; +use crate::data_refresh; +use crate::url; +use serde_json::json; + +pub async fn post_request(rkey: String, col: String) -> String { + let token = data_refresh(&"access"); + //let did = data_toml(&"did"); + let handle = data_toml(&"handle"); + + let url = url(&"record_delete"); + + let post = Some(json!({ + "repo": handle.to_string(), + "rkey": rkey.to_string(), + "collection": col.to_string() + })); + + let client = reqwest::Client::new(); + let res = client + .post(url) + .json(&post) + .header("Authorization", "Bearer ".to_owned() + &token) + .send() + .await + .unwrap() + .text() + .await + .unwrap(); + + return res; +} diff --git a/src/feed_get.rs b/src/feed_get.rs new file mode 100644 index 0000000..305868c --- /dev/null +++ b/src/feed_get.rs @@ -0,0 +1,33 @@ +extern crate reqwest; +use crate::data_refresh; +use crate::url; + +pub async fn get_request(feed: String) -> String { + let token = data_refresh(&"access"); + let url = url(&"feed_get"); + let feed = feed.to_string(); + //let col = "app.bsky.feed.generator".to_string(); + + let client = reqwest::Client::new(); + let res = client + .get(url) + .query(&[("feed", feed)]) + //.query(&[("feed", feed), ("collection", col)]) + .header("Authorization", "Bearer ".to_owned() + &token) + .send() + .await + .unwrap(); + + let status_ref = res.error_for_status_ref(); + + match status_ref { + Ok(_) => { + return res.text().await.unwrap(); + } + Err(_e) => { + let e = "err".to_string(); + return e; + } + } + +} diff --git a/src/main.rs b/src/main.rs index d403067..6d20abd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ use std::env; use crate::ascii::c_ascii; use crate::bot::c_bot; +use crate::bot::c_bot_feed; use crate::data::c_follow_all; use crate::data::c_openai_key; use crate::data::data_toml; @@ -37,6 +38,8 @@ pub mod repost; pub mod session; pub mod timeline_author; pub mod token; +pub mod feed_get; +pub mod delete_record; fn main() { let args: Vec = env::args().collect(); @@ -59,6 +62,10 @@ fn main() { Flag::new("admin", FlagType::String) .alias("a"), ) + .flag( + Flag::new("feed", FlagType::String) + .alias("f"), + ) .flag( Flag::new("manga_uri", FlagType::String) ) @@ -98,6 +105,12 @@ fn main() { .alias("t") .action(timeline), ) + .command( + Command::new("feed") + .description("feed ") + .alias("f") + .action(feed) + ) .command( Command::new("did") .description("did ") @@ -113,6 +126,16 @@ fn main() { .alias("l"), ) ) + .command( + Command::new("delete") + .description("d ") + .alias("d") + .action(delete) + .flag( + Flag::new("col", FlagType::String) + .alias("c"), + ) + ) .command( Command::new("like") .description("like -u ") @@ -274,6 +297,7 @@ fn bot(c: &Context) { refresh(c); loop { c_bot(c); + c_bot_feed(c); } } @@ -337,6 +361,22 @@ fn notify(c: &Context) { return res; } +fn feed(c: &Context) { + refresh(c); + let feed_d = "at://did:plc:4hqjfn7m6n5hno3doamuhgef/app.bsky.feed.generator/cmd".to_string(); + let h = async { + if c.args.len() == 0 { + let j = feed_get::get_request(feed_d).await; + println!("{}", j); + } else { + let j = feed_get::get_request(c.args[0].to_string()).await; + println!("{}", j); + } + }; + let res = tokio::runtime::Runtime::new().unwrap().block_on(h); + return res; +} + fn did(c: &Context) { refresh(c); let h = async { @@ -386,6 +426,19 @@ fn post(c: &Context) { return res; } +fn delete(c: &Context) { + refresh(c); + let m = c.args[0].to_string(); + let h = async { + if let Ok(col) = c.string_flag("col") { + let str = delete_record::post_request(m.to_string(), col); + println!("{}", str.await); + } + }; + let res = tokio::runtime::Runtime::new().unwrap().block_on(h); + return res; +} + fn like(c: &Context) { refresh(c); let m = c.args[0].to_string();