main
  1"""
  2Update artist monitoring settings in Lidarr.
  3
  4This script allows you to change the monitoring mode for artists in Lidarr.
  5You can update all artists or filter by name pattern.
  6"""
  7
  8from typing import Any, Dict, List
  9
 10from lib import (
 11    ArrClient,
 12    CommandContext,
 13    get_confirmation_decision,
 14    print_item_list,
 15    print_section_header,
 16)
 17
 18
 19def get_artists(client: ArrClient) -> List[Dict[str, Any]]:
 20    """Get all artists from Lidarr."""
 21    return client.get("/api/v1/artist")
 22
 23
 24def filter_artists(
 25    artists: List[Dict[str, Any]], pattern: str = None
 26) -> List[Dict[str, Any]]:
 27    """
 28    Filter artists by name pattern.
 29
 30    Args:
 31        artists: List of artist objects
 32        pattern: Optional substring to match in artist names (case-insensitive)
 33
 34    Returns:
 35        Filtered list of artists
 36    """
 37    if not pattern:
 38        return artists
 39
 40    pattern_lower = pattern.lower()
 41    return [
 42        artist
 43        for artist in artists
 44        if pattern_lower in artist.get("artistName", "").lower()
 45    ]
 46
 47
 48def update_artist_monitoring(
 49    client: ArrClient,
 50    artist: Dict[str, Any],
 51    monitor_mode: str,
 52    monitor_new_items: str = None,
 53) -> bool:
 54    """
 55    Update an artist's monitoring settings.
 56
 57    Args:
 58        client: Lidarr API client
 59        artist: Artist object to update
 60        monitor_mode: Monitoring mode (all, future, missing, existing, none)
 61        monitor_new_items: Monitor new items mode (all, new, none) - optional
 62
 63    Returns:
 64        True if successful, False otherwise
 65    """
 66    # Update the artist object with new monitoring settings
 67    artist["addOptions"] = {"monitor": monitor_mode}
 68
 69    # Update monitorNewItems if specified
 70    if monitor_new_items is not None:
 71        artist["monitorNewItems"] = monitor_new_items
 72
 73    # Send PUT request to update the artist
 74    result = client.put("/api/v1/artist", artist)
 75
 76    return bool(result and result.get("id"))
 77
 78
 79def run(
 80    lidarr_url: str,
 81    lidarr_api_key: str,
 82    monitor_mode: str,
 83    monitor_new_items: str,
 84    artist_pattern: str,
 85    dry_run: bool,
 86    no_confirm: bool,
 87):
 88    """Execute the lidarr update-monitoring command."""
 89    # Create client and context
 90    lidarr = ArrClient(lidarr_url, lidarr_api_key)
 91    ctx = CommandContext(dry_run, no_confirm)
 92
 93    # Fetch all artists
 94    print_section_header("FETCHING ARTISTS FROM LIDARR")
 95    print("Retrieving artists...")
 96    all_artists = get_artists(lidarr)
 97
 98    if not all_artists:
 99        print("\nNo artists found in Lidarr!")
100        return
101
102    print(f"Found {len(all_artists)} total artists in Lidarr")
103
104    # Filter artists if pattern provided
105    if artist_pattern:
106        print(f"\nFiltering artists by pattern: '{artist_pattern}'")
107        filtered_artists = filter_artists(all_artists, artist_pattern)
108        print(f"Matched {len(filtered_artists)} artists")
109    else:
110        filtered_artists = all_artists
111        print("\nNo filter specified - will update ALL artists")
112
113    if not filtered_artists:
114        print("\nNo artists match the specified pattern!")
115        return
116
117    # Display artists to be updated
118    print_section_header("ARTISTS TO UPDATE")
119    artist_names = [
120        artist.get("artistName", "Unknown") for artist in filtered_artists
121    ]
122
123    # Build description of what will be updated
124    update_desc = f"monitor mode '{monitor_mode}'"
125    if monitor_new_items:
126        update_desc += f" and monitor new items '{monitor_new_items}'"
127
128    print_item_list(
129        artist_names,
130        f"Artists that will be set to {update_desc}",
131        max_display=20,
132    )
133
134    # Confirm operation
135    confirm_msg = (
136        f"\nUpdate monitoring for {len(filtered_artists)} artist(s) "
137        f"to '{monitor_mode}'"
138    )
139    if monitor_new_items:
140        confirm_msg += f" (monitor new items: '{monitor_new_items}')"
141    confirm_msg += "?"
142
143    if not get_confirmation_decision(ctx, confirm_msg):
144        if not ctx.dry_run:
145            print("Operation cancelled")
146        return
147
148    # Update artists
149    print_section_header("UPDATING ARTISTS")
150
151    updated_count = 0
152    failed_count = 0
153
154    for idx, artist in enumerate(filtered_artists, 1):
155        artist_name = artist.get("artistName", "Unknown")
156        current_monitor_new = artist.get("monitorNewItems", "Unknown")
157        print(
158            f"[{idx}/{len(filtered_artists)}] {artist_name} "
159            f"(current monitorNewItems: {current_monitor_new})"
160        )
161
162        if not ctx.dry_run:
163            success = update_artist_monitoring(
164                lidarr, artist, monitor_mode, monitor_new_items
165            )
166            if success:
167                msg = f"  ✓ Updated to monitor '{monitor_mode}'"
168                if monitor_new_items:
169                    msg += f" (monitor new items: '{monitor_new_items}')"
170                print(msg)
171                updated_count += 1
172            else:
173                print("  ✗ Failed to update")
174                failed_count += 1
175        else:
176            msg = f"  [DRY RUN] Would update to monitor '{monitor_mode}'"
177            if monitor_new_items:
178                msg += f" (monitor new items: '{monitor_new_items}')"
179            print(msg)
180            updated_count += 1
181
182    # Final summary
183    print_section_header("FINAL SUMMARY")
184    print(f"\nTotal artists: {len(all_artists)}")
185    print(f"Artists selected: {len(filtered_artists)}")
186    print(f"  - Successfully updated: {updated_count}")
187    if failed_count > 0:
188        print(f"  - Failed: {failed_count}")
189
190    if ctx.dry_run:
191        print(
192            "\n[DRY RUN] No changes were made. "
193            "Remove --dry-run to update artists."
194        )
195    elif updated_count > 0:
196        summary_msg = f"\nArtists are now set to monitor: {monitor_mode}"
197        if monitor_new_items:
198            summary_msg += f"\nMonitor new items: {monitor_new_items}"
199        summary_msg += (
200            "\nLidarr will automatically search for albums based on "
201            "these settings."
202        )
203        print(summary_msg)