Added telegram messages

This commit is contained in:
euzu
2023-10-12 12:33:18 +02:00
parent dc23637871
commit 660ea384a8
12 changed files with 808 additions and 525 deletions
+2 -1
View File
@@ -4,7 +4,8 @@
* Added Xtream Cluster Live, Video, Series. M3u Playlist cluster guessing through video file endings.
* Added api-proxy config for xtream proxy, to define server info and user credentials
* Added Xtream Api Endpoints.
* Added multiple input support
* Added multiple input support
* Added Telegram message support
# v1.0.1(2023-09-07)
* Refactored sorting. Sorting channels inside group now possible
Generated
+747 -512
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -37,3 +37,4 @@ openssl = { version = "*", features = ["vendored"] } #https://docs.rs/openssl/0.
mime = "0.3.17"
log = "0.4.20"
env_logger = "0.10.0"
rustelebot = "0.3.2"
+19 -2
View File
@@ -11,6 +11,7 @@ m3u-filter is a simple application which can:
- use regular expressions for matching
- define filter as statements like `filter: (Group ~ "^FR.*") AND NOT(Group ~ ".*XXX.*" OR Group ~ ".*SERIES.*" OR Group ~".*MOVIES.*")`
- DRY - define templates and use them, don't repeat yourself
- Send a telegram bot message when something goes wrong
```
------------ |----> playlist_1
@@ -52,11 +53,13 @@ Target names should be provided in the config. The -t option overrides `enabled`
This means, even disabled inputs and targets are processed when the given target name as cli argument matches a target.
Top level entries in the config files are:
* `threads` _optional_
* `api`
* `working_dir`
* `templates` _optional_
* `sources`
* `threads` _optional_
* `messaging` _optional_
* `video_suffix` _optional_
### 1.1. `threads`
If you are running on a cpu which has multiple cores, you can set for example `threads: 2` to run two threads.
@@ -311,7 +314,21 @@ sources:
new_name: 1. DE$1
```
### 1.6 `video_suffix`
### 1.6 `messaging`
`messaging` is an optional configuration for receiving messages.
Currently only telegram is supported.
```yaml
messaging:
telegram:
bot_token: '<telegram bot token>'
chat_ids:
- '<telegram chat id>'
```
For more information: [Telegram bots](https://core.telegram.org/bots/tutorial)
### 1.7 `video_suffix`
video_suffix a optional list.
It is possible to define video file endings to assign the playlist entry to the xtream cluster video.
+3
View File
@@ -0,0 +1,3 @@
#!/bin/bash
cargo +nightly udeps
cargo +nightly udeps --all-targets
+1 -1
View File
@@ -26,7 +26,7 @@ fn prepare_file_path(input: &ConfigInput, working_dir: &String, action: &str) ->
pub(crate) fn get_m3u_playlist(cfg: &Config, input: &ConfigInput, working_dir: &String) -> Option<Vec<PlaylistGroup>> {
let url = input.url.as_str();
let file_path = prepare_file_path(input, working_dir, "");
let lines: Option<Vec<String>> = utils::get_input_content(working_dir, url, file_path);
let lines: Option<Vec<String>> = utils::get_input_content(cfg, working_dir, url, file_path);
lines.map(|l| m3u_parser::parse_m3u(cfg, &l))
}
+15 -1
View File
@@ -1,3 +1,17 @@
pub(crate) fn send_message(_msg: &str) {
use log::{debug, error};
use crate::model::config::{MessagingConfig};
pub(crate) fn send_message(cfg: &Option<MessagingConfig>, msg: &str) {
if let Some(messaging) = cfg {
if let Some(telegram) = &messaging.telegram {
for chat_id in &telegram.chat_ids {
let bot = rustelebot::create_instance(&telegram.bot_token, chat_id);
match rustelebot::send_message(&bot, msg, None)
{
Ok(_) => debug!("Text message sent successfully to {}", chat_id),
Err(e) => error!("Text message wasn't sent to {} because of: {}", chat_id, e)
}
};
}
}
}
+12
View File
@@ -249,6 +249,17 @@ impl ConfigApi {
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub(crate) struct TelegramMessagingConfig {
pub bot_token: String,
pub chat_ids: Vec<String>,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub(crate) struct MessagingConfig {
pub telegram: Option<TelegramMessagingConfig>,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub(crate) struct Config {
#[serde(default = "default_as_zero")]
@@ -259,6 +270,7 @@ pub(crate) struct Config {
pub templates: Option<Vec<PatternTemplate>>,
pub video_suffix: Option<Vec<String>>,
pub schedule: Option<String>,
pub messaging: Option<MessagingConfig>,
#[serde(skip_serializing, skip_deserializing)]
pub _api_proxy: Option<ApiProxyConfig>,
}
+1 -1
View File
@@ -159,7 +159,7 @@ fn write_strm_playlist(target: &ConfigTarget, cfg: &Config, new_playlist: &mut V
pub(crate) fn write_playlist(target: &ConfigTarget, cfg: &Config, playlist: &mut Vec<PlaylistGroup>) -> Result<(), std::io::Error> {
let mut new_playlist = playlist.to_owned();
if let Some(TargetType::Strm) = &target.output {
return write_strm_playlist(target, cfg, &mut new_playlist)
return write_strm_playlist(target, cfg, &mut new_playlist);
}
write_m3u_playlist(target, cfg, &mut new_playlist)
}
+2 -2
View File
@@ -88,7 +88,7 @@ pub(crate) fn xtream_save_playlist(target: &ConfigTarget, cfg: &Config, playlist
if let Some(path) = get_storage_path(cfg, &target.name) {
if fs::create_dir_all(&path).is_err() {
let msg = format!("Failed to save, can't create directory {}", &path.into_os_string().into_string().unwrap());
send_message(msg.as_str());
send_message(&cfg.messaging, msg.as_str());
return Err(Error::new(std::io::ErrorKind::Other, msg));
}
@@ -192,7 +192,7 @@ pub(crate) fn xtream_save_playlist(target: &ConfigTarget, cfg: &Config, playlist
}
if failed {
send_message(format!("Something went wrong persisting target {}", &target.name).as_str());
send_message(&cfg.messaging, format!("Something went wrong persisting target {}", &target.name).as_str());
}
Ok(())
}
+1 -1
View File
@@ -5,7 +5,7 @@ mod tests {
#[test]
fn test_filter() {
let flt1 = "(Group ~ \"A\" OR Group ~ \"B\") AND (Name ~ \"C\" OR Name ~ \"D\" OR Name ~ \"E\") OR (NOT (Title ~ \"F\") AND NOT Title ~ \"K\")";
let filter = get_filter(flt1, None, false);
let filter = get_filter(flt1, None);
assert_eq!(format!("{}", filter), flt1);
}
+4 -4
View File
@@ -5,7 +5,7 @@ use log::{debug, error};
use path_absolutize::*;
use reqwest::header;
use reqwest::header::{HeaderName, HeaderValue};
use crate::model::config::ConfigInput;
use crate::model::config::{Config, ConfigInput};
use crate::messaging::send_message;
#[macro_export]
@@ -101,13 +101,13 @@ pub(crate) fn open_file(file_name: &PathBuf, mandatory: bool) -> Option<fs::File
}
}
pub(crate) fn get_input_content(working_dir: &String, url_str: &str, persist_file: Option<PathBuf>) -> Option<Vec<String>> {
pub(crate) fn get_input_content(cfg: &Config, working_dir: &String, url_str: &str, persist_file: Option<PathBuf>) -> Option<Vec<String>> {
match url_str.parse::<url::Url>() {
Ok(url) => match download_content(url, persist_file) {
Ok(content) => Some(content),
Err(e) => {
error!("cant download input url: {} => {}", url_str, e);
send_message(format!("Failed to download: {}", url_str).as_str());
send_message(&cfg.messaging, format!("Failed to download: {}", url_str).as_str());
None
}
}
@@ -135,7 +135,7 @@ pub(crate) fn get_input_content(working_dir: &String, url_str: &str, persist_fil
None => {
let msg = format!("cant read input url: {:?}", &file_path.unwrap());
error!("{}", msg);
send_message(msg.as_str());
send_message(&cfg.messaging, msg.as_str());
None
}
}