mirror of
https://github.com/sphildreth/roadie
synced 2024-11-26 06:00:23 +00:00
Subsonic API Work.
This commit is contained in:
parent
4a62537a42
commit
be7aa45f16
11 changed files with 378 additions and 323 deletions
|
@ -12,7 +12,6 @@ using Roadie.Library.Identity;
|
|||
using Roadie.Library.Models.ThirdPartyApi.Subsonic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -24,6 +23,7 @@ namespace Roadie.Api.Controllers
|
|||
public class SubsonicController : EntityControllerBase
|
||||
{
|
||||
private IPlayActivityService PlayActivityService { get; }
|
||||
private IReleaseService ReleaseService { get; }
|
||||
private ISubsonicService SubsonicService { get; }
|
||||
|
||||
/// <summary>
|
||||
|
@ -32,7 +32,6 @@ namespace Roadie.Api.Controllers
|
|||
private Library.Models.Users.User SubsonicUser { get; set; }
|
||||
|
||||
private ITrackService TrackService { get; }
|
||||
private IReleaseService ReleaseService { get; }
|
||||
|
||||
public SubsonicController(ISubsonicService subsonicService, ITrackService trackService, IReleaseService releaseService, IPlayActivityService playActivityService, ILoggerFactory logger, ICacheManager cacheManager, IConfiguration configuration, UserManager<ApplicationUser> userManager)
|
||||
: base(cacheManager, configuration, userManager)
|
||||
|
@ -44,20 +43,6 @@ namespace Roadie.Api.Controllers
|
|||
this.PlayActivityService = playActivityService;
|
||||
}
|
||||
|
||||
[HttpGet("getAlbum.view")]
|
||||
[HttpPost("getAlbum.view")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> GetAlbum(SubsonicRequest request)
|
||||
{
|
||||
var authResult = await this.AuthenticateUser(request);
|
||||
if (authResult != null)
|
||||
{
|
||||
return authResult;
|
||||
}
|
||||
var result = await this.SubsonicService.GetAlbum(request, this.SubsonicUser);
|
||||
return this.BuildResponse(request, result, "album");
|
||||
}
|
||||
|
||||
[HttpGet("createBookmark.view")]
|
||||
[HttpPost("createBookmark.view")]
|
||||
[ProducesResponseType(200)]
|
||||
|
@ -72,6 +57,19 @@ namespace Roadie.Api.Controllers
|
|||
return this.BuildResponse(request, result);
|
||||
}
|
||||
|
||||
[HttpGet("createPlaylist.view")]
|
||||
[HttpPost("createPlaylist.view")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> CreatePlaylist(SubsonicRequest request, string playlistId, string name, string[] songId)
|
||||
{
|
||||
var authResult = await this.AuthenticateUser(request);
|
||||
if (authResult != null)
|
||||
{
|
||||
return authResult;
|
||||
}
|
||||
var result = await this.SubsonicService.CreatePlaylist(request, this.SubsonicUser, name, songId, playlistId);
|
||||
return this.BuildResponse(request, result, "playlist");
|
||||
}
|
||||
|
||||
[HttpGet("deleteBookmark.view")]
|
||||
[HttpPost("deleteBookmark.view")]
|
||||
|
@ -101,75 +99,46 @@ namespace Roadie.Api.Controllers
|
|||
return this.BuildResponse(request, result);
|
||||
}
|
||||
|
||||
[HttpGet("updatePlaylist.view")]
|
||||
[HttpPost("updatePlaylist.view")]
|
||||
[HttpGet("download.view")]
|
||||
[HttpPost("download.view")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> UpdatePlaylist(SubsonicRequest request, string playlistId, string name, string comment, bool? @public, string[] songIdToAdd, int[] songIndexToRemove)
|
||||
public async Task<IActionResult> Download(SubsonicRequest request)
|
||||
{
|
||||
var authResult = await this.AuthenticateUser(request);
|
||||
if (authResult != null)
|
||||
{
|
||||
return authResult;
|
||||
return Unauthorized();
|
||||
}
|
||||
var result = await this.SubsonicService.UpdatePlaylist(request, this.SubsonicUser, playlistId, name, comment, @public, songIdToAdd, songIndexToRemove);
|
||||
return this.BuildResponse(request, result);
|
||||
var trackId = request.TrackId;
|
||||
if (trackId != null)
|
||||
{
|
||||
return await base.StreamTrack(trackId.Value, this.TrackService, this.PlayActivityService, this.SubsonicUser);
|
||||
}
|
||||
var releaseId = request.ReleaseId;
|
||||
if (releaseId != null)
|
||||
{
|
||||
var releaseZip = await this.ReleaseService.ReleaseZipped(this.SubsonicUser, releaseId.Value);
|
||||
if (!releaseZip.IsSuccess)
|
||||
{
|
||||
return NotFound("Unknown Release id");
|
||||
}
|
||||
return File(releaseZip.Data, "application/zip", (string)releaseZip.AdditionalData["ZipFileName"]);
|
||||
}
|
||||
return NotFound($"Unknown download id `{ request.id }`");
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("getBookmarks.view")]
|
||||
[HttpPost("getBookmarks.view")]
|
||||
[HttpGet("getAlbum.view")]
|
||||
[HttpPost("getAlbum.view")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> GetBookmarks(SubsonicRequest request)
|
||||
public async Task<IActionResult> GetAlbum(SubsonicRequest request)
|
||||
{
|
||||
var authResult = await this.AuthenticateUser(request);
|
||||
if (authResult != null)
|
||||
{
|
||||
return authResult;
|
||||
}
|
||||
var result = await this.SubsonicService.GetBookmarks(request, this.SubsonicUser);
|
||||
return this.BuildResponse(request, result, "bookmarks");
|
||||
}
|
||||
|
||||
[HttpGet("star.view")]
|
||||
[HttpPost("star.view")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> Star(SubsonicRequest request, string[] albumId, string[] artistId)
|
||||
{
|
||||
var authResult = await this.AuthenticateUser(request);
|
||||
if (authResult != null)
|
||||
{
|
||||
return authResult;
|
||||
}
|
||||
var result = await this.SubsonicService.ToggleStar(request, this.SubsonicUser, true, albumId, artistId);
|
||||
return this.BuildResponse(request, result);
|
||||
}
|
||||
|
||||
[HttpGet("unstar.view")]
|
||||
[HttpPost("unstar.view")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> UnStar(SubsonicRequest request, string[] albumId, string[] artistId)
|
||||
{
|
||||
var authResult = await this.AuthenticateUser(request);
|
||||
if (authResult != null)
|
||||
{
|
||||
return authResult;
|
||||
}
|
||||
var result = await this.SubsonicService.ToggleStar(request, this.SubsonicUser, false, albumId, artistId);
|
||||
return this.BuildResponse(request, result);
|
||||
}
|
||||
|
||||
[HttpGet("setRating.view")]
|
||||
[HttpPost("setRating.view")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> SetRating(SubsonicRequest request, short rating)
|
||||
{
|
||||
var authResult = await this.AuthenticateUser(request);
|
||||
if (authResult != null)
|
||||
{
|
||||
return authResult;
|
||||
}
|
||||
var result = await this.SubsonicService.SetRating(request, this.SubsonicUser, rating);
|
||||
return this.BuildResponse(request, result);
|
||||
var result = await this.SubsonicService.GetAlbum(request, this.SubsonicUser);
|
||||
return this.BuildResponse(request, result, "album");
|
||||
}
|
||||
|
||||
[HttpGet("getAlbumInfo.view")]
|
||||
|
@ -293,6 +262,20 @@ namespace Roadie.Api.Controllers
|
|||
return Redirect($"/images/user/{ user.RoadieId }/{this.RoadieSettings.ThumbnailImageSize.Width}/{this.RoadieSettings.ThumbnailImageSize.Height}");
|
||||
}
|
||||
|
||||
[HttpGet("getBookmarks.view")]
|
||||
[HttpPost("getBookmarks.view")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> GetBookmarks(SubsonicRequest request)
|
||||
{
|
||||
var authResult = await this.AuthenticateUser(request);
|
||||
if (authResult != null)
|
||||
{
|
||||
return authResult;
|
||||
}
|
||||
var result = await this.SubsonicService.GetBookmarks(request, this.SubsonicUser);
|
||||
return this.BuildResponse(request, result, "bookmarks");
|
||||
}
|
||||
|
||||
[HttpGet("getCoverArt.view")]
|
||||
[HttpPost("getCoverArt.view")]
|
||||
[ProducesResponseType(200)]
|
||||
|
@ -379,6 +362,20 @@ namespace Roadie.Api.Controllers
|
|||
return this.BuildResponse(request, result, "musicFolders");
|
||||
}
|
||||
|
||||
[HttpGet("getNowPlaying.view")]
|
||||
[HttpPost("getNowPlaying.view")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> GetNowPlaying(SubsonicRequest request)
|
||||
{
|
||||
var authResult = await this.AuthenticateUser(request);
|
||||
if (authResult != null)
|
||||
{
|
||||
return authResult;
|
||||
}
|
||||
var result = await this.SubsonicService.GetNowPlaying(request, this.SubsonicUser);
|
||||
return this.BuildResponse(request, result, "nowPlaying");
|
||||
}
|
||||
|
||||
[HttpGet("getPlaylist.view")]
|
||||
[HttpPost("getPlaylist.view")]
|
||||
[ProducesResponseType(200)]
|
||||
|
@ -393,21 +390,6 @@ namespace Roadie.Api.Controllers
|
|||
return this.BuildResponse(request, result, "playlist");
|
||||
}
|
||||
|
||||
[HttpGet("createPlaylist.view")]
|
||||
[HttpPost("createPlaylist.view")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> CreatePlaylist(SubsonicRequest request, string playlistId, string name, string[] songId)
|
||||
{
|
||||
var authResult = await this.AuthenticateUser(request);
|
||||
if (authResult != null)
|
||||
{
|
||||
return authResult;
|
||||
}
|
||||
var result = await this.SubsonicService.CreatePlaylist(request, this.SubsonicUser, name, songId, playlistId);
|
||||
return this.BuildResponse(request, result, "playlist");
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("getPlaylists.view")]
|
||||
[HttpPost("getPlaylists.view")]
|
||||
[ProducesResponseType(200)]
|
||||
|
@ -634,6 +616,34 @@ namespace Roadie.Api.Controllers
|
|||
return this.BuildResponse(request, result, "searchResult3");
|
||||
}
|
||||
|
||||
[HttpGet("setRating.view")]
|
||||
[HttpPost("setRating.view")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> SetRating(SubsonicRequest request, short rating)
|
||||
{
|
||||
var authResult = await this.AuthenticateUser(request);
|
||||
if (authResult != null)
|
||||
{
|
||||
return authResult;
|
||||
}
|
||||
var result = await this.SubsonicService.SetRating(request, this.SubsonicUser, rating);
|
||||
return this.BuildResponse(request, result);
|
||||
}
|
||||
|
||||
[HttpGet("star.view")]
|
||||
[HttpPost("star.view")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> Star(SubsonicRequest request, string[] albumId, string[] artistId)
|
||||
{
|
||||
var authResult = await this.AuthenticateUser(request);
|
||||
if (authResult != null)
|
||||
{
|
||||
return authResult;
|
||||
}
|
||||
var result = await this.SubsonicService.ToggleStar(request, this.SubsonicUser, true, albumId, artistId);
|
||||
return this.BuildResponse(request, result);
|
||||
}
|
||||
|
||||
[HttpGet("stream.view")]
|
||||
[HttpPost("stream.view")]
|
||||
[ProducesResponseType(200)]
|
||||
|
@ -648,41 +658,37 @@ namespace Roadie.Api.Controllers
|
|||
if (trackId == null)
|
||||
{
|
||||
return NotFound("Invalid TrackId");
|
||||
|
||||
}
|
||||
return await base.StreamTrack(trackId.Value, this.TrackService, this.PlayActivityService, this.SubsonicUser);
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("download.view")]
|
||||
[HttpPost("download.view")]
|
||||
[HttpGet("unstar.view")]
|
||||
[HttpPost("unstar.view")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> Download(SubsonicRequest request)
|
||||
public async Task<IActionResult> UnStar(SubsonicRequest request, string[] albumId, string[] artistId)
|
||||
{
|
||||
var authResult = await this.AuthenticateUser(request);
|
||||
if (authResult != null)
|
||||
{
|
||||
return Unauthorized();
|
||||
return authResult;
|
||||
}
|
||||
var trackId = request.TrackId;
|
||||
if (trackId != null)
|
||||
{
|
||||
return await base.StreamTrack(trackId.Value, this.TrackService, this.PlayActivityService, this.SubsonicUser);
|
||||
}
|
||||
var releaseId = request.ReleaseId;
|
||||
if(releaseId != null)
|
||||
{
|
||||
var releaseZip = await this.ReleaseService.ReleaseZipped(this.SubsonicUser, releaseId.Value);
|
||||
if(!releaseZip.IsSuccess)
|
||||
{
|
||||
return NotFound("Unknown Release id");
|
||||
}
|
||||
return File(releaseZip.Data, "application/zip",(string)releaseZip.AdditionalData["ZipFileName"]);
|
||||
|
||||
}
|
||||
return NotFound($"Unknown download id `{ request.id }`");
|
||||
var result = await this.SubsonicService.ToggleStar(request, this.SubsonicUser, false, albumId, artistId);
|
||||
return this.BuildResponse(request, result);
|
||||
}
|
||||
|
||||
[HttpGet("updatePlaylist.view")]
|
||||
[HttpPost("updatePlaylist.view")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> UpdatePlaylist(SubsonicRequest request, string playlistId, string name, string comment, bool? @public, string[] songIdToAdd, int[] songIndexToRemove)
|
||||
{
|
||||
var authResult = await this.AuthenticateUser(request);
|
||||
if (authResult != null)
|
||||
{
|
||||
return authResult;
|
||||
}
|
||||
var result = await this.SubsonicService.UpdatePlaylist(request, this.SubsonicUser, playlistId, name, comment, @public, songIdToAdd, songIndexToRemove);
|
||||
return this.BuildResponse(request, result);
|
||||
}
|
||||
|
||||
private async Task<IActionResult> AuthenticateUser(SubsonicRequest request)
|
||||
{
|
||||
|
|
|
@ -57,8 +57,8 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> List([FromQuery]PagedRequest request, string inc)
|
||||
{
|
||||
var result = await this.TrackService.List(roadieUser: await this.CurrentUserModel(),
|
||||
request: request);
|
||||
var result = await this.TrackService.List(request: request,
|
||||
roadieUser: await this.CurrentUserModel());
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
|
|
|
@ -370,23 +370,23 @@ namespace Roadie.Api.Services
|
|||
}
|
||||
if(rows.Any() && (doArtistCounts ?? true))
|
||||
{
|
||||
var rowArtistIds = rows.Select(x => x.DatabaseId);
|
||||
var rowArtistIds = rows.Select(x => x.DatabaseId).ToArray();
|
||||
var artistReleases = (from a in this.DbContext.Artists
|
||||
join r in this.DbContext.Releases on a.Id equals r.ArtistId
|
||||
where a.ReleaseCount > 0
|
||||
where r.TrackCount > 0
|
||||
where rowArtistIds.Contains(a.Id)
|
||||
select new
|
||||
{
|
||||
r.Id,
|
||||
artistId = a.Id,
|
||||
releaseId = r.Id,
|
||||
r.TrackCount,
|
||||
r.PlayedCount
|
||||
}).ToList();
|
||||
}).ToArray();
|
||||
foreach(var row in rows)
|
||||
{
|
||||
row.ArtistReleaseCount = artistReleases.Where(r => r.Id == row.DatabaseId).Select(r => r.Id).Count();
|
||||
row.ArtistTrackCount = artistReleases.Where(r => r.Id == row.DatabaseId).Sum(r => r.TrackCount);
|
||||
row.ArtistPlayedCount = artistReleases.Where(r => r.Id == row.DatabaseId).Sum(r => r.PlayedCount);
|
||||
var rowArtistReleases = artistReleases.Where(r => r.artistId == row.DatabaseId);
|
||||
row.ArtistReleaseCount = rowArtistReleases.Select(r => r.releaseId).Count();
|
||||
row.ArtistTrackCount = rowArtistReleases.Sum(r => r.TrackCount);
|
||||
row.ArtistPlayedCount = rowArtistReleases.Sum(r => r.PlayedCount);
|
||||
}
|
||||
}
|
||||
if (rows.Any() && roadieUser != null)
|
||||
|
@ -400,7 +400,8 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
IsDisliked = userArtistRating.IsDisliked ?? false,
|
||||
IsFavorite = userArtistRating.IsFavorite ?? false,
|
||||
Rating = userArtistRating.Rating
|
||||
Rating = userArtistRating.Rating,
|
||||
RatedDate = userArtistRating.LastUpdated ?? userArtistRating.CreatedDate
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,13 +2,14 @@
|
|||
using Roadie.Library.Models;
|
||||
using Roadie.Library.Models.Pagination;
|
||||
using Roadie.Library.Models.Users;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Roadie.Api.Services
|
||||
{
|
||||
public interface IPlayActivityService
|
||||
{
|
||||
Task<PagedResult<PlayActivityList>> List(PagedRequest request, User roadieUser = null);
|
||||
Task<PagedResult<PlayActivityList>> List(PagedRequest request, User roadieUser = null, DateTime? newerThan = null);
|
||||
|
||||
Task<OperationResult<PlayActivityList>> CreatePlayActivity(User roadieUser, TrackStreamInfo streamInfo);
|
||||
}
|
||||
|
|
|
@ -66,6 +66,8 @@ namespace Roadie.Api.Services
|
|||
|
||||
SubsonicOperationResult<Response> Ping(Request request);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> GetNowPlaying(Request request, Roadie.Library.Models.Users.User roadieUser);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> Search(Request request, Roadie.Library.Models.Users.User roadieUser, SearchVersion version);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> ToggleStar(Request request, Roadie.Library.Models.Users.User roadieUser, bool star, string[] albumIds = null, string[] artistIds = null);
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
Task<OperationResult<Track>> ById(User roadieUser, Guid id, IEnumerable<string> includes);
|
||||
|
||||
Task<Library.Models.Pagination.PagedResult<TrackList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false, Guid? releaseId = null);
|
||||
Task<Library.Models.Pagination.PagedResult<TrackList>> List(PagedRequest request, User roadieUser, bool? doRandomize = false, Guid? releaseId = null);
|
||||
|
||||
Task<OperationResult<TrackStreamInfo>> TrackStreamInfo(Guid trackId, long beginBytes, long endBytes);
|
||||
}
|
||||
|
|
|
@ -328,7 +328,7 @@ namespace Roadie.Api.Services
|
|||
result.LastModified = DateTime.UtcNow;
|
||||
if (width.Value != this.Configuration.ThumbnailImageSize.Width || height.Value != this.Configuration.ThumbnailImageSize.Height)
|
||||
{
|
||||
this.Logger.LogInformation($"{ type }: Resized [{ id }], Width [{ width.Value }], Height [{ height.Value }]");
|
||||
this.Logger.LogTrace($"{ type }: Resized [{ id }], Width [{ width.Value }], Height [{ height.Value }]");
|
||||
}
|
||||
}
|
||||
sw.Stop();
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace Roadie.Api.Services
|
|||
this.PlayActivityHub = playHubContext;
|
||||
}
|
||||
|
||||
public async Task<Library.Models.Pagination.PagedResult<PlayActivityList>> List(PagedRequest request, User roadieUser = null)
|
||||
public async Task<Library.Models.Pagination.PagedResult<PlayActivityList>> List(PagedRequest request, User roadieUser = null, DateTime? newerThan = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -52,6 +52,7 @@ namespace Roadie.Api.Services
|
|||
join usertrack in this.DbContext.UserTracks on t.Id equals usertrack.TrackId
|
||||
join u in this.DbContext.Users on usertrack.UserId equals u.Id
|
||||
join releaseArtist in this.DbContext.Artists on r.ArtistId equals releaseArtist.Id
|
||||
where(newerThan == null || usertrack.LastPlayed >= newerThan)
|
||||
where ((roadieUser == null && !(u.IsPrivate ?? false)) || (roadieUser != null && (usertrack != null && usertrack.User.Id == roadieUser.Id)))
|
||||
where (request.FilterValue.Length == 0 || (request.FilterValue.Length > 0 && (
|
||||
t.Title != null && t.Title.ToLower().Contains(request.Filter.ToLower()) ||
|
||||
|
|
|
@ -39,6 +39,7 @@ namespace Roadie.Api.Services
|
|||
private ICollectionService CollectionService { get; }
|
||||
private IImageService ImageService { get; }
|
||||
private IPlaylistService PlaylistService { get; }
|
||||
private IPlayActivityService PlayActivityService { get; }
|
||||
private IReleaseService ReleaseService { get; }
|
||||
private ITrackService TrackService { get; }
|
||||
private UserManager<ApplicationUser> UserManger { get; }
|
||||
|
@ -56,6 +57,7 @@ namespace Roadie.Api.Services
|
|||
IReleaseService releaseService,
|
||||
IImageService imageService,
|
||||
IBookmarkService bookmarkService,
|
||||
IPlayActivityService playActivityService,
|
||||
UserManager<ApplicationUser> userManager
|
||||
)
|
||||
: base(configuration, httpEncoder, context, cacheManager, logger, httpContext)
|
||||
|
@ -65,6 +67,7 @@ namespace Roadie.Api.Services
|
|||
this.CollectionService = collectionService;
|
||||
this.ImageService = imageService;
|
||||
this.PlaylistService = playlistService;
|
||||
this.PlayActivityService = playActivityService;
|
||||
this.ReleaseService = releaseService;
|
||||
this.TrackService = trackService;
|
||||
this.UserManger = userManager;
|
||||
|
@ -199,6 +202,92 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates (or updates) a playlist.
|
||||
/// </summary>
|
||||
/// <param name="request">Populated Subsonic Request</param>
|
||||
/// <param name="roadieUser">Populated Roadie User</param>
|
||||
/// <param name="name">The human-readable name of the playlist.</param>
|
||||
/// <param name="songIds">ID of a song in the playlist. Use one songId parameter for each song in the playlist.</param>
|
||||
/// <param name="playlistId">The playlist ID. (if updating else blank is adding)</param>
|
||||
/// <returns></returns>
|
||||
public async Task<subsonic.SubsonicOperationResult<subsonic.Response>> CreatePlaylist(subsonic.Request request, User roadieUser, string name, string[] songIds, string playlistId = null)
|
||||
{
|
||||
data.Playlist playlist = null;
|
||||
|
||||
Guid?[] songRoadieIds = new Guid?[0];
|
||||
IQueryable<data.Track> submittedTracks = new data.Track[0].AsQueryable();
|
||||
|
||||
if (songIds != null && songIds.Any())
|
||||
{
|
||||
songRoadieIds = songIds.Select(x => SafeParser.ToGuid(x)).ToArray();
|
||||
// Add (if not already) given tracks to Playlist
|
||||
submittedTracks = (from t in this.DbContext.Tracks
|
||||
where songRoadieIds.Contains(t.RoadieId)
|
||||
select t);
|
||||
}
|
||||
var didCreate = false;
|
||||
if (!string.IsNullOrEmpty(playlistId))
|
||||
{
|
||||
request.id = playlistId;
|
||||
playlist = this.DbContext.Playlists.Include(x => x.Tracks).FirstOrDefault(x => x.RoadieId == request.PlaylistId);
|
||||
if (playlist == null)
|
||||
{
|
||||
return new subsonic.SubsonicOperationResult<subsonic.Response>(subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid PlaylistId [{ playlistId }]");
|
||||
}
|
||||
// When Create is called again on an existing delete all existing tracks and add given
|
||||
if (playlist.Tracks != null && playlist.Tracks.Any())
|
||||
{
|
||||
this.DbContext.PlaylistTracks.RemoveRange(playlist.Tracks);
|
||||
}
|
||||
var listNumber = playlist.Tracks != null && playlist.Tracks.Any() ? playlist.Tracks?.Max(x => x.ListNumber) ?? 0 : 0;
|
||||
foreach (var submittedTrack in submittedTracks)
|
||||
{
|
||||
if (playlist.Tracks == null || !playlist.Tracks.Any(x => x.TrackId == submittedTrack.Id))
|
||||
{
|
||||
listNumber++;
|
||||
this.DbContext.PlaylistTracks.Add(new data.PlaylistTrack
|
||||
{
|
||||
PlayListId = playlist.Id,
|
||||
ListNumber = listNumber,
|
||||
TrackId = submittedTrack.Id
|
||||
});
|
||||
}
|
||||
}
|
||||
playlist.Name = name ?? playlist.Name;
|
||||
playlist.LastUpdated = DateTime.UtcNow;
|
||||
}
|
||||
else
|
||||
{
|
||||
var tracks = new List<data.PlaylistTrack>();
|
||||
var listNumber = 0;
|
||||
foreach (var submittedTrack in submittedTracks)
|
||||
{
|
||||
listNumber++;
|
||||
tracks.Add(new data.PlaylistTrack
|
||||
{
|
||||
PlayListId = playlist.Id,
|
||||
ListNumber = listNumber,
|
||||
TrackId = submittedTrack.Id
|
||||
});
|
||||
}
|
||||
|
||||
playlist = new data.Playlist
|
||||
{
|
||||
IsPublic = false,
|
||||
Name = name,
|
||||
UserId = roadieUser.Id,
|
||||
Tracks = tracks
|
||||
};
|
||||
didCreate = true;
|
||||
this.DbContext.Playlists.Add(playlist);
|
||||
}
|
||||
await this.DbContext.SaveChangesAsync();
|
||||
this.Logger.LogInformation($"Subsonic: User `{ roadieUser }` { (didCreate ? "created" : "modified") } Playlist `{ playlist }` added [{ songRoadieIds.Count() }] Tracks.");
|
||||
request.id = subsonic.Request.PlaylistdIdentifier + playlist.RoadieId.ToString();
|
||||
return await this.GetPlaylist(request, roadieUser);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the bookmark for a given file.
|
||||
/// </summary>
|
||||
|
@ -235,6 +324,43 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a saved playlist.
|
||||
/// </summary>
|
||||
public async Task<subsonic.SubsonicOperationResult<subsonic.Response>> DeletePlaylist(subsonic.Request request, User roadieUser)
|
||||
{
|
||||
if (!request.PlaylistId.HasValue)
|
||||
{
|
||||
return new subsonic.SubsonicOperationResult<subsonic.Response>(subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid Playlist Id [{ request.id }]");
|
||||
}
|
||||
var playlist = this.GetPlaylist(request.PlaylistId.Value);
|
||||
if (playlist == null)
|
||||
{
|
||||
return new subsonic.SubsonicOperationResult<subsonic.Response>(subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid Playlist Id [{ request.TrackId.Value }]");
|
||||
}
|
||||
if (playlist.UserId != roadieUser.Id && !roadieUser.IsAdmin)
|
||||
{
|
||||
return new subsonic.SubsonicOperationResult<subsonic.Response>(subsonic.ErrorCodes.UserIsNotAuthorizedForGivenOperation, "User is not allowed to delete playlist.");
|
||||
}
|
||||
this.DbContext.Playlists.Remove(playlist);
|
||||
await this.DbContext.SaveChangesAsync();
|
||||
|
||||
var user = this.GetUser(roadieUser.UserId);
|
||||
this.CacheManager.ClearRegion(user.CacheRegion);
|
||||
|
||||
this.Logger.LogInformation($"Subsonic: Deleted Playlist `{ playlist}` for User `{ roadieUser }`");
|
||||
|
||||
return new subsonic.SubsonicOperationResult<subsonic.Response>
|
||||
{
|
||||
IsSuccess = true,
|
||||
Data = new subsonic.Response
|
||||
{
|
||||
version = SubsonicService.SubsonicVersion,
|
||||
status = subsonic.ResponseStatus.ok
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns details for an album, including a list of songs. This method organizes music according to ID3 tags.
|
||||
/// </summary>
|
||||
|
@ -251,7 +377,7 @@ namespace Roadie.Api.Services
|
|||
return new subsonic.SubsonicOperationResult<subsonic.Response>(subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid Release [{ request.ReleaseId}]");
|
||||
}
|
||||
var pagedRequest = request.PagedRequest;
|
||||
var releaseTracks = await this.TrackService.List(roadieUser, pagedRequest, false, releaseId);
|
||||
var releaseTracks = await this.TrackService.List(pagedRequest, roadieUser, false, releaseId);
|
||||
var userRelease = roadieUser == null ? null : this.DbContext.UserReleases.FirstOrDefault(x => x.ReleaseId == release.Id && x.UserId == roadieUser.Id);
|
||||
var genre = release.Genres.FirstOrDefault();
|
||||
return new subsonic.SubsonicOperationResult<subsonic.Response>
|
||||
|
@ -489,48 +615,11 @@ namespace Roadie.Api.Services
|
|||
/// </summary>
|
||||
public async Task<subsonic.SubsonicOperationResult<subsonic.Response>> GetArtists(subsonic.Request request, User roadieUser)
|
||||
{
|
||||
var indexes = new List<subsonic.IndexID3>();
|
||||
var musicFolder = this.MusicFolders().FirstOrDefault(x => x.id == (request.MusicFolderId ?? 2));
|
||||
var pagedRequest = request.PagedRequest;
|
||||
if (musicFolder == this.CollectionMusicFolder())
|
||||
var cacheKey = $"urn:subsonic_artists:{ roadieUser.UserName }";
|
||||
return await this.CacheManager.GetAsync<subsonic.SubsonicOperationResult<subsonic.Response>>(cacheKey, async () =>
|
||||
{
|
||||
// Indexes for "Collection" Artists alphabetically
|
||||
// not sure what to do here since this is albums not artists in a "Collection".
|
||||
}
|
||||
else
|
||||
{
|
||||
// Indexes for "Music" Artists alphabetically
|
||||
pagedRequest.SkipValue = 0;
|
||||
pagedRequest.Limit = int.MaxValue;
|
||||
pagedRequest.Sort = "Artist.Text";
|
||||
var artistList = await this.ArtistService.List(roadieUser: roadieUser,
|
||||
request:pagedRequest,
|
||||
doRandomize: false,
|
||||
onlyIncludeWithReleases: true,
|
||||
doArtistCounts: false);
|
||||
foreach (var artistGroup in artistList.Rows.GroupBy(x => x.Artist.Text.Substring(0, 1)))
|
||||
{
|
||||
indexes.Add(new subsonic.IndexID3
|
||||
{
|
||||
name = artistGroup.Key,
|
||||
artist = this.SubsonicArtistID3sForArtists(artistGroup)
|
||||
});
|
||||
};
|
||||
}
|
||||
return new subsonic.SubsonicOperationResult<subsonic.Response>
|
||||
{
|
||||
IsSuccess = true,
|
||||
Data = new subsonic.Response
|
||||
{
|
||||
version = SubsonicService.SubsonicVersion,
|
||||
status = subsonic.ResponseStatus.ok,
|
||||
ItemElementName = subsonic.ItemChoiceType.artists,
|
||||
Item = new subsonic.ArtistsID3
|
||||
{
|
||||
index = indexes.ToArray()
|
||||
}
|
||||
}
|
||||
};
|
||||
return await this.GetArtistsAction(request, roadieUser);
|
||||
}, CacheManagerBase.SystemCacheRegionUrn);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -543,7 +632,7 @@ namespace Roadie.Api.Services
|
|||
pagedRequest.Order = "DESC";
|
||||
var userBookmarkResult = await this.BookmarkService.List(roadieUser, pagedRequest, false, Library.Enums.BookmarkType.Track);
|
||||
pagedRequest.FilterToTrackIds = userBookmarkResult.Rows.Select(x => SafeParser.ToGuid(x.Bookmark.Value)).ToArray();
|
||||
var trackListResult = await this.TrackService.List(roadieUser, pagedRequest);
|
||||
var trackListResult = await this.TrackService.List(pagedRequest, roadieUser);
|
||||
return new subsonic.SubsonicOperationResult<subsonic.Response>
|
||||
{
|
||||
IsSuccess = true,
|
||||
|
@ -814,7 +903,7 @@ namespace Roadie.Api.Services
|
|||
directory.starredSpecified = true;
|
||||
}
|
||||
var pagedRequest = request.PagedRequest;
|
||||
var songTracks = await this.TrackService.List(roadieUser, pagedRequest, false, release.RoadieId);
|
||||
var songTracks = await this.TrackService.List(pagedRequest, roadieUser, false, release.RoadieId);
|
||||
directory.child = this.SubsonicChildrenForTracks(songTracks.Rows);
|
||||
directory.playCount = directory.child.Select(x => x.playCount).Sum();
|
||||
}
|
||||
|
@ -877,7 +966,7 @@ namespace Roadie.Api.Services
|
|||
}
|
||||
// For a playlist to show all the tracks in the playlist set the limit to the playlist size
|
||||
pagedRequest.Limit = playlist.PlaylistCount ?? pagedRequest.Limit;
|
||||
var tracksForPlaylist = await this.TrackService.List(roadieUser, pagedRequest);
|
||||
var tracksForPlaylist = await this.TrackService.List(pagedRequest, roadieUser);
|
||||
return new subsonic.SubsonicOperationResult<subsonic.Response>
|
||||
{
|
||||
IsSuccess = true,
|
||||
|
@ -945,7 +1034,7 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
var songs = new List<subsonic.Child>();
|
||||
|
||||
var randomSongs = await this.TrackService.List(roadieUser, request.PagedRequest, true);
|
||||
var randomSongs = await this.TrackService.List(request.PagedRequest, roadieUser, true);
|
||||
|
||||
return new subsonic.SubsonicOperationResult<subsonic.Response>
|
||||
{
|
||||
|
@ -1021,7 +1110,7 @@ namespace Roadie.Api.Services
|
|||
var pagedRequest = request.PagedRequest;
|
||||
pagedRequest.FilterToTrackId = request.TrackId.Value;
|
||||
pagedRequest.Sort = "Id";
|
||||
var trackResult = await this.TrackService.List(roadieUser, pagedRequest);
|
||||
var trackResult = await this.TrackService.List(pagedRequest, roadieUser);
|
||||
var track = trackResult.Rows.Any() ? trackResult.Rows.First() : null;
|
||||
if (track == null)
|
||||
{
|
||||
|
@ -1048,7 +1137,7 @@ namespace Roadie.Api.Services
|
|||
var pagedRequest = request.PagedRequest;
|
||||
pagedRequest.FilterByGenre = request.Genre;
|
||||
pagedRequest.Sort = "Id";
|
||||
var trackResult = await this.TrackService.List(roadieUser, pagedRequest);
|
||||
var trackResult = await this.TrackService.List(pagedRequest, roadieUser);
|
||||
|
||||
return new subsonic.SubsonicOperationResult<subsonic.Response>
|
||||
{
|
||||
|
@ -1077,7 +1166,7 @@ namespace Roadie.Api.Services
|
|||
|
||||
var artistList = await this.ArtistService.List(roadieUser, pagedRequest);
|
||||
var releaseList = await this.ReleaseService.List(roadieUser, pagedRequest);
|
||||
var songList = await this.TrackService.List(roadieUser, pagedRequest);
|
||||
var songList = await this.TrackService.List(pagedRequest, roadieUser);
|
||||
|
||||
switch (version)
|
||||
{
|
||||
|
@ -1132,7 +1221,7 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
artist = base.GetArtist(request.ArtistName);
|
||||
}
|
||||
else if(request.ArtistId.HasValue)
|
||||
else if (request.ArtistId.HasValue)
|
||||
{
|
||||
artist = this.GetArtist(request.ArtistId.Value);
|
||||
}
|
||||
|
@ -1145,7 +1234,7 @@ namespace Roadie.Api.Services
|
|||
pagedRequest.FilterTopPlayedOnly = true;
|
||||
pagedRequest.Sort = "PlayedCount";
|
||||
pagedRequest.Order = "DESC";
|
||||
var trackResult = await this.TrackService.List(roadieUser, pagedRequest);
|
||||
var trackResult = await this.TrackService.List(pagedRequest, roadieUser);
|
||||
return new subsonic.SubsonicOperationResult<subsonic.Response>
|
||||
{
|
||||
IsSuccess = true,
|
||||
|
@ -1251,7 +1340,7 @@ namespace Roadie.Api.Services
|
|||
trackPagedRequest.Limit = request.SongCount ?? trackPagedRequest.Limit;
|
||||
trackPagedRequest.SkipValue = request.SongOffset ?? trackPagedRequest.SkipValue;
|
||||
trackPagedRequest.Filter = query;
|
||||
var songResult = await this.TrackService.List(roadieUser, trackPagedRequest);
|
||||
var songResult = await this.TrackService.List(trackPagedRequest, roadieUser);
|
||||
var songs = this.SubsonicChildrenForTracks(songResult.Rows);
|
||||
|
||||
switch (version)
|
||||
|
@ -1432,129 +1521,6 @@ namespace Roadie.Api.Services
|
|||
return new subsonic.SubsonicOperationResult<subsonic.Response>(subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Unknown Star Id [{ JsonConvert.SerializeObject(request) }]");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates (or updates) a playlist.
|
||||
/// </summary>
|
||||
/// <param name="request">Populated Subsonic Request</param>
|
||||
/// <param name="roadieUser">Populated Roadie User</param>
|
||||
/// <param name="name">The human-readable name of the playlist.</param>
|
||||
/// <param name="songIds">ID of a song in the playlist. Use one songId parameter for each song in the playlist.</param>
|
||||
/// <param name="playlistId">The playlist ID. (if updating else blank is adding)</param>
|
||||
/// <returns></returns>
|
||||
public async Task<subsonic.SubsonicOperationResult<subsonic.Response>> CreatePlaylist(subsonic.Request request, User roadieUser, string name, string[] songIds, string playlistId = null)
|
||||
{
|
||||
data.Playlist playlist = null;
|
||||
|
||||
Guid?[] songRoadieIds = new Guid?[0];
|
||||
IQueryable<data.Track> submittedTracks = new data.Track[0].AsQueryable();
|
||||
|
||||
if (songIds != null && songIds.Any())
|
||||
{
|
||||
songRoadieIds = songIds.Select(x => SafeParser.ToGuid(x)).ToArray();
|
||||
// Add (if not already) given tracks to Playlist
|
||||
submittedTracks = (from t in this.DbContext.Tracks
|
||||
where songRoadieIds.Contains(t.RoadieId)
|
||||
select t);
|
||||
}
|
||||
var didCreate = false;
|
||||
if (!string.IsNullOrEmpty(playlistId))
|
||||
{
|
||||
request.id = playlistId;
|
||||
playlist = this.DbContext.Playlists.Include(x => x.Tracks).FirstOrDefault(x => x.RoadieId == request.PlaylistId);
|
||||
if(playlist == null)
|
||||
{
|
||||
return new subsonic.SubsonicOperationResult<subsonic.Response>(subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid PlaylistId [{ playlistId }]");
|
||||
}
|
||||
// When Create is called again on an existing delete all existing tracks and add given
|
||||
if (playlist.Tracks != null && playlist.Tracks.Any())
|
||||
{
|
||||
this.DbContext.PlaylistTracks.RemoveRange(playlist.Tracks);
|
||||
}
|
||||
var listNumber = playlist.Tracks != null && playlist.Tracks.Any() ? playlist.Tracks?.Max(x => x.ListNumber) ?? 0 : 0;
|
||||
foreach (var submittedTrack in submittedTracks)
|
||||
{
|
||||
if (playlist.Tracks == null || !playlist.Tracks.Any(x => x.TrackId == submittedTrack.Id))
|
||||
{
|
||||
listNumber++;
|
||||
this.DbContext.PlaylistTracks.Add(new data.PlaylistTrack
|
||||
{
|
||||
PlayListId = playlist.Id,
|
||||
ListNumber = listNumber,
|
||||
TrackId = submittedTrack.Id
|
||||
});
|
||||
}
|
||||
}
|
||||
playlist.Name = name ?? playlist.Name;
|
||||
playlist.LastUpdated = DateTime.UtcNow;
|
||||
}
|
||||
else
|
||||
{
|
||||
var tracks = new List<data.PlaylistTrack>();
|
||||
var listNumber = 0;
|
||||
foreach (var submittedTrack in submittedTracks)
|
||||
{
|
||||
listNumber++;
|
||||
tracks.Add(new data.PlaylistTrack
|
||||
{
|
||||
PlayListId = playlist.Id,
|
||||
ListNumber = listNumber,
|
||||
TrackId = submittedTrack.Id
|
||||
});
|
||||
}
|
||||
|
||||
playlist = new data.Playlist
|
||||
{
|
||||
IsPublic = false,
|
||||
Name = name,
|
||||
UserId = roadieUser.Id,
|
||||
Tracks = tracks
|
||||
};
|
||||
didCreate = true;
|
||||
this.DbContext.Playlists.Add(playlist);
|
||||
}
|
||||
await this.DbContext.SaveChangesAsync();
|
||||
this.Logger.LogInformation($"Subsonic: User `{ roadieUser }` { (didCreate ? "created": "modified") } Playlist `{ playlist }` added [{ songRoadieIds.Count() }] Tracks.");
|
||||
request.id = subsonic.Request.PlaylistdIdentifier + playlist.RoadieId.ToString();
|
||||
return await this.GetPlaylist(request, roadieUser);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a saved playlist.
|
||||
/// </summary>
|
||||
public async Task<subsonic.SubsonicOperationResult<subsonic.Response>> DeletePlaylist(subsonic.Request request, User roadieUser)
|
||||
{
|
||||
if (!request.PlaylistId.HasValue)
|
||||
{
|
||||
return new subsonic.SubsonicOperationResult<subsonic.Response>(subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid Playlist Id [{ request.id }]");
|
||||
}
|
||||
var playlist = this.GetPlaylist(request.PlaylistId.Value);
|
||||
if (playlist == null)
|
||||
{
|
||||
return new subsonic.SubsonicOperationResult<subsonic.Response>(subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid Playlist Id [{ request.TrackId.Value }]");
|
||||
}
|
||||
if(playlist.UserId != roadieUser.Id && !roadieUser.IsAdmin)
|
||||
{
|
||||
return new subsonic.SubsonicOperationResult<subsonic.Response>(subsonic.ErrorCodes.UserIsNotAuthorizedForGivenOperation, "User is not allowed to delete playlist.");
|
||||
}
|
||||
this.DbContext.Playlists.Remove(playlist);
|
||||
await this.DbContext.SaveChangesAsync();
|
||||
|
||||
var user = this.GetUser(roadieUser.UserId);
|
||||
this.CacheManager.ClearRegion(user.CacheRegion);
|
||||
|
||||
this.Logger.LogInformation($"Subsonic: Deleted Playlist `{ playlist}` for User `{ roadieUser }`");
|
||||
|
||||
return new subsonic.SubsonicOperationResult<subsonic.Response>
|
||||
{
|
||||
IsSuccess = true,
|
||||
Data = new subsonic.Response
|
||||
{
|
||||
version = SubsonicService.SubsonicVersion,
|
||||
status = subsonic.ResponseStatus.ok
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates a playlist. Only the owner of a playlist is allowed to update it.
|
||||
/// </summary>
|
||||
|
@ -1565,7 +1531,7 @@ namespace Roadie.Api.Services
|
|||
/// <param name="isPublic">true if the playlist should be visible to all users, false otherwise.</param>
|
||||
/// <param name="songIdsToAdd">Add this song with this ID to the playlist. Multiple parameters allowed</param>
|
||||
/// <param name="songIndexesToRemove">Remove the song at this position in the playlist. Multiple parameters allowed.</param>
|
||||
public async Task<subsonic.SubsonicOperationResult<subsonic.Response>> UpdatePlaylist(subsonic.Request request, User roadieUser, string playListId, string name = null, string comment =null, bool? isPublic = null, string[] songIdsToAdd = null, int[] songIndexesToRemove = null)
|
||||
public async Task<subsonic.SubsonicOperationResult<subsonic.Response>> UpdatePlaylist(subsonic.Request request, User roadieUser, string playListId, string name = null, string comment = null, bool? isPublic = null, string[] songIdsToAdd = null, int[] songIndexesToRemove = null)
|
||||
{
|
||||
request.id = playListId ?? request.id;
|
||||
if (!request.PlaylistId.HasValue)
|
||||
|
@ -1586,7 +1552,7 @@ namespace Roadie.Api.Services
|
|||
playlist.IsPublic = isPublic ?? playlist.IsPublic;
|
||||
playlist.LastUpdated = DateTime.UtcNow;
|
||||
|
||||
if(songIdsToAdd != null && songIdsToAdd.Any())
|
||||
if (songIdsToAdd != null && songIdsToAdd.Any())
|
||||
{
|
||||
// Add new if not already on Playlist
|
||||
var songIdsToAddRoadieIds = songIdsToAdd.Select(x => SafeParser.ToGuid(x)).ToArray();
|
||||
|
@ -1609,22 +1575,11 @@ namespace Roadie.Api.Services
|
|||
}
|
||||
}
|
||||
}
|
||||
if(songIndexesToRemove != null && songIndexesToRemove.Any())
|
||||
if (songIndexesToRemove != null && songIndexesToRemove.Any())
|
||||
{
|
||||
// Remove tracks from playlist
|
||||
//foreach (var submittedTrack in submittedTracks)
|
||||
//{
|
||||
// if (playlist.Tracks == null || !playlist.Tracks.Any(x => x.TrackId == submittedTrack.Id))
|
||||
// {
|
||||
// listNumber++;
|
||||
// this.DbContext.PlaylistTracks.Add(new data.PlaylistTrack
|
||||
// {
|
||||
// PlayListId = playlist.Id,
|
||||
// ListNumber = listNumber,
|
||||
// TrackId = submittedTrack.Id
|
||||
// });
|
||||
// }
|
||||
//}
|
||||
// Not clear from API documentation if this is zero based, wait until someone calls it to get values passed.
|
||||
throw new NotImplementedException($"Request [{ JsonConvert.SerializeObject(request) }]");
|
||||
}
|
||||
|
||||
await this.DbContext.SaveChangesAsync();
|
||||
|
@ -1643,9 +1598,98 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns what is currently being played by all users. Takes no extra parameters.
|
||||
/// </summary>
|
||||
public async Task<subsonic.SubsonicOperationResult<subsonic.Response>> GetNowPlaying(subsonic.Request request, User roadieUser)
|
||||
{
|
||||
var pagedRequest = request.PagedRequest;
|
||||
pagedRequest.Sort = "PlayedDateDateTime";
|
||||
pagedRequest.Order = "DESC";
|
||||
var playActivityResult = await this.PlayActivityService.List(pagedRequest, roadieUser, DateTime.UtcNow.AddDays(-1));
|
||||
|
||||
pagedRequest.Sort = null;
|
||||
pagedRequest.Order = null;
|
||||
pagedRequest.FilterToTrackIds = playActivityResult.Rows.Select(x => SafeParser.ToGuid(x.Track.Value)).Distinct().ToArray();
|
||||
var playActivityTracksResult = await this.TrackService.List(pagedRequest, roadieUser);
|
||||
|
||||
var playEntries = new List<subsonic.NowPlayingEntry>();
|
||||
var now = DateTime.UtcNow;
|
||||
foreach(var row in playActivityResult.Rows)
|
||||
{
|
||||
var rowTrack = playActivityTracksResult.Rows.FirstOrDefault(x => x.Track.Value == row.Track.Value);
|
||||
var playEntryTrackChild = this.SubsonicChildForTrack(rowTrack);
|
||||
var playEntry = playEntryTrackChild.Adapt<subsonic.NowPlayingEntry>();
|
||||
playEntry.username = row.User.Text;
|
||||
playEntry.minutesAgo = (int)(now - row.PlayedDateDateTime.Value).TotalMinutes;
|
||||
playEntry.playerId = 0;
|
||||
playEntry.playerName = string.Empty;
|
||||
playEntries.Add(playEntry);
|
||||
}
|
||||
|
||||
return new subsonic.SubsonicOperationResult<subsonic.Response>
|
||||
{
|
||||
IsSuccess = true,
|
||||
Data = new subsonic.Response
|
||||
{
|
||||
version = SubsonicService.SubsonicVersion,
|
||||
status = subsonic.ResponseStatus.ok,
|
||||
ItemElementName = subsonic.ItemChoiceType.nowPlaying,
|
||||
Item = new subsonic.NowPlaying
|
||||
{
|
||||
entry = playEntries.ToArray()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#region Privates
|
||||
|
||||
private async Task<subsonic.SubsonicOperationResult<subsonic.Response>> GetArtistsAction(subsonic.Request request, User roadieUser)
|
||||
{
|
||||
var indexes = new List<subsonic.IndexID3>();
|
||||
var musicFolder = this.MusicFolders().FirstOrDefault(x => x.id == (request.MusicFolderId ?? 2));
|
||||
var pagedRequest = request.PagedRequest;
|
||||
if (musicFolder == this.CollectionMusicFolder())
|
||||
{
|
||||
// Indexes for "Collection" Artists alphabetically
|
||||
}
|
||||
else
|
||||
{
|
||||
// Indexes for "Music" Artists alphabetically
|
||||
pagedRequest.SkipValue = 0;
|
||||
pagedRequest.Limit = int.MaxValue;
|
||||
pagedRequest.Sort = "Artist.Text";
|
||||
var artistList = await this.ArtistService.List(roadieUser: roadieUser,
|
||||
request: pagedRequest,
|
||||
doRandomize: false,
|
||||
onlyIncludeWithReleases: true,
|
||||
doArtistCounts: true);
|
||||
foreach (var artistGroup in artistList.Rows.GroupBy(x => x.Artist.Text.Substring(0, 1)))
|
||||
{
|
||||
indexes.Add(new subsonic.IndexID3
|
||||
{
|
||||
name = artistGroup.Key,
|
||||
artist = this.SubsonicArtistID3sForArtists(artistGroup)
|
||||
});
|
||||
};
|
||||
}
|
||||
return new subsonic.SubsonicOperationResult<subsonic.Response>
|
||||
{
|
||||
IsSuccess = true,
|
||||
Data = new subsonic.Response
|
||||
{
|
||||
version = SubsonicService.SubsonicVersion,
|
||||
status = subsonic.ResponseStatus.ok,
|
||||
ItemElementName = subsonic.ItemChoiceType.artists,
|
||||
Item = new subsonic.ArtistsID3
|
||||
{
|
||||
index = indexes.ToArray()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private string[] AllowedUsers()
|
||||
{
|
||||
return this.CacheManager.Get<string[]>(CacheManagerBase.SystemCacheRegionUrn + ":active_usernames", () =>
|
||||
|
@ -1698,7 +1742,7 @@ namespace Roadie.Api.Services
|
|||
pagedRequest.SkipValue = 0;
|
||||
pagedRequest.Limit = int.MaxValue;
|
||||
pagedRequest.Sort = "Artist.Text";
|
||||
var artistList = await this.ArtistService.List(roadieUser:roadieUser,
|
||||
var artistList = await this.ArtistService.List(roadieUser: roadieUser,
|
||||
request: pagedRequest,
|
||||
doRandomize: false,
|
||||
onlyIncludeWithReleases: true,
|
||||
|
|
|
@ -217,7 +217,7 @@ namespace Roadie.Api.Services
|
|||
return result;
|
||||
}
|
||||
|
||||
public async Task<Library.Models.Pagination.PagedResult<TrackList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false, Guid? releaseId = null)
|
||||
public async Task<Library.Models.Pagination.PagedResult<TrackList>> List(PagedRequest request, User roadieUser, bool? doRandomize = false, Guid? releaseId = null)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
@ -268,7 +268,6 @@ namespace Roadie.Api.Services
|
|||
randomLimit = request.LimitValue > randomLimit ? randomLimit : request.LimitValue;
|
||||
var sql = $"SELECT t.* FROM `track` t WHERE t.Hash IS NOT NULL ORDER BY RAND() LIMIT {randomLimit}";
|
||||
randomTrackIds = this.DbContext.Tracks.FromSql(sql).Select(x => x.Id).ToArray();
|
||||
|
||||
}
|
||||
Guid?[] filterToTrackIds = null;
|
||||
if(request.FilterToTrackId.HasValue || request.FilterToTrackIds != null)
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
"Serilog": {
|
||||
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.RollingFileAlternate" ],
|
||||
"MinimumLevel": {
|
||||
"Default": "Verbose",
|
||||
"Default": "Information",
|
||||
"Override": {
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft": "Information",
|
||||
"System": "Warning"
|
||||
}
|
||||
},
|
||||
|
@ -19,13 +19,14 @@
|
|||
{
|
||||
"Name": "Console",
|
||||
"Args": {
|
||||
"theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, Serilog.Sinks.Console"
|
||||
"theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, Serilog.Sinks.Console",
|
||||
"restrictedToMinimumLevel": "Verbose"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "RollingFileAlternate",
|
||||
"Args": {
|
||||
"restrictedToMinimumLevel": "Information",
|
||||
"restrictedToMinimumLevel": "Warning",
|
||||
"path": "{Date}.log",
|
||||
"logDirectory": "logs",
|
||||
"fileSizeLimitBytes": 26214400,
|
||||
|
|
Loading…
Reference in a new issue