Skip to content

Commit dccc131

Browse files
committed
[Twitter] Support multiple accounts
1 parent c396c6d commit dccc131

File tree

5 files changed

+57
-32
lines changed

5 files changed

+57
-32
lines changed

README.md

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,22 +33,26 @@ Create a configuration file with the following example format:
3333
```toml
3434
interval = '1min' # update interval for each subscription
3535

36+
# setup platform global configuration
37+
[platform.Twitter.account.MyTwitterAccount]
38+
cookies = "..."
39+
3640
[notify]
3741
# define a target of notifications with name `Personal`
3842
# notifications will be pushed to Telegram chat `@my_follows` under thread ID `114`
3943
Personal = { platform = "Telegram", username = "my_follows", thread_id = 114, token_env = "PERSONAL_TELEGRAM_BOT_TOKEN" }
40-
# define a target of notifications with name `Suzume`
41-
Suzume = { platform = "Telegram", id = 1145141919, token = "1234567890:AbCdEfGhiJkLmNoPq1R2s3T4u5V6w7X8y9z" }
44+
# define a target of notifications with name `SuzumeChannel`
45+
SuzumeChannel = { platform = "Telegram", id = 1145141919, token = "1234567890:AbCdEfGhiJkLmNoPq1R2s3T4u5V6w7X8y9z" }
4246

4347
[[subscription.Suzume]] # define a subscription with name `Suzume`
4448
# specify the platform and parameters
4549
platform = { name = "bilibili.live", user_id = 6610851 }
4650
# reference to notify defined above, notifications will be pushed when the status changed
47-
notify = ["Suzume"]
51+
notify = ["SuzumeChannel"]
4852

4953
[[subscription.Suzume]]
50-
platform = { name = "Twitter", username = "suzumiyasuzume" }
51-
notify = ["Suzume", "Personal"]
54+
platform = { name = "Twitter", username = "suzumiyasuzume", as = "MyTwitterAccount" }
55+
notify = ["SuzumeChannel", "Personal"]
5256

5357
[[subscription.CookieBacon]] # define a subscription with name `CookieBacon`
5458
platform = { name = "bilibili.live", user_id = 14172231 }
@@ -58,7 +62,9 @@ notify = [ { to = "Personal", thread_id = 514 } ]
5862
```
5963

6064
> [!NOTE]
61-
> This project is in an initial development phase, this configuration may frequently undergo breaking changes in releases.
65+
> This project is in an initial development phase, the configuration format may frequently undergo breaking changes in releases.
66+
>
67+
> The above example is incomplete, and there is currently no documentation. Please check the code for unit tests related to configuration for more detailed usage, and [open an issue](https://github.com/SpriteOvO/closely/issues/new) if you need help.
6268
6369
### 2. Build and Run
6470

src/config/mod.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -308,8 +308,8 @@ lagrange = { remote_http = { host = "localhost", port = 8000 } }
308308
[platform.Telegram]
309309
token = "ttt"
310310
311-
[platform.Twitter]
312-
auth = { cookies = "a=b;c=d;ct0=blah" }
311+
[platform.Twitter.account.MyTwitter]
312+
cookies = "a=b;c=d;ct0=blah"
313313
314314
[platform.bilibili]
315315
playback = { bililive_recorder = { listen_webhook = { host = "127.0.0.1", port = 8888 }, working_directory = "/brec/" } }
@@ -324,11 +324,11 @@ interval = '30s'
324324
notify = ["meow"]
325325
326326
[[subscription.meow]]
327-
platform = { name = "Twitter", username = "meowww" }
327+
platform = { name = "Twitter", username = "meowww", as = "MyTwitter" }
328328
notify = ["meow", "woof"]
329329
330330
[[subscription.meow]]
331-
platform = { name = "Twitter", username = "meowww2" }
331+
platform = { name = "Twitter", username = "meowww2", as = "MyTwitter" }
332332
notify = ["meow", "woof", { ref = "woof", id = 123 }]
333333
"#,
334334
|c| {
@@ -365,7 +365,7 @@ notify = ["meow", "woof", { ref = "woof", id = 123 }]
365365
experimental: Default::default()
366366
})),
367367
twitter: Accessor::new(Some(twitter::ConfigGlobal {
368-
auth: twitter::ConfigCookies::with_raw("a=b;c=d;ct0=blah")
368+
account: HashMap::from_iter([("MyTwitter".into(), Accessor::new(twitter::ConfigCookies::with_raw("a=b;c=d;ct0=blah")))])
369369
})),
370370
bilibili: Accessor::new(Some(bilibili::ConfigGlobal {
371371
playback: Accessor::new(Some(bilibili::source::playback::ConfigGlobal {
@@ -420,7 +420,8 @@ notify = ["meow", "woof", { ref = "woof", id = 123 }]
420420
SubscriptionRaw {
421421
platform: Accessor::new(SourceConfig::Twitter(
422422
Accessor::new(twitter::source::ConfigParams {
423-
username: "meowww".into()
423+
username: "meowww".into(),
424+
actor: "MyTwitter".into()
424425
})
425426
)),
426427
interval: None,
@@ -432,7 +433,8 @@ notify = ["meow", "woof", { ref = "woof", id = 123 }]
432433
SubscriptionRaw {
433434
platform: Accessor::new(SourceConfig::Twitter(
434435
Accessor::new(twitter::source::ConfigParams {
435-
username: "meowww2".into()
436+
username: "meowww2".into(),
437+
actor: "MyTwitter".into()
436438
})
437439
)),
438440
interval: None,

src/platform/qq/notify/mod.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ pub struct ConfigParams {
2323
pub chat: ConfigChat,
2424
#[serde(default)]
2525
pub mention_all: bool,
26-
pub from: String,
26+
#[serde(rename = "as")]
27+
pub actor: String,
2728
}
2829

2930
impl Validator for ConfigParams {
@@ -34,8 +35,8 @@ impl Validator for ConfigParams {
3435
.as_ref()
3536
.ok_or_else(|| anyhow!("QQ in global is missing"))?
3637
.account
37-
.get(&self.from)
38-
.ok_or_else(|| anyhow!("QQ account '{}' is not configured", self.from))?;
38+
.get(&self.actor)
39+
.ok_or_else(|| anyhow!("QQ account '{}' is not configured", self.actor))?;
3940
ensure!(
4041
!self.mention_all || matches!(self.chat, ConfigChat::GroupId(_)),
4142
"mention_all can only be enabled for group chat"
@@ -46,7 +47,7 @@ impl Validator for ConfigParams {
4647

4748
impl fmt::Display for ConfigParams {
4849
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49-
write!(f, "QQ:{},as={}", self.chat, self.from)?;
50+
write!(f, "QQ:{},as={}", self.chat, self.actor)?;
5051
Ok(())
5152
}
5253
}
@@ -58,7 +59,8 @@ pub struct ConfigOverride {
5859
#[serde(flatten)]
5960
pub chat: Option<ConfigChat>,
6061
pub mention_all: Option<bool>,
61-
pub from: Option<String>,
62+
#[serde(rename = "as")]
63+
pub actor: Option<String>,
6264
}
6365

6466
impl Overridable for ConfigParams {
@@ -75,7 +77,7 @@ impl Overridable for ConfigParams {
7577
},
7678
chat: new.chat.unwrap_or(self.chat),
7779
mention_all: new.mention_all.unwrap_or(self.mention_all),
78-
from: new.from.unwrap_or(self.from),
80+
actor: new.actor.unwrap_or(self.actor),
7981
}
8082
}
8183
}
@@ -109,7 +111,7 @@ impl Notifier {
109111
.as_ref()
110112
.unwrap()
111113
.account
112-
.get(&params.from)
114+
.get(&params.actor)
113115
.unwrap()
114116
.lagrange,
115117
);

src/platform/twitter/mod.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,30 @@
11
mod request;
22
pub(crate) mod source;
33

4+
use std::collections::HashMap;
5+
6+
use request::TwitterCookies;
47
use serde::Deserialize;
58

6-
use crate::{config::Validator, secret_enum};
9+
use crate::{
10+
config::{Accessor, AsSecretRef, Validator},
11+
secret_enum,
12+
};
713

814
// Global
915
//
1016

1117
#[derive(Clone, Debug, PartialEq, Deserialize)]
1218
pub struct ConfigGlobal {
13-
pub auth: ConfigCookies,
19+
pub account: HashMap<String, Accessor<ConfigCookies>>,
1420
}
1521

1622
impl Validator for ConfigGlobal {
1723
fn validate(&self) -> anyhow::Result<()> {
18-
self.auth.validate()?;
24+
for account in self.account.values() {
25+
account.validate()?;
26+
TwitterCookies::new(account.as_secret_ref().get_str()?)?;
27+
}
1928
Ok(())
2029
}
2130
}

src/platform/twitter/source/mod.rs

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::{
66
sync::Mutex as StdMutex,
77
};
88

9-
use anyhow::{anyhow, bail};
9+
use anyhow::anyhow;
1010
use chrono::DateTime;
1111
use once_cell::sync::Lazy;
1212
use serde::Deserialize;
@@ -27,17 +27,21 @@ use crate::{
2727
#[derive(Clone, Debug, PartialEq, Deserialize)]
2828
pub struct ConfigParams {
2929
pub username: String,
30+
#[serde(rename = "as")]
31+
pub actor: String,
3032
}
3133

3234
impl Validator for ConfigParams {
3335
fn validate(&self) -> anyhow::Result<()> {
34-
match &*Config::global().platform().twitter {
35-
Some(global_twitter) => {
36-
TwitterCookies::new(global_twitter.auth.as_secret_ref().get_str()?)?;
37-
Ok(())
38-
}
39-
None => bail!("cookies in global are missing"),
40-
}
36+
let _account = Config::global()
37+
.platform()
38+
.twitter
39+
.as_ref()
40+
.ok_or_else(|| anyhow!("Twitter in global is missing"))?
41+
.account
42+
.get(&self.actor)
43+
.ok_or_else(|| anyhow!("Twitter account '{}' is not configured", self.actor))?;
44+
Ok(())
4145
}
4246
}
4347

@@ -357,7 +361,9 @@ impl Fetcher {
357361
.twitter
358362
.as_ref()
359363
.unwrap()
360-
.auth
364+
.account
365+
.get(&params.actor)
366+
.unwrap()
361367
.as_secret_ref()
362368
.get_str()
363369
.unwrap();

0 commit comments

Comments
 (0)