diff --git a/notes/Speicher.md b/notes/Speicher.md index f2222cd..d0ed3b0 100644 --- a/notes/Speicher.md +++ b/notes/Speicher.md @@ -9,7 +9,7 @@ _ data |_ LinusTechTips |_ .ucast |_ videos.json # IDs und Metadaten aller heruntergeladenen Videos - |_ options.json # Kanalspezifische Optionen (ID, enabled) + |_ options.json # Kanalspezifische Optionen (ID, LastScan) |_ avatar.png # Profilbild des Kanals |_ feed.xml # RSS-Feed |_ covers # Cover-Bilder @@ -24,10 +24,15 @@ _ data ## Datenmodelle +### LastScan + +- LastScan: datetime + ### ChannelOptions - ID: str - Active: bool = True +- LastScan: datetime - SkipLivestreams: bool = True - SkipShorts: bool = True - KeepVideos: int = -1 @@ -38,7 +43,6 @@ _ data ### Video -- ID: str - Title: str - Slug: str (YYMMDD_Title, used as filename) - Published: datetime diff --git a/poetry.lock b/poetry.lock index 7909b86..ae17884 100644 --- a/poetry.lock +++ b/poetry.lock @@ -174,14 +174,6 @@ category = "dev" optional = false python-versions = "*" -[[package]] -name = "invoke" -version = "1.7.0" -description = "Pythonic task execution" -category = "dev" -optional = false -python-versions = "*" - [[package]] name = "itsdangerous" version = "2.1.2" @@ -447,7 +439,7 @@ websockets = "*" [metadata] lock-version = "1.1" python-versions = "^3.10" -content-hash = "cf8899258dac046f0ed3d0492161db330ab735dc8dcbe1c46d2c8d4e48b66342" +content-hash = "df5be5b98bd03da41732b908331f0a731408f65a96b078c0139773f0759afac3" [metadata.files] atomicwrites = [ @@ -695,10 +687,6 @@ iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, ] -invoke = [ - {file = "invoke-1.7.0-py3-none-any.whl", hash = "sha256:a5159fc63dba6ca2a87a1e33d282b99cea69711b03c64a35bb4e1c53c6c4afa0"}, - {file = "invoke-1.7.0.tar.gz", hash = "sha256:e332e49de40463f2016315f51df42313855772be86435686156bc18f45b5cc6c"}, -] itsdangerous = [ {file = "itsdangerous-2.1.2-py3-none-any.whl", hash = "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44"}, {file = "itsdangerous-2.1.2.tar.gz", hash = "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a"}, diff --git a/pyproject.toml b/pyproject.toml index ba48a57..353ea37 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,6 @@ fonts = "^0.0.3" [tool.poetry.dev-dependencies] pytest = "^7.1.1" pytest-cov = "^3.0.0" -invoke = "^1.7.0" [build-system] requires = ["poetry-core>=1.0.0"] diff --git a/tests/test_cover.py b/tests/test_cover.py index 745c2e6..d2e1407 100644 --- a/tests/test_cover.py +++ b/tests/test_cover.py @@ -1,14 +1,12 @@ # coding=utf-8 from typing import List -import tempfile -from pathlib import Path import pytest -from PIL import Image, ImageFont, ImageChops +from PIL import ImageFont from fonts.ttf import SourceSansPro import tests -from ucast import cover, types +from ucast import cover @pytest.mark.parametrize('height,width,text,expect', [ @@ -24,61 +22,3 @@ def test_split_text(height: int, width: int, text: str, expect: List[str]): font = ImageFont.truetype(SourceSansPro, 40) lines = cover._split_text(height, width, text, font, 8) assert lines == expect - - -@pytest.mark.parametrize('file_name,color', [ - ('t1.webp', (63, 63, 62)), - ('t2.webp', (74, 45, 37)), - ('t3.webp', (54, 24, 28)), -]) -def test_get_dominant_color(file_name: str, color: types.Color): - img = Image.open(tests.DIR_TESTFILES / 'thumbnail' / file_name) - c = cover._get_dominant_color(img) - assert c == color - - -@pytest.mark.parametrize('bg_color,text_color', [ - ((100, 0, 0), (255, 255, 255)), - ((200, 200, 0), (0, 0, 0)), -]) -def test_get_text_color(bg_color: types.Color, text_color: types.Color): - c = cover._get_text_color(bg_color) - assert c == text_color - - -@pytest.mark.parametrize('n_image,title,channel', [ - (1, 'ThetaDev @ Embedded World 2019', 'ThetaDev'), - (2, 'Sintel - Open Movie by Blender Foundation', 'Blender'), - (3, 'Systemabsturz Teaser zur DiVOC bb3', 'media.ccc.de'), -]) -def test_create_cover_image(n_image: int, title: str, channel: str): - tn_file = tests.DIR_TESTFILES / 'thumbnail' / f't{n_image}.webp' - av_file = tests.DIR_TESTFILES / 'avatar' / f'a{n_image}.jpg' - expected_cv_file = tests.DIR_TESTFILES / 'cover' / f'c{n_image}.png' - - tn_image = Image.open(tn_file) - av_image = Image.open(av_file) - expected_cv_image = Image.open(expected_cv_file) - - cv_image = cover._create_cover_image(tn_image, av_image, title, channel) - - diff = ImageChops.difference(cv_image, expected_cv_image) - assert diff.getbbox() is None - - -def test_create_cover_file(): - tn_file = tests.DIR_TESTFILES / 'thumbnail' / 't1.webp' - av_file = tests.DIR_TESTFILES / 'avatar' / 'a1.jpg' - expected_cv_file = tests.DIR_TESTFILES / 'cover' / 'c1.png' - - tmpdir_o = tempfile.TemporaryDirectory() - tmpdir = Path(tmpdir_o.name) - cv_file = tmpdir / 'cover.png' - - cover.create_cover_file(tn_file, av_file, 'ThetaDev @ Embedded World 2019', 'ThetaDev', cv_file) - - cv_image = Image.open(cv_file) - expected_cv_image = Image.open(expected_cv_file) - - diff = ImageChops.difference(cv_image, expected_cv_image) - assert diff.getbbox() is None diff --git a/tasks.py b/tests/testfiles/get_cover.py similarity index 70% rename from tasks.py rename to tests/testfiles/get_cover.py index cafe839..3bbec0d 100644 --- a/tasks.py +++ b/tests/testfiles/get_cover.py @@ -1,19 +1,21 @@ +# coding=utf-8 +import sys import os -from invoke import task - from ucast import youtube, util, cover import tests - -@task -def test(c): - c.run('pytest tests', pty=True) +# Mit diesem Skript kann man Coverbilder zum Testen erzeugen +# python tests/testfiles/get_cover.py -@task -def get_cover(c, vid=''): - vinfo = youtube.get_video_info(vid) +if __name__ == '__main__': + if len(sys.argv) <= 1: + print('No video id given') + sys.exit(1) + + video_id = sys.argv[1] + vinfo = youtube.get_video_info(video_id) title = vinfo['fulltitle'] channel_name = vinfo['uploader'] thumbnail_url = youtube.get_thumbnail_url(vinfo) diff --git a/ucast/cover.py b/ucast/cover.py index 7dd523b..e4a4aa7 100644 --- a/ucast/cover.py +++ b/ucast/cover.py @@ -1,6 +1,5 @@ # coding=utf-8 import math -from pathlib import Path from typing import Tuple, List, Optional from PIL import Image, ImageDraw, ImageFont @@ -160,8 +159,8 @@ def _create_cover_image(thumbnail: Image.Image, avatar: Optional[Image.Image], t return cover -def create_cover_file(thumbnail_path: Path, avatar_path: Optional[Path], title: str, channel: str, - cover_path: Path): +def create_cover_file(thumbnail_path: types.Path, avatar_path: Optional[types.Path], title: str, channel: str, + cover_path: types.Path): thumbnail = Image.open(thumbnail_path) avatar = None diff --git a/ucast/model.py b/ucast/model.py deleted file mode 100644 index 87062c3..0000000 --- a/ucast/model.py +++ /dev/null @@ -1,3 +0,0 @@ -# coding=utf-8 - - diff --git a/ucast/storage.py b/ucast/storage.py deleted file mode 100644 index 266aca2..0000000 --- a/ucast/storage.py +++ /dev/null @@ -1,44 +0,0 @@ -# coding=utf-8 -import os -from pathlib import Path - -UCAST_DIRNAME = '.ucast' - - -class ChannelFolder: - def __init__(self, dir_root: Path): - self.dir_root = dir_root - dir_ucast = self.dir_root / UCAST_DIRNAME - - self.file_videos = dir_ucast / 'videos.json' - self.file_options = dir_ucast / 'options.json' - self.file_avatar = dir_ucast / 'avatar.png' - self.file_feed = dir_ucast / 'feed.xml' - self.dir_covers = dir_ucast / 'covers' - - def does_exist(self) -> bool: - return os.path.isdir(self.dir_covers) - - def create(self): - os.makedirs(self.dir_covers, exist_ok=True) - - -class Storage: - def __init__(self, config_dir: Path, data_dir: Path): - self.dir_config = config_dir - self.dir_data = data_dir - - def get_channel_folder(self, channel_name: str): - cf = ChannelFolder(self.dir_data / channel_name) - if not cf.does_exist(): - raise FileNotFoundError('channel folder does not exist') - - return cf - - def create_channel_folder(self, channel_name: str): - cf = ChannelFolder(self.dir_data / channel_name) - if cf.does_exist(): - raise FileExistsError('channel folder already exists') - - cf.create() - return cf diff --git a/ucast/types.py b/ucast/types.py index 99876b6..2b54726 100644 --- a/ucast/types.py +++ b/ucast/types.py @@ -3,3 +3,4 @@ from os import PathLike from typing import Tuple, Union Color = Tuple[int, int, int] +Path = Union[str, bytes, PathLike]