diff --git a/.gitignore b/.gitignore index ec38561..2a1433f 100644 --- a/.gitignore +++ b/.gitignore @@ -62,4 +62,5 @@ web/ **/.DS_Store **/TODO.* **test** +**side-projects** diff --git a/VERSION b/VERSION index d2d61a7..e2cac26 100755 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.2.2 \ No newline at end of file +1.2.3 \ No newline at end of file diff --git a/config/config.sample.yml b/config/config.sample.yml index 4ac0c27..47b7caa 100755 --- a/config/config.sample.yml +++ b/config/config.sample.yml @@ -329,6 +329,26 @@ poster_cleanarr: upgradinatorr: # A script to upgrade Sonarr/Radarr libraries to the keep in line with trash-guides + # count: Number of items to search. + # tag_name: The name of the tag to add to items that have been processed. + # ignore_tag: The name of the tag to ignore. + # unattended: If true, the script will remove the checked_tag if all media is tagged, resulting in this running forever. + # season_monitored_threshold: (Sonarr only) The episode monitoring threshold to filter out seasons. + # If the monitored percentage of episodes in a season is less than this threshold, the season will be skipped. + # Example: season_monitored_threshold: 0.5 means 50% of episodes in a season must be monitored for the season to be searched. + # Default: 0 (disables the threshold, seasons will not be skipped based on episode monitoring). + + # Examples: + # The following configuration will process up to 1 item from the 'sonarr_1' instance, using 'checked' as the tag name + # and 'ignore' as the ignore tag. It will operate in unattended mode, and only search seasons if at least 50% + # of their episodes are monitored. + # + # sonarr_1: + # count: 1 + # tag_name: checked + # ignore_tag: ignore + # unattended: true + # season_monitored_threshold: 0.5 log_level: info dry_run: false instances: @@ -352,11 +372,13 @@ upgradinatorr: tag_name: checked ignore_tag: ignore unattended: true + season_monitored_threshold: 0.99 sonarr_3: count: 20 tag_name: checked ignore_tag: ignore unattended: true + season_monitored_threshold: 0.5 renameinatorr: # This script will rename all series in Sonarr/Radarr to match the naming scheme of the diff --git a/extra-scripts/backup_appdata.sh b/extra-scripts/backup_appdata.sh index f2ae794..8d02dfe 100755 --- a/extra-scripts/backup_appdata.sh +++ b/extra-scripts/backup_appdata.sh @@ -562,12 +562,12 @@ send_notification() { # Get a random joke from the specified file # Check if the webhook is for discord if [[ "$webhook" =~ ^https://discord\.com/api/webhooks/ ]]; then - joke=$(curl -s https://raw.githubusercontent.com/Drazzilb08/daps/master/jokes.txt | shuf -n 1) + joke=$(curl -s https://raw.githubusercontent.com/Drazzilb08/daps/master/jokes.txt | shuf -n 1 | sed 's/"/\\"/g') discord_common_fields bot_name="Notification Bot" # Call the discord_payload function to construct the payload if [ ${#new_container[@]} -gt 0 ]; then - joke=$(curl -s https://raw.githubusercontent.com/Drazzilb08/daps/master/jokes.txt | shuf -n 1) + joke=$(curl -s https://raw.githubusercontent.com/Drazzilb08/daps/master/jokes.txt | shuf -n 1 | sed 's/"/\\"/g') new_container_notification new_container_response=$(curl -s -H "Content-Type: application/json" -X POST -d "$payload" "$webhook") if [ "$dry_run" == "true" ]; then @@ -575,7 +575,7 @@ send_notification() { fi fi if [ ${#removed_containers[@]} -gt 0 ]; then - joke=$(curl -s https://raw.githubusercontent.com/Drazzilb08/daps/master/jokes.txt | shuf -n 1) + joke=$(curl -s https://raw.githubusercontent.com/Drazzilb08/daps/master/jokes.txt | shuf -n 1 | sed 's/"/\\"/g') removed_container_notification removed_container=$(curl -s -H "Content-Type: application/json" -X POST -d "$payload" "$webhook") if [ "$dry_run" == "true" ]; then @@ -594,11 +594,11 @@ send_notification() { fi # Check if the webhook is for notifiarr if [[ $webhook =~ ^https://notifiarr\.com/api/v1/notification/passthrough ]]; then - joke=$(curl -s https://raw.githubusercontent.com/Drazzilb08/daps/master/jokes.txt | shuf -n 1) + joke=$(curl -s https://raw.githubusercontent.com/Drazzilb08/daps/master/jokes.txt | shuf -n 1 | sed 's/"/\\"/g') notifiarr_common_fields # Call the notifiarr_payload function to construct the payload if [ ${#new_container[@]} -gt 0 ]; then - joke=$(curl -s https://raw.githubusercontent.com/Drazzilb08/daps/master/jokes.txt | shuf -n 1) + joke=$(curl -s https://raw.githubusercontent.com/Drazzilb08/daps/master/jokes.txt | shuf -n 1 | sed 's/"/\\"/g') new_container_notification new_container_response=$(curl -s -H "Content-Type: application/json" -X POST -d "$payload" "$webhook") if [ "$dry_run" == "true" ]; then @@ -606,7 +606,7 @@ send_notification() { fi fi if [ ${#removed_containers[@]} -gt 0 ]; then - joke=$(curl -s https://raw.githubusercontent.com/Drazzilb08/daps/master/jokes.txt | shuf -n 1) + joke=$(curl -s https://raw.githubusercontent.com/Drazzilb08/daps/master/jokes.txt | shuf -n 1 | sed 's/"/\\"/g') removed_container_notification removed_container=$(curl -s -H "Content-Type: application/json" -X POST -d "$payload" "$webhook") if [ "$dry_run" == "true" ]; then diff --git a/extra-scripts/backup_folder.sh b/extra-scripts/backup_folder.sh index bb8d5c1..da7f059 100755 --- a/extra-scripts/backup_folder.sh +++ b/extra-scripts/backup_folder.sh @@ -202,7 +202,7 @@ send_notification() { # Get current time in UTC format get_ts=$(date -u -Iseconds) # Get a random joke from the specified file - joke=$(curl -s https://raw.githubusercontent.com/Drazzilb08/daps/master/jokes.txt | shuf -n 1) + joke=$(curl -s https://raw.githubusercontent.com/Drazzilb08/daps/master/jokes.txt | shuf -n 1 | sed 's/"/\\"/g') # Check if the webhook is for discord if [[ $webhook =~ ^https://discord\.com/api/webhooks/ ]]; then # Call the discord_payload function to construct the payload diff --git a/extra-scripts/backup_plex.sh b/extra-scripts/backup_plex.sh index e68a53d..963234b 100755 --- a/extra-scripts/backup_plex.sh +++ b/extra-scripts/backup_plex.sh @@ -223,11 +223,7 @@ field_builder() { build_payload(){ get_ts=$(date -u -Iseconds) # Get a random joke from the specified file - joke=$(curl -s https://raw.githubusercontent.com/Drazzilb08/daps/master/jokes.txt | shuf -n 1) - # ensure joke is valid for json - # shellcheck disable=SC2001 - joke=$(echo "$joke" | sed 's/"/\\"/g') - # ensure jokes is valid for json + joke=$(curl -s https://raw.githubusercontent.com/Drazzilb08/daps/master/jokes.txt | shuf -n 1 | sed 's/"/\\"/g') if [[ $webhook =~ ^https://discord\.com/api/webhooks/ ]]; then bot_name="Notification Bot" title="name" diff --git a/modules/labelarr.py b/modules/labelarr.py index 7ab79f3..65baa9f 100755 --- a/modules/labelarr.py +++ b/modules/labelarr.py @@ -20,6 +20,7 @@ from util.arrpy import StARR from util.utility import * from util.logger import setup_logger +import re try: from plexapi.server import PlexServer @@ -31,101 +32,45 @@ script_name = "labelarr" -def process_data(plex_dict, media_dict, labels): - """ - Process the data to be synced to Plex. +def sync_to_plex(plex, labels, media_dict, app, starr_server_name, logger, library_names): - Args: - plex_dict (dict): The Plex data. - media_dict (dict): The Radarr/Sonarr data. - labels (list): The list of labels to sync. - - Returns: - data_dict (dict): The data to be synced to Plex. - """ + tag_ids = {} + + for label in labels: + tag_id = app.get_tag_id_from_name(label) + if tag_id: + tag_ids[label] = tag_id - - # Initialize the list to store data to be synced to Plex data_dict = [] - - # Iterate through each media item in the Radarr/Sonarr data - for media_item in media_dict: - # Iterate through each Plex item in the Plex data - for plex_item in plex_dict: - # Check if the normalized title and year match between Plex and media data - if ( - media_item['normalized_title'] == plex_item['normalized_title'] - and media_item['year'] == plex_item['year'] - ): - # Get labels from Plex and media tags from Radarr/Sonarr - plex_labels = plex_item.get('labels', []) - media_tags = media_item.get('tag_data', {}).keys() - - # Dictionary to store labels to add or remove - add_remove = {} - - # Check each label in the provided list - for label in labels: - # Determine labels to add or remove based on comparison between Plex labels and media tags - if label in plex_labels and label not in media_tags: - add_remove[label] = "remove" - elif label not in plex_labels and label in media_tags: - add_remove[label] = "add" - - # If there are labels to add or remove, append data to data_dict - if add_remove: - data_dict.append({ - "title": media_item['title'], - "year": media_item['year'], - "add_remove": add_remove - }) - - # Return the data to be synced to Plex + for library in tqdm(library_names, desc=f"Processing Library", unit="library"): + library_data = plex.library.section(library).all() + for library_item in tqdm(library_data, desc=f"Syncing labels between {library} and {starr_server_name.capitalize()}"): + try: + plex_item_labels = [label.tag.lower() for label in library_item.labels] + except AttributeError: + logger.error(f"Error fetching labels for {library_item.title} ({library_item.year})") + continue + normalized_title = normalize_titles(library_item.title) + for media_item in media_dict: + if normalized_title == media_item['normalized_title'] and library_item.year == media_item['year']: + add_remove = {} + for tag, id in tag_ids.items(): + if tag not in plex_item_labels and id in media_item['tags']: + add_remove[tag] = 'add' + if not dry_run: + library_item.addLabel(tag) + elif tag in plex_item_labels and id not in media_item['tags']: + add_remove[tag] = 'remove' + if not dry_run: + library_item.removeLabel(tag) + if add_remove: + data_dict.append({ + "title": library_item.title, + "year": library_item.year, + "add_remove": add_remove, + }) return data_dict - -def sync_to_plex(plex, data_dict, instance_type, logger): - """ - Sync the data to Plex. - - Args: - plex (obj): The Plex server object. - data_dict (dict): The data to be synced to Plex. - instance_type (str): The type of instance (radarr/sonarr). - - Returns: - None - """ - - # Loop through each item in the data_dict - for item in data_dict: - if instance_type == "sonarr": - type = "show" - elif instance_type == "radarr": - type = "movie" - - # Search for the item in the Plex library based on title and year - try: - plex_item = plex.library.search(item['title'], libtype=type, year=item['year'])[0] - except IndexError: - # Log an error if the title is not found in Plex and continue to the next item - logger.error(f"Title: {item['title']} ({item['year']}) | Title not found in Plex") - continue - - # If the Plex item is found - if plex_item: - # Iterate through each label and corresponding action (add/remove) - for label, action in item['add_remove'].items(): - # Perform add or remove action based on the label and action type - if action == "add": - plex_item.addLabel(label) - elif action == "remove": - plex_item.removeLabel(label) - - # No explicit return value, as it's modifying Plex items directly - return - - def handle_messages(data_dict, logger): """ Handle the messages to be sent to Discord. @@ -136,6 +81,10 @@ def handle_messages(data_dict, logger): Returns: None """ + table = [ + ["Results"], + ] + logger.info(create_table(table)) # Loop through each item in the data_dict for item in data_dict: # Log the title and year of the item @@ -201,54 +150,10 @@ def notification(data_dict, logger): if built_fields: for message_number, fields in built_fields.items(): print(f"Sending message {message_number} of {message_count}...") - # Discord function call (may require specific parameters to function) discord(fields, logger, script_name, description=f"{'__**Dry Run**__' if dry_run else ''}", color=0x00ff00, content=None) - - -def handle_tags(app, media_dict, tag_names): - """ - Handle the tags for the media. - - Args: - app (obj): The StARR object. - media_dict (dict): The media data. - tag_names (list): The list of tag names. - - Returns: - media_dict (dict): The media data with the tag data added. - """ - - tag_dict = {} - - # If tag_names list is not empty - if tag_names: - # Convert tag names to lowercase and store in 'tags' - tags = [tag.lower() for tag in tag_names] - - # Iterate through each tag in the lowercase 'tags' list - for tag in tags: - # Get the tag ID from StARR object for each tag - tag_id = app.get_tag_id_from_name(tag) - - # If tag ID exists, add it to the tag dictionary - if tag_id: - tag_dict[tag] = tag_id - - # If tag_dict is not empty - if tag_dict: - # Iterate through each item in the media dictionary - for item in media_dict: - tag_data = {} - # Check each tag and its ID against the item's tags - for tag, tag_id in tag_dict.items(): - # If the tag ID exists in the item's tags, add it to tag_data - if tag_id in item['tags']: - tag_data[tag] = tag_id - # Assign the collected tag_data to the item - item['tag_data'] = tag_data - - return media_dict - + if message_number % 5 == 0: + print("Pausing for 5 seconds to let Discord catch up...") + time.sleep(5) def main(config): """ @@ -291,7 +196,6 @@ def main(config): # Fetch and process media data from the StARR instance media_dict = handle_starr_data(app, starr_server_name, instance_type, include_episode=False) - media_dict = handle_tags(app, media_dict, labels) # If media data is found if media_dict: @@ -305,48 +209,28 @@ def main(config): # Connect to the Plex server try: logger.info("Connecting to Plex...") - plex = PlexServer(config.plex_config[plex_instance]['url'], config.plex_config[plex_instance]['api'], timeout=120) + plex = PlexServer(config.plex_config[plex_instance]['url'], config.plex_config[plex_instance]['api'], timeout=180) except BadRequest: logger.error(f"Error connecting to Plex instance: {plex_instance}") continue server_name = plex.friendlyName - - # Fetch Plex data and process it + # Process data for syncing to Plex if library_names: - library_names_str = ", ".join(library_names) - logger.info(f"Gathering plex data on {server_name} for {library_names_str}... Please wait...") - plex_dict = get_plex_data(plex, library_names, logger, include_smart=False, collections_only=False) - logger.info(f"Completed gathering plex data...") + logger.info("Syncing labels to Plex") + data_dict = sync_to_plex(plex, labels, media_dict, app, starr_server_name, logger, library_names) else: - logger.error(f"No library names provided for {starr_server_name}, against {server_name}. Skipping...") + logger.error(f"No library names provided for {server_name}. Skipping...") continue - # If Plex data is found - if plex_dict: - # Logging Plex data - logger.debug(f"Plex Data:\n{json.dumps(plex_dict, indent=4)}") - - # Process data for syncing to Plex - logger.info("Syncing labels to Plex") - data_dict = process_data(plex_dict, media_dict, labels) + + # Handle messages related to syncing actions + if data_dict: + handle_messages(data_dict, logger) - # If items to sync are found - if data_dict: - logger.debug(f"Items to sync:\n{json.dumps(data_dict, indent=4)}") - # Perform actual syncing to Plex if not in dry run mode - if not dry_run: - sync_to_plex(plex, data_dict, instance_type, logger) - - # Handle messages related to syncing actions - handle_messages(data_dict, logger) - - # Send notifications related to syncing actions - if discord_check(script_name): - notification(data_dict, logger) - else: - logger.info(f"No items to sync from {starr_server_name} to {server_name}.\n") + # Send notifications related to syncing actions + if discord_check(script_name): + notification(data_dict, logger) else: - logger.error(f"No Plex Data found for {server_name}. Skipping...") - continue + logger.info(f"No items to sync from {starr_server_name} to {server_name}.\n") else: continue except KeyboardInterrupt: diff --git a/modules/nohl.py b/modules/nohl.py index f7bc581..cfbe794 100755 --- a/modules/nohl.py +++ b/modules/nohl.py @@ -191,7 +191,7 @@ def handle_searches(app, search_list, instance_type): print(f"Searches performed: {searches}") return searched_for -def filter_media(app, media_list, nohl_data, instance_type, exclude_profiles, exclude_media, max_search): +def filter_media(app, media_list, nohl_data, instance_type, exclude_profiles, exclude_media, max_search, logger): """ Filters media based on quality profile and monitored status. @@ -224,6 +224,9 @@ def filter_media(app, media_list, nohl_data, instance_type, exclude_profiles, ex for media_item in media_list: # Compare media items with non-hardlinked items if media_item['normalized_title'] == nohl_item['normalized_title'] and media_item['year'] == nohl_item['year']: + # Check if the root path of the non-hardlinked item is in the root folder of the media item + if nohl_item['root_path'] not in media_item['root_folder']: + continue # Check if the media item is not monitored if media_item['monitored'] == False or (exclude_media is not None and media_item['title'] in exclude_media) or media_item['quality_profile'] in exclude_profile_ids: data_list['filtered_media'].append({ @@ -681,7 +684,7 @@ def main(config): if nohl_data: media_list = handle_starr_data(app, server_name, instance_type, include_episode=True) if media_list: - data_list = filter_media(app, media_list, nohl_data, instance_type, exclude_profiles, exclude_media, max_search) + data_list = filter_media(app, media_list, nohl_data, instance_type, exclude_profiles, exclude_media, max_search, logger) else: logger.info(f"No media found for server: {server_name}") if data_list: diff --git a/modules/upgradinatorr.py b/modules/upgradinatorr.py index 1ed25d8..c85c7da 100755 --- a/modules/upgradinatorr.py +++ b/modules/upgradinatorr.py @@ -25,19 +25,21 @@ script_name = "upgradinatorr" -def filter_media(media_dict, checked_tag_id, ignore_tag_id, count, logger): +def filter_media(media_dict, checked_tag_id, ignore_tag_id, count, season_monitored_threshold, logger): """ Filter media_dict to remove items that are: * not monitored * have the checked_tag_id * have the ignore_tag_id * not in the correct status + * do not have enough episodes monitored within a season Args: media_dict (list): A list of dictionaries containing media information. checked_tag_id (int): The checked_tag_id to filter out. ignore_tag_id (int): The ignore_tag_id to filter out. count (int): The number of items to return. + season_monitored_threshold (int): The episode monitoring threshold to filter out seasons. Returns: filtered_media_dict (list): A list of dictionaries containing media information. @@ -53,6 +55,25 @@ def filter_media(media_dict, checked_tag_id, ignore_tag_id, count, logger): # Log skipped items logger.debug(f"Skipping {item['title']} ({item['year']}), Status: {item['status']}, Monitored: {item['monitored']}, Tags: {item['tags']}") continue # Move to the next item if conditions are not met + # Check number of monitored episodes within a season + if item['seasons']: + series_monitored = False + for i, season in enumerate(item['seasons']): + monitored_count = 0 + for episode in season['episode_data']: + if episode['monitored']: + monitored_count += 1 + # Change monitoring of season depending on how many unmonitored episodes there are + monitored_percentage = monitored_count / len(season['episode_data']) + if monitored_percentage < season_monitored_threshold: + item['seasons'][i]['monitored'] = False + logger.debug(f"{item['title']}, Season {i} unmonitored. Reason: monitored percentage {monitored_percentage} less than season_monitored_threshold {season_monitored_threshold}") + if item['seasons'][i]['monitored']: + series_monitored = True + # Skip if all seasons are unmonitored + if series_monitored == False: + logger.debug(f"Skipping {item['title']} ({item['year']}), Status: {item['status']}, Monitored: {item['monitored']}, Tags: {item['tags']}") + continue filtered_media_dict.append(item) # Append the item to the filtered list filter_count += 1 # Increment the counter for filtered items return filtered_media_dict # Return the filtered list of media @@ -115,22 +136,26 @@ def process_instance(instance_type, instance_settings, app, logger): checked_tag_name = instance_settings.get('tag_name', "checked") ignore_tag_name = instance_settings.get('ignore_tag', "ignore") unattended = instance_settings.get('unattended', False) + # default 0 means that a season will NOT be unmonitored if all episodes ARE unmonitored + season_monitored_threshold = instance_settings.get('season_monitored_threshold', 0) # Logging instance settings table = [ [f"{instance_type} Settings"] ] logger.debug(create_table(table)) - logger.debug(f'{"Count:":<20}{count}') - logger.debug(f'{"checked_tag_name:":<20}{checked_tag_name}') - logger.debug(f'{"ignore_tag_name:":<20}{checked_tag_name}') - logger.debug(f'{"unattended:":<20}{unattended}') + logger.debug(f'{"Count:":<28}{count}') + logger.debug(f'{"checked_tag_name:":<28}{checked_tag_name}') + logger.debug(f'{"ignore_tag_name:":<28}{checked_tag_name}') + logger.debug(f'{"unattended:":<28}{unattended}') + if instance_type == 'sonarr': + logger.debug(f'{"season_monitored_threshold:":<28}{season_monitored_threshold}') logger.debug('*' * 40) # Fetch media from the instance print(f"Gathering media from {server_name}...") server_name = app.get_instance_name() - media_dict = handle_starr_data(app, server_name, instance_type, include_episode=False) + media_dict = handle_starr_data(app, server_name, instance_type, include_episode=True) logger.debug(f"media_dict:\n{json.dumps(media_dict, indent=4)}") # Get tag ID based on the provided tag name @@ -138,13 +163,13 @@ def process_instance(instance_type, instance_settings, app, logger): ignore_tag_id = app.get_tag_id_from_name(ignore_tag_name) # Filter media based on tag and count criteria - filtered_media_dict = filter_media(media_dict, checked_tag_id, ignore_tag_id, count, logger) + filtered_media_dict = filter_media(media_dict, checked_tag_id, ignore_tag_id, count, season_monitored_threshold, logger) if not filtered_media_dict and unattended: media_ids = [item['media_id'] for item in media_dict] logger.info("All media is tagged. Removing tags...") app.remove_tags(media_ids, checked_tag_id) - media_dict = handle_starr_data(app, server_name, instance_type, include_episode=False) - filtered_media_dict = filter_media(media_dict, checked_tag_id, ignore_tag_id, count, logger) + media_dict = handle_starr_data(app, server_name, instance_type, include_episode=True) + filtered_media_dict = filter_media(media_dict, checked_tag_id, ignore_tag_id, count, season_monitored_threshold, logger) # If no filtered_media and not unattended return if not filtered_media_dict and not unattended: @@ -173,29 +198,55 @@ def process_instance(instance_type, instance_settings, app, logger): # Processing media data if not dry_run: - media_ids = [item['media_id'] for item in filtered_media_dict] - search_response = app.search_media(media_ids) - app.add_tags(media_ids, checked_tag_id) - ready = app.wait_for_command(search_response['id']) - if ready: - sleep_time = 10 # Set the sleep time to 5 seconds - print(f"Waiting for {sleep_time} seconds to allow for search results to populate in the queue...") - time.sleep(sleep_time) - queue = app.get_queue(instance_type) - logger.debug(f"queue:\n{json.dumps(queue, indent=4)}") - queue_dict = process_queue(queue, instance_type, media_ids) - logger.debug(f"queue_dict:\n{json.dumps(queue_dict, indent=4)}") - for item in filtered_media_dict: - downloads = {} - for queue_item in queue_dict: - if item['media_id'] == queue_item['media_id']: - downloads[queue_item['download']] = queue_item['torrent_custom_format_score'] - output_dict['data'].append({ - 'media_id': item['media_id'], - 'title': item['title'], - 'year': item['year'], - 'download': downloads - }) + + def process_search_response(search_response, media_id): + if search_response: + logger.debug(f"Waiting for command to complete for search response ID: {search_response['id']}") + ready = app.wait_for_command(search_response['id']) + if ready: + logger.debug(f"Command completed successfully for search response ID: {search_response['id']}") + else: + logger.warning(f"Command did not complete successfully for search response ID: {search_response['id']}") + else: + logger.warning(f"No search response for media ID: {media_id}") + + media_ids = [] + for item in filtered_media_dict: + media_ids.append(item['media_id']) + logger.debug(f"Processing media item with ID: {item['media_id']}") + + if item['seasons'] is None: + logger.debug(f"Searching media without seasons for media ID: {item['media_id']}") + search_response = app.search_media(item['media_id']) + process_search_response(search_response, item['media_id']) + else: + for season in item['seasons']: + if season['monitored']: + logger.debug(f"Searching season {season['season_number']} for media ID: {item['media_id']}") + search_response = app.search_season(item['media_id'], season['season_number']) + process_search_response(search_response, item['media_id']) + + logger.debug(f"Adding tag {checked_tag_id} to media ID: {item['media_id']}") + app.add_tags(item['media_id'], checked_tag_id) + + sleep_time = 10 # Set the sleep time to 10 seconds + print(f"Waiting for {sleep_time} seconds to allow for search results to populate in the queue...") + time.sleep(sleep_time) + queue = app.get_queue(instance_type) + logger.debug(f"queue:\n{json.dumps(queue, indent=4)}") + queue_dict = process_queue(queue, instance_type, media_ids) + logger.debug(f"queue_dict:\n{json.dumps(queue_dict, indent=4)}") + for item in filtered_media_dict: + downloads = {} + for queue_item in queue_dict: + if item['media_id'] == queue_item['media_id']: + downloads[queue_item['download']] = queue_item['torrent_custom_format_score'] + output_dict['data'].append({ + 'media_id': item['media_id'], + 'title': item['title'], + 'year': item['year'], + 'download': downloads + }) else: for item in filtered_media_dict: output_dict['data'].append({ diff --git a/schemas/config-schema.json b/schemas/config-schema.json index aec6a4e..1e87998 100644 --- a/schemas/config-schema.json +++ b/schemas/config-schema.json @@ -466,7 +466,10 @@ }, "ignore_media": { - "type":"string" + "type": [ + "array", + "null" + ] }, "ignore_collections": { "$ref": "#/definitions/uniqueArray" diff --git a/scripts/nohl_bash.sh b/scripts/nohl_bash.sh index c4fd4ad..f945f41 100755 --- a/scripts/nohl_bash.sh +++ b/scripts/nohl_bash.sh @@ -165,8 +165,15 @@ send_notification() { if [ -f "/tmp/nohl.tmp" ]; then # Get the number of issues in the file number_of_issues=$(sed -e'/^\s*$/d' /tmp/nohl.tmp | wc -l) - # Get the list of issues in the file - list_of_issues=$(sed -e '/^\s*$/d' -e 's/\(.*\) - S\([0-9][0-9]\)E\([0-9][0-9]\) - [0-9]* -.*/\1 - S\2E\3/' -e 's/\(.*\) {\(.*\)}/\1/' /tmp/nohl.tmp | jq -Rs . | cut -c 2- | rev | cut -c 2- | rev) + # Get the list of issues in the file only keeping the filename + list_of_issues=$(sed -e '/^\s*$/d' -e 's/\(.*\) - S\([0-9][0-9]\)E\([0-9][0-9]\) - .*/\1 - S\2E\3/' -e 's/\(.*\) {\(.*\)}/\1/' /tmp/nohl.tmp | while read -r line; do + filename=$(basename "$line") + if [[ "$filename" =~ S[0-9]{2}E[0-9]{2} ]]; then + echo "$filename" | sed -e 's/^\(.*S[0-9][0-9]E[0-9][0-9]\).*/\1/' + else + echo "$filename" | sed -e 's/^\(.*(\([0-9]\{4\}\))\).*/\1/' + fi + done | jq -Rs . | cut -c 2- | rev | cut -c 2- | rev) fi # Check if the webhook is for discord if [[ $webhook =~ ^https://discord\.com/api/webhooks/ ]]; then