From 85e5c3e0e5b6931314da15ea2e8677cf85b602ad Mon Sep 17 00:00:00 2001 From: Asuna Date: Sun, 30 Jun 2024 23:21:03 +0800 Subject: [PATCH] Support enabling spoiler for media --- src/notify/telegram/mod.rs | 16 +++++--- src/notify/telegram/request.rs | 67 +++++++++++++++++++++++++--------- src/source/bilibili/space.rs | 6 +++ src/source/bilibili/video.rs | 1 + src/source/mod.rs | 21 +++++++++-- src/source/twitter/mod.rs | 6 +++ 6 files changed, 91 insertions(+), 26 deletions(-) diff --git a/src/notify/telegram/mod.rs b/src/notify/telegram/mod.rs index 97f8a28..0124523 100644 --- a/src/notify/telegram/mod.rs +++ b/src/notify/telegram/mod.rs @@ -207,7 +207,13 @@ impl Notifier { let text = make_live_text(&title_history, live_status, source); let resp = Request::new(&token) - .send_photo(&self.params.chat, &live_status.cover_image_url) + .send_photo( + &self.params.chat, + MediaPhoto { + url: &live_status.cover_image_url, + has_spoiler: false, + }, + ) .thread_id_opt(self.params.thread_id) .text(text) .send() @@ -431,10 +437,10 @@ impl Notifier { match attachment { PostAttachment::Image(image) => { // TODO: `sendAnimation` for single GIF? - Request::new(token).send_photo(&self.params.chat, &image.media_url) + Request::new(token).send_photo(&self.params.chat, image.into()) } PostAttachment::Video(video) => { - Request::new(token).send_video(&self.params.chat, &video.media_url) + Request::new(token).send_video(&self.params.chat, video.into()) } } .text(text) @@ -468,8 +474,8 @@ impl Notifier { let medias = attachments.iter().map(|attachment| match attachment { // TODO: Mixing GIF in media group to send is not yet supported in Telegram, add // an overlay like video? (see comment in twitter.com implementation) - PostAttachment::Image(image) => Media::Photo(&image.media_url), - PostAttachment::Video(video) => Media::Video(&video.media_url), + PostAttachment::Image(image) => Media::Photo(image.into()), + PostAttachment::Video(video) => Media::Video(video.into()), }); Request::new(token) diff --git a/src/notify/telegram/request.rs b/src/notify/telegram/request.rs index ce6f366..14dd636 100644 --- a/src/notify/telegram/request.rs +++ b/src/notify/telegram/request.rs @@ -14,6 +14,7 @@ use serde_json::{self as json, json}; use spdlog::prelude::*; use super::ConfigChat; +use crate::source::{PostAttachmentImage, PostAttachmentVideo}; pub struct Request<'a> { token: &'a str, @@ -110,7 +111,7 @@ impl<'a> Request<'a> { } } - pub fn send_photo(self, chat: &'a ConfigChat, photo: &'a str) -> SendMedia<'a> { + pub fn send_photo(self, chat: &'a ConfigChat, photo: MediaPhoto<'a>) -> SendMedia<'a> { SendMedia { base: self, chat, @@ -122,7 +123,7 @@ impl<'a> Request<'a> { } } - pub fn send_video(self, chat: &'a ConfigChat, video: &'a str) -> SendMedia<'a> { + pub fn send_video(self, chat: &'a ConfigChat, video: MediaVideo<'a>) -> SendMedia<'a> { SendMedia { base: self, chat, @@ -303,8 +304,36 @@ impl<'a> SendMessage<'a> { } pub enum Media<'a> { - Photo(&'a str), // TODO: Make a enum for it - Video(&'a str), + Photo(MediaPhoto<'a>), + Video(MediaVideo<'a>), +} + +pub struct MediaPhoto<'a> { + pub url: &'a str, + pub has_spoiler: bool, +} + +impl<'a> From<&'a PostAttachmentImage> for MediaPhoto<'a> { + fn from(value: &'a PostAttachmentImage) -> Self { + Self { + url: &value.media_url, + has_spoiler: value.has_spoiler, + } + } +} + +pub struct MediaVideo<'a> { + pub url: &'a str, + pub has_spoiler: bool, +} + +impl<'a> From<&'a PostAttachmentVideo> for MediaVideo<'a> { + fn from(value: &'a PostAttachmentVideo) -> Self { + Self { + url: &value.media_url, + has_spoiler: value.has_spoiler, + } + } } pub struct SendMedia<'a> { @@ -365,14 +394,16 @@ impl<'a> SendMedia<'a> { "disable_notification": self.disable_notification } ); - let (method, url) = match self.media { - Media::Photo(url) => { - body["photo"] = url.into(); - ("sendPhoto", url) + let (method, url) = match &self.media { + Media::Photo(photo) => { + body["photo"] = photo.url.into(); + body["has_spoiler"] = photo.has_spoiler.into(); + ("sendPhoto", photo.url) } - Media::Video(url) => { - body["video"] = url.into(); - ("sendVideo", url) + Media::Video(video) => { + body["video"] = video.url.into(); + body["has_spoiler"] = video.has_spoiler.into(); + ("sendVideo", video.url) } }; if let Some(text) = self.text { @@ -467,16 +498,18 @@ impl<'a> SendMediaGroup<'a> { .medias .iter() .map(|media| match media { - Media::Photo(url) => { + Media::Photo(photo) => { json!({ "type": "photo", - "media": url, + "media": photo.url, + "has_spoiler": photo.has_spoiler, }) } - Media::Video(url) => { + Media::Video(video) => { json!({ "type": "video", - "media": url, + "media": video.url, + "has_spoiler": video.has_spoiler, }) } }) @@ -508,8 +541,8 @@ impl<'a> SendMediaGroup<'a> { .map(|(i, (media, kind))| { media["media"] = format_attach_url(i).into(); match kind { - Media::Photo(url) => FileUrl::new_photo(url), - Media::Video(url) => FileUrl::new_video(url), + Media::Photo(photo) => FileUrl::new_photo(photo.url), + Media::Video(video) => FileUrl::new_video(video.url), } }) .collect::>(); diff --git a/src/source/bilibili/space.rs b/src/source/bilibili/space.rs index b805c74..4588f38 100644 --- a/src/source/bilibili/space.rs +++ b/src/source/bilibili/space.rs @@ -537,12 +537,14 @@ fn parse_response(resp: data::SpaceHistory) -> anyhow::Result { .map(|pic| { PostAttachment::Image(PostAttachmentImage { media_url: upgrade_to_https(&pic.url), + has_spoiler: false, }) }) .collect(), data::ModuleDynamicMajor::Archive(archive) => { vec![PostAttachment::Image(PostAttachmentImage { media_url: upgrade_to_https(&archive.archive.cover), + has_spoiler: false, })] } data::ModuleDynamicMajor::Article(article) => article @@ -552,6 +554,7 @@ fn parse_response(resp: data::SpaceHistory) -> anyhow::Result { .map(|cover| { PostAttachment::Image(PostAttachmentImage { media_url: upgrade_to_https(cover), + has_spoiler: false, }) }) .collect(), @@ -562,17 +565,20 @@ fn parse_response(resp: data::SpaceHistory) -> anyhow::Result { .map(|item| { PostAttachment::Image(PostAttachmentImage { media_url: upgrade_to_https(&item.src), + has_spoiler: false, }) }) .collect(), data::ModuleDynamicMajor::Common(common) => { vec![PostAttachment::Image(PostAttachmentImage { media_url: upgrade_to_https(&common.common.cover), + has_spoiler: false, })] } data::ModuleDynamicMajor::Pgc(pgc) => { vec![PostAttachment::Image(PostAttachmentImage { media_url: upgrade_to_https(&pgc.pgc.cover), + has_spoiler: false, })] } data::ModuleDynamicMajor::LiveRcmd => unreachable!(), diff --git a/src/source/bilibili/video.rs b/src/source/bilibili/video.rs index d23bd04..1ed91a7 100644 --- a/src/source/bilibili/video.rs +++ b/src/source/bilibili/video.rs @@ -131,6 +131,7 @@ fn parse_response(resp: data::SeriesArchives) -> anyhow::Result { repost_from: None, attachments: vec![PostAttachment::Image(PostAttachmentImage { media_url: upgrade_to_https(&archive.pic), + has_spoiler: false, })], }) .collect(); diff --git a/src/source/mod.rs b/src/source/mod.rs index 182427f..9edd2cb 100644 --- a/src/source/mod.rs +++ b/src/source/mod.rs @@ -253,21 +253,34 @@ impl Post { } } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq)] pub enum PostAttachment { Image(PostAttachmentImage), - #[allow(dead_code)] Video(PostAttachmentVideo), } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug)] pub struct PostAttachmentImage { pub media_url: String, + pub has_spoiler: bool, +} + +impl PartialEq for PostAttachmentImage { + fn eq(&self, other: &Self) -> bool { + self.media_url.eq(&other.media_url) + } } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug)] pub struct PostAttachmentVideo { pub media_url: String, + pub has_spoiler: bool, +} + +impl PartialEq for PostAttachmentVideo { + fn eq(&self, other: &Self) -> bool { + self.media_url.eq(&other.media_url) + } } #[derive(Debug, Eq, PartialEq)] diff --git a/src/source/twitter/mod.rs b/src/source/twitter/mod.rs index 4b4fd0a..ca8d7b6 100644 --- a/src/source/twitter/mod.rs +++ b/src/source/twitter/mod.rs @@ -477,6 +477,8 @@ fn parse_tweet(tweet: data::Tweet) -> Post { } .map(|result| RepostFrom::Recursion(Box::new(parse_tweet(result.result.into_tweet())))); + let possibly_sensitive = tweet.legacy.possibly_sensitive.unwrap_or(false); + let card_attachment = tweet.card.and_then(|card| { const IMAGE_KEYS: [&str; 3] = [ "photo_image_full_size_original", @@ -495,6 +497,7 @@ fn parse_tweet(tweet: data::Tweet) -> Post { Some(data::TweetCardValue::Image { image_value }) => { Some(PostAttachment::Image(PostAttachmentImage { media_url: image_value.url.clone(), + has_spoiler: possibly_sensitive, })) } Some(_) => { @@ -517,6 +520,7 @@ fn parse_tweet(tweet: data::Tweet) -> Post { .map(|media| match media.kind { data::TweetLegacyEntityMediaKind::Photo => PostAttachment::Image(PostAttachmentImage { media_url: media.media_url_https, + has_spoiler: possibly_sensitive, }), data::TweetLegacyEntityMediaKind::Video | data::TweetLegacyEntityMediaKind::AnimatedGif => { @@ -530,9 +534,11 @@ fn parse_tweet(tweet: data::Tweet) -> Post { match video_info { Some(video_info) => PostAttachment::Video(PostAttachmentVideo { media_url: video_info.url, + has_spoiler: possibly_sensitive, }), None => PostAttachment::Image(PostAttachmentImage { media_url: media.media_url_https, + has_spoiler: possibly_sensitive, }), } }