Skip to content

Commit

Permalink
Update to version v1.14.0
Browse files Browse the repository at this point in the history
Create two new card types, rewrite almost all user card types, fix Plex mismatch for titles with commas, many other changes and fixes
  • Loading branch information
CollinHeist authored Apr 24, 2023
2 parents 4798a2b + e38db9f commit b7d97fa
Show file tree
Hide file tree
Showing 36 changed files with 2,202 additions and 1,243 deletions.
5 changes: 5 additions & 0 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: Discord
url: https://discord.gg/bJ3bHtw8wH
about: Please use Discord to ask for support.
56 changes: 56 additions & 0 deletions .github/ISSUE_TEMPLATE/help.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: Request help
description: Ask for help regarding an issue with your setup
title: 'HELP - '
labels: ['question']
assignees: 'CollinHeist'

body:
- type: dropdown
id: docker
attributes:
label: Installation
description: Are you using Docker or Github; and which branch/tag?
options:
- Docker - master tag
- Docker - develop tag
- GitHub - master branch
- GitHub - develop branch
validations:
required: true
- type: textarea
id: description
attributes:
label: Describe your Problem
description: A clear and concise description of your issue.
validations:
required: true
- type: textarea
id: screenshots
attributes:
label: Screenshots
description: Attach any applicable screenshots that illustrate your problem.
- type: textarea
id: preferences
attributes:
label: Preference File
description: >
Paste your Preferences file (likely preferences.yml), with your API keys and URLs omitted.
This will be automatically formatted as YAML, so no need for backticks.
render: yaml
validations:
required: true
- type: textarea
id: seriesyaml
attributes:
label: Series YAML
description: >
Paste the YAML of the relevent series.
This will be automatically formatted as YAML, so no need for backticks.
render: yaml
- type: textarea
id: log
attributes:
label: Debug Log
description: Attach the relevant log file(s) from the logs/ directory.
validations:
required: true
18 changes: 9 additions & 9 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@ verify_ssl = true
name = "pypi"

[packages]
regex = "==2022.10.31"
regex = "==2023.3.23"
num2words = "==0.5.12"
pyyaml = "==6.0"
requests = "==2.28.1"
requests = "==2.28.2"
titlecase = "==2.4"
tqdm = "==4.64.1"
fonttools = "==4.38.0"
plexapi = "==4.13.2"
tenacity = "==8.1.0"
tinydb = "==4.7.0"
schedule = "==1.1.0"
tqdm = "==4.65.0"
fonttools = "==4.39.3"
plexapi = "==4.13.4"
tenacity = "==8.2.2"
tinydb = "==4.7.1"
schedule = "==1.2.0"
tmdbapis = "==1.1.0"
"ruamel.yaml" = "*"
"ruamel.yaml" = "==0.17.21"

[dev-packages]

Expand Down
285 changes: 166 additions & 119 deletions Pipfile.lock
100755 → 100644

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ An automated title card maker for the Plex, Jellyfin, and Emby media servers. Al
## Description
`TitleCardMaker` is a program and [Docker container](https://hub.docker.com/r/collinheist/titlecardmaker) written in Python that automates the creation of customized title cards (which are image previews of an episode of TV) for use in personal media server services like [Plex](https://www.plex.tv/), [Jellyfin](https://jellyfin.org/), or [Emby](https://emby.media/).

TitleCardMaker can be automated such that everything can be pulled without manual intervention. All your series can be read from your media server or Sonarr; episode data can be pulled from Sonarr, your media server, or [TheMovieDatabase](https://www.themoviedb.org/); images from TheMovieDatabase, or your media server; and TitleCardMaker can even utilize an episode's watch status to create "spoiler free" versions of title cards automatically, as shown below:
TitleCardMaker can be automated such that everything can be done without manual intervention. All your series can be read from your media server or Sonarr; episode data can be pulled from Sonarr, your media server, or [TheMovieDatabase](https://www.themoviedb.org/); images from TheMovieDatabase, or your media server; and TitleCardMaker can even utilize an episode's watch status to create "spoiler free" versions of title cards automatically, as shown below:

<img alt="card unblurring process" src="https://user-images.githubusercontent.com/17693271/185819730-a2c55a3a-63cc-4f0e-8061-891edd8d64d0.gif"/>

All configuration/automation of the TitleCardMaker is done via YAML files, and the actual image creation is done using the open-source and free image library called [ImageMagick](https://imagemagick.org/).

## Getting Started
> The [Wiki](https://github.com/CollinHeist/TitleCardMaker/wiki) has very extensive documentation on every feature and customization available in TitleCardMaker. I __highly__ recommend looking here as the first step when troubleshooting or customizing your setup.
> The [Wiki](https://github.com/CollinHeist/TitleCardMaker/wiki) has very extensive documentation on every feature and customization available in TitleCardMaker. I __highly__ recommend looking here as the first step when troubleshooting or customizing your setup. [The Discord](https://discord.gg/bJ3bHtw8wH) is also a great place to get detailed help.
Read the [Getting Started](https://github.com/CollinHeist/TitleCardMaker/wiki) page on the Wiki for the traditional install, or the [Getting Started on Docker](https://github.com/CollinHeist/TitleCardMaker/wiki/Docker-Tutorial) page to install using Docker.

Expand All @@ -40,15 +40,15 @@ pipenv run python main.py --run

For invocation and configuration details, read [here](https://github.com/CollinHeist/TitleCardMaker/wiki/Running-the-TitleCardMaker).

> If you have trouble getting the Maker working, or have a problem, [create an issue on GitHub](https://github.com/CollinHeist/TitleCardMaker/issues/new)!
> If you have trouble getting the Maker working, or have a problem, [create an issue on GitHub](https://github.com/CollinHeist/TitleCardMaker/issues/new), or [join the Discord](https://discord.gg/bJ3bHtw8wH) for help.
## Examples
Below are some examples of each style of title card that can be created automatically by the TitleCardMaker:

### Built-in Card Types
<img alt="Anime" src="https://user-images.githubusercontent.com/17693271/185820454-4e3dca1c-c0df-4fa0-a7a7-81e070aa9e69.jpg" height="150"/> <img alt="Cutout" src="https://user-images.githubusercontent.com/17693271/212500535-e88daff6-ecc0-4cc8-8627-82069114c7e0.jpg" height="150"/> <img alt="Fade" src="https://user-images.githubusercontent.com/17693271/214648223-b4f68553-e982-4efa-a16b-9662018b5d40.jpg" height="150"/> <img alt="Frame" src="https://user-images.githubusercontent.com/17693271/202352614-155a176a-fdb0-4476-9f11-6a3a20533a54.jpg" height="150"/> <img alt="Landscape" src="https://user-images.githubusercontent.com/17693271/202352137-b411da21-65ce-4bed-991b-90428c71ec34.jpg" height="150"/> <img alt="Logo" src="https://user-images.githubusercontent.com/17693271/172227163-0ee4990a-b0a8-4dbd-91b3-3f57dfe6e732.jpg" height="150"/> <img alt="Olivier" src="https://user-images.githubusercontent.com/17693271/212500009-067f14ff-4f48-4f75-bacd-7311a9aba716.jpg" height="150"/> <img alt="Poster" src="https://user-images.githubusercontent.com/17693271/180627387-f72bb58e-e001-4608-b4be-82a26263c628.jpg" height="150"/> <img alt="Roman" src="https://user-images.githubusercontent.com/17693271/203910966-4dde1466-6c7e-4422-923b-1f9222ad49e9.jpg" height="150"/> <img alt="Standard" src="https://user-images.githubusercontent.com/17693271/212500240-ae946f2c-a5c8-4881-85f2-83ccb45bf46e.jpg" height="150"/> <img alt="Star Wars" src="https://user-images.githubusercontent.com/17693271/170836059-136fa6eb-40ef-4cd7-9aca-8ad8e0537239.jpg" height="150"/> <img alt="Tinted Glass" src="https://user-images.githubusercontent.com/17693271/213939482-6018b2be-28c5-42dd-988d-d7b9733fe0e8.jpg" height="150"/>
<img alt="Anime" src="https://user-images.githubusercontent.com/17693271/185820454-4e3dca1c-c0df-4fa0-a7a7-81e070aa9e69.jpg" height="150"/> <img alt="Cutout" src="https://user-images.githubusercontent.com/17693271/212500535-e88daff6-ecc0-4cc8-8627-82069114c7e0.jpg" height="150"/> <img alt="Divider" src="https://user-images.githubusercontent.com/17693271/232378485-a9a737dc-9faf-47c2-b639-7df3d3ffb194.jpg" height="150"> <img alt="Fade" src="https://user-images.githubusercontent.com/17693271/214648223-b4f68553-e982-4efa-a16b-9662018b5d40.jpg" height="150"/> <img alt="Frame" src="https://user-images.githubusercontent.com/17693271/202352614-155a176a-fdb0-4476-9f11-6a3a20533a54.jpg" height="150"/> <img alt="Landscape" src="https://user-images.githubusercontent.com/17693271/202352137-b411da21-65ce-4bed-991b-90428c71ec34.jpg" height="150"/> <img alt="Logo" src="https://user-images.githubusercontent.com/17693271/172227163-0ee4990a-b0a8-4dbd-91b3-3f57dfe6e732.jpg" height="150"/> <img alt="Olivier" src="https://user-images.githubusercontent.com/17693271/212500009-067f14ff-4f48-4f75-bacd-7311a9aba716.jpg" height="150"/> <img alt="Poster" src="https://user-images.githubusercontent.com/17693271/180627387-f72bb58e-e001-4608-b4be-82a26263c628.jpg" height="150"/> <img alt="Roman" src="https://user-images.githubusercontent.com/17693271/203910966-4dde1466-6c7e-4422-923b-1f9222ad49e9.jpg" height="150"/> <img alt="Standard" src="https://user-images.githubusercontent.com/17693271/212500240-ae946f2c-a5c8-4881-85f2-83ccb45bf46e.jpg" height="150"/> <img alt="Star Wars" src="https://user-images.githubusercontent.com/17693271/170836059-136fa6eb-40ef-4cd7-9aca-8ad8e0537239.jpg" height="150"> <img alt="tinted Frame" src="https://user-images.githubusercontent.com/17693271/233257029-8b17ce2e-01ea-4ae3-bc73-54e152be4d31.jpg" height="150"> <img alt="Tinted Glass" src="https://user-images.githubusercontent.com/17693271/213939482-6018b2be-28c5-42dd-988d-d7b9733fe0e8.jpg" height="150">

> The above cards are, in order, the [anime](https://github.com/CollinHeist/TitleCardMaker/wiki/AnimeTitleCard), [cutout](https://github.com/CollinHeist/TitleCardMaker/wiki/CutoutTitleCard), [fade](https://github.com/CollinHeist/TitleCardMaker/wiki/FadeTitleCard), [frame](https://github.com/CollinHeist/TitleCardMaker/wiki/FrameTitleCard), [landscape](https://github.com/CollinHeist/TitleCardMaker/wiki/LandscapeTitleCard), [logo](https://github.com/CollinHeist/TitleCardMaker/wiki/LogoTitleCard), [olivier](https://github.com/CollinHeist/TitleCardMaker/wiki/OlivierTitleCard), [poster](https://github.com/CollinHeist/TitleCardMaker/wiki/PosterTitleCard), [roman](https://github.com/CollinHeist/TitleCardMaker/wiki/RomanNumeralTitleCard), [standard](https://github.com/CollinHeist/TitleCardMaker/wiki/StandardTitleCard), [star wars](https://github.com/CollinHeist/TitleCardMaker/wiki/StarWarsTitleCard), and the [tinted glass](https://github.com/CollinHeist/TitleCardMaker/wiki/TintedGlassTitleCard) title cards - the [textless](https://github.com/CollinHeist/TitleCardMaker/wiki/TitleCard) card is not shown.
> The above cards are, in order, the [anime](https://github.com/CollinHeist/TitleCardMaker/wiki/AnimeTitleCard), [cutout](https://github.com/CollinHeist/TitleCardMaker/wiki/CutoutTitleCard), [divider](https://github.com/CollinHeist/TitleCardMaker/wiki/DividerTitleCard) [fade](https://github.com/CollinHeist/TitleCardMaker/wiki/FadeTitleCard), [frame](https://github.com/CollinHeist/TitleCardMaker/wiki/FrameTitleCard), [landscape](https://github.com/CollinHeist/TitleCardMaker/wiki/LandscapeTitleCard), [logo](https://github.com/CollinHeist/TitleCardMaker/wiki/LogoTitleCard), [olivier](https://github.com/CollinHeist/TitleCardMaker/wiki/OlivierTitleCard), [poster](https://github.com/CollinHeist/TitleCardMaker/wiki/PosterTitleCard), [roman](https://github.com/CollinHeist/TitleCardMaker/wiki/RomanNumeralTitleCard), [standard](https://github.com/CollinHeist/TitleCardMaker/wiki/StandardTitleCard), [star wars](https://github.com/CollinHeist/TitleCardMaker/wiki/StarWarsTitleCard), [tinted frame](https://github.com/CollinHeist/TitleCardMaker/wiki/TintedFrameTitleCard), and the [tinted glass](https://github.com/CollinHeist/TitleCardMaker/wiki/TintedGlassTitleCard) title cards - the [textless](https://github.com/CollinHeist/TitleCardMaker/wiki/TitleCard) card is not shown.

<details><summary><h3>User-Created Card Types</h3></summary>

Expand Down
40 changes: 21 additions & 19 deletions mini_maker.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@
metavar=('TITLE_LINE'),
help="The title text for this card")
title_card_group.add_argument(
'--font', '--font-file',
'--font-file', '--font',
type=Path,
default='__default',
metavar='FONT_FILE',
Expand All @@ -111,25 +111,25 @@
metavar='#HEX',
help='A custom font color for this card')
title_card_group.add_argument(
'--vertical-shift', '--shift',
'--font-vertical-shift', '--vertical-shift',
type=float,
default=0.0,
metavar='PIXELS',
help='How many pixels to vertically shift the title text')
title_card_group.add_argument(
'--interline-spacing', '--spacing',
'--font-interline-spacing', '--interline-spacing',
type=float,
default=0.0,
metavar='PIXELS',
help='How many pixels to increase the interline spacing of the title text')
title_card_group.add_argument(
'--kerning',
'--font-kerning', '--kerning',
type=str,
default='100%',
metavar='SCALE%',
help='Specify the font kerning scale (as percentage)')
title_card_group.add_argument(
'--stroke-width', '--stroke',
'--font-stroke-width', '--stroke-width','
type=str,
default='100%',
metavar='SCALE%',
Expand Down Expand Up @@ -383,28 +383,29 @@
RemoteFile.reset_loaded_database()

# Override unspecified defaults with their class specific defaults
if args.font == Path('__default'):
args.font = Path(str(CardClass.TITLE_FONT))
if args.font_file == Path('__default'):
args.font_file = Path(str(CardClass.TITLE_FONT))
if args.font_color == '__default':
args.font_color = CardClass.TITLE_COLOR

# Create the given card
output_file = CleanPath(args.title_card[1]).sanitize()
output_file.unlink(missing_ok=True)
card = CardClass(
episode_text=args.episode,
source=Path(args.title_card[0]),
output_file=output_file,
source_file=CleanPath(args.title_card[0]).sanitize(),
card_file=output_file,
title_text='\n'.join(args.title),
season_text=('' if not args.season else args.season),
title='\n'.join(args.title),
font=args.font.resolve(),
episode_text=args.episode,
hide_season_text=(not bool(args.season)),
hide_episode_text=(not bool(args.episode)),
font_color=args.font_color,
font_file=args.font_file.resolve(),
font_interline_spacing=args.font_interline_spacing,
font_kerning=float(args.font_kerning[:-1])/100.0,
font_size=float(args.font_size[:-1])/100.0,
title_color=args.font_color,
hide_season=(not bool(args.season)),
vertical_shift=args.vertical_shift,
interline_spacing=args.interline_spacing,
kerning=float(args.kerning[:-1])/100.0,
stroke_width=float(args.stroke_width[:-1])/100.0,
font_stroke_width=float(args.sfont_troke_width[:-1])/100.0,
font_vertical_shift=args.font_vertical_shift,
blur=args.blur,
grayscale=args.grayscale,
omit_gradient=args.no_gradient,
Expand Down Expand Up @@ -460,9 +461,10 @@
top_subtitle=args.movie_top_subtitle,
movie_index=args.movie_index,
logo=args.movie_logo,
font=args.movie_font,
font_file=args.movie_font,
font_color=args.movie_font_color,
font_size=float(args.movie_font_size[:-1])/100.0,
borderless=args.borderless,
omit_gradient=args.no_gradient,
).create()

Expand Down
42 changes: 33 additions & 9 deletions modules/BaseCardType.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from abc import abstractmethod
from typing import Any, Optional
from typing import Any, Optional, Union

from titlecase import titlecase

Expand Down Expand Up @@ -51,7 +51,7 @@ class BaseCardType(ImageMaker):

@property
@abstractmethod
def TITLE_CHARACTERISTICS(self) -> dict[str, 'int | bool']:
def TITLE_CHARACTERISTICS(self) -> dict[str, Union[int, bool]]:
"""
Characteristics of title splitting for this card type. Must have
keys for max_line_width, max_line_count, and top_heavy. See
Expand Down Expand Up @@ -180,10 +180,10 @@ def is_custom_season_titles() -> bool:


@property
def resize_and_style(self) -> ImageMagickCommands:
def resize(self) -> ImageMagickCommands:
"""
ImageMagick commands to resize and apply any style modifiers to
an image.
ImageMagick commands to only resize an image to the output title
card size.
Returns:
List of ImageMagick commands.
Expand All @@ -200,19 +200,37 @@ def resize_and_style(self) -> ImageMagickCommands:
# Fit to title card size
f'-resize "{self.TITLE_CARD_SIZE}^"',
f'-extent "{self.TITLE_CARD_SIZE}"',
]


@property
def style(self) -> ImageMagickCommands:
"""
ImageMagick commands to apply any style modifiers to an image.
Returns:
List of ImageMagick commands.
"""

return [
# Full sRGB colorspace on source image
f'-set colorspace sRGB',
# Ignore profile conversion warnings
f'+profile "*"',
# Optionally blur
f'-blur {self.BLUR_PROFILE}' if self.blur else '',
# Optionally set gray colorspace
f'-colorspace gray' if self.grayscale else '',
# Reset to full colorspace
f'-set colorspace sRGB',
f'-set colorspace sRGB' if self.grayscale else '',
]


@property
def style(self) -> ImageMagickCommands:
def resize_and_style(self) -> ImageMagickCommands:
"""
ImageMagick commands to apply any style modifiers to an image.
ImageMagick commands to resize and apply any style modifiers to
an image.
Returns:
List of ImageMagick commands.
Expand All @@ -223,12 +241,18 @@ def style(self) -> ImageMagickCommands:
f'-set colorspace sRGB',
# Ignore profile conversion warnings
f'+profile "*"',
# Background resize shouldn't fill with any color
f'-background transparent',
f'-gravity center',
# Fit to title card size
f'-resize "{self.TITLE_CARD_SIZE}^"',
f'-extent "{self.TITLE_CARD_SIZE}"',
# Optionally blur
f'-blur {self.BLUR_PROFILE}' if self.blur else '',
# Optionally set gray colorspace
f'-colorspace gray' if self.grayscale else '',
# Reset to full colorspace
f'-set colorspace sRGB' if self.grayscale else '',
f'-set colorspace sRGB',
]


Expand Down
7 changes: 4 additions & 3 deletions modules/EmbyInterface.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ def set_episode_ids(self, series_info: SeriesInfo,
self.get_all_episodes(series_info)


def get_library_paths(self, filter_libraries: list[str]=[]
def get_library_paths(self, filter_libraries: list[str] = []
) -> dict[str, list[str]]:
"""
Get all libraries and their associated base directories.
Expand Down Expand Up @@ -267,8 +267,9 @@ def include_library(emby_library) -> bool:
}


def get_all_series(self, filter_libraries: list[str]=[],
required_tags: list[str]=[]) -> list[tuple[SeriesInfo, str, str]]:
def get_all_series(self,
filter_libraries: list[str] = [],
required_tags: list[str] = []) -> list[tuple[SeriesInfo, str, str]]:
"""
Get all series within Emby, as filtered by the given libraries.
Expand Down
Loading

0 comments on commit b7d97fa

Please sign in to comment.