Skip to content

Commit

Permalink
Merge pull request #111 from bralbral/develop
Browse files Browse the repository at this point in the history
New Platforms
  • Loading branch information
bralbral authored Sep 26, 2024
2 parents ee36a2a + f49ed12 commit 1ec2001
Show file tree
Hide file tree
Showing 88 changed files with 1,401 additions and 1,663 deletions.
8 changes: 5 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
repos:
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.3.0
rev: v1.8.0
hooks:
- id: mypy
exclude: deprecated|deploy|venv
args: [--python-version=3.11, --ignore-missing-imports, --install-types, --non-interactive,]
additional_dependencies:
- sqlmodel==0.0.22
args: [--python-version=3.12, --ignore-missing-imports, --install-types, --non-interactive,]

- repo: local
hooks:
Expand All @@ -20,7 +22,7 @@ repos:
entry: black
language: python
types: [ python ]
args: [ --line-length=88, --target-version=py311 ]
args: [ --line-length=88, --target-version=py312, --force-exclude, src/db/migrations/*]

# For upgrade python code syntax for newer versions of the language
- id: pyupgrade
Expand Down
27 changes: 1 addition & 26 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,29 +1,4 @@
#FROM python:3.11-slim-bookworm
#
## Update the package list and install required packages
#RUN apt-get update && \
# apt-get install -y git && \
# apt-get clean && \
# rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
#
## Copy the application source code to the container and set the working directory
#COPY ./requirements.txt /app/requirements.txt
#COPY ./src /app/src
#
## Copy alembic files
#COPY alembic.ini alembic-upgrade.bash /app/
#
#WORKDIR /app
#
## Install Python dependencies
#RUN pip3 install --no-cache-dir --upgrade pip && \
# pip3 install --no-cache-dir -r requirements.txt
#
## Set the user to non-root
#USER 1000


FROM python:3.11-alpine
FROM python:3.12-alpine

# Set up environment variables for non-interactive installation
ENV PYTHONDONTWRITEBYTECODE=1 \
Expand Down
22 changes: 14 additions & 8 deletions README.MD
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
# telegram-youtube-notifier-bot
# telegram-stream-notifier-bot (former telegram-youtube-notifier-bot)

> ⚠️ Warning: project is still under development, use with caution.
Simple Youtube LiveStreams notifier in telegram based on [youtube-dlp](https://github.com/yt-dlp/yt-dlp) and [aiogram](https://github.com/aiogram/aiogram) .
Simple LiveStreams notifier in telegram based on [aiogram](https://github.com/aiogram/aiogram), [aiogram-dialog](https://github.com/Tishka17/aiogram_dialog) and [aps-schedule](https://github.com/agronholm/apscheduler).

Use this bot to receive periodic reports on live broadcasts on YouTube and generate and send the report to telegram.
### Available platforms

| Platform | Based on | Status |
|-----------------|-------------------------------------------------|----------------------------------------------------------------------|
| Youtube | [youtube-dlp](https://github.com/yt-dlp/yt-dlp) ||
| Twitch | [twitch-api](https://github.com/Teekeks/pyTwitchAPI) ||

Use this bot to receive periodic reports on live broadcasts on stream platforms and generate and send the report to telegram.

The current version of the bot works in the telegram channel [НАСРАНО](https://t.me/HACPAH1).

Expand All @@ -16,7 +23,7 @@ The current version of the bot works in the telegram channel [НАСРАНО](ht

3. Regularly checking active channels using [aps-schedule](https://github.com/agronholm/apscheduler).

4. Getting information about streams using [youtube-dlp](https://github.com/yt-dlp/yt-dlp).
4. Getting information about streams using packages from [list](#Available-platforms).

## Commands

Expand All @@ -26,19 +33,18 @@ The current version of the bot works in the telegram channel [НАСРАНО](ht
| channels | User | Channels Administration |
| cancel | User | Clear current fsm-state (if error) |
| add_user | Superuser | Add user |
| add_channels | Superuser | Bulk channels importing from file |
| scheduler_start | Superuser | Start scheduling periodic tasks of fetching information about streams |
| scheduler_pause | Superuser | Pause scheduling periodic tasks of fetching information about streams |

## Database schema

<img src="src/db/svg_schema/db-schema.svg">
<img src="db-schema.png">

## Deploy

### Install from source

> Tested on Ubuntu 22.04, python 3.11
> Tested on Ubuntu 22.04, python 3.12
Just copy source code:

Expand Down Expand Up @@ -96,7 +102,7 @@ Or you can do it step by step:

`kubectl apply -f <file from config dir>`

## Setup Cookies
## Setup Cookies for Youtube

You can use own cookies for yt-dlp extractors.

Expand Down
Binary file added db-schema.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 10 additions & 1 deletion deploy/docker/example.config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ chat_id: 123456789
temp_chat_id: 987654321

# Report customization
# With Jinja2 template you can access to ChanelDescription object via 'channel' variable
# With Jinja2 template you can access to ChanelDescription object via 'channel_listing' variable
#
#class ChannelDescription(BaseModel):
# url: str
Expand Down Expand Up @@ -51,3 +51,12 @@ start_scheduler: False
# interval between checks in seconds
interval_s: 60

# For notification from Twitch
# You can obtain from https://dev.twitch.tv/console
# twitch:
# app_id: xxxxxxxxxxxxxxxxxxxxxxxxxx
# app_secret: xxxxxxxxxxxxxxxxxxxxxxxxxx

# Path to cookie file for youtube-dlp
# youtube:
# cookies_filepath: /path/to/cookies.txt
2 changes: 2 additions & 0 deletions deploy/docker/example.docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ services:
restart: always
volumes:
- ./config.yaml:/app/config.yaml
# youtube cookies optional
# make sure that has same path at config
- ./cookies.txt:/app/cookies.txt:touch
- ./youtube-notifier-bot.db:/app/youtube-notifier-bot.db
- /etc/timezone:/etc/timezone:ro
Expand Down
8 changes: 8 additions & 0 deletions deploy/k8s/01_configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ data:
start_scheduler: True
interval_s: 300
# For notification from Twitch
# You can obtain from https://dev.twitch.tv/console
# twitch:
# app_id: xxxxxxxxxxxxxxxxxxxxxxxxxx
# app_secret: xxxxxxxxxxxxxxxxxxxxxxxxxx
# Path to cookie file for youtube-dlp
# youtube:
# cookies_filepath: /path/to/cookies.txt
cookies.txt: |
# Netscape HTTP Cookie File
# This file is generated by yt-dlp. Do not edit.
1 change: 1 addition & 0 deletions erd-generator.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
eralchemy -i sqlite:///youtube-notifier-bot.db -o db-schema.png --exclude-tables alembic_version --exclude-columns created_at updated_at
9 changes: 5 additions & 4 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
aiogram==3.10.0
aiogram==3.13.1
aiogram-dialog==2.2.0
pydantic==2.8.2
APScheduler==3.10.4
yt-dlp==2024.8.6
twitchapi==4.3.1
sulguk==0.8.0
jinja2==3.1.4
pyyaml==6.0.2
pydantic_settings==2.4.0
structlog==24.4.0
orjson==3.10.5
orjson==3.10.7
uvloop==0.20.0
SQLAlchemy==2.0.31
SQLAlchemy==2.0.35
alembic==1.13.2
aiosqlite==0.20.0
asyncclick==8.1.7.2
anyio==4.4.0
aiocache==0.12.2
sqlalchemy-data-model-visualizer==0.1.3
sqlmodel==0.0.22
3 changes: 2 additions & 1 deletion requirements_dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ pre-commit==3.8.0
black==24.8.0
autoflake==2.3.1
reorder-python-imports==3.13.0
pyupgrade==3.16.0
pyupgrade==3.17.0
pytest==8.3.2
pytest-cov==5.0.0
eralchemy==1.5.0
git+https://github.com/aio-libs/sort-all.git
7 changes: 3 additions & 4 deletions src/bot/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,16 @@
def superuser_commands() -> list[BotCommand]:
commands = [
BotCommand(command="add_user", description="Add user to bot."),
BotCommand(command="add_channels", description="Add channels from file."),
BotCommand(command="scheduler_start", description="Start scheduler"),
BotCommand(command="scheduler_pause", description="Stop scheduler"),
BotCommand(command="scheduler_start", description="Start scheduler."),
BotCommand(command="scheduler_pause", description="Stop scheduler."),
]
return commands


def user_commands() -> list[BotCommand]:
commands = [
BotCommand(command="cancel", description="Clear current state."),
BotCommand(command="add_channel", description="Add channel."),
BotCommand(command="add_channel", description="Add channel_listing."),
BotCommand(
command="channels", description="Start Channels Administration Dialog."
),
Expand Down
4 changes: 2 additions & 2 deletions src/bot/dialogs/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from aiogram import Dispatcher

from .channel import channel_dialog
from .user import register_user_dialogs


def register_dialogs(dp: Dispatcher) -> None:
dp.include_router(channel_dialog)
register_user_dialogs(dp=dp)


__all__ = ["register_dialogs"]
12 changes: 12 additions & 0 deletions src/bot/dialogs/user/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from aiogram import Dispatcher

from .channel import channel_create_dialog
from .channel import channels_list_dialog


def register_user_dialogs(dp: Dispatcher) -> None:
dp.include_router(channel_create_dialog)
dp.include_router(channels_list_dialog)


__all__ = ["register_user_dialogs"]
5 changes: 5 additions & 0 deletions src/bot/dialogs/user/channel/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from .add import channel_create_dialog
from .list import channels_list_dialog


__all__ = ["channel_create_dialog", "channels_list_dialog"]
16 changes: 16 additions & 0 deletions src/bot/dialogs/user/channel/add/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from aiogram_dialog import Dialog
from aiogram_dialog import LaunchMode

from .windows import label_handler_window
from .windows import select_channel_type_window
from .windows import url_handler_window

channel_create_dialog = Dialog(
select_channel_type_window(),
url_handler_window(),
label_handler_window(),
launch_mode=LaunchMode.STANDARD,
)


__all__ = ["channel_create_dialog"]
18 changes: 18 additions & 0 deletions src/bot/dialogs/user/channel/add/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from src.db.models.channel_type import ChannelType
from src.utils import kick_channel_url_validator
from src.utils import twitch_channel_url_validator
from src.utils import youtube_channel_url_validator

url_validators: dict = {
ChannelType.YOUTUBE: youtube_channel_url_validator,
ChannelType.TWITCH: twitch_channel_url_validator,
ChannelType.KICK: kick_channel_url_validator,
}

url_examples: dict = {
ChannelType.YOUTUBE: "https://www.youtube.com/@username",
ChannelType.TWITCH: "https://www.twitch.tv/username",
ChannelType.KICK: "empty",
}

__all__ = ["url_examples", "url_validators"]
45 changes: 45 additions & 0 deletions src/bot/dialogs/user/channel/add/getters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from aiogram_dialog import DialogManager

from .constants import url_examples
from .constants import url_validators
from src.db import DataAccessLayer
from src.db.models.channel_type import ChannelType


async def select_channel_type_window_getter(dialog_manager: DialogManager, **kwargs):

dal: DataAccessLayer = dialog_manager.start_data["dal"]

channels = await dal.get_channels()

dialog_manager.dialog_data["dal"] = dal
dialog_manager.dialog_data["channels"] = channels
dialog_manager.dialog_data["channel_types"] = ChannelType.list()

return {
"channel_types": dialog_manager.dialog_data["channel_types"],
}


async def url_handler_window_getter(dialog_manager: DialogManager, **kwargs):

selected_channel_type = dialog_manager.dialog_data["selected_channel_type"]
url_validator = url_validators[selected_channel_type]
url_example = url_examples[selected_channel_type]

dialog_manager.dialog_data["url_validator"] = url_validator
dialog_manager.dialog_data["url_example"] = url_example

return {"url_example": url_example}


async def label_handler_window_getter(dialog_manager: DialogManager, **kwargs):

return {"url": dialog_manager.dialog_data["url"]}


__all__ = [
"label_handler_window_getter",
"select_channel_type_window_getter",
"url_handler_window_getter",
]
Loading

0 comments on commit 1ec2001

Please sign in to comment.