summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/ipcam_server.md8
-rw-r--r--src/home/util.py35
-rwxr-xr-xsrc/ipcam_server.py47
3 files changed, 80 insertions, 10 deletions
diff --git a/doc/ipcam_server.md b/doc/ipcam_server.md
index f443094..a22c239 100644
--- a/doc/ipcam_server.md
+++ b/doc/ipcam_server.md
@@ -21,11 +21,15 @@ camera:
motion:
padding: 2
+ telegram: true
logging:
verbose: true
-
-motion_threshold: 1
+
+telegram:
+ token: ""
+ chat_id: ""
+ parse_mode: HTML
```
## Usage
diff --git a/src/home/util.py b/src/home/util.py
index a6ac906..4e47f49 100644
--- a/src/home/util.py
+++ b/src/home/util.py
@@ -1,3 +1,4 @@
+import functools
import json
import socket
import time
@@ -7,6 +8,7 @@ import traceback
import logging
import string
import random
+import asyncio
from enum import Enum
from .config import config
@@ -100,8 +102,31 @@ def send_datagram(message: str, addr: Addr) -> None:
def send_telegram(text: str,
parse_mode: str = None,
- disable_web_page_preview: bool = False,
- ):
+ disable_web_page_preview: bool = False):
+ data, token = _send_telegram_data(text, parse_mode, disable_web_page_preview)
+ r = requests.post('https://api.telegram.org/bot%s/sendMessage' % token, data=data)
+ if r.status_code != 200:
+ logger.error(r.text)
+ raise RuntimeError("telegram returned %d" % r.status_code)
+
+
+async def send_telegram_aio(text: str,
+ parse_mode: str = None,
+ disable_web_page_preview: bool = False):
+ loop = asyncio.get_event_loop()
+ data, token = _send_telegram_data(text, parse_mode, disable_web_page_preview)
+ r = await loop.run_in_executor(None,
+ functools.partial(requests.post,
+ 'https://api.telegram.org/bot%s/sendMessage' % token,
+ data=data))
+ if r.status_code != 200:
+ logger.error(r.text)
+ raise RuntimeError("telegram returned %d" % r.status_code)
+
+
+def _send_telegram_data(text: str,
+ parse_mode: str = None,
+ disable_web_page_preview: bool = False) -> tuple[dict, str]:
data = {
'chat_id': config['telegram']['chat_id'],
'text': text
@@ -115,11 +140,7 @@ def send_telegram(text: str,
if disable_web_page_preview or 'disable_web_page_preview' in config['telegram']:
data['disable_web_page_preview'] = 1
- r = requests.post('https://api.telegram.org/bot%s/sendMessage' % config['telegram']['token'], data=data)
-
- if r.status_code != 200:
- logger.error(r.text)
- raise RuntimeError("telegram returned %d" % r.status_code)
+ return data, config['telegram']['token']
def format_tb(exc) -> Optional[list[str]]:
diff --git a/src/ipcam_server.py b/src/ipcam_server.py
index 56b6e18..6856621 100755
--- a/src/ipcam_server.py
+++ b/src/ipcam_server.py
@@ -7,7 +7,7 @@ import time
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from home.config import config
-from home.util import parse_addr
+from home.util import parse_addr, send_telegram_aio
from home import http
from home.database.sqlite import SQLiteBase
from home.camera import util as camutil
@@ -22,6 +22,11 @@ class TimeFilterType(Enum):
MOTION = 'motion'
+class TelegramLinkType(Enum):
+ FRAGMENT = 'fragment'
+ ORIGINAL_FILE = 'original_file'
+
+
def valid_recording_name(filename: str) -> bool:
return filename.startswith('record_') and filename.endswith('.mp4')
@@ -325,6 +330,46 @@ async def process_fragments(camera: int,
start_pos=start,
duration=duration)
+ try:
+ if fragments and config['motion']['telegram']:
+ asyncio.ensure_future(motion_notify_tg(camera, filename, fragments))
+ except KeyError:
+ pass
+
+
+async def motion_notify_tg(camera: int,
+ filename: str,
+ fragments: list[tuple[int, int]]):
+ dt_file = filename_to_datetime(filename)
+ fmt = '%H:%M:%S'
+
+ text = f'Camera: <b>{camera}</b>\n'
+ text += f'Original file: <b>{filename}</b> '
+ text += _tg_links(TelegramLinkType.ORIGINAL_FILE, camera, filename)
+
+ for start, end in fragments:
+ duration = end - start
+ if duration < 0:
+ duration = 0
+
+ dt1 = dt_file + timedelta(seconds=start)
+ dt2 = dt_file + timedelta(seconds=end)
+
+ text += f'\nFragment: <b>{duration}s</b>, {dt1.strftime(fmt)} - {dt2.strftime(fmt)} '
+ text += _tg_links(TelegramLinkType.FRAGMENT, camera, f'{dt1.strftime(datetime_format)}__{dt2.strftime(datetime_format)}.mp4')
+
+ await send_telegram_aio(text)
+
+
+def _tg_links(link_type: TelegramLinkType,
+ camera: int,
+ file: str) -> str:
+ links = []
+ for link_name, link_template in config['telegram'][f'{link_type.value}_url_templates']:
+ link = link_template.replace('{camera}', str(camera)).replace('{file}', file)
+ links.append(f'<a href="{link}">{link_name}</a>')
+ return ' '.join(links)
+
async def fix_job() -> None:
global fix_job_running