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
2 changes: 1 addition & 1 deletion .envrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
layout python3
layout pyenv 3.11.10
python -m pip install --upgrade pip
python -m pip install -r requirements.txt

2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
**/*.pickle
**/*.sqlite

config.yaml

Kometa/metadata-items

Plex/movies
Expand Down
41 changes: 41 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Run current Kometa file",
"type": "debugpy",
"justMyCode": false,
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"cwd": "${workspaceFolder}/Kometa",
"purpose": [
"debug-in-terminal"
],
"args": [ ]
},
{
"name": "Run current Plex file",
"type": "debugpy",
"justMyCode": false,
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"cwd": "${workspaceFolder}/Plex",
"purpose": [
"debug-in-terminal"
],
"args": [ ]
},
{
"name": "Python Debugger: Current File",
"type": "debugpy",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal"
}
]
}
23 changes: 0 additions & 23 deletions Kometa/.env.example

This file was deleted.

89 changes: 61 additions & 28 deletions Kometa/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,11 @@ Misc scripts and tools. Undocumented scripts probably do what I need them to but

See the top-level [README](../README.md) for setup instructions.

All these scripts use the same `.env` and requirements.
All these scripts use the same `config.yaml` and requirements.

Any that communicate with Plex require:
```
PLEXAPI_AUTH_SERVER_BASEURL=https://plex.domain.tld
# Just the base URL, no /web or anything at the end.
# i.e. http://192.168.1.11:32400 or the like
PLEXAPI_AUTH_SERVER_TOKEN=PLEX-TOKEN
```
### `config.template.yaml` contents

The `config.yaml` template can be viewed here: [../config.template.yaml](../config.template.yaml).

## Scripts:
1. [clean-overlay-backup.py](#clean-overlay-backuppy) - clean out leftover overlay backup art
Expand All @@ -34,18 +30,21 @@ You've deleted stuff from Plex and want to clean up the leftover backup art that

### Settings

The script uses these settings from the `.env`:
```
LIBRARY_NAMES=Movies,TV Shows,Movies 4K # comma-separated list of libraries to act on
DELAY=1 # optional delay between items
KOMETA_CONFIG_DIR=/opt/kometa/config/ # path to Kometa config directory
The script uses these settings from the `config.yaml`:
```yaml
general:
delay: 1 # optional delay between items
library_names: Movies,TV Shows,Movies 4K # comma-separated list of libraries to act on

kometa:
config_dir: /kometa/is/here # location of Kometa config dir as seen by this script
```

### Usage
1. setup as above
2. Run with `python clean-overlay-backup.py`

The script will catalog the backup files and current Plex contents for each library listed in the `.env`.
The script will catalog the backup files and current Plex contents for each library listed in the `config.yaml`.

It then compares the two lists, and any files in the backup dir that do not correspond to current items in Plkex are deleted.

Expand All @@ -56,7 +55,7 @@ connecting to https://plex.bing.bang...
Loading Movies ...
Loading movies from Movies ...
Completed loading 6965 of 6965 movie(s) from Movies
Clean Overlay Backup Movies |████████████████████████████████████████| 6965/6965 [100%] in 11.0s (633.23/s)
Clean Overlay Backup Movies |████████████████████████████████████████| 6965/6965 [100%] in 11.0s (633.23/s)
Processed 6965 of 6965
0 items to delete
279 items in Plex with no backup art
Expand All @@ -72,6 +71,7 @@ You're getting started with Kometa and you want to export your existing collecti
Here is a quick and dirty [emphasis on "quick" and "dirty"] way to do that.

### Usage

1. setup as above
2. Run with `python extract-collections.py`

Expand Down Expand Up @@ -110,7 +110,7 @@ Here is a basic script to do that.

The script will clone or update the `Kometa-Images` repo, then iterate through it applying overlays to each image and storing them in a parallel file system rooted at `Kometa-Images-Overlaid`, ready for you to use with the Kometa Asset Directory [after moving them to that directory] or via template variables.

It chooses the overlay by name based on the "group" that each collection is part of:
It chooses the overlay by name based on the "group" that each collection is part of:
```
Kometa-Images
├── aspect
Expand Down Expand Up @@ -143,7 +143,7 @@ If there isn't a specific image for a "group", then `Kometa/default_collection_o
Fetch/Pull on Kometa-Images
Using default_collection_overlays/overlay-template.png as global overlay
building list of targets
Applying overlays |████████████████████████████▎ | ▇▅▃ 5027/7119 [71%] in 3:53 (21.6/s, eta: 1:37)
Applying overlays |████████████████████████████▎ | ▇▅▃ 5027/7119 [71%] in 3:53 (21.6/s, eta: 1:37)
Kometa-Images/genre/Sword & Sandal.jpg
```

Expand Down Expand Up @@ -266,18 +266,29 @@ Note, this will only copy images that have received overlays, and for which the

If you don't have overlays on any episodes, this script will not put any episode images in the asset directory, and so on.

```yaml
image_download:
where_to_put_it:
use_asset_folders: 1 # should those Kometa-Asset-Directory names use asset folders?
asset_dir: "assets" # top-level directory for those Kometa-Asset-Directory images
```
# ORIGINAL TO ASSETS
USE_ASSET_FOLDERS=1 # should the asset directory use asset folders?
ASSET_DIR=assets # top-level directory for those assets

The asset file system will be rooted at the directory in the `asset_dir` setting, and `use_asset_folders` controls whether the images are stored as:

```yaml
use_asset_folders: 1
```
The asset file system will be rooted at the directory in the `ASSET_DIR` setting, and `USE_ASSET_FOLDERS` controls whether the images are stored as:

`USE_ASSET_FOLDERS=1`
```
Media-Scripts/Plex/assets/All That Jazz (1979) {imdb-tt0078754} {tmdb-16858}.jpg
```
or `USE_ASSET_FOLDERS=0`

or

```yaml
use_asset_folders: 0
```

```
Media-Scripts/Plex/assets/All That Jazz (1979) {imdb-tt0078754} {tmdb-16858}/poster.jpg
```
Expand All @@ -289,7 +300,7 @@ connecting to https://test-plex.DOMAIN.TLD...
Loading Test-Movies ...
Loading movies ...
Completed loading 35 of 35 movie(s) from Test-Movies
Grab all posters Test-Movies |████████████████████████████████████████| 35/35 [100%] in 0.2s (190.63/s)
Grab all posters Test-Movies |████████████████████████████████████████| 35/35 [100%] in 0.2s (190.63/s)
Processed 35 of 35
Complete!
```
Expand All @@ -300,6 +311,24 @@ You want to seed a Kometa metadata file with the contents of one or more librari

Here is a basic script to do that.

Script-specific variables in `config.yaml`:

```yaml
metadata:
download_images: false # should the script download files like images and themes
only_first_genre: true # should the script include only the first genre that Plex has assigned to the item?

include_audience_rating: true
include_content_rating: true
# ... rest of fields redacted for space...
```

There has recently been a regression in some PlexAPI code such that for the moment you should leave `download_images: false`

This should be cleared up relatively soon.

You can turn off individual fields with the `include_` flags.

### Usage
1. setup as above
1. Run with `metadata-extractor.py`
Expand All @@ -310,6 +339,8 @@ IMPORTANT NOTES:

This script backs up all Kometa-supported metadata [with a few minor exceptions], which includes things you may not have changed. It also includes the "Overlay" label. It backs up this label because it *also* backs up the current art, which might be overlaid. You will probably want to edit or trim this file before using it to restore.

NOTE: This functionality is hobbled currently by the image-downloading issue.

Metadata not backed up:
```
metadata_language Movie, Show
Expand Down Expand Up @@ -370,10 +401,12 @@ For each movie, gets the cast from TMDB; keeps track across all movies how many

At the end, builds a basic Kometa metadata file for the top N actors.

Script-specific variables in .env:
```
CAST_DEPTH=20 ### HOW DEEP TO GO INTO EACH MOVIE CAST
TOP_COUNT=10 ### PUT THIS MANY INTO THE FILE AT THE END
Script-specific variables in `config.yaml`:

```yaml
actor:
cast_depth: 20 # how deep to go into the cast for actor collections
top_count: 10 # how many actors to export
```

`CAST_DEPTH` is meant to prevent some journeyman character actor from showing up in the top ten; I'm thinking of someone like Clint Howard who's been in the cast of many movies, but I'm guessing when you think of the top ten actors in your library you're not thinking about Clint. Maybe you are, though, in which case set that higher.
Expand Down
67 changes: 67 additions & 0 deletions Kometa/captions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
from pytube import Channel
import os

def download_subtitles_from_channel(channel_url, output_path='.'):
"""
Downloads subtitles for all videos from a YouTube channel.

Args:
channel_url (str): The URL of the YouTube channel.
output_path (str): The directory to save the subtitles.
"""
try:
c = Channel(channel_url)
print(f"Processing channel: {c.channel_name}")

# Create output directory if it doesn't exist
if not os.path.exists(output_path):
os.makedirs(output_path)
print(f"Created output directory: {output_path}")

video_count = 0
caption_count = 0

for video in c.videos:
video_count += 1
print(f"\nProcessing video {video_count}: {video.title}")

try:
# Check if captions are available
if video.captions:
# You can specify the language code, e.g., 'en' for English
# Use video.captions to see all available caption languages
if 'en' in video.captions:
caption = video.captions['en']
print("Downloading English captions...")

# Generate a safe filename
filename = f"{video.title}.en.srt"
safe_filename = "".join(x for x in filename if x.isalnum() or x in "._- ").strip()
file_path = os.path.join(output_path, safe_filename)

# Save the captions as an .srt file
with open(file_path, 'w', encoding='utf-8') as f:
f.write(caption.generate_srt_file())
caption_count += 1
print(f"✅ Downloaded and saved captions to: {file_path}")
else:
print("⚠️ English captions not found for this video. Skipping.")
else:
print("⚠️ No captions available for this video. Skipping.")

except Exception as e:
print(f"An error occurred while processing video {video.title}: {e}")

print(f"\n--- Script finished ---")

Check failure on line 55 in Kometa/captions.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (F541)

Kometa/captions.py:55:15: F541 f-string without any placeholders
print(f"Successfully processed {len(c.videos)} videos.")
print(f"Successfully downloaded captions for {caption_count} videos.")

except Exception as e:
print(f"An error occurred with the channel URL: {e}")

# --- USAGE ---
# Replace with the URL of the YouTube channel you want to download from
CHANNEL_URL = 'https://www.youtube.com/@freecodecamp'
OUTPUT_FOLDER = './youtube_captions'

download_subtitles_from_channel(CHANNEL_URL, OUTPUT_FOLDER)
Loading