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:
@@ -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)}"
|
||||
|
||||
Reference in New Issue
Block a user