Implement album deletion feature after metadata migration

- Added a new command-line argument `--delete` to allow users to delete single albums after successful metadata migration.
- Integrated the `unmonitor_and_delete_album` function to handle the deletion process for albums that meet the migration criteria.
- Enhanced the `migrate_plex_metadata` function to support exclusion of smart playlists during migration.
- Updated logging to provide detailed feedback on the deletion process and migration results.
This commit is contained in:
Danilo Reyes
2025-11-14 02:04:11 -06:00
parent af5a2bf825
commit cc9521f7a4
4 changed files with 149 additions and 33 deletions

View File

@@ -29,55 +29,71 @@ def find_plex_track_by_path(
try:
mapped_path = map_docker_path(file_path, docker_mount)
logger.debug(
f"Searching for track: lidarr_path={file_path}, mapped_path={mapped_path}"
)
music_sections = [
s for s in plex_server.library.sections() if s.type == "artist"
]
if not music_sections:
logger.warning("No music sections found in Plex")
return None
# Try searching by exact mapped path first
for section in music_sections:
results = section.search(filters={"track.file": mapped_path})
if results:
logger.debug(f"Found track by mapped path: {mapped_path}")
return results[0]
# Try original path (might be what Plex sees in Docker)
for section in music_sections:
results = section.search(filters={"track.file": file_path})
if results:
logger.debug(f"Found track by original path: {file_path}")
return results[0]
# Fallback: search by filename in all tracks
filename = os.path.basename(file_path)
# Strategy: Check track.locations (list of file paths)
for section in music_sections:
all_tracks = section.searchTracks()
for track in all_tracks:
for media in track.media:
for part in media.parts:
if part.file and (
part.file == mapped_path
or part.file == file_path
or part.file.endswith(filename)
):
logger.debug(f"Found track by filename match: {part.file}")
return track
track_locations = getattr(track, "locations", [])
if mapped_path in track_locations or file_path in track_locations:
logger.debug(
f"Found track by locations match: {track.title} - {track_locations[0] if track_locations else 'unknown'}"
)
return track
logger.warning(
f"Could not find Plex track for path: {file_path} (mapped: {mapped_path})"
f"Could not find Plex track. Paths tried: {file_path}, {mapped_path}"
)
return None
except Exception as e:
logger.debug(f"Could not find Plex track for path {file_path}: {e}")
logger.error(f"Error finding Plex track for path {file_path}: {e}")
import traceback
logger.debug(traceback.format_exc())
return None
def get_plex_playlists_for_track(plex_server, track) -> List:
"""Get all playlists containing this track"""
def get_smart_playlist_ids(plex_server) -> set:
"""Get set of smart playlist IDs to exclude from migration"""
try:
smart_playlists = [
p.ratingKey
for p in plex_server.playlists()
if p.playlistType == "audio" and p.smart
]
if smart_playlists:
logger.info(
f"Found {len(smart_playlists)} smart playlists (will exclude from migration)"
)
return set(smart_playlists)
except Exception as e:
logger.debug(f"Could not get smart playlists: {e}")
return set()
def get_plex_playlists_for_track(
plex_server, track, exclude_smart_playlists: set = None
) -> List:
"""Get all manual playlists containing this track (excludes smart playlists)"""
if exclude_smart_playlists is None:
exclude_smart_playlists = set()
try:
return [
playlist
for playlist in plex_server.playlists()
if playlist.playlistType == "audio"
and playlist.ratingKey not in exclude_smart_playlists
and any(item.ratingKey == track.ratingKey for item in playlist.items())
]
except Exception as e:
@@ -216,6 +232,7 @@ def migrate_plex_metadata(
single_file_path: str,
album_file_path: str,
docker_mount: Optional[str] = None,
exclude_smart_playlists: set = None,
) -> Tuple[bool, str]:
"""Migrate Plex metadata from single to album track. Returns (success, message)"""
if not plex_server:
@@ -231,7 +248,9 @@ def migrate_plex_metadata(
single_rating = getattr(single_track, "userRating", None)
single_plays = getattr(single_track, "viewCount", 0) or 0
single_playlists = get_plex_playlists_for_track(plex_server, single_track)
single_playlists = get_plex_playlists_for_track(
plex_server, single_track, exclude_smart_playlists
)
logger.info(
f" Single track metadata: rating={single_rating or 'none'}, plays={single_plays}, playlists={len(single_playlists)}"