mirror of
https://github.com/euzu/tuliprox.git
synced 2026-09-28 20:12:12 +02:00
new messaging option
This commit is contained in:
+3
-1
@@ -1,7 +1,9 @@
|
||||
# Changelog
|
||||
# v1.1.5(2023-12-??)
|
||||
# v1.1.5(2024-01-11)
|
||||
* Changed api-proxy user default proxy type from `reverse` to `redirect`
|
||||
* Added `xtream_resolve_series` and `xtream_resolve_series_delay` option for `m3u` target
|
||||
* Messaging calling rest endpoint added
|
||||
* Messaging added 'Watch' option as OptIn
|
||||
|
||||
# v1.1.4(2023-12-06)
|
||||
* Breaking change, `config.yml` split into `config.yml` and `source.yml`
|
||||
|
||||
@@ -11,7 +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
|
||||
- Send a telegram bot or rest message when something goes wrong
|
||||
- Watch changes in groups and get a message on changes
|
||||
|
||||

|
||||
@@ -66,13 +66,15 @@ With this configuration, you should create a `data` directory where you execute
|
||||
|
||||
### 1.4 `messaging`
|
||||
`messaging` is an optional configuration for receiving messages.
|
||||
Currently only telegram is supported.
|
||||
Currently only and rest is supported.
|
||||
|
||||
Messaging is Opt-In, you need to set the `notify_on` message types which are
|
||||
- `info`
|
||||
- `stats`
|
||||
- `error`
|
||||
|
||||
`telegram` and `rest` configurations are optional.
|
||||
|
||||
```yaml
|
||||
messaging:
|
||||
notify_on:
|
||||
@@ -83,6 +85,8 @@ messaging:
|
||||
bot_token: '<telegram bot token>'
|
||||
chat_ids:
|
||||
- '<telegram chat id>'
|
||||
rest:
|
||||
url: '<api url as POST endpoint for json data>'
|
||||
```
|
||||
|
||||
For more information: [Telegram bots](https://core.telegram.org/bots/tutorial)
|
||||
@@ -426,6 +430,13 @@ watch:
|
||||
Changes from this groups will be printed as info on console and send to
|
||||
the configured messaging (f.e. telegram channel).
|
||||
|
||||
To get the watch notifications over messaging notify_on `watch` should be enabled.
|
||||
In `config.yml`
|
||||
```yaml
|
||||
messaging:
|
||||
notify_on:
|
||||
- watch
|
||||
```
|
||||
|
||||
## 2. `mapping.yml`
|
||||
Has the root item `mappings` which has the following top level entries:
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
# TODO
|
||||
## Bugs
|
||||
|
||||
- xtream api, only looks for first input configuration.
|
||||
But if you have multiple xtream sources merged,
|
||||
each entry should have a pointer to his input to get the right provider url.
|
||||
-
|
||||
- double download from web-ui possible
|
||||
|
||||
|
||||
## Features
|
||||
- m3u8 support missing.
|
||||
- download from web-ui is not cancellable
|
||||
- resume download if available
|
||||
- display file size from header if available
|
||||
- on web-ui page refresh download list should be fetched
|
||||
|
||||
## Open topics
|
||||
- xmltv api delivers original content if no epg_url is provided for input for reverse or makes redirect.
|
||||
- web ui should fetch series info when expanded
|
||||
@@ -9,10 +9,13 @@ messaging:
|
||||
- error
|
||||
- info
|
||||
- stats
|
||||
- watch
|
||||
telegram:
|
||||
bot_token: '<your telegram bot token>'
|
||||
chat_ids:
|
||||
- <your telegram chat_id>
|
||||
rest:
|
||||
url: http://<ip>/<maybe_path>/<notification>
|
||||
video:
|
||||
web_search: 'https://www.imdb.com/search/title/?title={}'
|
||||
extensions:
|
||||
|
||||
@@ -12,6 +12,7 @@ import FormView, {FormFieldType} from "../form-view/from-view";
|
||||
import TabSet from "../tab-set/tab-set";
|
||||
import {getIconByName} from "../../icons/icons";
|
||||
import {useServices} from "../../provider/service-provider";
|
||||
import {MessageKind} from "../../model/message-kind";
|
||||
|
||||
const isNumber = (value: string): boolean => {
|
||||
return !isNaN(value as any);
|
||||
@@ -22,6 +23,7 @@ const CONFIG_API_FIELDS = [
|
||||
{name: 'port', label: 'Port', fieldType: FormFieldType.NUMBER, validator: isNumber},
|
||||
{name: 'web_root', label: 'Web-Root', fieldType: FormFieldType.TEXT, validator: undefined},
|
||||
];
|
||||
|
||||
const CONFIG_FIELDS = [
|
||||
{name: 'threads', label: 'Threads', fieldType: FormFieldType.NUMBER, validator: isNumber},
|
||||
{name: 'working_dir', label: 'Working dir', fieldType: FormFieldType.TEXT, validator: undefined},
|
||||
@@ -32,33 +34,33 @@ const CONFIG_FIELDS = [
|
||||
const CONFIG_MESSAGING_FIELDS = [
|
||||
{
|
||||
name: 'notify_on', label: 'Notify on', fieldType: FormFieldType.MULTI_SELECT, options:
|
||||
[{value: 'error', label: 'Error'}, {value: 'info', label: 'Info'}, {value: 'stats', label: 'Stats'}]
|
||||
Object.keys(MessageKind).map((key) => ({value: (MessageKind as any)[key], label: key}))
|
||||
},
|
||||
]
|
||||
];
|
||||
|
||||
const CONFIG_TELEGRAM_FIELDS = [
|
||||
{name: 'bot_token', label: 'Bot Token', fieldType: FormFieldType.TEXT},
|
||||
{name: 'chat_ids', label: 'Chat Ids', fieldType: FormFieldType.TAGS},
|
||||
]
|
||||
];
|
||||
|
||||
const CONFIG_VIDEO_FIELDS = [
|
||||
{name: 'web_search', label: 'Web Search Url', fieldType: FormFieldType.TEXT},
|
||||
{name: 'extensions', label: 'Extensions', fieldType: FormFieldType.TEXT},
|
||||
]
|
||||
];
|
||||
|
||||
const CONFIG_VIDEO_DOWNLOAD_FIELDS = [
|
||||
{name: 'headers', label: 'Headers', fieldType: FormFieldType.MAP},
|
||||
{name: 'directory', label: 'Directory', fieldType: FormFieldType.TEXT},
|
||||
{name: 'organize_into_directories', label: 'Organize Into Directories', fieldType: FormFieldType.CHECK},
|
||||
{name: 'episode_pattern', label: 'Episode Pattern', fieldType: FormFieldType.TEXT},
|
||||
]
|
||||
];
|
||||
|
||||
const TABS = [
|
||||
{label: 'Api', key: 'api'},
|
||||
{label: 'Main', key: 'main'},
|
||||
{label: 'Messaging', key: 'messaging'},
|
||||
{label: 'Video', key: 'video'}
|
||||
]
|
||||
];
|
||||
|
||||
interface MainConfigViewProps {
|
||||
config: ServerConfig;
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
export enum MessageKind {
|
||||
Info = "info",
|
||||
Stats = "stats",
|
||||
Error = "error",
|
||||
Watch = "watch",
|
||||
}
|
||||
@@ -213,6 +213,7 @@ async fn xtream_get_stream_info(app_state: &AppState, target_name: &str, stream_
|
||||
if response.status().is_success() {
|
||||
match response.text().await {
|
||||
Ok(content) => {
|
||||
// TODO we are not replacing direct_source, we should add an option to do this.
|
||||
xtream_persist_stream_info(app_state, target_name, stream_id, cluster,
|
||||
target_input, content.as_str()).await;
|
||||
return Ok(content);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use log::{debug, error};
|
||||
use reqwest::header;
|
||||
use crate::model::config::{MessagingConfig};
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq)]
|
||||
@@ -9,6 +10,8 @@ pub(crate) enum MsgKind {
|
||||
Stats,
|
||||
#[serde(rename = "error")]
|
||||
Error,
|
||||
#[serde(rename = "watch")]
|
||||
Watch,
|
||||
}
|
||||
|
||||
fn is_enabled(kind: &MsgKind, cfg: &MessagingConfig) -> bool {
|
||||
@@ -28,6 +31,22 @@ pub(crate) fn send_message(kind: &MsgKind, cfg: &Option<MessagingConfig>, msg: &
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if let Some(rest) = &messaging.rest {
|
||||
let url = rest.url.to_owned();
|
||||
let data = msg.to_owned();
|
||||
actix_rt::spawn(async move {
|
||||
let client = reqwest::Client::new();
|
||||
match client.post(&url)
|
||||
.header(header::CONTENT_TYPE, mime::APPLICATION_JSON.to_string())
|
||||
.body(data)
|
||||
.send()
|
||||
.await {
|
||||
Ok(_) => debug!("Text message sent successfully to rest api"),
|
||||
Err(e) => error!("Text message wasn't sent to rest api because of: {}", e)
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,11 +445,17 @@ pub(crate) struct TelegramMessagingConfig {
|
||||
pub chat_ids: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub(crate) struct RestMessagingConfig {
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub(crate) struct MessagingConfig {
|
||||
#[serde(default = "default_as_empty_list")]
|
||||
pub notify_on: Vec<MsgKind>,
|
||||
pub telegram: Option<TelegramMessagingConfig>,
|
||||
pub rest: Option<RestMessagingConfig>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
|
||||
+2
-2
@@ -8,7 +8,7 @@ pub(crate) struct PlaylistStats {
|
||||
|
||||
impl ToString for PlaylistStats {
|
||||
fn to_string(&self) -> String {
|
||||
format!("{{groups: {}, channels: {}}}", self.group_count, self.channel_count)
|
||||
format!("{{\"groups\": {}, \"channels\": {}}}", self.group_count, self.channel_count)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ pub(crate) struct InputStats {
|
||||
|
||||
impl ToString for InputStats {
|
||||
fn to_string(&self) -> String {
|
||||
format!("{{name: {}, type: {}, errors: {}, raw: {}, processed: {}}}",
|
||||
format!("{{\"name\": {}, \"type\": {}, \"errors\": {}, \"raw\": {}, \"processed\": {}}}",
|
||||
self.name, self.input_type.to_string(), self.error_count,
|
||||
self.raw_stats.to_string(), self.processed_stats.to_string())
|
||||
}
|
||||
|
||||
@@ -535,7 +535,7 @@ fn persist_playlist(playlist: &[PlaylistGroup], epg: Option<Epg>,
|
||||
|
||||
pub(crate) async fn exec_processing(cfg: Arc<Config>, targets: Arc<ProcessTargets>) {
|
||||
let (stats, errors) = process_sources(cfg.to_owned(), targets.to_owned()).await;
|
||||
let stats_msg = format!("Stats: {}", stats.iter().map(|stat| stat.to_string()).collect::<Vec<String>>().join("\n"));
|
||||
let stats_msg = format!("{{\"stats\": {}}}", stats.iter().map(|stat| stat.to_string()).collect::<Vec<String>>().join("\n"));
|
||||
// print stats
|
||||
info!("{}", stats_msg);
|
||||
// send stats
|
||||
@@ -544,6 +544,7 @@ pub(crate) async fn exec_processing(cfg: Arc<Config>, targets: Arc<ProcessTarget
|
||||
errors.iter().for_each(|err| error!("{}", err.message));
|
||||
// send errors
|
||||
if let Some(message) = get_errors_notify_message!(errors, 255) {
|
||||
send_message(&MsgKind::Error, &cfg.messaging, message.as_str());
|
||||
let error_msg = format!("{{\"errors\": \"{}\"}}",message.as_str());
|
||||
send_message(&MsgKind::Error, &cfg.messaging, error_msg.as_str());
|
||||
}
|
||||
}
|
||||
@@ -72,7 +72,7 @@ fn handle_watch_notification(cfg: &Config, added: BTreeSet<String>, removed: BTr
|
||||
if !message.is_empty() {
|
||||
let msg = format!("Changes {}/{}\n{}", target_name, group_name, message.join(""));
|
||||
info!("{}", &msg);
|
||||
send_message(&MsgKind::Info, &cfg.messaging, &msg);
|
||||
send_message(&MsgKind::Watch, &cfg.messaging, &msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user