Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion knowledgeseeker/clips.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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')

Expand All @@ -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')

Expand Down
100 changes: 50 additions & 50 deletions library/atla.json
Original file line number Diff line number Diff line change
@@ -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" }
] }
]
4 changes: 2 additions & 2 deletions sample_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
Expand Down
35 changes: 35 additions & 0 deletions sample_docker-compose.yml
Original file line number Diff line number Diff line change
@@ -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