| @@ 361-442 (lines=82) @@ | ||
| 358 | ||
| 359 | ||
| 360 | # --- Main Function (UPDATED) --- |
|
| 361 | def main(): |
|
| 362 | """Main execution loop.""" |
|
| 363 | logging.info("Starting Collexions Script") |
|
| 364 | while True: |
|
| 365 | run_start = time.time() |
|
| 366 | config = load_config() |
|
| 367 | if not all(k in config for k in ['plex_url', 'plex_token', 'pinning_interval']): |
|
| 368 | logging.critical("Config essentials missing. Exit."); sys.exit(1) |
|
| 369 | ||
| 370 | pin_interval = config.get('pinning_interval', 60); |
|
| 371 | if not isinstance(pin_interval, (int, float)) or pin_interval <= 0: pin_interval = 60 |
|
| 372 | sleep_sec = pin_interval * 60 |
|
| 373 | ||
| 374 | plex = connect_to_plex(config) |
|
| 375 | if not plex: |
|
| 376 | logging.error(f"Plex connection failed. Retrying in {pin_interval} min.") |
|
| 377 | else: |
|
| 378 | exclusion_list = config.get('exclusion_list', []); |
|
| 379 | if not isinstance(exclusion_list, list): exclusion_list = [] |
|
| 380 | library_names = config.get('library_names', []) |
|
| 381 | if not isinstance(library_names, list): library_names = [] |
|
| 382 | collections_per_library_config = config.get('number_of_collections_to_pin', {}) |
|
| 383 | if not isinstance(collections_per_library_config, dict): collections_per_library_config = {} |
|
| 384 | ||
| 385 | selected_collections = load_selected_collections() # Load current history |
|
| 386 | current_timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S') |
|
| 387 | # Don't pre-initialize timestamp entry, add only if non-specials are pinned |
|
| 388 | newly_pinned_titles_this_run = [] # Track all pins for this run |
|
| 389 | ||
| 390 | # --- Get all special titles ONCE per cycle --- |
|
| 391 | all_special_titles = get_all_special_collection_names(config) |
|
| 392 | # ------------------------------------------- |
|
| 393 | ||
| 394 | for library_name in library_names: |
|
| 395 | library_process_start = time.time() |
|
| 396 | if not isinstance(library_name, str): logging.warning(f"Skipping invalid library name: {library_name}"); continue |
|
| 397 | ||
| 398 | pin_limit = collections_per_library_config.get(library_name, 0); |
|
| 399 | if not isinstance(pin_limit, int) or pin_limit < 0: pin_limit = 0 |
|
| 400 | if pin_limit == 0: logging.info(f"Skip '{library_name}': 0 limit."); continue |
|
| 401 | ||
| 402 | logging.info(f"Processing '{library_name}' (Limit: {pin_limit})") |
|
| 403 | unpin_collections(plex, [library_name], exclusion_list) |
|
| 404 | active_specials = get_active_special_collections(config) |
|
| 405 | all_colls = get_collections_from_all_libraries(plex, [library_name]) |
|
| 406 | if not all_colls: logging.info(f"No collections in '{library_name}'."); continue |
|
| 407 | ||
| 408 | colls_to_pin = filter_collections(config, all_colls, active_specials, pin_limit, library_name, selected_collections) |
|
| 409 | if colls_to_pin: |
|
| 410 | pin_collections(colls_to_pin, config) |
|
| 411 | # Add ALL pinned titles to the list for THIS run's tracking |
|
| 412 | newly_pinned_titles_this_run.extend([c.title for c in colls_to_pin if hasattr(c, 'title')]) |
|
| 413 | else: logging.info(f"No collections selected for '{library_name}'.") |
|
| 414 | logging.info(f"Finished '{library_name}' in {time.time() - library_process_start:.2f}s.") |
|
| 415 | ||
| 416 | # --- Modified History Update Logic --- |
|
| 417 | if newly_pinned_titles_this_run: |
|
| 418 | unique_new_pins_all = set(newly_pinned_titles_this_run) |
|
| 419 | # Filter out special collections before saving to history |
|
| 420 | non_special_pins_for_history = { |
|
| 421 | title for title in unique_new_pins_all |
|
| 422 | if title not in all_special_titles # Use the set fetched earlier |
|
| 423 | } |
|
| 424 | # Only update history file if there were non-special items pinned |
|
| 425 | if non_special_pins_for_history: |
|
| 426 | history_entry = sorted(list(non_special_pins_for_history)) |
|
| 427 | selected_collections[current_timestamp] = history_entry |
|
| 428 | save_selected_collections(selected_collections) |
|
| 429 | logging.info(f"Updated history for {current_timestamp} with {len(history_entry)} non-special items.") |
|
| 430 | if len(unique_new_pins_all) > len(non_special_pins_for_history): |
|
| 431 | logging.info(f"Note: {len(unique_new_pins_all) - len(non_special_pins_for_history)} special collection(s) were pinned but not added to recency history.") |
|
| 432 | else: |
|
| 433 | logging.info("Only special collections were pinned this cycle. History not updated for recency blocking.") |
|
| 434 | else: |
|
| 435 | logging.info("Nothing pinned this cycle, history not updated.") |
|
| 436 | # --- End Modified History Update --- |
|
| 437 | ||
| 438 | run_end = time.time() |
|
| 439 | logging.info(f"Cycle finished in {run_end - run_start:.2f} seconds.") |
|
| 440 | logging.info(f"Sleeping for {pin_interval} minutes...") |
|
| 441 | try: time.sleep(sleep_sec) |
|
| 442 | except KeyboardInterrupt: logging.info("Script interrupted. Exiting."); break |
|
| 443 | ||
| 444 | # --- Script Entry Point --- |
|
| 445 | if __name__ == "__main__": |
|
| @@ 361-442 (lines=82) @@ | ||
| 358 | ||
| 359 | ||
| 360 | # --- Main Function (UPDATED) --- |
|
| 361 | def main(): |
|
| 362 | """Main execution loop.""" |
|
| 363 | logging.info("Starting Collexions Script") |
|
| 364 | while True: |
|
| 365 | run_start = time.time() |
|
| 366 | config = load_config() |
|
| 367 | if not all(k in config for k in ['plex_url', 'plex_token', 'pinning_interval']): |
|
| 368 | logging.critical("Config essentials missing. Exit."); sys.exit(1) |
|
| 369 | ||
| 370 | pin_interval = config.get('pinning_interval', 60); |
|
| 371 | if not isinstance(pin_interval, (int, float)) or pin_interval <= 0: pin_interval = 60 |
|
| 372 | sleep_sec = pin_interval * 60 |
|
| 373 | ||
| 374 | plex = connect_to_plex(config) |
|
| 375 | if not plex: |
|
| 376 | logging.error(f"Plex connection failed. Retrying in {pin_interval} min.") |
|
| 377 | else: |
|
| 378 | exclusion_list = config.get('exclusion_list', []); |
|
| 379 | if not isinstance(exclusion_list, list): exclusion_list = [] |
|
| 380 | library_names = config.get('library_names', []) |
|
| 381 | if not isinstance(library_names, list): library_names = [] |
|
| 382 | collections_per_library_config = config.get('number_of_collections_to_pin', {}) |
|
| 383 | if not isinstance(collections_per_library_config, dict): collections_per_library_config = {} |
|
| 384 | ||
| 385 | selected_collections = load_selected_collections() # Load current history |
|
| 386 | current_timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S') |
|
| 387 | # Don't pre-initialize timestamp entry, add only if non-specials are pinned |
|
| 388 | newly_pinned_titles_this_run = [] # Track all pins for this run |
|
| 389 | ||
| 390 | # --- Get all special titles ONCE per cycle --- |
|
| 391 | all_special_titles = get_all_special_collection_names(config) |
|
| 392 | # ------------------------------------------- |
|
| 393 | ||
| 394 | for library_name in library_names: |
|
| 395 | library_process_start = time.time() |
|
| 396 | if not isinstance(library_name, str): logging.warning(f"Skipping invalid library name: {library_name}"); continue |
|
| 397 | ||
| 398 | pin_limit = collections_per_library_config.get(library_name, 0); |
|
| 399 | if not isinstance(pin_limit, int) or pin_limit < 0: pin_limit = 0 |
|
| 400 | if pin_limit == 0: logging.info(f"Skip '{library_name}': 0 limit."); continue |
|
| 401 | ||
| 402 | logging.info(f"Processing '{library_name}' (Limit: {pin_limit})") |
|
| 403 | unpin_collections(plex, [library_name], exclusion_list) |
|
| 404 | active_specials = get_active_special_collections(config) |
|
| 405 | all_colls = get_collections_from_all_libraries(plex, [library_name]) |
|
| 406 | if not all_colls: logging.info(f"No collections in '{library_name}'."); continue |
|
| 407 | ||
| 408 | colls_to_pin = filter_collections(config, all_colls, active_specials, pin_limit, library_name, selected_collections) |
|
| 409 | if colls_to_pin: |
|
| 410 | pin_collections(colls_to_pin, config) |
|
| 411 | # Add ALL pinned titles to the list for THIS run's tracking |
|
| 412 | newly_pinned_titles_this_run.extend([c.title for c in colls_to_pin if hasattr(c, 'title')]) |
|
| 413 | else: logging.info(f"No collections selected for '{library_name}'.") |
|
| 414 | logging.info(f"Finished '{library_name}' in {time.time() - library_process_start:.2f}s.") |
|
| 415 | ||
| 416 | # --- Modified History Update Logic --- |
|
| 417 | if newly_pinned_titles_this_run: |
|
| 418 | unique_new_pins_all = set(newly_pinned_titles_this_run) |
|
| 419 | # Filter out special collections before saving to history |
|
| 420 | non_special_pins_for_history = { |
|
| 421 | title for title in unique_new_pins_all |
|
| 422 | if title not in all_special_titles # Use the set fetched earlier |
|
| 423 | } |
|
| 424 | # Only update history file if there were non-special items pinned |
|
| 425 | if non_special_pins_for_history: |
|
| 426 | history_entry = sorted(list(non_special_pins_for_history)) |
|
| 427 | selected_collections[current_timestamp] = history_entry |
|
| 428 | save_selected_collections(selected_collections) |
|
| 429 | logging.info(f"Updated history for {current_timestamp} with {len(history_entry)} non-special items.") |
|
| 430 | if len(unique_new_pins_all) > len(non_special_pins_for_history): |
|
| 431 | logging.info(f"Note: {len(unique_new_pins_all) - len(non_special_pins_for_history)} special collection(s) were pinned but not added to recency history.") |
|
| 432 | else: |
|
| 433 | logging.info("Only special collections were pinned this cycle. History not updated for recency blocking.") |
|
| 434 | else: |
|
| 435 | logging.info("Nothing pinned this cycle, history not updated.") |
|
| 436 | # --- End Modified History Update --- |
|
| 437 | ||
| 438 | run_end = time.time() |
|
| 439 | logging.info(f"Cycle finished in {run_end - run_start:.2f} seconds.") |
|
| 440 | logging.info(f"Sleeping for {pin_interval} minutes...") |
|
| 441 | try: time.sleep(sleep_sec) |
|
| 442 | except KeyboardInterrupt: logging.info("Script interrupted. Exiting."); break |
|
| 443 | ||
| 444 | # --- Script Entry Point --- |
|
| 445 | if __name__ == "__main__": |
|