[3] Added the `mass_added_at_update` operation

pull/2038/head
meisnate12 7 months ago
parent 2aac1cd1ae
commit 188063cb19

@ -4,6 +4,7 @@
# New Features # New Features
Checks requirement versions to print a message if one needs to be updated Checks requirement versions to print a message if one needs to be updated
Added the `mass_added_at_update` operation to mass set the Added At field of Movies and Shows.
# Updates # Updates
Changed the `overlay_artwork_filetype` Setting to accept `webp_lossy` and `webp_lossless` while the old attribute `webp` will be treated as `webp_lossy`. Changed the `overlay_artwork_filetype` Setting to accept `webp_lossy` and `webp_lossless` while the old attribute `webp` will be treated as `webp_lossy`.

@ -1 +1 @@
2.0.1-develop2 2.0.1-develop3

@ -302,6 +302,45 @@ You can create individual blocks of operations by using a list under `operations
- 1900-01-01 - 1900-01-01
``` ```
###### Mass Added At Update
??? blank "`mass_added_at_update` - Updates the added at date of every item in the library.<a class="headerlink" href="#mass-added-at-update" title="Permanent link"></a>"
<div id="mass-added-at-update" />Updates every item's added at date in the library to the chosen site's date.
<hr style="margin: 0px;">
**Attribute:** `mass_added_at_update`
**Accepted Values:** Source or List of sources to use in that order
<table class="clearTable">
<tr><td>`tmdb`</td><td>Use TMDb Release Date</td></tr>
<tr><td>`tvdb`</td><td>Use TVDb Release Date</td></tr>
<tr><td>`omdb`</td><td>Use IMDb Release Date through OMDb</td></tr>
<tr><td>`mdb`</td><td>Use MDBList Release Date</td></tr>
<tr><td>`mdb_digital`</td><td>Use MDBList Digital Release Date</td></tr>
<tr><td>`anidb`</td><td>Use AniDB Release Date</td></tr>
<tr><td>`mal`</td><td>Use MyAnimeList Release Date</td></tr>
<tr><td>`lock`</td><td>Lock Added At Field</td></tr>
<tr><td>`unlock`</td><td>Unlock Added At Field</td></tr>
<tr><td>`remove`</td><td>Remove Added At and Lock Field</td></tr>
<tr><td>`reset`</td><td>Remove Added At and Unlock Field</td></tr>
<tr><td colspan="2">Any String in the Format: YYYY-MM-DD for Added At (<code>2022-05-28</code>)</td></tr>
</table>
???+ example "Example"
```yaml
libraries:
TV Shows:
operations:
mass_added_at_update:
- mdb_digital
- mdb
- 1900-01-01
```
###### Mass Rating Update ###### Mass Rating Update
??? blank "`mass_***_rating_update` - Updates the audience/critic/user rating of every item in the library.<a class="headerlink" href="#mass-star-rating-update" title="Permanent link"></a>" ??? blank "`mass_***_rating_update` - Updates the audience/critic/user rating of every item in the library.<a class="headerlink" href="#mass-star-rating-update" title="Permanent link"></a>"

@ -1429,6 +1429,10 @@
"type": "string", "type": "string",
"enum": ["tmdb","tvdb","omdb","mdb","anidb","mal","lock","unlock","remove","reset"] "enum": ["tmdb","tvdb","omdb","mdb","anidb","mal","lock","unlock","remove","reset"]
}, },
"mass_added_at_update": {
"type": "string",
"enum": ["tmdb","tvdb","omdb","mdb","anidb","mal","lock","unlock","remove","reset"]
},
"mass_audience_rating_update": { "mass_audience_rating_update": {
"anyOf": [ "anyOf": [
{ {

@ -135,8 +135,8 @@ library_operations = {
"mass_audience_rating_update": mass_rating_options, "mass_episode_audience_rating_update": mass_episode_rating_options, "mass_audience_rating_update": mass_rating_options, "mass_episode_audience_rating_update": mass_episode_rating_options,
"mass_critic_rating_update": mass_rating_options, "mass_episode_critic_rating_update": mass_episode_rating_options, "mass_critic_rating_update": mass_rating_options, "mass_episode_critic_rating_update": mass_episode_rating_options,
"mass_user_rating_update": mass_rating_options, "mass_episode_user_rating_update": mass_episode_rating_options, "mass_user_rating_update": mass_rating_options, "mass_episode_user_rating_update": mass_episode_rating_options,
"mass_original_title_update": mass_original_title_options, "mass_originally_available_update": mass_available_options, "mass_original_title_update": mass_original_title_options, "mass_imdb_parental_labels": imdb_label_options,
"mass_imdb_parental_labels": imdb_label_options, "mass_originally_available_update": mass_available_options, "mass_added_at_update": mass_available_options,
"mass_collection_mode": "mass_collection_mode", "mass_poster_update": "dict", "mass_background_update": "dict", "mass_collection_mode": "mass_collection_mode", "mass_poster_update": "dict", "mass_background_update": "dict",
"metadata_backup": "dict", "delete_collections": "dict", "genre_mapper": "dict", "content_rating_mapper": "dict", "metadata_backup": "dict", "delete_collections": "dict", "genre_mapper": "dict", "content_rating_mapper": "dict",
} }
@ -917,7 +917,7 @@ class ConfigFile:
final_list.append(str(list_attr)) final_list.append(str(list_attr))
elif op == "mass_genre_update": elif op == "mass_genre_update":
final_list.append(list_attr if isinstance(list_attr, list) else [list_attr]) final_list.append(list_attr if isinstance(list_attr, list) else [list_attr])
elif op == "mass_originally_available_update": elif op in ["mass_originally_available_update", "mass_added_at_update"]:
final_list.append(util.validate_date(list_attr)) final_list.append(util.validate_date(list_attr))
elif op.endswith("rating_update"): elif op.endswith("rating_update"):
final_list.append(util.check_int(list_attr, datatype="float", minimum=0, maximum=10, throw=True)) final_list.append(util.check_int(list_attr, datatype="float", minimum=0, maximum=10, throw=True))

@ -97,6 +97,7 @@ class Library(ABC):
self.mass_content_rating_update = params["mass_content_rating_update"] self.mass_content_rating_update = params["mass_content_rating_update"]
self.mass_original_title_update = params["mass_original_title_update"] self.mass_original_title_update = params["mass_original_title_update"]
self.mass_originally_available_update = params["mass_originally_available_update"] self.mass_originally_available_update = params["mass_originally_available_update"]
self.mass_added_at_update = params["mass_added_at_update"]
self.mass_imdb_parental_labels = params["mass_imdb_parental_labels"] self.mass_imdb_parental_labels = params["mass_imdb_parental_labels"]
self.mass_poster_update = params["mass_poster_update"] self.mass_poster_update = params["mass_poster_update"]
self.mass_background_update = params["mass_background_update"] self.mass_background_update = params["mass_background_update"]
@ -124,7 +125,7 @@ class Library(ABC):
self.items_library_operation = True if self.assets_for_all or self.mass_genre_update or self.remove_title_parentheses \ self.items_library_operation = True if self.assets_for_all or self.mass_genre_update or self.remove_title_parentheses \
or self.mass_audience_rating_update or self.mass_critic_rating_update or self.mass_user_rating_update \ or self.mass_audience_rating_update or self.mass_critic_rating_update or self.mass_user_rating_update \
or self.mass_episode_audience_rating_update or self.mass_episode_critic_rating_update or self.mass_episode_user_rating_update \ or self.mass_episode_audience_rating_update or self.mass_episode_critic_rating_update or self.mass_episode_user_rating_update \
or self.mass_content_rating_update or self.mass_originally_available_update or self.mass_original_title_update\ or self.mass_content_rating_update or self.mass_originally_available_update or self.mass_added_at_update or self.mass_original_title_update\
or self.mass_imdb_parental_labels or self.genre_mapper or self.content_rating_mapper or self.mass_studio_update\ or self.mass_imdb_parental_labels or self.genre_mapper or self.content_rating_mapper or self.mass_studio_update\
or self.radarr_add_all_existing or self.sonarr_add_all_existing or self.mass_poster_update or self.mass_background_update else False or self.radarr_add_all_existing or self.sonarr_add_all_existing or self.mass_poster_update or self.mass_background_update else False
self.library_operation = True if self.items_library_operation or self.delete_collections or self.mass_collection_mode \ self.library_operation = True if self.items_library_operation or self.delete_collections or self.mass_collection_mode \

@ -1,5 +1,5 @@
import os, re import os, re
from datetime import datetime from datetime import datetime, timedelta, timezone
from modules import plex, util, anidb from modules import plex, util, anidb
from modules.util import Failed, LimitReached, YAML from modules.util import Failed, LimitReached, YAML
from plexapi.exceptions import NotFound from plexapi.exceptions import NotFound
@ -10,14 +10,15 @@ logger = util.logger
meta_operations = [ meta_operations = [
"mass_audience_rating_update", "mass_user_rating_update", "mass_critic_rating_update", "mass_audience_rating_update", "mass_user_rating_update", "mass_critic_rating_update",
"mass_episode_audience_rating_update", "mass_episode_user_rating_update", "mass_episode_critic_rating_update", "mass_episode_audience_rating_update", "mass_episode_user_rating_update", "mass_episode_critic_rating_update",
"mass_genre_update", "mass_content_rating_update", "mass_originally_available_update", "mass_original_title_update", "mass_genre_update", "mass_content_rating_update", "mass_originally_available_update", "mass_added_at_update",
"mass_poster_update", "mass_background_update", "mass_studio_update" "mass_original_title_update", "mass_poster_update", "mass_background_update", "mass_studio_update"
] ]
name_display = { name_display = {
"audienceRating": "Audience Rating", "audienceRating": "Audience Rating",
"rating": "Critic Rating", "rating": "Critic Rating",
"userRating": "User Rating", "userRating": "User Rating",
"originallyAvailableAt": "Originally Available Date", "originallyAvailableAt": "Originally Available Date",
"addedAt": "Added At Date",
"contentRating": "Content Rating" "contentRating": "Content Rating"
} }
@ -45,6 +46,7 @@ class Operations:
logger.debug(f"Mass Content Rating Update: {self.library.mass_content_rating_update}") logger.debug(f"Mass Content Rating Update: {self.library.mass_content_rating_update}")
logger.debug(f"Mass Original Title Update: {self.library.mass_original_title_update}") logger.debug(f"Mass Original Title Update: {self.library.mass_original_title_update}")
logger.debug(f"Mass Originally Available Update: {self.library.mass_originally_available_update}") logger.debug(f"Mass Originally Available Update: {self.library.mass_originally_available_update}")
logger.debug(f"Mass Added At Update: {self.library.mass_added_at_update}")
logger.debug(f"Mass IMDb Parental Labels: {self.library.mass_imdb_parental_labels}") logger.debug(f"Mass IMDb Parental Labels: {self.library.mass_imdb_parental_labels}")
logger.debug(f"Mass Poster Update: {self.library.mass_poster_update}") logger.debug(f"Mass Poster Update: {self.library.mass_poster_update}")
logger.debug(f"Mass Background Update: {self.library.mass_background_update}") logger.debug(f"Mass Background Update: {self.library.mass_background_update}")
@ -88,7 +90,7 @@ class Operations:
genre_edits = {"add": {}, "remove": {}} genre_edits = {"add": {}, "remove": {}}
content_edits = {} content_edits = {}
studio_edits = {} studio_edits = {}
available_edits = {} date_edits = {"originallyAvailableAt": {}, "addedAt": {}}
remove_edits = {} remove_edits = {}
reset_edits = {} reset_edits = {}
lock_edits = {} lock_edits = {}
@ -664,65 +666,69 @@ class Operations:
except Failed: except Failed:
continue continue
if self.library.mass_originally_available_update: for attribute, item_attr in [
current_available = item.originallyAvailableAt (self.library.mass_originally_available_update, "originallyAvailableAt"),
if current_available: (self.library.mass_added_at_update, "addedAt")
current_available = current_available.strftime("%Y-%m-%d") ]:
for option in self.library.mass_originally_available_update: if attribute:
if option in ["lock", "remove"]: current = getattr(item, item_attr)
if option == "remove" and current_available: if current:
if "originallyAvailableAt" not in remove_edits: current = current.strftime("%Y-%m-%d")
remove_edits["originallyAvailableAt"] = [] for option in attribute:
remove_edits["originallyAvailableAt"].append(item.ratingKey) if option in ["lock", "remove"]:
item_edits += "\nRemove Originally Available Date (Batched)" if option == "remove" and current:
elif "originallyAvailableAt" not in locked_fields: if item_attr not in remove_edits:
if "originallyAvailableAt" not in lock_edits: remove_edits[item_attr] = []
lock_edits["originallyAvailableAt"] = [] remove_edits[item_attr].append(item.ratingKey)
lock_edits["originallyAvailableAt"].append(item.ratingKey) item_edits += f"\nRemove {name_display[item_attr]} (Batched)"
item_edits += "\nLock Originally Available Date (Batched)" elif item_attr not in locked_fields:
break if item_attr not in lock_edits:
elif option in ["unlock", "reset"]: lock_edits[item_attr] = []
if option == "reset" and current_available: lock_edits[item_attr].append(item.ratingKey)
if "originallyAvailableAt" not in reset_edits: item_edits += f"\nLock {name_display[item_attr]} (Batched)"
reset_edits["originallyAvailableAt"] = []
reset_edits["originallyAvailableAt"].append(item.ratingKey)
item_edits += "\nReset Originally Available Date (Batched)"
elif "originallyAvailableAt" in locked_fields:
if "originallyAvailableAt" not in unlock_edits:
unlock_edits["originallyAvailableAt"] = []
unlock_edits["originallyAvailableAt"].append(item.ratingKey)
item_edits += "\nUnlock Originally Available Date (Batched)"
break
else:
try:
if option == "tmdb":
new_available = tmdb_obj().release_date if self.library.is_movie else tmdb_obj().first_air_date # noqa
elif option == "omdb":
new_available = omdb_obj().released # noqa
elif option == "tvdb":
new_available = tvdb_obj().release_date # noqa
elif option == "mdb":
new_available = mdb_obj().released # noqa
elif option == "mdb_digital":
new_available = mdb_obj().released_digital # noqa
elif option == "anidb":
new_available = anidb_obj().released # noqa
elif option == "mal":
new_available = mal_obj().aired # noqa
else:
new_available = option
if not new_available:
logger.info(f"No {option} Originally Available Date Found")
raise Failed
new_available = new_available.strftime("%Y-%m-%d")
if current_available != new_available:
if new_available not in available_edits:
available_edits[new_available] = []
available_edits[new_available].append(item.ratingKey)
item_edits += f"\nUpdate Originally Available Date (Batched) | {new_available}"
break break
except Failed: elif option in ["unlock", "reset"]:
continue if option == "reset" and current:
if item_attr not in reset_edits:
reset_edits[item_attr] = []
reset_edits[item_attr].append(item.ratingKey)
item_edits += f"\nReset {name_display[item_attr]} (Batched)"
elif item_attr in locked_fields:
if item_attr not in unlock_edits:
unlock_edits[item_attr] = []
unlock_edits[item_attr].append(item.ratingKey)
item_edits += f"\nUnlock {name_display[item_attr]} (Batched)"
break
else:
try:
if option == "tmdb":
new_date = tmdb_obj().release_date if self.library.is_movie else tmdb_obj().first_air_date # noqa
elif option == "omdb":
new_date = omdb_obj().released # noqa
elif option == "tvdb":
new_date = tvdb_obj().release_date # noqa
elif option == "mdb":
new_date = mdb_obj().released # noqa
elif option == "mdb_digital":
new_date = mdb_obj().released_digital # noqa
elif option == "anidb":
new_date = anidb_obj().released # noqa
elif option == "mal":
new_date = mal_obj().aired # noqa
else:
new_date = option
if not new_date:
logger.info(f"No {option} {name_display[item_attr]} Found")
raise Failed
new_date = new_date.strftime("%Y-%m-%d")
if current != new_date:
if new_date not in date_edits[item_attr]:
date_edits[item_attr][new_date] = []
date_edits[item_attr][new_date].append(item.ratingKey)
item_edits += f"\nUpdate {name_display[item_attr]} (Batched) | {new_date}"
break
except Failed:
continue
if len(item_edits) > 0: if len(item_edits) > 0:
logger.info(f"Item Edits{item_edits}") logger.info(f"Item Edits{item_edits}")
@ -920,11 +926,27 @@ class Operations:
self.library.Plex.editStudio(new_studio) self.library.Plex.editStudio(new_studio)
self.library.Plex.saveMultiEdits() self.library.Plex.saveMultiEdits()
_size = len(available_edits.items()) _size = len(date_edits["originallyAvailableAt"].items())
for i, (new_available, rating_keys) in enumerate(sorted(available_edits.items()), 1): for i, (new_date, rating_keys) in enumerate(sorted(date_edits["originallyAvailableAt"].items()), 1):
logger.info(get_batch_info(i, _size, "originallyAvailableAt", len(rating_keys), display_value=new_available)) logger.info(get_batch_info(i, _size, "originallyAvailableAt", len(rating_keys), display_value=new_date))
self.library.Plex.batchMultiEdits(self.library.load_list_from_cache(rating_keys)) self.library.Plex.batchMultiEdits(self.library.load_list_from_cache(rating_keys))
self.library.Plex.editOriginallyAvailable(new_available) self.library.Plex.editOriginallyAvailable(new_date)
self.library.Plex.saveMultiEdits()
epoch = datetime(1970, 1, 1)
_size = len(date_edits["addedAt"].items())
for i, (new_date, rating_keys) in enumerate(sorted(date_edits["addedAt"].items()), 1):
logger.info(get_batch_info(i, _size, "addedAt", len(rating_keys), display_value=new_date))
self.library.Plex.batchMultiEdits(self.library.load_list_from_cache(rating_keys))
new_date = datetime.strptime(new_date, "%Y-%m-%d")
logger.trace(new_date)
try:
ts = int(round(new_date.timestamp()))
except (TypeError, OSError):
offset = int(datetime(2000, 1, 1, tzinfo=timezone.utc).timestamp() - datetime(2000, 1, 1).timestamp())
ts = int((new_date - epoch).total_seconds()) - offset
logger.trace(epoch + timedelta(seconds=ts))
self.library.Plex.editAddedAt(ts)
self.library.Plex.saveMultiEdits() self.library.Plex.saveMultiEdits()
_size = len(remove_edits.items()) _size = len(remove_edits.items())

Loading…
Cancel
Save