[178] add delete labels

pull/1152/head
meisnate12 2 years ago
parent 36ef657938
commit 2bf45597b3

@ -1 +1 @@
1.17.3-develop177 1.17.3-develop178

@ -14,8 +14,8 @@ templates:
exclude_prefix: exclude_prefix:
- "!" - "!"
- "~" - "~"
summary: <<collectionless_summary>> summary_collectionless: <<collectionless_summary>>
name: <<collectionless_name>> name_collectionless: <<collectionless_name>>
sort_title: ~_Collectionless sort_title: ~_Collectionless
collection_order: alpha collection_order: alpha
url_poster: https://raw.githubusercontent.com/meisnate12/Plex-Meta-Manager-Images/master/collectionless.jpg url_poster: https://raw.githubusercontent.com/meisnate12/Plex-Meta-Manager-Images/master/collectionless.jpg
@ -25,8 +25,8 @@ templates:
url_poster: <<url_poster>> url_poster: <<url_poster>>
collection_order: <<collection_order>> collection_order: <<collection_order>>
sort_title: <<sort_title>> sort_title: <<sort_title>>
summary: <<summary>>> summary: <<summary_collectionless>>
name: <<name>> name: <<name_collectionless>>
plex_collectionless: plex_collectionless:
exclude_prefix: <<exclude_prefix>> exclude_prefix: <<exclude_prefix>>
exclude: <<exclude>> exclude: <<exclude>>

@ -40,15 +40,15 @@ Note that the `templates_variables:` section only needs to be used if you do wan
**[Shared Collection Variables](../variables) are NOT available to this default file.** **[Shared Collection Variables](../variables) are NOT available to this default file.**
| Variable | Description & Values | | Variable | Description & Values |
|:-------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| |:-------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `name` | **Description:** Changes the name of the collection.<br>**Values:** New Collection Name | | `name_collectionless` | **Description:** Changes the name of the collection.<br>**Values:** New Collection Name |
| `summary` | **Description:** Changes the summary of the collection.<br>**Values:** New Collection Summary | | `summary_collectionless` | **Description:** Changes the summary of the collection.<br>**Values:** New Collection Summary |
| `sort_title` | **Description:** Sets the sort title for the collection.<br>**Default:** `~_Collectionless`<br>**Values:** Any String | | `sort_title` | **Description:** Sets the sort title for the collection.<br>**Default:** `~_Collectionless`<br>**Values:** Any String |
| `collection_order` | **Description:** Changes the Collection Order for all collections in this file.<br>**Default:** `alpha`<br>**Values:**<table class="clearTable"><tr><td>`release`</td><td>Order Collection by Release Dates</td></tr><tr><td>`alpha`</td><td>Order Collection Alphabetically</td></tr><tr><td>`custom`</td><td>Order Collection Via the Builder Order</td></tr><tr><td>[Any `plex_search` Sort Option](../../metadata/builders/plex.md#sort-options)</td><td>Order Collection by any `plex_search` Sort Option</td></tr></table> | | `collection_order` | **Description:** Changes the Collection Order for all collections in this file.<br>**Default:** `alpha`<br>**Values:**<table class="clearTable"><tr><td>`release`</td><td>Order Collection by Release Dates</td></tr><tr><td>`alpha`</td><td>Order Collection Alphabetically</td></tr><tr><td>`custom`</td><td>Order Collection Via the Builder Order</td></tr><tr><td>[Any `plex_search` Sort Option](../../metadata/builders/plex.md#sort-options)</td><td>Order Collection by any `plex_search` Sort Option</td></tr></table> |
| `url_poster` | **Description:** Changes the poster url of thecollection.<br>**Values:** URL directly to the Image | | `url_poster` | **Description:** Changes the poster url of thecollection.<br>**Values:** URL directly to the Image |
| `exclude` | **Description:** Exclude these Collections from being considered for collectionless.<br>**Values:** List of Collections | | `exclude` | **Description:** Exclude these Collections from being considered for collectionless.<br>**Values:** List of Collections |
| `exclude_prefix` | **Description:** Overrides the [default exclude_prefix list](#default-exclude_prefix). Exclude Collections with one of these prefixes from being considered for collectionless.<br>**Default:** [default exclude_prefix list](#default-exclude_prefix)<br>**Values:** List of Prefixes | | | `exclude_prefix` | **Description:** Overrides the [default exclude_prefix list](#default-exclude_prefix). Exclude Collections with one of these prefixes from being considered for collectionless.<br>**Default:** [default exclude_prefix list](#default-exclude_prefix)<br>**Values:** List of Prefixes | |
The below is an example config.yml extract with some Template Variables added in to change how the file works. The below is an example config.yml extract with some Template Variables added in to change how the file works.

@ -5,174 +5,304 @@
```yaml ```yaml
libraries: libraries:
Movies: Movies: # Must match a library name in your Plex
report_path: config/missing/Movies_report.yml
template_variables:
sep_style: gray # use the gray separators globally for this library
collection_mode: hide # hide the collections
language: fr # could be default, de, fr, pt-br or another language code that we have tranlsated
metadata_path: metadata_path:
- pmm: bafta - pmm: separator_award # An "index card"
- pmm: cannes - pmm: bafta # BAFTA Awards
- pmm: choice template_variables: # based on when the award show started
- pmm: golden data:
- pmm: oscars starting: 2014
- pmm: other_award ending: current_year
- pmm: spirit - pmm: cannes # Cannes Film Fstical Awards
- pmm: sundance template_variables: # based on when the award show started
- pmm: anilist data:
- pmm: basic starting: 2016
- pmm: imdb ending: current_year
- pmm: myanimelist - pmm: choice # Critic's Choice Awards
- pmm: other_chart template_variables: # based on when the award show started
- pmm: tautulli data:
- pmm: tmdb starting: 2014
- pmm: trakt ending: current_year
- pmm: actor - pmm: golden # Golden Globes Awards
- pmm: audio_language template_variables: # based on when the award show started
- pmm: content_rating_us # Choose content_rating_uk or content_rating_us data:
- pmm: genre starting: 1943
- pmm: resolution_standards # Choose resolution_standards or resolution ending: current_year
- pmm: streaming - pmm: oscars # The Oscars
- pmm: studio template_variables: # based on when the award show started
- pmm: subtitle_language data:
- pmm: year starting: 1927
- pmm: country ending: current_year
- pmm: decade - pmm: other_award # Other award collections
- pmm: director - pmm: spirit # Independent Spirit Awards
- pmm: franchise template_variables: # based on when the award show started
- pmm: universe data:
- pmm: producer starting: 2014
- pmm: seasonal ending: current_year
- pmm: writer - pmm: sundance # Sundance Film Festival Awards
template_variables: # based on when the award show started
data:
starting: 2010
ending: current_year
- pmm: separator_chart # An "index card"
- pmm: anilist # AniDB Charts (Popular, Trending, etc.)
- pmm: imdb # IMDb Charts (Popular, Trending, etc.)
- pmm: myanimelist # MAL Charts (Popular, Trending, etc.)
- pmm: other_chart # Other Charts (Popular, Trending, etc.)
- pmm: tautulli # Tautulli Charts (Popular, Trending, etc.)
- pmm: tmdb # TMDb Charts (Popular, Trending, etc.)
- pmm: trakt # Trakt Charts (Popular, Trending, etc.)
- pmm: flixpatrol # Flixpatrol Charts (Popular, Trending, etc.)
- pmm: basic # Keep this as the last chart item so that collection_mode: hide works properly on library tab for CHART COLLECTION
- pmm: collectionless # Collectionless movies/shows (Keep this as the last chart item so that collection_mode: hide works properly on library tab for CHART COLLECTION)
- pmm: actor # Actors
template_variables: # bw, rainier, or orig style is used. depth and limit is set low but sometimes I boost to 10, 150
style: bw
data:
depth: 1
limit: 15
- pmm: director # Directors
template_variables: # bw, rainier, or orig style is used. depth and limit is set low but sometimes I boost to 10, 150
style: bw
data:
depth: 1
limit: 15
- pmm: producer # Producers
template_variables: # bw, rainier, or orig style is used. depth and limit is set low but sometimes I boost to 10, 150
exclude: # ever have some random person... you can exclude them if you want
- Jeremy Kleiner
- Thomas Hayslip
style: bw
data:
depth: 1
limit: 15
- pmm: writer # Writers
template_variables: # bw, rainier, or orig style is used. depth and limit is set low but sometimes I boost to 10, 150
style: bw
data:
depth: 1
limit: 15
- pmm: audio_language # English, French, Arabic, German, etc. audio language
- pmm: content_rating_cs # Choose content_rating_uk, content_rating_us, or content_rating_cs
- pmm: genre # Action, Comedy, Drama, etc.
- pmm: resolution # 4K HDR, 1080P FHD, etc. with the standards style
template_variables:
style: standards
- pmm: studio # DreamWorks Studios, Lucasfilm Ltd, etc.
- pmm: studio_anime # Anime Studios etc.
- pmm: subtitle_language # English, French, Arabic, German, etc. subtitles
- pmm: year # Year the media item was released starting from 1880 to current_year
template_variables:
data:
starting: 1880
ending: current_year
- pmm: country # Country associated to the media item
- pmm: decade # Decade the media item was released
- pmm: seasonal # Christmas, Halloween, etc.
template_variables: # Canadian Thankgsgiving is a different date range. Otherwise, I want to ALWAYS see the seasonal
schedule_independence: daily
schedule_easter: daily
schedule_valentine: daily
schedule_patrick: daily
schedule_thanksgiving: range(10/01-10/31)
schedule_halloween: daily
schedule_christmas: daily
schedule_years: daily
schedule_mother: daily
schedule_memorial: daily
schedule_father: daily
schedule_labor: daily
- pmm: streaming # Streaming on Disney+, Netflix, etc.
- pmm: universe # Marvel Cinematic Universe, Wizarding World, etc.
overlay_path: overlay_path:
- remove_overlays: false - remove_overlays: false # Set to true if you want to remove overlays
- pmm: audio_codec - reapply_overlay: false # If you are doing a lot of testing and changes like me, keep this to true to always reapply overlays
- pmm: audio_language - pmm: audio_codec # FLAC, DTS-X, TrueHD, etc.
- pmm: commonsense - pmm: language_count # blank means 1 audio language track, dual means 2, multi means > 2
- pmm: direct_play - pmm: commonsense # Age 2+, Age 14+, etc.
- pmm: edition - pmm: flixpatrol # Top 10 flixpatrol for 'this_year', positioned on the left
- pmm: episode_info
- pmm: flixpatrol
- pmm: mediastinger
- pmm: ratings
template_variables: template_variables:
rating1: critic position: left
time_window: this_year
- pmm: mediastinger # Mediastinger overlay when the media item contains a stinger at the end of the movie/show or during the credits
- pmm: ratings # Ratings with custom fonts matched to the style of the rating, font_size, and on the right in 'square' format
template_variables:
rating1: user
rating1_image: rt_tomato rating1_image: rt_tomato
- pmm: resolution
- pmm: ribbon rating2: critic
- pmm: runtimes rating2_image: imdb
- pmm: special_release
- pmm: streaming rating3: audience
- pmm: versions rating3_image: tmdb
- pmm: video_format
TV Shows: horizontal_position: right
- pmm: resolution # 4K HDR, 1080P FHD, etc.
- pmm: ribbon # Used for ribbon in bottom right
- pmm: streaming # Streaming on Disney+, Netflix, etc.
- pmm: versions # Will show duplicates for that media item in top right area
- pmm: video_format # Remux, DVD, Blu-Ray, etc. in bottom left
settings:
asset_directory:
- config/assets
operations:
split_duplicates: false
assets_for_all: false
delete_unmanaged_collections: true # Any manually added collection outside of PMM will be deleted
mass_user_rating_update: mdb_tomatoes # Update user ratings with mdb_tomatoes
mass_critic_rating_update: imdb # Update critic ratings with imdb
mass_audience_rating_update: tmdb # Update audience ratings with tmdb
mass_genre_update: tmdb # Update all genres from tmdb
mass_content_rating_update: mdb_commonsense # Changes Content Rating to "1", "2" etc. to specify appropriate age
mass_originally_available_update: tmdb # Update all original available date from tmdb
mass_imdb_parental_labels: without_none
TV Shows: # Must match a library name in your Plex
report_path: config/missing/TV_missing.yml
template_variables:
sep_style: gray # use the gray separators globally for this library
collection_mode: hide # hide the collections
language: fr # could be default, de, fr, pt-br or another lang code that we have tranlsated
metadata_path: metadata_path:
- pmm: choice - pmm: separator_award # An "index card"
- pmm: golden - pmm: choice # Critic's Choice Awards
- pmm: emmy template_variables: # based on when the award show started
- pmm: anilist data:
- pmm: basic starting: 2014
- pmm: imdb ending: current_year
- pmm: myanimelist - pmm: golden # Golden Globes Awards
- pmm: other_chart template_variables: # based on when the award show started
- pmm: tautulli data:
- pmm: tmdb starting: 1943
- pmm: trakt ending: current_year
- pmm: actor - pmm: emmy # Emmy Awards
- pmm: audio_language template_variables: # based on when the award show started
- pmm: content_rating_us # Choose content_rating_uk or content_rating_us data:
- pmm: genre starting: 1947
- pmm: resolution_standards # Choose resolution_standards or resolution ending: current_year
- pmm: streaming - pmm: separator_chart # An "index card"
- pmm: studio - pmm: anilist # AniDB Charts (Popular, Trending, etc.)
- pmm: subtitle_language - pmm: imdb # IMDb Charts (Popular, Trending, etc.)
- pmm: year - pmm: myanimelist # MAL Charts (Popular, Trending, etc.)
- pmm: country - pmm: other_chart # Other Charts (Popular, Trending, etc.)
- pmm: decade - pmm: tautulli # Tautulli Charts (Popular, Trending, etc.)
- pmm: network - pmm: tmdb # TMDb Charts (Popular, Trending, etc.)
- pmm: trakt # Trakt Charts (Popular, Trending, etc.)
- pmm: flixpatrol # Flixpatrol Charts (Popular, Trending, etc.)
- pmm: basic # Keep this as the last chart item so that collection_mode: hide works properly on library tab for CHART COLLECTION
- pmm: collectionless # Collectionless movies/shows (Keep this as the last chart item so that collection_mode: hide works properly on library tab for CHART COLLECTION)
- pmm: actor # Actors
template_variables: # bw, rainier, or orig style is used. depth and limit is set low but sometimes I boost to 10, 150
exclude: # ever have some random person... you can exclude them if you want
- Macy Nyman
style: bw
data:
depth: 1
limit: 15
- pmm: audio_language # English, French, Arabic, German, etc. audio language
- pmm: content_rating_cs # Choose content_rating_uk, content_rating_us, or content_rating_cs
- pmm: genre # Action, Comedy, Drama, etc.
- pmm: resolution # 4K HDR, 1080P FHD, etc. with the standards style
template_variables:
style: standards
- pmm: studio # DreamWorks Studios, Lucasfilm Ltd, etc.
- pmm: studio_anime # Anime Studios etc.
- pmm: subtitle_language # English, French, Arabic, German, etc. subtitles
- pmm: year # Year the media item was released starting from 1880 to current_year
template_variables:
data:
starting: 1880
ending: current_year
- pmm: country # Country associated to the media item
- pmm: decade # Decade the media item was released
- pmm: network # ABC, CBC, NBC, FOX, etc.
- pmm: streaming # Streaming on Disney+, Netflix, etc.
overlay_path: overlay_path:
- remove_overlays: false - remove_overlays: false # Set to true if you want to remove overlays
- pmm: audio_codec - reapply_overlay: false # If you are doing a lot of testing and changes like me, keep this to true to always reapply overlays
- pmm: audio_codec # FLAC, DTS-X, TrueHD, etc. and works with overlay_level show, episode, and season
- pmm: audio_codec - pmm: audio_codec
template_variables: template_variables:
overlay_level: episode overlay_level: episode
- pmm: audio_codec - pmm: audio_codec
template_variables: template_variables:
overlay_level: season overlay_level: season
- pmm: audio_language - pmm: language_count # blank means 1 audio language track, dual means 2, multi means > 2 and works with overlay_level show, episode, and season
- pmm: audio_language - pmm: language_count
template_variables: template_variables:
overlay_level: episode overlay_level: episode
- pmm: audio_language - pmm: language_count
template_variables: template_variables:
overlay_level: season overlay_level: season
- pmm: commonsense - pmm: commonsense # Age 2+, Age 14+, etc. and works with overlay_level show, episode, and season
- pmm: commonsense - pmm: commonsense
template_variables: template_variables:
overlay_level: episode overlay_level: episode
- pmm: commonsense - pmm: commonsense
template_variables: template_variables:
overlay_level: season overlay_level: season
- pmm: direct_play - pmm: episode_info # SE##E## information in bottom right and works with overlay_level episode
- pmm: direct_play
template_variables:
overlay_level: episode
- pmm: direct_play
template_variables:
overlay_level: season
- pmm: edition
- pmm: edition
template_variables:
overlay_level: episode
- pmm: episode_info
template_variables:
overlay_level: episode
- pmm: flixpatrol
- pmm: flixpatrol
template_variables:
overlay_level: episode
- pmm: flixpatrol
template_variables:
overlay_level: season
- pmm: mediastinger
- pmm: mediastinger
template_variables: template_variables:
overlay_level: episode overlay_level: episode
- pmm: mediastinger - pmm: flixpatrol # Top 10 flixpatrol for 'this_year', positioned on the left and works with overlay_level show
template_variables: template_variables:
overlay_level: season position: left
- pmm: ratings time_window: this_year
- pmm: mediastinger # Mediastinger overlay when the media item contains a stinger at the end of the movie/show or during the credits and works with overlay_level show
- pmm: ratings # Ratings with custom fonts matched to the style of the rating, font_size, and on the right in 'square' format. overlay_level: show has 3 ratings max
template_variables: template_variables:
rating2: audience rating1: user
rating1_image: rt_tomato
rating2: critic
rating2_image: imdb rating2_image: imdb
- pmm: ratings
rating3: audience
rating3_image: tmdb
horizontal_position: right
- pmm: ratings # Ratings with custom fonts matched to the style of the rating, font_size, and on the right in 'square' format. overlay_level: episode has 2 ratings max
template_variables: template_variables:
rating1: critic
rating1_image: imdb
rating2: audience rating2: audience
rating2_image: imdb rating2_image: tmdb
horizontal_position: right
overlay_level: episode overlay_level: episode
- pmm: resolution - pmm: resolution # 4K HDR, 1080P FHD, etc. and works with overlay_level show, episode, and season
- pmm: resolution - pmm: resolution
template_variables: template_variables:
overlay_level: episode overlay_level: episode
- pmm: resolution - pmm: resolution
template_variables: template_variables:
overlay_level: season overlay_level: season
- pmm: ribbon - pmm: ribbon # Used for ribbon in bottom right and works with overlay_level show and season
- pmm: ribbon
template_variables:
overlay_level: episode
- pmm: ribbon - pmm: ribbon
template_variables: template_variables:
overlay_level: season overlay_level: season
- pmm: runtimes - pmm: episode_info # Runtime information in bottom right and works with overlay_level episode
template_variables: template_variables:
overlay_level: episode overlay_level: episode
- pmm: special_release - pmm: status # Airing, Returning, Ended, Canceled and works with overlay_level show
- pmm: special_release - pmm: streaming # Streaming on Disney+, Netflix, etc. and works with overlay_level show, episode, and season
- pmm: streaming
template_variables: template_variables:
overlay_level: episode overlay_level: episode
- pmm: special_release - pmm: streaming
template_variables: template_variables:
overlay_level: season overlay_level: season
- pmm: streaming - pmm: versions # Will show duplicates for that media item in top right area and works with overlay_level show, episode, and season
- pmm: versions
- pmm: versions
template_variables: template_variables:
overlay_level: episode overlay_level: episode
- pmm: versions - pmm: versions
@ -181,14 +311,33 @@ libraries:
- pmm: versions - pmm: versions
template_variables: template_variables:
overlay_level: show overlay_level: show
- pmm: video_format - pmm: video_format # Remux, DVD, Blu-Ray, etc. in bottom left and works with overlay_level show, episode, and season
- pmm: video_format - pmm: video_format
template_variables: template_variables:
overlay_level: episode overlay_level: episode
- pmm: video_format - pmm: video_format
template_variables: template_variables:
overlay_level: season overlay_level: season
settings:
asset_directory:
- config/assets
operations:
split_duplicates: false
assets_for_all: false
delete_unmanaged_collections: true # Any manually added collection outside of PMM will be deleted
mass_user_rating_update: mdb_tomatoes # Update user ratings with mdb_tomatoes
mass_critic_rating_update: imdb # Update critic ratings with imdb
mass_audience_rating_update: tmdb # Update audience ratings with tmdb
mass_genre_update: tmdb # Update all genres from tmdb
mass_content_rating_update: mdb_commonsense # Changes Content Rating to "1", "2" etc. to specify appropriate age
mass_originally_available_update: tmdb # Update all original available date from tmdb
mass_episode_critic_rating_update: imdb # Update critic ratings with imdb for episodes
mass_episode_audience_rating_update: tmdb # Update audience ratings with tmdb for episodes
mass_imdb_parental_labels: without_none
playlist_files: playlist_files:
- pmm: playlist - pmm: playlist
template_variables:
libraries: Movies, TV Shows
``` ```
</details> </details>

@ -130,9 +130,7 @@ All [Shared Overlay Variables](variables) are available with the default values
| Variable | Description & Values | | Variable | Description & Values |
|:------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| |:------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `position` | **Description:** Changes the position of all Overlay Queues in this File.<br>**Default:** `left`<br>**Values:** `left`, `right`, `half`, or List of Coordinates | | `position` | **Description:** Use the Custom Given Queue instead of the the provided Queues.<br>**Values:** List of Coordinates |
| `position_audio_flags` | **Description:** Changes the position of the audio flags Overlays.<br>**Default:** `left`<br>**Values:** `left`, `right`, `half`, or List of Coordinates |
| `position_subtitle_flags` | **Description:** Changes the position of the subtitle flags Overlays.<br>**Default:** `left`<br>**Values:** `left`, `right`, `half`, or List of Coordinates |
| `horizontal_position` | **Description:** Choose the horizontal position for the flag group.<br>**Default:** `left`<br>**Values:** `left`, `right`, or `center` | | `horizontal_position` | **Description:** Choose the horizontal position for the flag group.<br>**Default:** `left`<br>**Values:** `left`, `right`, or `center` |
| `vertical_position` | **Description:** Choose the vertical position for the flag group.<br>**Default:** `top`<br>**Values:** `top`, `bottom`, or `center` | | `vertical_position` | **Description:** Choose the vertical position for the flag group.<br>**Default:** `top`<br>**Values:** `top`, `bottom`, or `center` |
| `flag_alignment` | **Description:** Choose the display alignment for the flag group.<br>**Default:** `vertical`<br>**Values:** `horizontal`, or `vertical` | | `flag_alignment` | **Description:** Choose the display alignment for the flag group.<br>**Default:** `vertical`<br>**Values:** `horizontal`, or `vertical` |

@ -1,6 +1,6 @@
# Ratings Overlays # Ratings Overlays
The `ratings` Default Overlay File is used to create an overlay based on if there's an after credit scene on each item within your library. The `ratings` Default Overlay File is used to create an overlay based on the Critic Rating, Audience Rating, and User Rating in Plex for each item within your library.
This file only updates the overlays based on the data in Plex. Use the [Mass * Rating Update Library Operation](../../config/operations.md#mass--rating-update) and the [Mass Episode * Rating Update Library Operation](../../config/operations.md#mass-episode--rating-update) to update Plex to the Ratings you want on the Overlay. This file only updates the overlays based on the data in Plex. Use the [Mass * Rating Update Library Operation](../../config/operations.md#mass--rating-update) and the [Mass Episode * Rating Update Library Operation](../../config/operations.md#mass-episode--rating-update) to update Plex to the Ratings you want on the Overlay.

@ -9,10 +9,10 @@ Below are the available variables which can be used to customize the file.
| Variable | Description & Values | | Variable | Description & Values |
|:--------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| |:--------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `use_<<key>>`<sup>1</sup> | **Description:** Turns off individual Overlays in a Defaults file.<br>**Values:** `false` to turn off the overlay | | `use_<<key>>`<sup>1</sup> | **Description:** Turns off individual Overlays in a Defaults file.<br>**Values:** `false` to turn off the overlay |
| `file` | **Description:** Controls the image associated with the Overlay to a local file. Use `pmm: null` with this to no use the default image.<br>**Values:** Filepath to Overlay Image | | `file` | **Description:** Controls the image associated with the Overlay to a local file. Use `pmm: null` with this to not use the default image.<br>**Values:** Filepath to Overlay Image |
| `url` | **Description:** Controls the image associated with the Overlay to a url. Use `pmm: null` with this to no use the default image.<br>**Values:** URL to Overlay Image | | `url` | **Description:** Controls the image associated with the Overlay to a url. Use `pmm: null` with this to not use the default image.<br>**Values:** URL to Overlay Image |
| `git` | **Description:** Controls the image associated with the Overlay to the git repo. Use `pmm: null` with this to no use the default image.<br>**Values:** Git Path to Overlay Image | | `git` | **Description:** Controls the image associated with the Overlay to the git repo. Use `pmm: null` with this to not use the default image.<br>**Values:** Git Path to Overlay Image |
| `repo` | **Description:** Controls the image associated with the Overlay to a custom repo. Use `pmm: null` with this to no use the default image.<br>**Values:** Repo Path to Overlay Image | | `repo` | **Description:** Controls the image associated with the Overlay to a custom repo. Use `pmm: null` with this to not use the default image.<br>**Values:** Repo Path to Overlay Image |
| `pmm` | **Description:** Controls the image associated with the Overlay to a pmm file.<br>**Values:** PMM Overlay Image | | `pmm` | **Description:** Controls the image associated with the Overlay to a pmm file.<br>**Values:** PMM Overlay Image |
| `horizontal_offset` | **Description:** Controls the Horizontal Offset of this overlay. Can be a %.<br>**Values:** Number 0 or greater or 0%-100% | | `horizontal_offset` | **Description:** Controls the Horizontal Offset of this overlay. Can be a %.<br>**Values:** Number 0 or greater or 0%-100% |
| `horizontal_align` | **Description:** Controls the Horizontal Alignment of the overlay.<br>**Values:** `left`, `center`, or `right` | | `horizontal_align` | **Description:** Controls the Horizontal Alignment of the overlay.<br>**Values:** `left`, `center`, or `right` |

@ -27,6 +27,7 @@ These docs are assuming you have a basic understanding of Docker concepts. One
| [Ignore Ghost](#ignore-ghost) | `-ig` or `--ignore-ghost` | `PMM_IGNORE_GHOST` | | [Ignore Ghost](#ignore-ghost) | `-ig` or `--ignore-ghost` | `PMM_IGNORE_GHOST` |
| [Cache Libraries](#cache-libraries) | `-ca` or `--cache-libraries` | `PMM_CACHE_LIBRARIES` | | [Cache Libraries](#cache-libraries) | `-ca` or `--cache-libraries` | `PMM_CACHE_LIBRARIES` |
| [Delete Collections](#delete-collections) | `-dc` or `--delete-collections` | `PMM_DELETE_COLLECTIONS` | | [Delete Collections](#delete-collections) | `-dc` or `--delete-collections` | `PMM_DELETE_COLLECTIONS` |
| [Delete Labels](#delete-labels) | `-dl` or `--delete-labels` | `PMM_DELETE_LABELS` |
| [Resume Run](#resume-run) | `-re` or `--resume` | `PMM_RESUME` | | [Resume Run](#resume-run) | `-re` or `--resume` | `PMM_RESUME` |
| [No Countdown](#no-countdown) | `-nc` or `--no-countdown` | `PMM_NO_COUNTDOWN` | | [No Countdown](#no-countdown) | `-nc` or `--no-countdown` | `PMM_NO_COUNTDOWN` |
| [No Missing](#no-missing) | `-nm` or `--no-missing` | `PMM_NO_MISSING` | | [No Missing](#no-missing) | `-nm` or `--no-missing` | `PMM_NO_MISSING` |
@ -815,6 +816,45 @@ docker run -it -v "X:\Media\Plex Meta Manager\config:/config:rw" meisnate12/plex
</details> </details>
### Delete Labels
Delete all labels on every item in a Library prior to running collections/operations.
<table class="dualTable colwidths-auto align-default table">
<tr>
<th style="background-color: #222;"></th>
<th>Shell</th>
<th>Environment</th>
</tr>
<tr>
<th>Flags</th>
<td><code>-dl</code> or <code>--delete-labels</code></td>
<td><code>PMM_DELETE_LABELS</code></td>
</tr>
<tr>
<th>Example</th>
<td><code>--delete-labels</code></td>
<td><code>PMM_DELETE_LABELS=true</code></td>
</tr>
</table>
<details>
<summary>Local Environment</summary>
```shell
python plex_meta_manager.py --delete-labels
```
</details>
<details>
<summary>Docker Environment</summary>
```shell
docker run -it -v "X:\Media\Plex Meta Manager\config:/config:rw" meisnate12/plex-meta-manager --delete-labels
```
</details>
### Resume Run ### Resume Run
Perform a resume run immediately resuming from the first instance of the specified collection, bypassing the time to run flag. Perform a resume run immediately resuming from the first instance of the specified collection, bypassing the time to run flag.

@ -415,6 +415,30 @@ class CollectionBuilder:
else: else:
server_check = pl_library.PlexServer.machineIdentifier server_check = pl_library.PlexServer.machineIdentifier
self.smart_filter_details = ""
self.smart_label = {"sort_by": "random", "all": {"label": [self.name]}}
self.smart_label_collection = False
if "smart_label" in methods and not self.playlist and not self.overlay and not self.library.is_music:
logger.debug("")
logger.debug("Validating Method: smart_label")
self.smart_label_collection = True
if not self.data[methods["smart_label"]]:
logger.warning(f"{self.Type} Error: smart_label attribute is blank defaulting to random")
else:
logger.debug(f"Value: {self.data[methods['smart_label']]}")
if isinstance(self.data[methods["smart_label"]], dict):
_data, replaced = util.replace_label(self.name, self.data[methods["smart_label"]])
if not replaced:
raise Failed("Config Error: <<smart_label>> not found in the smart_label attribute data")
self.smart_label = _data
elif (self.library.is_movie and str(self.data[methods["smart_label"]]).lower() in plex.movie_sorts) \
or (self.library.is_show and str(self.data[methods["smart_label"]]).lower() in plex.show_sorts):
self.smart_label["sort_by"] = str(self.data[methods["smart_label"]]).lower()
else:
logger.warning(f"{self.Type} Error: smart_label attribute: {self.data[methods['smart_label']]} is invalid defaulting to random")
if self.smart_label_collection and self.library.smart_label_check(self.name):
_, self.smart_filter_details, _ = self.build_filter("smart_label", self.smart_label, default_sort="random")
if "delete_not_scheduled" in methods and not self.overlay: if "delete_not_scheduled" in methods and not self.overlay:
logger.debug("") logger.debug("")
logger.debug("Validating Method: delete_not_scheduled") logger.debug("Validating Method: delete_not_scheduled")
@ -535,30 +559,6 @@ class CollectionBuilder:
else: else:
raise Failed(f"{self.Type} Error: No valid TMDb Person IDs in {self.data[methods['tmdb_person']]}") raise Failed(f"{self.Type} Error: No valid TMDb Person IDs in {self.data[methods['tmdb_person']]}")
self.smart_filter_details = ""
self.smart_label = {"sort_by": "random", "all": {"label": [self.name]}}
self.smart_label_collection = False
if "smart_label" in methods and not self.playlist and not self.overlay and not self.library.is_music:
logger.debug("")
logger.debug("Validating Method: smart_label")
self.smart_label_collection = True
if not self.data[methods["smart_label"]]:
logger.warning(f"{self.Type} Error: smart_label attribute is blank defaulting to random")
else:
logger.debug(f"Value: {self.data[methods['smart_label']]}")
if isinstance(self.data[methods["smart_label"]], dict):
_data, replaced = util.replace_label(self.name, self.data[methods["smart_label"]])
if not replaced:
raise Failed("Config Error: <<smart_label>> not found in the smart_label attribute data")
self.smart_label = _data
elif (self.library.is_movie and str(self.data[methods["smart_label"]]).lower() in plex.movie_sorts) \
or (self.library.is_show and str(self.data[methods["smart_label"]]).lower() in plex.show_sorts):
self.smart_label["sort_by"] = str(self.data[methods["smart_label"]]).lower()
else:
logger.warning(f"{self.Type} Error: smart_label attribute: {self.data[methods['smart_label']]} is invalid defaulting to random")
if self.smart_label_collection and self.library.smart_label_check(self.name):
_, self.smart_filter_details, _ = self.build_filter("smart_label", self.smart_label, default_sort="random")
self.smart_url = None self.smart_url = None
self.smart_type_key = None self.smart_type_key = None
if "smart_url" in methods and not self.playlist and not self.overlay: if "smart_url" in methods and not self.playlist and not self.overlay:
@ -767,7 +767,7 @@ class CollectionBuilder:
self.sonarr_details["add_missing"] = self.library.Sonarr.add_missing if self.library.Sonarr else False self.sonarr_details["add_missing"] = self.library.Sonarr.add_missing if self.library.Sonarr else False
if "add_existing" not in self.sonarr_details: if "add_existing" not in self.sonarr_details:
self.sonarr_details["add_existing"] = self.library.Sonarr.add_existing if self.library.Sonarr else False self.sonarr_details["add_existing"] = self.library.Sonarr.add_existing if self.library.Sonarr else False
if self.smart_url or self.collectionless or self.library.is_music: if self.smart_url or self.collectionless or self.library.is_music:
self.radarr_details["add_missing"] = False self.radarr_details["add_missing"] = False
self.radarr_details["add_existing"] = False self.radarr_details["add_existing"] = False
@ -2725,6 +2725,9 @@ class CollectionBuilder:
output += f"\n{self.Type} {'deleted' if self.obj else 'not found'} on {self.library.account.username}" output += f"\n{self.Type} {'deleted' if self.obj else 'not found'} on {self.library.account.username}"
elif self.obj: elif self.obj:
output = f"{self.Type} {self.obj.title} deleted" output = f"{self.Type} {self.obj.title} deleted"
if self.smart_label_collection:
for item in self.library.search(label=self.name, libtype=self.builder_level):
self.library.edit_tags("label", item, remove_tags=self.name)
else: else:
output = "" output = ""
if self.obj: if self.obj:

@ -103,17 +103,12 @@ class ConfigFile:
self.version = attrs["version"] if "version" in attrs else None self.version = attrs["version"] if "version" in attrs else None
self.no_missing = attrs["no_missing"] if "no_missing" in attrs else None self.no_missing = attrs["no_missing"] if "no_missing" in attrs else None
self.no_report = attrs["no_report"] if "no_report" in attrs else None self.no_report = attrs["no_report"] if "no_report" in attrs else None
self.test_mode = attrs["test"] if "test" in attrs else False
self.trace_mode = attrs["trace"] if "trace" in attrs else False
self.delete_collections = attrs["delete"] if "delete" in attrs else False
self.ignore_schedules = attrs["ignore_schedules"] if "ignore_schedules" in attrs else False self.ignore_schedules = attrs["ignore_schedules"] if "ignore_schedules" in attrs else False
self.library_first = attrs["library_first"] if "library_first" in attrs else False
self.start_time = attrs["time_obj"] self.start_time = attrs["time_obj"]
self.run_hour = datetime.strptime(attrs["time"], "%H:%M").hour 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_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_libraries = util.get_list(attrs["libraries"]) if "libraries" in attrs else None
self.requested_metadata_files = [mf[:-4] if str(mf).endswith(".yml") else mf for mf in util.get_list(attrs["metadata_files"])] if "metadata_files" in attrs and attrs["metadata_files"] else None self.requested_metadata_files = [mf[:-4] if str(mf).endswith(".yml") else mf for mf in util.get_list(attrs["metadata_files"])] if "metadata_files" in attrs and attrs["metadata_files"] else None
self.resume_from = attrs["resume"] if "resume" in attrs else None
self.collection_only = attrs["collection_only"] if "collection_only" in attrs else False self.collection_only = attrs["collection_only"] if "collection_only" in attrs else False
self.operations_only = attrs["operations_only"] if "operations_only" in attrs else False self.operations_only = attrs["operations_only"] if "operations_only" in attrs else False
self.overlays_only = attrs["overlays_only"] if "overlays_only" in attrs else False self.overlays_only = attrs["overlays_only"] if "overlays_only" in attrs else False

@ -18,8 +18,7 @@ class Library(ABC):
self.Notifiarr = None self.Notifiarr = None
self.collections = [] self.collections = []
self.metadatas = [] self.metadatas = []
self.queues = {} self.queue_names = []
self.queue_current = 0
self.metadata_files = [] self.metadata_files = []
self.overlay_files = [] self.overlay_files = []
self.overlay_names = [] self.overlay_names = []
@ -150,11 +149,9 @@ class Library(ABC):
if not operations_only and not collection_only: if not operations_only and not collection_only:
for file_type, overlay_file, temp_vars, asset_directory in self.overlay_path: for file_type, overlay_file, temp_vars, asset_directory in self.overlay_path:
try: try:
overlay_obj = OverlayFile(self.config, self, file_type, overlay_file, temp_vars, asset_directory, self.queue_current) overlay_obj = OverlayFile(self.config, self, file_type, overlay_file, temp_vars, asset_directory)
self.overlay_files.append(overlay_obj) self.overlay_files.append(overlay_obj)
for qk, qv in overlay_obj.queues.items(): self.queue_names.extend([q for q in overlay_obj.queues])
self.queues[self.queue_current] = qv
self.queue_current += 1
except Failed as e: except Failed as e:
logger.error(e) logger.error(e)
logger.info(f"Overlay File Failed To Load") logger.info(f"Overlay File Failed To Load")

@ -184,13 +184,14 @@ class Mdblist:
logger.info(f"Limit: {data['limit']} items") logger.info(f"Limit: {data['limit']} items")
params["limit"] = data["limit"] params["limit"] = data["limit"]
parsed_url = urlparse(data["url"]) parsed_url = urlparse(data["url"])
url_base = parsed_url._replace(query=None).geturl() url_base = str(parsed_url._replace(query=None).geturl())
url_base = url_base if url_base.endswith("/") else f"{url_base}/" url_base = url_base if url_base.endswith("/") else f"{url_base}/"
url_base = url_base if url_base.endswith("json/") else f"{url_base}json/" url_base = url_base if url_base.endswith("json/") else f"{url_base}json/"
try: try:
response = self.config.get_json(url_base, headers=headers, params=params) response = self.config.get_json(url_base, headers=headers, params=params)
if "error" in response: if (isinstance(response, dict) and "error" in response) or (isinstance(response, list) and response and "error" in response[0]):
if response["error"] == "empty": err = response["error"] if isinstance(response, dict) else response[0]["error"]
if "empty" in err:
raise Failed(f"Mdblist Error: No Items Returned. Lists can take 24 hours to update so try again later.") raise Failed(f"Mdblist Error: No Items Returned. Lists can take 24 hours to update so try again later.")
raise Failed(f"Mdblist Error: Invalid Response {response}") raise Failed(f"Mdblist Error: Invalid Response {response}")
results = [] results = []

@ -1479,7 +1479,6 @@ class Plex(Library):
if failures > failure_threshold: if failures > failure_threshold:
return False return False
elif filter_attr in builder.number_filters or modifier in [".gt", ".gte", ".lt", ".lte", ".count_gt", ".count_gte", ".count_lt", ".count_lte"]: elif filter_attr in builder.number_filters or modifier in [".gt", ".gte", ".lt", ".lte", ".count_gt", ".count_gte", ".count_lt", ".count_lte"]:
divider = 60000 if filter_attr == "duration" else 1
test_number = [] test_number = []
if filter_attr in ["channels", "height", "width", "aspect"]: if filter_attr in ["channels", "height", "width", "aspect"]:
test_number = 0 test_number = 0
@ -1497,12 +1496,14 @@ class Plex(Library):
for media in item.media: for media in item.media:
for part in media.parts: for part in media.parts:
test_number.extend([s.language for s in part.subtitleStreams()]) test_number.extend([s.language for s in part.subtitleStreams()])
elif filter_attr == "duration":
test_number = getattr(item, filter_actual) / 60000
else: else:
test_number = getattr(item, filter_actual) test_number = getattr(item, filter_actual)
if modifier in [".count_gt", ".count_gte", ".count_lt", ".count_lte"]: if modifier in [".count_gt", ".count_gte", ".count_lt", ".count_lte"]:
test_number = len(test_number) if test_number else 0 test_number = len(test_number) if test_number else 0
modifier = f".{modifier[7:]}" modifier = f".{modifier[7:]}"
if test_number is None or util.is_number_filter(test_number / divider, modifier, filter_data): if test_number is None or util.is_number_filter(test_number, modifier, filter_data):
return False return False
else: else:
attrs = [] attrs = []

@ -37,7 +37,8 @@ parser.add_argument("-rc", "-cl", "--collection", "--collections", "--run-collec
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("-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", "--metadata-files", "--run-metadata-files", 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("-ca", "--cache-library", "--cache-libraries", dest="cache_libraries", help="Cache Library load for 1 day", action="store_true", default=False) parser.add_argument("-ca", "--cache-library", "--cache-libraries", dest="cache_libraries", help="Cache Library load for 1 day", action="store_true", default=False)
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("-dc", "--delete", "--delete-collections", dest="delete_collections", help="Deletes all Collections in the Plex Library before running", action="store_true", default=False)
parser.add_argument("-dl", "--delete-label", "--delete-labels", dest="delete_labels", help="Deletes all Labels 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("-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) parser.add_argument("-nm", "--no-missing", dest="no_missing", help="Run without running the missing section", action="store_true", default=False)
parser.add_argument("-nr", "--no-report", dest="no_report", help="Run without saving a report", action="store_true", default=False) parser.add_argument("-nr", "--no-report", dest="no_report", help="Run without saving a report", action="store_true", default=False)
@ -86,7 +87,8 @@ collections = get_arg("PMM_COLLECTIONS", args.collections)
libraries = get_arg("PMM_LIBRARIES", args.libraries) libraries = get_arg("PMM_LIBRARIES", args.libraries)
metadata_files = get_arg("PMM_METADATA_FILES", args.metadata) metadata_files = get_arg("PMM_METADATA_FILES", args.metadata)
cache_libraries = get_arg("PMM_CACHE_LIBRARIES", args.cache_libraries, arg_bool=True) cache_libraries = get_arg("PMM_CACHE_LIBRARIES", args.cache_libraries, arg_bool=True)
delete = get_arg("PMM_DELETE_COLLECTIONS", args.delete, arg_bool=True) delete_collections = get_arg("PMM_DELETE_COLLECTIONS", args.delete_collections, arg_bool=True)
delete_labels = get_arg("PMM_DELETE_LABELS", args.delete_labels, arg_bool=True)
resume = get_arg("PMM_RESUME", args.resume) resume = get_arg("PMM_RESUME", args.resume)
no_countdown = get_arg("PMM_NO_COUNTDOWN", args.no_countdown, arg_bool=True) no_countdown = get_arg("PMM_NO_COUNTDOWN", args.no_countdown, arg_bool=True)
no_missing = get_arg("PMM_NO_MISSING", args.no_missing, arg_bool=True) no_missing = get_arg("PMM_NO_MISSING", args.no_missing, arg_bool=True)
@ -218,7 +220,8 @@ def start(attrs):
logger.debug(f"--ignore-schedules (PMM_IGNORE_SCHEDULES): {ignore_schedules}") logger.debug(f"--ignore-schedules (PMM_IGNORE_SCHEDULES): {ignore_schedules}")
logger.debug(f"--ignore-ghost (PMM_IGNORE_GHOST): {ignore_ghost}") logger.debug(f"--ignore-ghost (PMM_IGNORE_GHOST): {ignore_ghost}")
logger.debug(f"--cache-libraries (PMM_CACHE_LIBRARIES): {cache_libraries}") logger.debug(f"--cache-libraries (PMM_CACHE_LIBRARIES): {cache_libraries}")
logger.debug(f"--delete-collections (PMM_DELETE_COLLECTIONS): {delete}") logger.debug(f"--delete-collections (PMM_DELETE_COLLECTIONS): {delete_collections}")
logger.debug(f"--delete-labels (PMM_DELETE_LABELS): {delete_labels}")
logger.debug(f"--resume (PMM_RESUME): {resume}") logger.debug(f"--resume (PMM_RESUME): {resume}")
logger.debug(f"--no-countdown (PMM_NO_COUNTDOWN): {no_countdown}") logger.debug(f"--no-countdown (PMM_NO_COUNTDOWN): {no_countdown}")
logger.debug(f"--no-missing (PMM_NO_MISSING): {no_missing}") logger.debug(f"--no-missing (PMM_NO_MISSING): {no_missing}")
@ -446,7 +449,7 @@ def run_libraries(config):
logger.debug(f"Optimize: {library.optimize}") logger.debug(f"Optimize: {library.optimize}")
logger.debug(f"Timeout: {library.timeout}") logger.debug(f"Timeout: {library.timeout}")
if config.delete_collections and not playlist_only: if delete_collections and not playlist_only:
time_start = datetime.now() time_start = datetime.now()
logger.info("") logger.info("")
logger.separator(f"Deleting all Collections from the {library.name} Library", space=False, border=False) logger.separator(f"Deleting all Collections from the {library.name} Library", space=False, border=False)
@ -459,6 +462,25 @@ def run_libraries(config):
logger.error(f"Collection {collection.title} Failed to Delete") logger.error(f"Collection {collection.title} Failed to Delete")
library_status[library.name]["All Collections Deleted"] = str(datetime.now() - time_start).split('.')[0] library_status[library.name]["All Collections Deleted"] = str(datetime.now() - time_start).split('.')[0]
if delete_labels and not playlist_only:
time_start = datetime.now()
logger.info("")
logger.separator(f"Deleting all Labels from All items in the {library.name} Library", space=False, border=False)
logger.info("")
if library.is_show:
library_types = ["show", "season", "episode"]
elif library.is_music:
library_types = ["artist", "album", "track"]
else:
library_types = ["movie"]
for library_type in library_types:
for item in library.get_all(builder_level=library_type):
try:
library.edit_tags("label", item, sync_tags=[])
except NotFound:
logger.error(f"{item.title[:25]:<25} | Labels Failed to be Removed")
library_status[library.name]["All Labels Deleted"] = str(datetime.now() - time_start).split('.')[0]
time_start = datetime.now() time_start = datetime.now()
temp_items = None temp_items = None
list_key = None list_key = None
@ -484,13 +506,13 @@ def run_libraries(config):
library_status[library.name]["Library Loading and Mapping"] = str(datetime.now() - time_start).split('.')[0] library_status[library.name]["Library Loading and Mapping"] = str(datetime.now() - time_start).split('.')[0]
def run_operations_and_overlays(): def run_operations_and_overlays():
if not config.test_mode and not collection_only and not playlist_only and not config.requested_metadata_files: if not test and not collection_only and not playlist_only and not config.requested_metadata_files:
if not overlays_only and library.library_operation: if not overlays_only and library.library_operation:
library_status[library.name]["Library Operations"] = library.Operations.run_operations() library_status[library.name]["Library Operations"] = library.Operations.run_operations()
if not operations_only and (library.overlay_files or library.remove_overlays): if not operations_only and (library.overlay_files or library.remove_overlays):
library_status[library.name]["Library Overlays"] = library.Overlays.run_overlays() library_status[library.name]["Library Overlays"] = library.Overlays.run_overlays()
if config.library_first: if library_first:
run_operations_and_overlays() run_operations_and_overlays()
if not operations_only and not overlays_only and not playlist_only: if not operations_only and not overlays_only and not playlist_only:
@ -503,26 +525,26 @@ def run_libraries(config):
continue continue
logger.info("") logger.info("")
logger.separator(f"Running {metadata_name} Metadata File\n{metadata.path}") logger.separator(f"Running {metadata_name} Metadata File\n{metadata.path}")
if not config.test_mode and not config.resume_from and not collection_only: if not test and not resume and not collection_only:
try: try:
metadata.update_metadata() metadata.update_metadata()
except Failed as e: except Failed as e:
library.notify(e) library.notify(e)
logger.error(e) logger.error(e)
collections_to_run = metadata.get_collections(config.requested_collections) collections_to_run = metadata.get_collections(config.requested_collections)
if config.resume_from and config.resume_from not in collections_to_run: if resume and resume not in collections_to_run:
logger.info("") logger.info("")
logger.warning(f"Collection: {config.resume_from} not in Metadata File: {metadata.path}") logger.warning(f"Collection: {resume} not in Metadata File: {metadata.path}")
continue continue
if collections_to_run: if collections_to_run:
logger.info("") logger.info("")
logger.separator(f"{'Test ' if config.test_mode else ''}Collections") logger.separator(f"{'Test ' if test else ''}Collections")
logger.remove_library_handler(library.mapping_name) logger.remove_library_handler(library.mapping_name)
run_collection(config, library, metadata, collections_to_run) run_collection(config, library, metadata, collections_to_run)
logger.re_add_library_handler(library.mapping_name) logger.re_add_library_handler(library.mapping_name)
library_status[library.name]["Library Metadata Files"] = str(datetime.now() - time_start).split('.')[0] library_status[library.name]["Library Metadata Files"] = str(datetime.now() - time_start).split('.')[0]
if not config.library_first: if not library_first:
run_operations_and_overlays() run_operations_and_overlays()
logger.remove_library_handler(library.mapping_name) logger.remove_library_handler(library.mapping_name)
@ -536,7 +558,7 @@ def run_collection(config, library, metadata, requested_collections):
logger.info("") logger.info("")
for mapping_name, collection_attrs in requested_collections.items(): for mapping_name, collection_attrs in requested_collections.items():
collection_start = datetime.now() collection_start = datetime.now()
if config.test_mode and ("test" not in collection_attrs or collection_attrs["test"] is not True): if test and ("test" not in collection_attrs or collection_attrs["test"] is not True):
no_template_test = True no_template_test = True
if "template" in collection_attrs and collection_attrs["template"]: if "template" in collection_attrs and collection_attrs["template"]:
for data_template in util.get_list(collection_attrs["template"], split=False): for data_template in util.get_list(collection_attrs["template"], split=False):
@ -551,10 +573,10 @@ def run_collection(config, library, metadata, requested_collections):
if no_template_test: if no_template_test:
continue continue
if config.resume_from and config.resume_from != mapping_name: if resume and resume != mapping_name:
continue continue
elif config.resume_from == mapping_name: elif resume == mapping_name:
config.resume_from = None resume = None
logger.info("") logger.info("")
logger.separator(f"Resuming Collections") logger.separator(f"Resuming Collections")
@ -723,7 +745,7 @@ def run_playlists(config):
for playlist_file in config.playlist_files: for playlist_file in config.playlist_files:
for mapping_name, playlist_attrs in playlist_file.playlists.items(): for mapping_name, playlist_attrs in playlist_file.playlists.items():
playlist_start = datetime.now() playlist_start = datetime.now()
if config.test_mode and ("test" not in playlist_attrs or playlist_attrs["test"] is not True): if test and ("test" not in playlist_attrs or playlist_attrs["test"] is not True):
no_template_test = True no_template_test = True
if "template" in playlist_attrs and playlist_attrs["template"]: if "template" in playlist_attrs and playlist_attrs["template"]:
for data_template in util.get_list(playlist_attrs["template"], split=False): for data_template in util.get_list(playlist_attrs["template"], split=False):
@ -896,19 +918,12 @@ def run_playlists(config):
if __name__ == "__main__": if __name__ == "__main__":
try: try:
params = {"config_file": config_file, "ignore_schedules": ignore_schedules}
if run or test or collections or libraries or metadata_files or resume: if run or test or collections or libraries or metadata_files or resume:
process({ params["collections"] = collections
"config_file": config_file, params["libraries"] = libraries
"test": test, params["metadata_files"] = metadata_files
"delete": delete, process(params)
"ignore_schedules": ignore_schedules,
"collections": collections,
"libraries": libraries,
"metadata_files": metadata_files,
"library_first": library_first,
"resume": resume,
"trace": trace
})
else: else:
times_to_run = util.get_list(times) times_to_run = util.get_list(times)
valid_times = [] valid_times = []
@ -921,7 +936,7 @@ if __name__ == "__main__":
else: else:
raise Failed(f"Argument Error: blank time argument") raise Failed(f"Argument Error: blank time argument")
for time_to_run in valid_times: for time_to_run in valid_times:
schedule.every().day.at(time_to_run).do(process, {"config_file": config_file, "time": time_to_run, "delete": delete, "library_first": library_first, "trace": trace}) schedule.every().day.at(time_to_run).do(process, params)
while True: while True:
schedule.run_pending() schedule.run_pending()
if not no_countdown: if not no_countdown:

Loading…
Cancel
Save