mirror of
https://github.com/sphildreth/roadie
synced 2025-02-16 21:18:26 +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 Roadie.Library.Models.ThirdPartyApi.Subsonic;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
@ -24,6 +23,7 @@ namespace Roadie.Api.Controllers
|
||||||
public class SubsonicController : EntityControllerBase
|
public class SubsonicController : EntityControllerBase
|
||||||
{
|
{
|
||||||
private IPlayActivityService PlayActivityService { get; }
|
private IPlayActivityService PlayActivityService { get; }
|
||||||
|
private IReleaseService ReleaseService { get; }
|
||||||
private ISubsonicService SubsonicService { get; }
|
private ISubsonicService SubsonicService { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -32,7 +32,6 @@ namespace Roadie.Api.Controllers
|
||||||
private Library.Models.Users.User SubsonicUser { get; set; }
|
private Library.Models.Users.User SubsonicUser { get; set; }
|
||||||
|
|
||||||
private ITrackService TrackService { get; }
|
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)
|
public SubsonicController(ISubsonicService subsonicService, ITrackService trackService, IReleaseService releaseService, IPlayActivityService playActivityService, ILoggerFactory logger, ICacheManager cacheManager, IConfiguration configuration, UserManager<ApplicationUser> userManager)
|
||||||
: base(cacheManager, configuration, userManager)
|
: base(cacheManager, configuration, userManager)
|
||||||
|
@ -44,20 +43,6 @@ namespace Roadie.Api.Controllers
|
||||||
this.PlayActivityService = playActivityService;
|
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")]
|
[HttpGet("createBookmark.view")]
|
||||||
[HttpPost("createBookmark.view")]
|
[HttpPost("createBookmark.view")]
|
||||||
[ProducesResponseType(200)]
|
[ProducesResponseType(200)]
|
||||||
|
@ -72,6 +57,19 @@ namespace Roadie.Api.Controllers
|
||||||
return this.BuildResponse(request, result);
|
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")]
|
[HttpGet("deleteBookmark.view")]
|
||||||
[HttpPost("deleteBookmark.view")]
|
[HttpPost("deleteBookmark.view")]
|
||||||
|
@ -101,75 +99,46 @@ namespace Roadie.Api.Controllers
|
||||||
return this.BuildResponse(request, result);
|
return this.BuildResponse(request, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("updatePlaylist.view")]
|
[HttpGet("download.view")]
|
||||||
[HttpPost("updatePlaylist.view")]
|
[HttpPost("download.view")]
|
||||||
[ProducesResponseType(200)]
|
[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);
|
var authResult = await this.AuthenticateUser(request);
|
||||||
if (authResult != null)
|
if (authResult != null)
|
||||||
{
|
{
|
||||||
return authResult;
|
return Unauthorized();
|
||||||
}
|
}
|
||||||
var result = await this.SubsonicService.UpdatePlaylist(request, this.SubsonicUser, playlistId, name, comment, @public, songIdToAdd, songIndexToRemove);
|
var trackId = request.TrackId;
|
||||||
return this.BuildResponse(request, result);
|
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("getAlbum.view")]
|
||||||
[HttpGet("getBookmarks.view")]
|
[HttpPost("getAlbum.view")]
|
||||||
[HttpPost("getBookmarks.view")]
|
|
||||||
[ProducesResponseType(200)]
|
[ProducesResponseType(200)]
|
||||||
public async Task<IActionResult> GetBookmarks(SubsonicRequest request)
|
public async Task<IActionResult> GetAlbum(SubsonicRequest request)
|
||||||
{
|
{
|
||||||
var authResult = await this.AuthenticateUser(request);
|
var authResult = await this.AuthenticateUser(request);
|
||||||
if (authResult != null)
|
if (authResult != null)
|
||||||
{
|
{
|
||||||
return authResult;
|
return authResult;
|
||||||
}
|
}
|
||||||
var result = await this.SubsonicService.GetBookmarks(request, this.SubsonicUser);
|
var result = await this.SubsonicService.GetAlbum(request, this.SubsonicUser);
|
||||||
return this.BuildResponse(request, result, "bookmarks");
|
return this.BuildResponse(request, result, "album");
|
||||||
}
|
|
||||||
|
|
||||||
[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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("getAlbumInfo.view")]
|
[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}");
|
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")]
|
[HttpGet("getCoverArt.view")]
|
||||||
[HttpPost("getCoverArt.view")]
|
[HttpPost("getCoverArt.view")]
|
||||||
[ProducesResponseType(200)]
|
[ProducesResponseType(200)]
|
||||||
|
@ -379,6 +362,20 @@ namespace Roadie.Api.Controllers
|
||||||
return this.BuildResponse(request, result, "musicFolders");
|
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")]
|
[HttpGet("getPlaylist.view")]
|
||||||
[HttpPost("getPlaylist.view")]
|
[HttpPost("getPlaylist.view")]
|
||||||
[ProducesResponseType(200)]
|
[ProducesResponseType(200)]
|
||||||
|
@ -393,21 +390,6 @@ namespace Roadie.Api.Controllers
|
||||||
return this.BuildResponse(request, result, "playlist");
|
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")]
|
[HttpGet("getPlaylists.view")]
|
||||||
[HttpPost("getPlaylists.view")]
|
[HttpPost("getPlaylists.view")]
|
||||||
[ProducesResponseType(200)]
|
[ProducesResponseType(200)]
|
||||||
|
@ -634,6 +616,34 @@ namespace Roadie.Api.Controllers
|
||||||
return this.BuildResponse(request, result, "searchResult3");
|
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")]
|
[HttpGet("stream.view")]
|
||||||
[HttpPost("stream.view")]
|
[HttpPost("stream.view")]
|
||||||
[ProducesResponseType(200)]
|
[ProducesResponseType(200)]
|
||||||
|
@ -648,41 +658,37 @@ namespace Roadie.Api.Controllers
|
||||||
if (trackId == null)
|
if (trackId == null)
|
||||||
{
|
{
|
||||||
return NotFound("Invalid TrackId");
|
return NotFound("Invalid TrackId");
|
||||||
|
|
||||||
}
|
}
|
||||||
return await base.StreamTrack(trackId.Value, this.TrackService, this.PlayActivityService, this.SubsonicUser);
|
return await base.StreamTrack(trackId.Value, this.TrackService, this.PlayActivityService, this.SubsonicUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet("unstar.view")]
|
||||||
[HttpGet("download.view")]
|
[HttpPost("unstar.view")]
|
||||||
[HttpPost("download.view")]
|
|
||||||
[ProducesResponseType(200)]
|
[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);
|
var authResult = await this.AuthenticateUser(request);
|
||||||
if (authResult != null)
|
if (authResult != null)
|
||||||
{
|
{
|
||||||
return Unauthorized();
|
return authResult;
|
||||||
}
|
}
|
||||||
var trackId = request.TrackId;
|
var result = await this.SubsonicService.ToggleStar(request, this.SubsonicUser, false, albumId, artistId);
|
||||||
if (trackId != null)
|
return this.BuildResponse(request, result);
|
||||||
{
|
|
||||||
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("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)
|
private async Task<IActionResult> AuthenticateUser(SubsonicRequest request)
|
||||||
{
|
{
|
||||||
|
|
|
@ -57,8 +57,8 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(200)]
|
[ProducesResponseType(200)]
|
||||||
public async Task<IActionResult> List([FromQuery]PagedRequest request, string inc)
|
public async Task<IActionResult> List([FromQuery]PagedRequest request, string inc)
|
||||||
{
|
{
|
||||||
var result = await this.TrackService.List(roadieUser: await this.CurrentUserModel(),
|
var result = await this.TrackService.List(request: request,
|
||||||
request: request);
|
roadieUser: await this.CurrentUserModel());
|
||||||
if (!result.IsSuccess)
|
if (!result.IsSuccess)
|
||||||
{
|
{
|
||||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||||
|
|
|
@ -370,23 +370,23 @@ namespace Roadie.Api.Services
|
||||||
}
|
}
|
||||||
if(rows.Any() && (doArtistCounts ?? true))
|
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
|
var artistReleases = (from a in this.DbContext.Artists
|
||||||
join r in this.DbContext.Releases on a.Id equals r.ArtistId
|
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)
|
where rowArtistIds.Contains(a.Id)
|
||||||
select new
|
select new
|
||||||
{
|
{
|
||||||
r.Id,
|
artistId = a.Id,
|
||||||
|
releaseId = r.Id,
|
||||||
r.TrackCount,
|
r.TrackCount,
|
||||||
r.PlayedCount
|
r.PlayedCount
|
||||||
}).ToList();
|
}).ToArray();
|
||||||
foreach(var row in rows)
|
foreach(var row in rows)
|
||||||
{
|
{
|
||||||
row.ArtistReleaseCount = artistReleases.Where(r => r.Id == row.DatabaseId).Select(r => r.Id).Count();
|
var rowArtistReleases = artistReleases.Where(r => r.artistId == row.DatabaseId);
|
||||||
row.ArtistTrackCount = artistReleases.Where(r => r.Id == row.DatabaseId).Sum(r => r.TrackCount);
|
row.ArtistReleaseCount = rowArtistReleases.Select(r => r.releaseId).Count();
|
||||||
row.ArtistPlayedCount = artistReleases.Where(r => r.Id == row.DatabaseId).Sum(r => r.PlayedCount);
|
row.ArtistTrackCount = rowArtistReleases.Sum(r => r.TrackCount);
|
||||||
|
row.ArtistPlayedCount = rowArtistReleases.Sum(r => r.PlayedCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (rows.Any() && roadieUser != null)
|
if (rows.Any() && roadieUser != null)
|
||||||
|
@ -400,7 +400,8 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
IsDisliked = userArtistRating.IsDisliked ?? false,
|
IsDisliked = userArtistRating.IsDisliked ?? false,
|
||||||
IsFavorite = userArtistRating.IsFavorite ?? 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;
|
||||||
using Roadie.Library.Models.Pagination;
|
using Roadie.Library.Models.Pagination;
|
||||||
using Roadie.Library.Models.Users;
|
using Roadie.Library.Models.Users;
|
||||||
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Roadie.Api.Services
|
namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
public interface IPlayActivityService
|
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);
|
Task<OperationResult<PlayActivityList>> CreatePlayActivity(User roadieUser, TrackStreamInfo streamInfo);
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,6 +66,8 @@ namespace Roadie.Api.Services
|
||||||
|
|
||||||
SubsonicOperationResult<Response> Ping(Request request);
|
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>> 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);
|
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<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);
|
Task<OperationResult<TrackStreamInfo>> TrackStreamInfo(Guid trackId, long beginBytes, long endBytes);
|
||||||
}
|
}
|
||||||
|
|
|
@ -328,7 +328,7 @@ namespace Roadie.Api.Services
|
||||||
result.LastModified = DateTime.UtcNow;
|
result.LastModified = DateTime.UtcNow;
|
||||||
if (width.Value != this.Configuration.ThumbnailImageSize.Width || height.Value != this.Configuration.ThumbnailImageSize.Height)
|
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();
|
sw.Stop();
|
||||||
|
|
|
@ -37,7 +37,7 @@ namespace Roadie.Api.Services
|
||||||
this.PlayActivityHub = playHubContext;
|
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
|
try
|
||||||
{
|
{
|
||||||
|
@ -52,6 +52,7 @@ namespace Roadie.Api.Services
|
||||||
join usertrack in this.DbContext.UserTracks on t.Id equals usertrack.TrackId
|
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 u in this.DbContext.Users on usertrack.UserId equals u.Id
|
||||||
join releaseArtist in this.DbContext.Artists on r.ArtistId equals releaseArtist.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 ((roadieUser == null && !(u.IsPrivate ?? false)) || (roadieUser != null && (usertrack != null && usertrack.User.Id == roadieUser.Id)))
|
||||||
where (request.FilterValue.Length == 0 || (request.FilterValue.Length > 0 && (
|
where (request.FilterValue.Length == 0 || (request.FilterValue.Length > 0 && (
|
||||||
t.Title != null && t.Title.ToLower().Contains(request.Filter.ToLower()) ||
|
t.Title != null && t.Title.ToLower().Contains(request.Filter.ToLower()) ||
|
||||||
|
|
|
@ -39,6 +39,7 @@ namespace Roadie.Api.Services
|
||||||
private ICollectionService CollectionService { get; }
|
private ICollectionService CollectionService { get; }
|
||||||
private IImageService ImageService { get; }
|
private IImageService ImageService { get; }
|
||||||
private IPlaylistService PlaylistService { get; }
|
private IPlaylistService PlaylistService { get; }
|
||||||
|
private IPlayActivityService PlayActivityService { get; }
|
||||||
private IReleaseService ReleaseService { get; }
|
private IReleaseService ReleaseService { get; }
|
||||||
private ITrackService TrackService { get; }
|
private ITrackService TrackService { get; }
|
||||||
private UserManager<ApplicationUser> UserManger { get; }
|
private UserManager<ApplicationUser> UserManger { get; }
|
||||||
|
@ -56,6 +57,7 @@ namespace Roadie.Api.Services
|
||||||
IReleaseService releaseService,
|
IReleaseService releaseService,
|
||||||
IImageService imageService,
|
IImageService imageService,
|
||||||
IBookmarkService bookmarkService,
|
IBookmarkService bookmarkService,
|
||||||
|
IPlayActivityService playActivityService,
|
||||||
UserManager<ApplicationUser> userManager
|
UserManager<ApplicationUser> userManager
|
||||||
)
|
)
|
||||||
: base(configuration, httpEncoder, context, cacheManager, logger, httpContext)
|
: base(configuration, httpEncoder, context, cacheManager, logger, httpContext)
|
||||||
|
@ -65,6 +67,7 @@ namespace Roadie.Api.Services
|
||||||
this.CollectionService = collectionService;
|
this.CollectionService = collectionService;
|
||||||
this.ImageService = imageService;
|
this.ImageService = imageService;
|
||||||
this.PlaylistService = playlistService;
|
this.PlaylistService = playlistService;
|
||||||
|
this.PlayActivityService = playActivityService;
|
||||||
this.ReleaseService = releaseService;
|
this.ReleaseService = releaseService;
|
||||||
this.TrackService = trackService;
|
this.TrackService = trackService;
|
||||||
this.UserManger = userManager;
|
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>
|
/// <summary>
|
||||||
/// Deletes the bookmark for a given file.
|
/// Deletes the bookmark for a given file.
|
||||||
/// </summary>
|
/// </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>
|
/// <summary>
|
||||||
/// Returns details for an album, including a list of songs. This method organizes music according to ID3 tags.
|
/// Returns details for an album, including a list of songs. This method organizes music according to ID3 tags.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -251,7 +377,7 @@ namespace Roadie.Api.Services
|
||||||
return new subsonic.SubsonicOperationResult<subsonic.Response>(subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid Release [{ request.ReleaseId}]");
|
return new subsonic.SubsonicOperationResult<subsonic.Response>(subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid Release [{ request.ReleaseId}]");
|
||||||
}
|
}
|
||||||
var pagedRequest = request.PagedRequest;
|
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 userRelease = roadieUser == null ? null : this.DbContext.UserReleases.FirstOrDefault(x => x.ReleaseId == release.Id && x.UserId == roadieUser.Id);
|
||||||
var genre = release.Genres.FirstOrDefault();
|
var genre = release.Genres.FirstOrDefault();
|
||||||
return new subsonic.SubsonicOperationResult<subsonic.Response>
|
return new subsonic.SubsonicOperationResult<subsonic.Response>
|
||||||
|
@ -489,48 +615,11 @@ namespace Roadie.Api.Services
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task<subsonic.SubsonicOperationResult<subsonic.Response>> GetArtists(subsonic.Request request, User roadieUser)
|
public async Task<subsonic.SubsonicOperationResult<subsonic.Response>> GetArtists(subsonic.Request request, User roadieUser)
|
||||||
{
|
{
|
||||||
var indexes = new List<subsonic.IndexID3>();
|
var cacheKey = $"urn:subsonic_artists:{ roadieUser.UserName }";
|
||||||
var musicFolder = this.MusicFolders().FirstOrDefault(x => x.id == (request.MusicFolderId ?? 2));
|
return await this.CacheManager.GetAsync<subsonic.SubsonicOperationResult<subsonic.Response>>(cacheKey, async () =>
|
||||||
var pagedRequest = request.PagedRequest;
|
|
||||||
if (musicFolder == this.CollectionMusicFolder())
|
|
||||||
{
|
{
|
||||||
// Indexes for "Collection" Artists alphabetically
|
return await this.GetArtistsAction(request, roadieUser);
|
||||||
// not sure what to do here since this is albums not artists in a "Collection".
|
}, CacheManagerBase.SystemCacheRegionUrn);
|
||||||
}
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -543,7 +632,7 @@ namespace Roadie.Api.Services
|
||||||
pagedRequest.Order = "DESC";
|
pagedRequest.Order = "DESC";
|
||||||
var userBookmarkResult = await this.BookmarkService.List(roadieUser, pagedRequest, false, Library.Enums.BookmarkType.Track);
|
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();
|
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>
|
return new subsonic.SubsonicOperationResult<subsonic.Response>
|
||||||
{
|
{
|
||||||
IsSuccess = true,
|
IsSuccess = true,
|
||||||
|
@ -814,7 +903,7 @@ namespace Roadie.Api.Services
|
||||||
directory.starredSpecified = true;
|
directory.starredSpecified = true;
|
||||||
}
|
}
|
||||||
var pagedRequest = request.PagedRequest;
|
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.child = this.SubsonicChildrenForTracks(songTracks.Rows);
|
||||||
directory.playCount = directory.child.Select(x => x.playCount).Sum();
|
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
|
// For a playlist to show all the tracks in the playlist set the limit to the playlist size
|
||||||
pagedRequest.Limit = playlist.PlaylistCount ?? pagedRequest.Limit;
|
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>
|
return new subsonic.SubsonicOperationResult<subsonic.Response>
|
||||||
{
|
{
|
||||||
IsSuccess = true,
|
IsSuccess = true,
|
||||||
|
@ -945,7 +1034,7 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
var songs = new List<subsonic.Child>();
|
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>
|
return new subsonic.SubsonicOperationResult<subsonic.Response>
|
||||||
{
|
{
|
||||||
|
@ -1021,7 +1110,7 @@ namespace Roadie.Api.Services
|
||||||
var pagedRequest = request.PagedRequest;
|
var pagedRequest = request.PagedRequest;
|
||||||
pagedRequest.FilterToTrackId = request.TrackId.Value;
|
pagedRequest.FilterToTrackId = request.TrackId.Value;
|
||||||
pagedRequest.Sort = "Id";
|
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;
|
var track = trackResult.Rows.Any() ? trackResult.Rows.First() : null;
|
||||||
if (track == null)
|
if (track == null)
|
||||||
{
|
{
|
||||||
|
@ -1048,7 +1137,7 @@ namespace Roadie.Api.Services
|
||||||
var pagedRequest = request.PagedRequest;
|
var pagedRequest = request.PagedRequest;
|
||||||
pagedRequest.FilterByGenre = request.Genre;
|
pagedRequest.FilterByGenre = request.Genre;
|
||||||
pagedRequest.Sort = "Id";
|
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>
|
return new subsonic.SubsonicOperationResult<subsonic.Response>
|
||||||
{
|
{
|
||||||
|
@ -1077,7 +1166,7 @@ namespace Roadie.Api.Services
|
||||||
|
|
||||||
var artistList = await this.ArtistService.List(roadieUser, pagedRequest);
|
var artistList = await this.ArtistService.List(roadieUser, pagedRequest);
|
||||||
var releaseList = await this.ReleaseService.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)
|
switch (version)
|
||||||
{
|
{
|
||||||
|
@ -1132,7 +1221,7 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
artist = base.GetArtist(request.ArtistName);
|
artist = base.GetArtist(request.ArtistName);
|
||||||
}
|
}
|
||||||
else if(request.ArtistId.HasValue)
|
else if (request.ArtistId.HasValue)
|
||||||
{
|
{
|
||||||
artist = this.GetArtist(request.ArtistId.Value);
|
artist = this.GetArtist(request.ArtistId.Value);
|
||||||
}
|
}
|
||||||
|
@ -1145,7 +1234,7 @@ namespace Roadie.Api.Services
|
||||||
pagedRequest.FilterTopPlayedOnly = true;
|
pagedRequest.FilterTopPlayedOnly = true;
|
||||||
pagedRequest.Sort = "PlayedCount";
|
pagedRequest.Sort = "PlayedCount";
|
||||||
pagedRequest.Order = "DESC";
|
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>
|
return new subsonic.SubsonicOperationResult<subsonic.Response>
|
||||||
{
|
{
|
||||||
IsSuccess = true,
|
IsSuccess = true,
|
||||||
|
@ -1251,7 +1340,7 @@ namespace Roadie.Api.Services
|
||||||
trackPagedRequest.Limit = request.SongCount ?? trackPagedRequest.Limit;
|
trackPagedRequest.Limit = request.SongCount ?? trackPagedRequest.Limit;
|
||||||
trackPagedRequest.SkipValue = request.SongOffset ?? trackPagedRequest.SkipValue;
|
trackPagedRequest.SkipValue = request.SongOffset ?? trackPagedRequest.SkipValue;
|
||||||
trackPagedRequest.Filter = query;
|
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);
|
var songs = this.SubsonicChildrenForTracks(songResult.Rows);
|
||||||
|
|
||||||
switch (version)
|
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) }]");
|
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>
|
/// <summary>
|
||||||
/// Updates a playlist. Only the owner of a playlist is allowed to update it.
|
/// Updates a playlist. Only the owner of a playlist is allowed to update it.
|
||||||
/// </summary>
|
/// </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="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="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>
|
/// <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;
|
request.id = playListId ?? request.id;
|
||||||
if (!request.PlaylistId.HasValue)
|
if (!request.PlaylistId.HasValue)
|
||||||
|
@ -1586,7 +1552,7 @@ namespace Roadie.Api.Services
|
||||||
playlist.IsPublic = isPublic ?? playlist.IsPublic;
|
playlist.IsPublic = isPublic ?? playlist.IsPublic;
|
||||||
playlist.LastUpdated = DateTime.UtcNow;
|
playlist.LastUpdated = DateTime.UtcNow;
|
||||||
|
|
||||||
if(songIdsToAdd != null && songIdsToAdd.Any())
|
if (songIdsToAdd != null && songIdsToAdd.Any())
|
||||||
{
|
{
|
||||||
// Add new if not already on Playlist
|
// Add new if not already on Playlist
|
||||||
var songIdsToAddRoadieIds = songIdsToAdd.Select(x => SafeParser.ToGuid(x)).ToArray();
|
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
|
// Remove tracks from playlist
|
||||||
//foreach (var submittedTrack in submittedTracks)
|
// 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) }]");
|
||||||
// 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
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.DbContext.SaveChangesAsync();
|
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
|
#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()
|
private string[] AllowedUsers()
|
||||||
{
|
{
|
||||||
return this.CacheManager.Get<string[]>(CacheManagerBase.SystemCacheRegionUrn + ":active_usernames", () =>
|
return this.CacheManager.Get<string[]>(CacheManagerBase.SystemCacheRegionUrn + ":active_usernames", () =>
|
||||||
|
@ -1698,9 +1742,9 @@ namespace Roadie.Api.Services
|
||||||
pagedRequest.SkipValue = 0;
|
pagedRequest.SkipValue = 0;
|
||||||
pagedRequest.Limit = int.MaxValue;
|
pagedRequest.Limit = int.MaxValue;
|
||||||
pagedRequest.Sort = "Artist.Text";
|
pagedRequest.Sort = "Artist.Text";
|
||||||
var artistList = await this.ArtistService.List(roadieUser:roadieUser,
|
var artistList = await this.ArtistService.List(roadieUser: roadieUser,
|
||||||
request: pagedRequest,
|
request: pagedRequest,
|
||||||
doRandomize: false,
|
doRandomize: false,
|
||||||
onlyIncludeWithReleases: true,
|
onlyIncludeWithReleases: true,
|
||||||
doArtistCounts: false);
|
doArtistCounts: false);
|
||||||
foreach (var artistGroup in artistList.Rows.GroupBy(x => x.Artist.Text.Substring(0, 1)))
|
foreach (var artistGroup in artistList.Rows.GroupBy(x => x.Artist.Text.Substring(0, 1)))
|
||||||
|
@ -1708,7 +1752,7 @@ namespace Roadie.Api.Services
|
||||||
indexes.Add(new subsonic.Index
|
indexes.Add(new subsonic.Index
|
||||||
{
|
{
|
||||||
name = artistGroup.Key,
|
name = artistGroup.Key,
|
||||||
artist = this.SubsonicArtistsForArtists(artistGroup)
|
artist = this.SubsonicArtistsForArtists(artistGroup)
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -217,7 +217,7 @@ namespace Roadie.Api.Services
|
||||||
return result;
|
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();
|
var sw = new Stopwatch();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
|
@ -268,7 +268,6 @@ namespace Roadie.Api.Services
|
||||||
randomLimit = request.LimitValue > randomLimit ? randomLimit : request.LimitValue;
|
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}";
|
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();
|
randomTrackIds = this.DbContext.Tracks.FromSql(sql).Select(x => x.Id).ToArray();
|
||||||
|
|
||||||
}
|
}
|
||||||
Guid?[] filterToTrackIds = null;
|
Guid?[] filterToTrackIds = null;
|
||||||
if(request.FilterToTrackId.HasValue || request.FilterToTrackIds != null)
|
if(request.FilterToTrackId.HasValue || request.FilterToTrackIds != null)
|
||||||
|
|
|
@ -9,9 +9,9 @@
|
||||||
"Serilog": {
|
"Serilog": {
|
||||||
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.RollingFileAlternate" ],
|
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.RollingFileAlternate" ],
|
||||||
"MinimumLevel": {
|
"MinimumLevel": {
|
||||||
"Default": "Verbose",
|
"Default": "Information",
|
||||||
"Override": {
|
"Override": {
|
||||||
"Microsoft": "Warning",
|
"Microsoft": "Information",
|
||||||
"System": "Warning"
|
"System": "Warning"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -19,13 +19,14 @@
|
||||||
{
|
{
|
||||||
"Name": "Console",
|
"Name": "Console",
|
||||||
"Args": {
|
"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",
|
"Name": "RollingFileAlternate",
|
||||||
"Args": {
|
"Args": {
|
||||||
"restrictedToMinimumLevel": "Information",
|
"restrictedToMinimumLevel": "Warning",
|
||||||
"path": "{Date}.log",
|
"path": "{Date}.log",
|
||||||
"logDirectory": "logs",
|
"logDirectory": "logs",
|
||||||
"fileSizeLimitBytes": 26214400,
|
"fileSizeLimitBytes": 26214400,
|
||||||
|
|
Loading…
Add table
Reference in a new issue