[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,62 +666,66 @@ 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:
current = getattr(item, item_attr)
if current:
current = current.strftime("%Y-%m-%d")
for option in attribute:
if option in ["lock", "remove"]: if option in ["lock", "remove"]:
if option == "remove" and current_available: if option == "remove" and current:
if "originallyAvailableAt" not in remove_edits: if item_attr not in remove_edits:
remove_edits["originallyAvailableAt"] = [] remove_edits[item_attr] = []
remove_edits["originallyAvailableAt"].append(item.ratingKey) remove_edits[item_attr].append(item.ratingKey)
item_edits += "\nRemove Originally Available Date (Batched)" item_edits += f"\nRemove {name_display[item_attr]} (Batched)"
elif "originallyAvailableAt" not in locked_fields: elif item_attr not in locked_fields:
if "originallyAvailableAt" not in lock_edits: if item_attr not in lock_edits:
lock_edits["originallyAvailableAt"] = [] lock_edits[item_attr] = []
lock_edits["originallyAvailableAt"].append(item.ratingKey) lock_edits[item_attr].append(item.ratingKey)
item_edits += "\nLock Originally Available Date (Batched)" item_edits += f"\nLock {name_display[item_attr]} (Batched)"
break break
elif option in ["unlock", "reset"]: elif option in ["unlock", "reset"]:
if option == "reset" and current_available: if option == "reset" and current:
if "originallyAvailableAt" not in reset_edits: if item_attr not in reset_edits:
reset_edits["originallyAvailableAt"] = [] reset_edits[item_attr] = []
reset_edits["originallyAvailableAt"].append(item.ratingKey) reset_edits[item_attr].append(item.ratingKey)
item_edits += "\nReset Originally Available Date (Batched)" item_edits += f"\nReset {name_display[item_attr]} (Batched)"
elif "originallyAvailableAt" in locked_fields: elif item_attr in locked_fields:
if "originallyAvailableAt" not in unlock_edits: if item_attr not in unlock_edits:
unlock_edits["originallyAvailableAt"] = [] unlock_edits[item_attr] = []
unlock_edits["originallyAvailableAt"].append(item.ratingKey) unlock_edits[item_attr].append(item.ratingKey)
item_edits += "\nUnlock Originally Available Date (Batched)" item_edits += f"\nUnlock {name_display[item_attr]} (Batched)"
break break
else: else:
try: try:
if option == "tmdb": if option == "tmdb":
new_available = tmdb_obj().release_date if self.library.is_movie else tmdb_obj().first_air_date # noqa new_date = tmdb_obj().release_date if self.library.is_movie else tmdb_obj().first_air_date # noqa
elif option == "omdb": elif option == "omdb":
new_available = omdb_obj().released # noqa new_date = omdb_obj().released # noqa
elif option == "tvdb": elif option == "tvdb":
new_available = tvdb_obj().release_date # noqa new_date = tvdb_obj().release_date # noqa
elif option == "mdb": elif option == "mdb":
new_available = mdb_obj().released # noqa new_date = mdb_obj().released # noqa
elif option == "mdb_digital": elif option == "mdb_digital":
new_available = mdb_obj().released_digital # noqa new_date = mdb_obj().released_digital # noqa
elif option == "anidb": elif option == "anidb":
new_available = anidb_obj().released # noqa new_date = anidb_obj().released # noqa
elif option == "mal": elif option == "mal":
new_available = mal_obj().aired # noqa new_date = mal_obj().aired # noqa
else: else:
new_available = option new_date = option
if not new_available: if not new_date:
logger.info(f"No {option} Originally Available Date Found") logger.info(f"No {option} {name_display[item_attr]} Found")
raise Failed raise Failed
new_available = new_available.strftime("%Y-%m-%d") new_date = new_date.strftime("%Y-%m-%d")
if current_available != new_available: if current != new_date:
if new_available not in available_edits: if new_date not in date_edits[item_attr]:
available_edits[new_available] = [] date_edits[item_attr][new_date] = []
available_edits[new_available].append(item.ratingKey) date_edits[item_attr][new_date].append(item.ratingKey)
item_edits += f"\nUpdate Originally Available Date (Batched) | {new_available}" item_edits += f"\nUpdate {name_display[item_attr]} (Batched) | {new_date}"
break break
except Failed: except Failed:
continue continue
@ -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