mirror of
https://github.com/meisnate12/Plex-Meta-Manager
synced 2024-11-21 20:13:05 +00:00
v1.15.1 finishing touches
This commit is contained in:
parent
9e02ba04e7
commit
4c4fa2e1df
12 changed files with 52 additions and 86 deletions
44
.github/workflows/develop-arm7.yml
vendored
44
.github/workflows/develop-arm7.yml
vendored
|
@ -1,44 +0,0 @@
|
|||
name: Docker Develop Release Arm7
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ develop ]
|
||||
pull_request:
|
||||
branches: [ develop ]
|
||||
|
||||
jobs:
|
||||
|
||||
docker-develop:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
||||
- name: Check Out Repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: develop
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@master
|
||||
with:
|
||||
platforms: all
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
|
||||
- name: Build and push
|
||||
id: docker_build
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: ./
|
||||
file: ./Dockerfile
|
||||
platforms: linux/arm/v7
|
||||
push: true
|
||||
tags: ${{ secrets.DOCKER_HUB_USERNAME }}/plex-meta-manager:develop
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -9,7 +9,7 @@ __pycache__/
|
|||
# Distribution / packaging
|
||||
.idea
|
||||
.Python
|
||||
/test.py
|
||||
/test*
|
||||
logs/
|
||||
config/*
|
||||
!config/overlays/
|
||||
|
|
|
@ -80,9 +80,9 @@ Before posting on GitHub about an enhancement, error, or configuration question
|
|||
- [MyAnimeList Attributes](https://github.com/meisnate12/Plex-Meta-Manager/wiki/MyAnimeList-Attributes)
|
||||
- [Metadata and Playlist Files](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Metadata-and-Playlist-Files)
|
||||
- Metadata
|
||||
- [Movies Metadata](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Movies-Metadata)
|
||||
- [Shows Metadata](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Shows-Metadata)
|
||||
- [Artists Metadata](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Artists-Metadata)
|
||||
- [Movie Library Metadata](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Movie-Library-Metadata)
|
||||
- [TV Show Library Metadata](https://github.com/meisnate12/Plex-Meta-Manager/wiki/TV-Show-Library-Metadata)
|
||||
- [Music Library Metadata](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Music-Library-Metadata)
|
||||
- [Templates](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Templates)
|
||||
- [Filters](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Filters)
|
||||
- Builders
|
||||
|
@ -93,6 +93,7 @@ Before posting on GitHub about an enhancement, error, or configuration question
|
|||
- [IMDb Builders](https://github.com/meisnate12/Plex-Meta-Manager/wiki/IMDb-Builders)
|
||||
- [Trakt Builders](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Trakt-Builders)
|
||||
- [Tautulli Builders](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Tautulli-Builders)
|
||||
- [MdbList Builders](https://github.com/meisnate12/Plex-Meta-Manager/wiki/MdbList-Builders)
|
||||
- [Letterboxd Builders](https://github.com/meisnate12/Plex-Meta-Manager/wiki/Letterboxd-Builders)
|
||||
- [ICheckMovies Builders](https://github.com/meisnate12/Plex-Meta-Manager/wiki/ICheckMovies-Builders)
|
||||
- [FlixPatrol Builders](https://github.com/meisnate12/Plex-Meta-Manager/wiki/FlixPatrol-Builders)
|
||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
1.15.0-develop220122
|
||||
1.15.1
|
|
@ -26,6 +26,8 @@ settings: # Can be individually specified
|
|||
dimensional_asset_rename: false
|
||||
download_url_assets: false
|
||||
show_missing_season_assets: false
|
||||
show_missing_episode_assets: false
|
||||
show_asset_not_needed: true
|
||||
sync_mode: append
|
||||
minimum_items: 1
|
||||
default_collection_order:
|
||||
|
@ -43,6 +45,7 @@ settings: # Can be individually specified
|
|||
tvdb_language: eng
|
||||
ignore_ids:
|
||||
ignore_imdb_ids:
|
||||
item_refresh_delay: 0
|
||||
playlist_sync_to_user: all
|
||||
verify_ssl: true
|
||||
webhooks: # Can be individually specified per library as well
|
||||
|
|
|
@ -109,7 +109,7 @@ sonarr_details = [
|
|||
"sonarr_add_missing", "sonarr_add_existing", "sonarr_folder", "sonarr_monitor", "sonarr_language", "sonarr_series",
|
||||
"sonarr_quality", "sonarr_season", "sonarr_search", "sonarr_cutoff_search", "sonarr_tag"
|
||||
]
|
||||
album_details = ["item_label", "item_album_sorting"]
|
||||
album_details = ["non_item_remove_label", "item_label", "item_album_sorting"]
|
||||
filters_by_type = {
|
||||
"movie_show_season_episode_artist_album_track": ["title", "summary", "collection", "has_collection", "added", "last_played", "user_rating", "plays"],
|
||||
"movie_show_season_episode_album_track": ["year"],
|
||||
|
@ -165,7 +165,7 @@ custom_sort_builders = [
|
|||
"flixpatrol_url", "flixpatrol_demographics", "flixpatrol_popular", "flixpatrol_top",
|
||||
"trakt_recommended_daily", "trakt_recommended_weekly", "trakt_recommended_monthly", "trakt_recommended_yearly", "trakt_recommended_all",
|
||||
"trakt_watched_daily", "trakt_watched_weekly", "trakt_watched_monthly", "trakt_watched_yearly", "trakt_watched_all",
|
||||
"tautulli_popular", "tautulli_watched", "letterboxd_list", "icheckmovies_list",
|
||||
"tautulli_popular", "tautulli_watched", "mdblist_list", "letterboxd_list", "icheckmovies_list",
|
||||
"anilist_top_rated", "anilist_popular", "anilist_trending", "anilist_search",
|
||||
"mal_all", "mal_airing", "mal_upcoming", "mal_tv", "mal_movie", "mal_ova", "mal_special",
|
||||
"mal_popular", "mal_favorite", "mal_suggested", "mal_userlist", "mal_season", "mal_genre", "mal_studio"
|
||||
|
@ -182,7 +182,7 @@ playlist_attributes = [
|
|||
"server_preroll", "changes_webhooks", "minimum_items",
|
||||
] + custom_sort_builders + summary_details + poster_details + radarr_details + sonarr_details
|
||||
music_attributes = [
|
||||
"item_label", "item_assets", "item_lock_background", "item_lock_poster", "item_lock_title",
|
||||
"non_item_remove_label", "item_label", "item_assets", "item_lock_background", "item_lock_poster", "item_lock_title",
|
||||
"item_refresh", "item_refresh_delay", "plex_search", "plex_all", "filters"
|
||||
] + details + summary_details + poster_details + background_details
|
||||
|
||||
|
@ -1090,7 +1090,7 @@ class CollectionBuilder:
|
|||
self.builders.append((method_name, self._parse(method_name, method_data, "bool")))
|
||||
|
||||
def _mdblist(self, method_name, method_data):
|
||||
for mdb_dict in self.config.Mdblist.validate_mdb_lists(method_data, self.language):
|
||||
for mdb_dict in self.config.Mdblist.validate_mdblist_lists(method_data):
|
||||
self.builders.append((method_name, mdb_dict))
|
||||
|
||||
def _tautulli(self, method_name, method_data):
|
||||
|
@ -1356,7 +1356,7 @@ class CollectionBuilder:
|
|||
if tvdb_id not in self.missing_shows:
|
||||
self.missing_shows.append(tvdb_id)
|
||||
except Failed as e:
|
||||
logger.error(e)
|
||||
logger.warning(e)
|
||||
elif show_id not in self.missing_shows:
|
||||
self.missing_shows.append(show_id)
|
||||
else:
|
||||
|
@ -1374,7 +1374,7 @@ class CollectionBuilder:
|
|||
try:
|
||||
input_id = self.config.Convert.tmdb_to_tvdb(input_id, fail=True)
|
||||
except Failed as e:
|
||||
logger.error(e)
|
||||
logger.warning(e)
|
||||
continue
|
||||
if input_id not in self.ignore_ids:
|
||||
if input_id in self.library.show_map:
|
||||
|
@ -1396,7 +1396,7 @@ class CollectionBuilder:
|
|||
if tvdb_id not in self.missing_shows:
|
||||
self.missing_shows.append(tvdb_id)
|
||||
except Failed as e:
|
||||
logger.error(e)
|
||||
logger.warning(e)
|
||||
continue
|
||||
if not isinstance(rating_keys, list):
|
||||
rating_keys = [rating_keys]
|
||||
|
@ -2514,4 +2514,4 @@ class CollectionBuilder:
|
|||
logger.info(f"{name} {self.Type} | ? | {title} (TVDb: {missing_id})")
|
||||
logger.info(f"{len(self.run_again_shows)} Show{'s' if len(self.run_again_shows) > 1 else ''} Missing")
|
||||
|
||||
return amount_added
|
||||
return amount_added
|
||||
|
|
|
@ -54,7 +54,7 @@ class ConfigFile:
|
|||
self.run_hour = datetime.strptime(attrs["time"], "%H:%M").hour
|
||||
self.requested_collections = util.get_list(attrs["collections"]) if "collections" in attrs else None
|
||||
self.requested_libraries = util.get_list(attrs["libraries"]) if "libraries" in attrs else None
|
||||
self.requested_metadata = util.get_list(attrs["metadata"]) if "metadata" in attrs else None
|
||||
self.requested_metadata_files = util.get_list(attrs["metadata_files"]) if "metadata_files" in attrs else None
|
||||
self.resume_from = attrs["resume"] if "resume" in attrs else None
|
||||
|
||||
yaml.YAML().allow_duplicate_keys = True
|
||||
|
@ -667,11 +667,14 @@ class ConfigFile:
|
|||
if lib["operations"]["genre_mapper"] and isinstance(lib["operations"]["genre_mapper"], dict):
|
||||
params["genre_mapper"] = {}
|
||||
for new_genre, old_genres in lib["operations"]["genre_mapper"].items():
|
||||
for old_genre in util.get_list(old_genres):
|
||||
if old_genre == new_genre:
|
||||
logger.error("Config Error: genres cannot be mapped to themselves")
|
||||
else:
|
||||
params["genre_mapper"][old_genre] = new_genre
|
||||
if old_genres is None:
|
||||
params["genre_mapper"][new_genre] = old_genres
|
||||
else:
|
||||
for old_genre in util.get_list(old_genres):
|
||||
if old_genre == new_genre:
|
||||
logger.error("Config Error: genres cannot be mapped to themselves")
|
||||
else:
|
||||
params["genre_mapper"][old_genre] = new_genre
|
||||
else:
|
||||
logger.error("Config Error: genre_mapper is blank")
|
||||
if "genre_collections" in lib["operations"]:
|
||||
|
|
|
@ -75,9 +75,9 @@ class Convert:
|
|||
elif anidb_id in self.anidb_to_tvdb:
|
||||
ids.append((self.anidb_to_tvdb[anidb_id], "tvdb"))
|
||||
elif anidb_id in self.anidb_ids:
|
||||
logger.error(f"Convert Error: No TVDb ID or IMDb ID found for AniDB ID: {anidb_id}")
|
||||
logger.warning(f"Convert Error: No TVDb ID or IMDb ID found for AniDB ID: {anidb_id}")
|
||||
else:
|
||||
logger.error(f"Convert Error: AniDB ID: {anidb_id} not found")
|
||||
logger.warning(f"Convert Error: AniDB ID: {anidb_id} not found")
|
||||
return ids
|
||||
|
||||
def anilist_to_ids(self, anilist_ids, library):
|
||||
|
@ -86,7 +86,7 @@ class Convert:
|
|||
if anilist_id in self.anilist_to_anidb:
|
||||
anidb_ids.append(self.anilist_to_anidb[anilist_id])
|
||||
else:
|
||||
logger.error(f"Convert Error: AniDB ID not found for AniList ID: {anilist_id}")
|
||||
logger.warning(f"Convert Error: AniDB ID not found for AniList ID: {anilist_id}")
|
||||
return self.anidb_to_ids(anidb_ids, library)
|
||||
|
||||
def myanimelist_to_ids(self, mal_ids, library):
|
||||
|
@ -97,7 +97,7 @@ class Convert:
|
|||
elif int(mal_id) in self.mal_to_anidb:
|
||||
ids.extend(self.anidb_to_ids(self.mal_to_anidb[int(mal_id)], library))
|
||||
else:
|
||||
logger.error(f"Convert Error: AniDB ID not found for MyAnimeList ID: {mal_id}")
|
||||
logger.warning(f"Convert Error: AniDB ID not found for MyAnimeList ID: {mal_id}")
|
||||
return ids
|
||||
|
||||
def tmdb_to_imdb(self, tmdb_id, is_movie=True, fail=False):
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import logging, os, requests, shutil, time
|
||||
import logging, os, shutil, time
|
||||
from abc import ABC, abstractmethod
|
||||
from modules import util
|
||||
from modules.meta import MetadataFile
|
||||
|
|
|
@ -1,19 +1,20 @@
|
|||
import logging
|
||||
from modules import util
|
||||
from modules.util import Failed
|
||||
from urllib.parse import urlparse
|
||||
|
||||
logger = logging.getLogger("Plex Meta Manager")
|
||||
|
||||
builders = ["mdblist_list"]
|
||||
base_url = "https://mdblist.com/lists"
|
||||
|
||||
headers = { 'User-Agent': 'Plex-Meta-Manager' }
|
||||
headers = {"User-Agent": "Plex-Meta-Manager"}
|
||||
|
||||
class Mdblist:
|
||||
def __init__(self, config):
|
||||
self.config = config
|
||||
|
||||
def validate_mdb_lists(self, mdb_lists, language):
|
||||
def validate_mdblist_lists(self, mdb_lists):
|
||||
valid_lists = []
|
||||
for mdb_dict in util.get_list(mdb_lists, split=False):
|
||||
if not isinstance(mdb_dict, dict):
|
||||
|
@ -49,7 +50,9 @@ class Mdblist:
|
|||
if method == "mdblist_list":
|
||||
limit_status = f" Limit at: {data['limit']} items" if data['limit'] > 0 else ''
|
||||
logger.info(f"Processing Mdblist.com List: {data['url']}{limit_status}")
|
||||
url = f"{data['url']}?limit={data['limit']}"
|
||||
return [(i["imdb_id"], "imdb") for i in self.config.get_json(url,headers=headers)]
|
||||
parsed_url = urlparse(data["url"])
|
||||
url_base = parsed_url._replace(query=None).geturl()
|
||||
params = {"limit": data["limit"]} if data["limit"] > 0 else None
|
||||
return [(i["imdb_id"], "imdb") for i in self.config.get_json(url_base, headers=headers, params=params)]
|
||||
else:
|
||||
raise Failed(f"Mdblist Error: Method {method} not supported")
|
||||
|
|
|
@ -31,18 +31,18 @@ def get_dict(attribute, attr_data, check_list=None):
|
|||
new_dict = {}
|
||||
for _name, _data in attr_data[attribute].items():
|
||||
if _name in check_list:
|
||||
logger.error(f"Config Warning: Skipping duplicate {attribute[:-1] if attribute[-1] == 's' else attribute}: {_name}")
|
||||
logger.warning(f"Config Warning: Skipping duplicate {attribute[:-1] if attribute[-1] == 's' else attribute}: {_name}")
|
||||
elif _data is None:
|
||||
logger.error(f"Config Warning: {attribute[:-1] if attribute[-1] == 's' else attribute}: {_name} has no data")
|
||||
logger.error(f"Config Error: {attribute[:-1] if attribute[-1] == 's' else attribute}: {_name} has no data")
|
||||
elif not isinstance(_data, dict):
|
||||
logger.error(f"Config Warning: {attribute[:-1] if attribute[-1] == 's' else attribute}: {_name} must be a dictionary")
|
||||
logger.error(f"Config Error: {attribute[:-1] if attribute[-1] == 's' else attribute}: {_name} must be a dictionary")
|
||||
else:
|
||||
new_dict[str(_name)] = _data
|
||||
return new_dict
|
||||
else:
|
||||
logger.warning(f"Config Warning: {attribute} must be a dictionary")
|
||||
logger.error(f"Config Error: {attribute} must be a dictionary")
|
||||
else:
|
||||
logger.warning(f"Config Warning: {attribute} attribute is blank")
|
||||
logger.error(f"Config Error: {attribute} attribute is blank")
|
||||
return None
|
||||
|
||||
|
||||
|
@ -238,7 +238,7 @@ class MetadataFile(DataFile):
|
|||
logger.info("")
|
||||
logger.info(f"Loading Metadata {file_type}: {path}")
|
||||
data = self.load_file()
|
||||
self.metadata = get_dict("metadata", data, library.metadatas)
|
||||
self.metadata = get_dict("metadata", data, library.metadata_files)
|
||||
self.templates = get_dict("templates", data)
|
||||
self.collections = get_dict("collections", data, library.collections)
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ parser.add_argument("-lo", "--library-only", "--libraries-only", dest="library_o
|
|||
parser.add_argument("-lf", "--library-first", "--libraries-first", dest="library_first", help="Run library operations before collections", action="store_true", default=False)
|
||||
parser.add_argument("-rc", "-cl", "--collection", "--collections", "--run-collection", "--run-collections", dest="collections", help="Process only specified collections (comma-separated list)", type=str)
|
||||
parser.add_argument("-rl", "-l", "--library", "--libraries", "--run-library", "--run-libraries", dest="libraries", help="Process only specified libraries (comma-separated list)", type=str)
|
||||
parser.add_argument("-rm", "-m", "--metadata", "--metadatas", "--run-metadata", "--run-metadatas", dest="metadata", help="Process only specified Metadata files (comma-separated list)", type=str)
|
||||
parser.add_argument("-rm", "-m", "--metadata", "--metadata-files", "--run-metadata-files", dest="metadata", help="Process only specified Metadata files (comma-separated list)", type=str)
|
||||
parser.add_argument("-dc", "--delete", "--delete-collections", dest="delete", help="Deletes all Collections in the Plex Library before running", action="store_true", default=False)
|
||||
parser.add_argument("-nc", "--no-countdown", dest="no_countdown", help="Run without displaying the countdown", action="store_true", default=False)
|
||||
parser.add_argument("-nm", "--no-missing", dest="no_missing", help="Run without running the missing section", action="store_true", default=False)
|
||||
|
@ -70,7 +70,7 @@ library_only = get_arg("PMM_LIBRARIES_ONLY", args.library_only, arg_bool=True)
|
|||
library_first = get_arg("PMM_LIBRARIES_FIRST", args.library_first, arg_bool=True)
|
||||
collections = get_arg("PMM_COLLECTIONS", args.collections)
|
||||
libraries = get_arg("PMM_LIBRARIES", args.libraries)
|
||||
metadatas = get_arg("PMM_METADATA", args.metadata)
|
||||
metadata_files = get_arg("PMM_METADATA_FILES", args.metadata)
|
||||
delete = get_arg("PMM_DELETE_COLLECTIONS", args.delete, arg_bool=True)
|
||||
resume = get_arg("PMM_RESUME", args.resume)
|
||||
no_countdown = get_arg("PMM_NO_COUNTDOWN", args.no_countdown, arg_bool=True)
|
||||
|
@ -160,7 +160,7 @@ def start(attrs):
|
|||
logger.debug(f"--libraries-first (PMM_LIBRARIES_FIRST): {library_first}")
|
||||
logger.debug(f"--run-collections (PMM_COLLECTIONS): {collections}")
|
||||
logger.debug(f"--run-libraries (PMM_LIBRARIES): {libraries}")
|
||||
logger.debug(f"--run-metadata (PMM_METADATA): {metadatas}")
|
||||
logger.debug(f"--run-metadata-files (PMM_METADATA_FILES): {metadata_files}")
|
||||
logger.debug(f"--ignore-schedules (PMM_IGNORE_SCHEDULES): {ignore_schedules}")
|
||||
logger.debug(f"--delete-collections (PMM_DELETE_COLLECTIONS): {delete}")
|
||||
logger.debug(f"--resume (PMM_RESUME): {resume}")
|
||||
|
@ -262,7 +262,7 @@ def update_libraries(config):
|
|||
library.map_guids()
|
||||
for metadata in library.metadata_files:
|
||||
metadata_name = metadata.get_file_name()
|
||||
if config.requested_metadata and metadata_name not in config.requested_metadata:
|
||||
if config.requested_metadata_files and metadata_name not in config.requested_metadata_files:
|
||||
continue
|
||||
logger.info("")
|
||||
util.separator(f"Running {metadata_name} Metadata File\n{metadata.path}")
|
||||
|
@ -1072,7 +1072,7 @@ def run_playlists(config):
|
|||
try:
|
||||
input_id = config.Convert.tmdb_to_tvdb(input_id, fail=True)
|
||||
except Failed as e:
|
||||
logger.error(e)
|
||||
logger.warning(e)
|
||||
continue
|
||||
if input_id not in builder.ignore_ids:
|
||||
found = False
|
||||
|
@ -1121,7 +1121,7 @@ def run_playlists(config):
|
|||
if tvdb_id not in builder.missing_shows:
|
||||
builder.missing_shows.append(tvdb_id)
|
||||
except Failed as e:
|
||||
logger.error(e)
|
||||
logger.warning(e)
|
||||
continue
|
||||
if not isinstance(rating_keys, list):
|
||||
rating_keys = [rating_keys]
|
||||
|
@ -1225,7 +1225,7 @@ def run_playlists(config):
|
|||
return status, stats
|
||||
|
||||
try:
|
||||
if run or test or collections or libraries or metadatas or resume:
|
||||
if run or test or collections or libraries or metadata_files or resume:
|
||||
start({
|
||||
"config_file": config_file,
|
||||
"test": test,
|
||||
|
@ -1233,7 +1233,7 @@ try:
|
|||
"ignore_schedules": ignore_schedules,
|
||||
"collections": collections,
|
||||
"libraries": libraries,
|
||||
"metadata": metadatas,
|
||||
"metadata_files": metadata_files,
|
||||
"library_first": library_first,
|
||||
"resume": resume,
|
||||
"trace": trace
|
||||
|
|
Loading…
Reference in a new issue