mirror of
https://github.com/SoPat712/allstarr.git
synced 2026-02-09 23:55:10 -05:00
Add favorite-to-keep feature for external tracks
- When favoriting an external track, automatically copy to /kept folder - Organized as Artist/Album/Track structure - Includes cover art if available - Downloads track first if not already cached - Add KEPT_PATH and CACHE_PATH volumes to docker-compose - Update .env.example and README with new feature
This commit is contained in:
@@ -1118,12 +1118,24 @@ public class JellyfinController : ControllerBase
|
||||
}
|
||||
|
||||
// Check if this is an external song/album
|
||||
var (isExternal, _, _) = _localLibraryService.ParseSongId(itemId);
|
||||
var (isExternal, provider, externalId) = _localLibraryService.ParseSongId(itemId);
|
||||
if (isExternal)
|
||||
{
|
||||
// External items don't exist in Jellyfin, so we can't favorite them there
|
||||
// Just return success - the client will show it as favorited
|
||||
_logger.LogDebug("Favoriting external item {ItemId} (not synced to Jellyfin)", itemId);
|
||||
_logger.LogInformation("Favoriting external item {ItemId}, copying to kept folder", itemId);
|
||||
|
||||
// Copy the track to kept folder in background
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await CopyExternalTrackToKeptAsync(itemId, provider!, externalId!);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to copy external track {ItemId} to kept folder", itemId);
|
||||
}
|
||||
});
|
||||
|
||||
return Ok(new { IsFavorite = true });
|
||||
}
|
||||
|
||||
@@ -2083,6 +2095,76 @@ public class JellyfinController : ControllerBase
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies an external track to the kept folder when favorited.
|
||||
/// </summary>
|
||||
private async Task CopyExternalTrackToKeptAsync(string itemId, string provider, string externalId)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Get the song metadata
|
||||
var song = await _metadataService.GetSongAsync(provider, externalId);
|
||||
if (song == null)
|
||||
{
|
||||
_logger.LogWarning("Could not find song metadata for {ItemId}", itemId);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if file exists in downloads folder
|
||||
var downloadPath = PathHelper.GetSongPath(song.Artist, song.Album, song.Title);
|
||||
if (!System.IO.File.Exists(downloadPath))
|
||||
{
|
||||
_logger.LogInformation("Track not yet downloaded, triggering download for {ItemId}", itemId);
|
||||
|
||||
// Download the track first
|
||||
var downloadResult = await _downloadService.DownloadSongAsync(provider, externalId);
|
||||
if (!downloadResult.IsSuccess)
|
||||
{
|
||||
_logger.LogWarning("Failed to download track {ItemId}: {Error}", itemId, downloadResult.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
downloadPath = downloadResult.Value!.FilePath;
|
||||
}
|
||||
|
||||
// Create kept folder structure: /app/kept/Artist/Album/
|
||||
var keptBasePath = "/app/kept";
|
||||
var keptArtistPath = Path.Combine(keptBasePath, PathHelper.SanitizeFileName(song.Artist));
|
||||
var keptAlbumPath = Path.Combine(keptArtistPath, PathHelper.SanitizeFileName(song.Album));
|
||||
|
||||
Directory.CreateDirectory(keptAlbumPath);
|
||||
|
||||
// Copy file to kept folder
|
||||
var fileName = Path.GetFileName(downloadPath);
|
||||
var keptFilePath = Path.Combine(keptAlbumPath, fileName);
|
||||
|
||||
if (System.IO.File.Exists(keptFilePath))
|
||||
{
|
||||
_logger.LogInformation("Track already exists in kept folder: {Path}", keptFilePath);
|
||||
return;
|
||||
}
|
||||
|
||||
System.IO.File.Copy(downloadPath, keptFilePath, overwrite: false);
|
||||
_logger.LogInformation("✓ Copied favorited track to kept folder: {Path}", keptFilePath);
|
||||
|
||||
// Also copy cover art if it exists
|
||||
var coverPath = Path.Combine(Path.GetDirectoryName(downloadPath)!, "cover.jpg");
|
||||
if (System.IO.File.Exists(coverPath))
|
||||
{
|
||||
var keptCoverPath = Path.Combine(keptAlbumPath, "cover.jpg");
|
||||
if (!System.IO.File.Exists(keptCoverPath))
|
||||
{
|
||||
System.IO.File.Copy(coverPath, keptCoverPath, overwrite: false);
|
||||
_logger.LogDebug("Copied cover art to kept folder");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error copying external track {ItemId} to kept folder", itemId);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads missing tracks from file cache as fallback when Redis is empty.
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user