diff --git a/knowledgeseeker/clips.py b/knowledgeseeker/clips.py index cefe0a3..33cbfdd 100644 --- a/knowledgeseeker/clips.py +++ b/knowledgeseeker/clips.py @@ -5,7 +5,7 @@ from datetime import timedelta from pathlib import Path -from PIL import Image, ImageDraw, ImageFont +from PIL import Image, ImageDraw, ImageFont, ImageFilter, ImageChops import knowledgeseeker.ffmpeg as ff from knowledgeseeker.database import get_db, match_episode @@ -80,6 +80,16 @@ def wrap(t): text = wrap(top_text[:MAX_LENGTH]) size = draw.multiline_textsize(text, font=font, spacing=TEXT_SPACING) pos = (round(image.width/2 - size[0]/2), round(TEXT_VMARGIN*image.height)) + + blurred = Image.new('RGBA', image.size) + blurredDraw = ImageDraw.Draw(blurred) + blurredDraw.multiline_text(pos, text, fill='black', font=font, + spacing=TEXT_SPACING, align='center') + blurred = blurred.filter(ImageFilter.BoxBlur(7)) + + # Paste soft text onto background + image.paste(blurred,blurred) + draw.multiline_text(pos, text, font=font, spacing=TEXT_SPACING, align='center') @@ -88,6 +98,16 @@ def wrap(t): size = draw.multiline_textsize(text, font=font, spacing=TEXT_SPACING) pos = (round(image.width/2 - size[0]/2), image.height - round(TEXT_VMARGIN*image.height) - size[1]) + + blurred = Image.new('RGBA', image.size) + blurredDraw = ImageDraw.Draw(blurred) + blurredDraw.multiline_text(pos, text, fill='black', font=font, + spacing=TEXT_SPACING, align='center') + blurred = blurred.filter(ImageFilter.BoxBlur(7)) + + # Paste soft text onto background + image.paste(blurred,blurred) + draw.multiline_text(pos, text, font=font, spacing=TEXT_SPACING, align='center') diff --git a/library/atla.json b/library/atla.json index 216422f..32380a4 100644 --- a/library/atla.json +++ b/library/atla.json @@ -1,87 +1,87 @@ [ { "seasonSlug": "atla_b1", "seasonName": "Book One: Water", - "seasonIcon": "icons/water.png", + "seasonIcon": "Avatar The Last Airbender/knowledgeseeker/icons/water.png", "episodes": [ - { "episodeSlug": "e1", + { "episodeSlug": "e01", "episodeName": "The Boy in the Iceberg", - "videoFile": "videos/101 The Boy in the Iceberg.mp4", - "subtitleFile": "subtitles/101 The Boy in the Iceberg.srt" }, - { "episodeSlug": "e2", + "videoFile": "Avatar The Last Airbender/101 The Boy in the Iceberg.mp4", + "subtitleFile": "Avatar The Last Airbender/101 The Boy in the Iceberg.srt" }, + { "episodeSlug": "e02", "episodeName": "The Avatar Returns", - "videoFile": "videos/102 The Avatar Returns.mp4", - "subtitleFile": "subtitles/102 The Avatar Returns.srt" }, - { "episodeSlug": "e3", + "videoFile": "Avatar The Last Airbender/102 The Avatar Returns.mp4", + "subtitleFile": "Avatar The Last Airbender/102 The Avatar Returns.srt" }, + { "episodeSlug": "e03", "episodeName": "The Southern Air Temple", - "videoFile": "videos/103 The Southern Air Temple.mp4", - "subtitleFile": "subtitles/103 The Southern Air Temple.srt" }, - { "episodeSlug": "e4", + "videoFile": "Avatar The Last Airbender/103 The Southern Air Temple.mp4", + "subtitleFile": "Avatar The Last Airbender/103 The Southern Air Temple.srt" }, + { "episodeSlug": "e04", "episodeName": "The Warriors of Kyoshi", - "videoFile": "videos/104 The Warriors of Kyoshi.mp4", - "subtitleFile": "subtitles/104 The Warriors of Kyoshi.srt" }, - { "episodeSlug": "e5", + "videoFile": "Avatar The Last Airbender/104 The Warriors of Kyoshi.mp4", + "subtitleFile": "Avatar The Last Airbender/104 The Warriors of Kyoshi.srt" }, + { "episodeSlug": "e05", "episodeName": "The King of Omashu", - "videoFile": "videos/105 The King of Omashu.mp4", - "subtitleFile": "subtitles/105 The King of Omashu.srt" }, - { "episodeSlug": "e6", + "videoFile": "Avatar The Last Airbender/105 The King of Omashu.mp4", + "subtitleFile": "Avatar The Last Airbender/105 The King of Omashu.srt" }, + { "episodeSlug": "e06", "episodeName": "Imprisoned", - "videoFile": "videos/106 Imprisoned.mp4", - "subtitleFile": "subtitles/106 Imprisoned.srt" }, - { "episodeSlug": "e7", + "videoFile": "Avatar The Last Airbender/106 Imprisoned.mp4", + "subtitleFile": "Avatar The Last Airbender/106 Imprisoned.srt" }, + { "episodeSlug": "e07", "episodeName": "Winter Solstice, Part 1: The Spirit World", - "videoFile": "videos/107 Winter Solstice, Part 1: The Spirit World.mp4", - "subtitleFile": "subtitles/107 Winter Solstice, Part 1: The Spirit World.srt" }, - { "episodeSlug": "e8", + "videoFile": "Avatar The Last Airbender/107 Winter Solstice, Part 1: The Spirit World.mp4", + "subtitleFile": "Avatar The Last Airbender/107 Winter Solstice, Part 1: The Spirit World.srt" }, + { "episodeSlug": "e08", "episodeName": "Winter Solstice, Part 2: Avatar Roku", - "videoFile": "videos/108 Winter Solstice, Part 2: Avatar Roku.mp4", - "subtitleFile": "subtitles/108 Winter Solstice, Part 2: Avatar Roku.srt" }, - { "episodeSlug": "e9", + "videoFile": "Avatar The Last Airbender/108 Winter Solstice, Part 2: Avatar Roku.mp4", + "subtitleFile": "Avatar The Last Airbender/108 Winter Solstice, Part 2: Avatar Roku.srt" }, + { "episodeSlug": "e09", "episodeName": "The Waterbending Scroll", - "videoFile": "videos/109 The Waterbending Scroll.mp4", - "subtitleFile": "subtitles/109 The Waterbending Scroll.srt" }, + "videoFile": "Avatar The Last Airbender/109 The Waterbending Scroll.mp4", + "subtitleFile": "Avatar The Last Airbender/109 The Waterbending Scroll.srt" }, { "episodeSlug": "e10", "episodeName": "Jet", - "videoFile": "videos/110 Jet.mp4", - "subtitleFile": "subtitles/110 Jet.srt" }, + "videoFile": "Avatar The Last Airbender/110 Jet.mp4", + "subtitleFile": "Avatar The Last Airbender/110 Jet.srt" }, { "episodeSlug": "e11", "episodeName": "The Great Divide", - "videoFile": "videos/111 The Great Divide.mp4", - "subtitleFile": "subtitles/111 The Great Divide.srt" }, + "videoFile": "Avatar The Last Airbender/111 The Great Divide.mp4", + "subtitleFile": "Avatar The Last Airbender/111 The Great Divide.srt" }, { "episodeSlug": "e12", "episodeName": "The Storm", - "videoFile": "videos/112 The Storm.mp4", - "subtitleFile": "subtitles/112 The Storm.srt" }, + "videoFile": "Avatar The Last Airbender/112 The Storm.mp4", + "subtitleFile": "Avatar The Last Airbender/112 The Storm.srt" }, { "episodeSlug": "e13", "episodeName": "The Blue Spirit", - "videoFile": "videos/113 The Blue Spirit.mp4", - "subtitleFile": "subtitles/113 The Blue Spirit.srt" }, + "videoFile": "Avatar The Last Airbender/113 The Blue Spirit.mp4", + "subtitleFile": "Avatar The Last Airbender/113 The Blue Spirit.srt" }, { "episodeSlug": "e14", "episodeName": "The Fortuneteller", - "videoFile": "videos/114 The Fortuneteller.mp4", - "subtitleFile": "subtitles/114 The Fortuneteller.srt" }, + "videoFile": "Avatar The Last Airbender/114 The Fortuneteller.mp4", + "subtitleFile": "Avatar The Last Airbender/114 The Fortuneteller.srt" }, { "episodeSlug": "e15", "episodeName": "Bato of the Water Tribe", - "videoFile": "videos/115 Bato of the Water Tribe.mp4", - "subtitleFile": "subtitles/115 Bato of the Water Tribe.srt" }, + "videoFile": "Avatar The Last Airbender/115 Bato of the Water Tribe.mp4", + "subtitleFile": "Avatar The Last Airbender/115 Bato of the Water Tribe.srt" }, { "episodeSlug": "e16", "episodeName": "The Deserter", - "videoFile": "videos/116 The Deserter.mp4", - "subtitleFile": "subtitles/116 The Deserter.srt" }, + "videoFile": "Avatar The Last Airbender/116 The Deserter.mp4", + "subtitleFile": "Avatar The Last Airbender/116 The Deserter.srt" }, { "episodeSlug": "e17", "episodeName": "The Northern Air Temple", - "videoFile": "videos/117 The Northern Air Temple.mp4", - "subtitleFile": "subtitles/117 The Northern Air Temple.srt" }, + "videoFile": "Avatar The Last Airbender/117 The Northern Air Temple.mp4", + "subtitleFile": "Avatar The Last Airbender/117 The Northern Air Temple.srt" }, { "episodeSlug": "e18", "episodeName": "The Waterbending Master", - "videoFile": "videos/118 The Waterbending Master.mp4", - "subtitleFile": "subtitles/118 The Waterbending Master.srt" }, + "videoFile": "Avatar The Last Airbender/118 The Waterbending Master.mp4", + "subtitleFile": "Avatar The Last Airbender/118 The Waterbending Master.srt" }, { "episodeSlug": "e19", "episodeName": "The Siege of the North, Part 1", - "videoFile": "videos/119 The Siege of the North, Part 1.mp4", - "subtitleFile": "subtitles/119 The Siege of the North, Part 1.srt" }, + "videoFile": "Avatar The Last Airbender/119 The Siege of the North, Part 1.mp4", + "subtitleFile": "Avatar The Last Airbender/119 The Siege of the North, Part 1.srt" }, { "episodeSlug": "e20", "episodeName": "The Siege of the North, Part 2", - "videoFile": "videos/120 The Siege of the North, Part 2.mp4", - "subtitleFile": "subtitles/120 The Siege of the North, Part 2.srt" } + "videoFile": "Avatar The Last Airbender/120 The Siege of the North, Part 2.mp4", + "subtitleFile": "Avatar The Last Airbender/120 The Siege of the North, Part 2.srt" } ] } ] diff --git a/sample_config.py b/sample_config.py index b5259e0..c310558 100644 --- a/sample_config.py +++ b/sample_config.py @@ -12,7 +12,7 @@ JPEG_VRES = 720 JPEG_TINY_VRES = 100 # Path to a font acceptable to Pillow. -PIL_FONT = Path('library/fonts/Herculanum.wolff') +PIL_FONT = Path('library/Avatar The Last Airbender/knowledgeseeker/fonts/Herculanum.woff') PIL_FONT_SIZE = 60 PIL_MAXWIDTH = 30 @@ -26,7 +26,7 @@ MAX_GIF_LENGTH = timedelta(seconds=10) MAX_WEBM_LENGTH = timedelta(seconds=15) # Ffmpeg requires a path to the directory containing your desired font... -FF_FONT_DIR = Path('library/fonts/') +FF_FONT_DIR = Path('library/Avatar The Last Airbender/knowledgeseeker/fonts/') # ...and its filename, without the extension. FF_FONT_NAME = 'Herculanum' FF_FONT_SIZE = 24 diff --git a/sample_docker-compose.yml b/sample_docker-compose.yml new file mode 100644 index 0000000..643dd2e --- /dev/null +++ b/sample_docker-compose.yml @@ -0,0 +1,35 @@ +version: "3.8" + +services: + knowledgeseeker: + image: knowledge-seeker:latest # https://docs.docker.com/compose/compose-file/compose-file-v3/#image + # https://github.com/YoRyan/knowledge-seeker + configs: + - source: knowledgeseeker_config.py + target: /home/ks/.local/var/knowledgeseeker-instance/config.py + - source: atla.json + target: /home/ks/.local/var/knowledgeseeker-instance/library/atla.json + volumes: # https://docs.docker.com/compose/compose-file/compose-file-v3/#volumes + - "/home/Media/TV/Avatar The Last Airbender:/home/ks/.local/var/knowledgeseeker-instance/library/Avatar The Last Airbender" + - "/home/Media/TV/Avatar The Last Airbender/knowledge-seeker/data.db:/home/ks/.local/var/knowledgeseeker-instance/data.db" + networks: # https://docs.docker.com/compose/compose-file/compose-file-v3/#networks + - traefik + deploy: # https://docs.docker.com/compose/compose-file/compose-file-v3/#deploy + labels: # https://docs.docker.com/compose/compose-file/compose-file-v3/#labels-1 + # Essential traefik labels https://doc.traefik.io/traefik/providers/docker/ + - "traefik.enable=true" + - "traefik.http.routers.knowledgeseeker.entrypoints=websecure" + - "traefik.http.routers.knowledgeseeker.rule=Host(`knowledgeseeker.exampledomain.net`)" + - "traefik.http.services.knowledgeseeker.loadbalancer.server.port=8080" # Port traefik needs to route traffic to + # Enable middlewares + - "traefik.http.routers.knowledgeseeker.middlewares=default_circuitbreaker@file,default_security_headers@file" + +networks: + traefik: + external: true + +configs: + knowledgeseeker_config.py: + external: true + atla.json: + external: true \ No newline at end of file