mirror of
https://github.com/sphildreth/roadie
synced 2024-11-22 12:13:10 +00:00
Subsonic API Work
This commit is contained in:
parent
f56cfb9cbd
commit
969393128c
14 changed files with 195 additions and 77 deletions
|
@ -10,6 +10,7 @@ using Roadie.Library.Configuration;
|
|||
using Roadie.Library.Identity;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using models = Roadie.Library.Models.Users;
|
||||
|
@ -56,20 +57,36 @@ namespace Roadie.Api.Controllers
|
|||
return result;
|
||||
}
|
||||
|
||||
protected async Task<FileStreamResult> StreamTrack(Guid id, ITrackService trackService, IPlayActivityService playActivityService, models.User currentUser = null)
|
||||
protected async Task<IActionResult> StreamTrack(Guid id, ITrackService trackService, IPlayActivityService playActivityService, models.User currentUser = null)
|
||||
{
|
||||
var user = currentUser ?? await this.CurrentUserModel();
|
||||
var track = await trackService.ById(user, id, null);
|
||||
if (track == null || track.IsNotFoundResult)
|
||||
if (track == null || ( track?.IsNotFoundResult ?? false))
|
||||
{
|
||||
Response.StatusCode = (int)HttpStatusCode.NotFound;
|
||||
if (track?.Errors != null && (track?.Errors.Any() ?? false))
|
||||
{
|
||||
this.Logger.LogCritical($"StreamTrack: ById Invalid For TrackId [{ id }] OperationResult Errors [{ string.Join('|', track?.Errors ?? new Exception[0]) }], For User [{ currentUser }]");
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Logger.LogCritical($"StreamTrack: ById Invalid For TrackId [{ id }] OperationResult Messages [{ string.Join('|', track?.Messages ?? new string[0]) }], For User [{ currentUser }]");
|
||||
}
|
||||
return NotFound("Unknown TrackId");
|
||||
}
|
||||
var info = await trackService.TrackStreamInfo(id,
|
||||
Services.TrackService.DetermineByteStartFromHeaders(this.Request.Headers),
|
||||
Services.TrackService.DetermineByteEndFromHeaders(this.Request.Headers, track.Data.FileSize));
|
||||
if (!info.IsSuccess)
|
||||
if (!info?.IsSuccess ?? false || info?.Data == null)
|
||||
{
|
||||
Response.StatusCode = (int)HttpStatusCode.InternalServerError;
|
||||
if (info?.Errors != null && (info?.Errors.Any() ?? false))
|
||||
{
|
||||
this.Logger.LogCritical($"StreamTrack: TrackStreamInfo Invalid For TrackId [{ id }] OperationResult Errors [{ string.Join('|', info?.Errors ?? new Exception[0]) }], For User [{ currentUser }]");
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Logger.LogCritical($"StreamTrack: TrackStreamInfo Invalid For TrackId [{ id }] OperationResult Messages [{ string.Join('|', info?.Messages ?? new string[0]) }], For User [{ currentUser }]");
|
||||
}
|
||||
return NotFound("Unknown TrackId");
|
||||
}
|
||||
Response.Headers.Add("Content-Disposition", info.Data.ContentDisposition);
|
||||
Response.Headers.Add("X-Content-Duration", info.Data.ContentDuration);
|
||||
|
@ -87,7 +104,7 @@ namespace Roadie.Api.Controllers
|
|||
Response.Headers.Add("Expires", info.Data.Expires);
|
||||
var stream = new MemoryStream(info.Data.Bytes);
|
||||
var playListUser = await playActivityService.CreatePlayActivity(user, info.Data);
|
||||
this.Logger.LogInformation($"StreamTrack PlayActivity `{ playListUser?.ToString() }`, StreamInfo `{ info.Data.ToString() }`");
|
||||
this.Logger.LogInformation($"StreamTrack PlayActivity `{ playListUser?.Data.ToString() }`, StreamInfo `{ info.Data.ToString() }`");
|
||||
return new FileStreamResult(stream, info.Data.ContentType)
|
||||
{
|
||||
FileDownloadName = info.Data.FileName
|
||||
|
|
|
@ -66,7 +66,7 @@ namespace Roadie.Api.Controllers
|
|||
}
|
||||
|
||||
[HttpGet("track/{id}.{mp3?}")]
|
||||
public async Task<FileStreamResult> StreamTrack(Guid id)
|
||||
public async Task<IActionResult> StreamTrack(Guid id)
|
||||
{
|
||||
return await base.StreamTrack(id, this.TrackService, this.PlayActivityService);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,9 @@ using Roadie.Library.Extensions;
|
|||
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;
|
||||
|
||||
|
@ -265,14 +268,6 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> GetPlaylist(SubsonicRequest request)
|
||||
{
|
||||
this.Logger.Log(LogLevel.Critical, ":: Critial");
|
||||
this.Logger.Log(LogLevel.Debug, ":: Debug");
|
||||
this.Logger.Log(LogLevel.Error, ":: Error");
|
||||
this.Logger.Log(LogLevel.Information, ":: Information");
|
||||
this.Logger.Log(LogLevel.None, ":: None");
|
||||
this.Logger.Log(LogLevel.Trace, ":: Trace");
|
||||
this.Logger.Log(LogLevel.Warning, ":: Warning");
|
||||
|
||||
var authResult = await this.AuthenticateUser(request);
|
||||
if (authResult != null)
|
||||
{
|
||||
|
@ -438,8 +433,13 @@ namespace Roadie.Api.Controllers
|
|||
[HttpGet("ping.view")]
|
||||
[HttpPost("ping.view")]
|
||||
[ProducesResponseType(200)]
|
||||
public IActionResult Ping(SubsonicRequest request)
|
||||
public async Task<IActionResult> Ping(SubsonicRequest request)
|
||||
{
|
||||
var authResult = await this.AuthenticateUser(request);
|
||||
if (authResult != null)
|
||||
{
|
||||
return authResult;
|
||||
}
|
||||
if (request.IsJSONRequest)
|
||||
{
|
||||
var result = this.SubsonicService.Ping(request);
|
||||
|
@ -496,17 +496,18 @@ namespace Roadie.Api.Controllers
|
|||
[HttpGet("stream.view")]
|
||||
[HttpPost("stream.view")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<FileStreamResult> StreamTrack(SubsonicRequest request)
|
||||
public async Task<IActionResult> StreamTrack(SubsonicRequest request)
|
||||
{
|
||||
var authResult = await this.AuthenticateUser(request);
|
||||
if (authResult != null)
|
||||
{
|
||||
Response.StatusCode = (int)HttpStatusCode.Unauthorized;
|
||||
return Unauthorized();
|
||||
}
|
||||
var trackId = request.TrackId;
|
||||
if (trackId == null)
|
||||
{
|
||||
Response.StatusCode = (int)HttpStatusCode.InternalServerError;
|
||||
return NotFound("Invalid TrackId");
|
||||
|
||||
}
|
||||
return await base.StreamTrack(trackId.Value, this.TrackService, this.PlayActivityService, this.SubsonicUser);
|
||||
}
|
||||
|
@ -527,7 +528,28 @@ namespace Roadie.Api.Controllers
|
|||
private IActionResult BuildResponse(SubsonicRequest request, SubsonicOperationResult<Response> response = null, string responseType = null)
|
||||
{
|
||||
var acceptHeader = this.Request.Headers["Accept"];
|
||||
this.Logger.LogTrace($"Subsonic Request: Method [{ this.Request.Method }], Accept Header [{ acceptHeader }], Path [{ this.Request.Path }], Query String [{ this.Request.QueryString }], Response Error Code [{ response?.ErrorCode }], Request [{ JsonConvert.SerializeObject(request) }] ResponseType [{ responseType }]");
|
||||
string postBody = null;
|
||||
string queryString = this.Request.QueryString.ToString();
|
||||
string queryPath = this.Request.Path;
|
||||
string method = this.Request.Method;
|
||||
|
||||
if (!this.Request.Method.Equals("GET", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrEmpty(this.Request.ContentType))
|
||||
{
|
||||
var formCollection = this.Request.Form;
|
||||
var formDictionary = new Dictionary<string, object>();
|
||||
if (formCollection != null && formCollection.Any())
|
||||
{
|
||||
foreach (var form in formCollection)
|
||||
{
|
||||
if (!formDictionary.ContainsKey(form.Key))
|
||||
{
|
||||
formDictionary[form.Key] = form.Value.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
postBody = JsonConvert.SerializeObject(formDictionary);
|
||||
}
|
||||
this.Logger.LogTrace($"Subsonic Request: Method [{ method }], Accept Header [{ acceptHeader }], Path [{ queryPath }], Query String [{ queryString }], Posted Body [{ postBody }], Response Error Code [{ response?.ErrorCode }], Request [{ JsonConvert.SerializeObject(request) }] ResponseType [{ responseType }]");
|
||||
if (response?.ErrorCode.HasValue ?? false)
|
||||
{
|
||||
return this.SendError(request, response);
|
||||
|
|
|
@ -89,6 +89,10 @@ namespace Roadie.Api.ModelBinding
|
|||
{
|
||||
modelDictionary[form.Key] = form.Value.FirstOrDefault();
|
||||
}
|
||||
else
|
||||
{
|
||||
modelDictionary.Add(form.Key, form.Value.FirstOrDefault());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,8 @@
|
|||
<PackageReference Include="Serilog.Exceptions" Version="4.1.0" />
|
||||
<PackageReference Include="Serilog.Settings.Configuration" Version="3.0.1" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="4.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.RollingFileAlternate" Version="2.0.9" />
|
||||
<PackageReference Include="Serilog.Sinks.SQLite" Version="4.0.0" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="5.3.0" />
|
||||
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.0.9" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -206,7 +206,11 @@ namespace Roadie.Api.Services
|
|||
}
|
||||
if (includes.Contains("playlists"))
|
||||
{
|
||||
var r = await this.PlaylistService.List(request: new PagedRequest(), artistId: artist.RoadieId);
|
||||
var pg = new PagedRequest
|
||||
{
|
||||
FilterToArtistId = artist.RoadieId
|
||||
};
|
||||
var r = await this.PlaylistService.List(pg);
|
||||
if (r.IsSuccess)
|
||||
{
|
||||
result.PlaylistsWithArtistReleases = r.Rows.ToArray();
|
||||
|
|
|
@ -8,6 +8,6 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
public interface IPlaylistService
|
||||
{
|
||||
Task<PagedResult<PlaylistList>> List(PagedRequest request, User roadieUser = null, Guid? artistId = null);
|
||||
Task<PagedResult<PlaylistList>> List(PagedRequest request, User roadieUser = null);
|
||||
}
|
||||
}
|
|
@ -222,10 +222,18 @@ namespace Roadie.Api.Services
|
|||
try
|
||||
{
|
||||
// See if artist images exists in artist folder
|
||||
var artistImages = Directory.GetFiles(artist.ArtistFileFolder(this.Configuration, this.Configuration.LibraryFolder), "artist*.*");
|
||||
if (artistImages.Any())
|
||||
artistFolder = artist.ArtistFileFolder(this.Configuration, this.Configuration.LibraryFolder);
|
||||
if (!Directory.Exists(artistFolder))
|
||||
{
|
||||
imageBytes = File.ReadAllBytes(artistImages.First());
|
||||
this.Logger.LogWarning($"Artist Folder [{ artistFolder }], Not Found For Artist [{ artist.ToString() }]");
|
||||
}
|
||||
else
|
||||
{
|
||||
var artistImages = Directory.GetFiles(artistFolder, "artist*.*");
|
||||
if (artistImages.Any())
|
||||
{
|
||||
imageBytes = File.ReadAllBytes(artistImages.First());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -424,19 +432,35 @@ namespace Roadie.Api.Services
|
|||
}
|
||||
byte[] imageBytes = null;
|
||||
string artistFolder = null;
|
||||
string releaseFolder = null;
|
||||
try
|
||||
{
|
||||
// See if cover art file exists in release folder
|
||||
artistFolder = release.Artist.ArtistFileFolder(this.Configuration, this.Configuration.LibraryFolder);
|
||||
var coverArtFiles = Directory.GetFiles(release.ReleaseFileFolder(artistFolder), "cover*.*");
|
||||
if (coverArtFiles.Any())
|
||||
if (!Directory.Exists(artistFolder))
|
||||
{
|
||||
imageBytes = File.ReadAllBytes(coverArtFiles.First());
|
||||
this.Logger.LogWarning($"Artist Folder [{ artistFolder }], Not Found For Artist [{ release.Artist.ToString() }]");
|
||||
}
|
||||
else
|
||||
{
|
||||
releaseFolder = release.ReleaseFileFolder(artistFolder);
|
||||
if (!Directory.Exists(releaseFolder))
|
||||
{
|
||||
this.Logger.LogWarning($"Release Folder [{ releaseFolder }], Not Found For Release [{ release.ToString() }]");
|
||||
}
|
||||
else
|
||||
{
|
||||
var coverArtFiles = Directory.GetFiles(releaseFolder, "cover*.*");
|
||||
if (coverArtFiles.Any())
|
||||
{
|
||||
imageBytes = File.ReadAllBytes(coverArtFiles.First());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.LogError(ex, $"Error Reading Folder [{ artistFolder }] For Artist [{ release.Artist.Id }]");
|
||||
this.Logger.LogError(ex, $"Error Reading Release Folder [{ releaseFolder }] Artist Folder [{ artistFolder }] For Artist [{ release.Artist.Id }]");
|
||||
}
|
||||
imageBytes = imageBytes ?? release.Thumbnail;
|
||||
var image = new data.Image
|
||||
|
|
|
@ -29,25 +29,33 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
}
|
||||
|
||||
public async Task<Library.Models.Pagination.PagedResult<PlaylistList>> List(PagedRequest request, User roadieUser = null, Guid? artistId = null)
|
||||
public async Task<Library.Models.Pagination.PagedResult<PlaylistList>> List(PagedRequest request, User roadieUser = null)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
int[] playlistWithArtistTrackIds = new int[0];
|
||||
if(request.FilterToArtistId.HasValue)
|
||||
{
|
||||
playlistWithArtistTrackIds = (from pl in this.DbContext.Playlists
|
||||
join pltr in this.DbContext.PlaylistTracks on pl.Id equals pltr.PlayListId
|
||||
join t in this.DbContext.Tracks on pltr.TrackId equals t.Id
|
||||
join rm in this.DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||
join r in this.DbContext.Releases on rm.ReleaseId equals r.Id
|
||||
join a in this.DbContext.Artists on r.ArtistId equals a.Id
|
||||
where a.RoadieId == request.FilterToArtistId
|
||||
select pl.Id
|
||||
).ToArray();
|
||||
}
|
||||
|
||||
var result = (from pl in this.DbContext.Playlists
|
||||
join pltr in this.DbContext.PlaylistTracks on pl.Id equals pltr.PlayListId
|
||||
join t in this.DbContext.Tracks on pltr.TrackId equals t.Id
|
||||
join rm in this.DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||
join r in this.DbContext.Releases on rm.ReleaseId equals r.Id
|
||||
join a in this.DbContext.Artists on r.ArtistId equals a.Id
|
||||
join u in this.DbContext.Users on pl.UserId equals u.Id
|
||||
let duration = (from plt in this.DbContext.PlaylistTracks
|
||||
join t in this.DbContext.Tracks on plt.TrackId equals t.Id
|
||||
select t.Duration).Sum()
|
||||
where (request.FilterToPlaylistId == null || pl.RoadieId == request.FilterToPlaylistId)
|
||||
where (request.FilterToArtistId == null || a.RoadieId == request.FilterToArtistId)
|
||||
where (request.FilterToArtistId == null || playlistWithArtistTrackIds.Contains(pl.Id))
|
||||
where ((roadieUser == null && pl.IsPublic) || (roadieUser != null && u.RoadieId == roadieUser.UserId || pl.IsPublic))
|
||||
where (artistId == null || (artistId != null && a.RoadieId == artistId))
|
||||
where (request.FilterValue.Length == 0 || (request.FilterValue.Length > 0 && (
|
||||
pl.Name != null && pl.Name.Contains(request.FilterValue))
|
||||
))
|
||||
|
@ -57,6 +65,7 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
Text = pl.Name,
|
||||
Value = pl.RoadieId.ToString()
|
||||
|
||||
},
|
||||
User = new DataToken
|
||||
{
|
||||
|
@ -71,7 +80,7 @@ namespace Roadie.Api.Services
|
|||
UserThumbnail = MakeUserThumbnailImage(u.RoadieId),
|
||||
Id = pl.RoadieId,
|
||||
Thumbnail = MakePlaylistThumbnailImage(pl.RoadieId)
|
||||
}).Distinct();
|
||||
});
|
||||
var sortBy = string.IsNullOrEmpty(request.Sort) ? request.OrderValue(new Dictionary<string, string> { { "Playlist.Text", "ASC" } }) : request.OrderValue(null);
|
||||
var rowCount = result.Count();
|
||||
var rows = result.OrderBy(sortBy).Skip(request.SkipValue).Take(request.LimitValue).ToArray();
|
||||
|
|
|
@ -136,6 +136,21 @@ namespace Roadie.Api.Services
|
|||
where g.Name == request.FilterByGenre
|
||||
select rg.ReleaseId).ToArray();
|
||||
}
|
||||
if(request.FilterFromYear.HasValue || request.FilterToYear.HasValue)
|
||||
{
|
||||
// If from is larger than to then reverse values and set sort order to desc
|
||||
if(request.FilterToYear > request.FilterFromYear)
|
||||
{
|
||||
var t = request.FilterToYear;
|
||||
request.FilterToYear = request.FilterFromYear;
|
||||
request.FilterFromYear = t;
|
||||
request.Order = "DESC";
|
||||
}
|
||||
else
|
||||
{
|
||||
request.Order = "ASC";
|
||||
}
|
||||
}
|
||||
var result = (from r in this.DbContext.Releases.Include("Artist")
|
||||
join a in this.DbContext.Artists on r.ArtistId equals a.Id
|
||||
where (request.FilterMinimumRating == null || r.Rating >= request.FilterMinimumRating.Value)
|
||||
|
|
|
@ -814,6 +814,8 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
return new subsonic.SubsonicOperationResult<subsonic.Response>(subsonic.ErrorCodes.TheRequestedDataWasNotFound, $"Invalid PlaylistId [{ request.id }]");
|
||||
}
|
||||
// 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);
|
||||
return new subsonic.SubsonicOperationResult<subsonic.Response>
|
||||
{
|
||||
|
@ -833,31 +835,37 @@ namespace Roadie.Api.Services
|
|||
/// </summary>
|
||||
public async Task<subsonic.SubsonicOperationResult<subsonic.Response>> GetPlaylists(subsonic.Request request, User roadieUser, string filterToUserName)
|
||||
{
|
||||
var playlists = (from playlist in this.DbContext.Playlists
|
||||
join u in this.DbContext.Users on playlist.UserId equals u.Id
|
||||
let trackCount = (from pl in this.DbContext.PlaylistTracks
|
||||
where pl.PlayListId == playlist.Id
|
||||
select pl.Id).Count()
|
||||
let playListDuration = (from pl in this.DbContext.PlaylistTracks
|
||||
join t in this.DbContext.Tracks on pl.TrackId equals t.Id
|
||||
where pl.PlayListId == playlist.Id
|
||||
select t.Duration).Sum()
|
||||
where (playlist.IsPublic) || (roadieUser != null && playlist.UserId == roadieUser.Id)
|
||||
select new subsonic.Playlist
|
||||
{
|
||||
id = playlist.RoadieId.ToString(),
|
||||
name = playlist.Name,
|
||||
comment = playlist.Description,
|
||||
owner = u.UserName,
|
||||
songCount = trackCount,
|
||||
duration = playListDuration.ToSecondsFromMilliseconds(),
|
||||
created = playlist.CreatedDate,
|
||||
changed = playlist.LastUpdated ?? playlist.CreatedDate,
|
||||
coverArt = this.MakePlaylistThumbnailImage(playlist.RoadieId).Url,
|
||||
@public = playlist.IsPublic,
|
||||
publicSpecified = playlist.IsPublic
|
||||
}
|
||||
);
|
||||
//var playlists = (from playlist in this.DbContext.Playlists
|
||||
// join u in this.DbContext.Users on playlist.UserId equals u.Id
|
||||
// let trackCount = (from pl in this.DbContext.PlaylistTracks
|
||||
// where pl.PlayListId == playlist.Id
|
||||
// select pl.Id).Count()
|
||||
// let playListDuration = (from pl in this.DbContext.PlaylistTracks
|
||||
// join t in this.DbContext.Tracks on pl.TrackId equals t.Id
|
||||
// where pl.PlayListId == playlist.Id
|
||||
// select t.Duration).Sum()
|
||||
// where (playlist.IsPublic) || (roadieUser != null && playlist.UserId == roadieUser.Id)
|
||||
// select new subsonic.Playlist
|
||||
// {
|
||||
// id = playlist.RoadieId.ToString(),
|
||||
// name = playlist.Name,
|
||||
// comment = playlist.Description,
|
||||
// owner = u.UserName,
|
||||
// songCount = trackCount,
|
||||
// duration = playListDuration.ToSecondsFromMilliseconds(),
|
||||
// created = playlist.CreatedDate,
|
||||
// changed = playlist.LastUpdated ?? playlist.CreatedDate,
|
||||
// coverArt = this.MakePlaylistThumbnailImage(playlist.RoadieId).Url,
|
||||
// @public = playlist.IsPublic,
|
||||
// publicSpecified = playlist.IsPublic
|
||||
// }
|
||||
// );
|
||||
|
||||
var pagedRequest = request.PagedRequest;
|
||||
pagedRequest.Sort = "Playlist.Text";
|
||||
pagedRequest.Order = "ASC";
|
||||
var playlistResult = await this.PlaylistService.List(pagedRequest, roadieUser);
|
||||
|
||||
|
||||
return new subsonic.SubsonicOperationResult<subsonic.Response>
|
||||
{
|
||||
|
@ -869,7 +877,7 @@ namespace Roadie.Api.Services
|
|||
ItemElementName = subsonic.ItemChoiceType.playlists,
|
||||
Item = new subsonic.Playlists
|
||||
{
|
||||
playlist = playlists.ToArray()
|
||||
playlist = this.SubsonicPlaylistsForPlaylists(playlistResult.Rows)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1518,12 +1526,21 @@ namespace Roadie.Api.Services
|
|||
return tracks.Select(x => this.SubsonicChildForTrack(x)).ToArray();
|
||||
}
|
||||
|
||||
private subsonic.Playlist SubsonicPlaylistForPlaylist(Library.Models.Playlists.PlaylistList playlist, IEnumerable<TrackList> playlistTracks)
|
||||
private subsonic.Playlist[] SubsonicPlaylistsForPlaylists(IEnumerable<Library.Models.Playlists.PlaylistList> playlists)
|
||||
{
|
||||
if (playlists == null || !playlists.Any())
|
||||
{
|
||||
return new subsonic.Playlist[0];
|
||||
}
|
||||
return playlists.Select(x => this.SubsonicPlaylistForPlaylist(x)).ToArray();
|
||||
}
|
||||
|
||||
private subsonic.Playlist SubsonicPlaylistForPlaylist(Library.Models.Playlists.PlaylistList playlist, IEnumerable<TrackList> playlistTracks = null)
|
||||
{
|
||||
return new subsonic.PlaylistWithSongs
|
||||
{
|
||||
coverArt = this.MakePlaylistThumbnailImage(playlist.Id).Url,
|
||||
allowedUser = this.AllowedUsers(),
|
||||
allowedUser = playlist.IsPublic ? this.AllowedUsers() : null,
|
||||
changed = playlist.LastUpdated ?? playlist.CreatedDate ?? DateTime.UtcNow,
|
||||
created = playlist.CreatedDate ?? DateTime.UtcNow,
|
||||
duration = playlist.Duration ?? 0,
|
||||
|
|
|
@ -239,6 +239,7 @@ namespace Roadie.Api.Services
|
|||
join p in this.DbContext.Playlists on plt.PlayListId equals p.Id
|
||||
join t in this.DbContext.Tracks on plt.TrackId equals t.Id
|
||||
where p.RoadieId == request.FilterToPlaylistId.Value
|
||||
orderby plt.ListNumber
|
||||
select new {
|
||||
plt.ListNumber, t.Id
|
||||
}).Skip(request.SkipValue).Take(request.LimitValue).ToDictionary(x => x.Id, x => x.ListNumber);
|
||||
|
@ -467,6 +468,7 @@ namespace Roadie.Api.Services
|
|||
info.Bytes = trackBytes;
|
||||
return new OperationResult<TrackStreamInfo>
|
||||
{
|
||||
IsSuccess = true,
|
||||
Data = info
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
}
|
||||
},
|
||||
"Serilog": {
|
||||
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
|
||||
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.RollingFileAlternate", "Serilog.Sinks.SQLite" ],
|
||||
"MinimumLevel": {
|
||||
"Default": "Verbose",
|
||||
"Override": {
|
||||
|
@ -20,17 +20,24 @@
|
|||
"Name": "Console",
|
||||
"Args": {
|
||||
"theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, Serilog.Sinks.Console"
|
||||
},
|
||||
"Default": "Verbose"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "File",
|
||||
"Name": "RollingFileAlternate",
|
||||
"Args": {
|
||||
"restrictedToMinimumLevel": "Information",
|
||||
"rollingInterval": "Day",
|
||||
"path": "C:\\logs\\roadie-log-.log",
|
||||
"path": "{Date}.log",
|
||||
"logDirectory": "logs",
|
||||
"fileSizeLimitBytes": 26214400,
|
||||
"buffered": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "SQLite",
|
||||
"Args": {
|
||||
"restrictedToMinimumLevel": "Error",
|
||||
"sqliteDbPath": "logs\\errors.sqlite"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId", "WithExceptionDetails" ],
|
||||
|
|
|
@ -17,10 +17,6 @@
|
|||
<PackageReference Include="Orthogonal.NTagLite" Version="2.0.9" />
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="2.1.2" />
|
||||
<PackageReference Include="RestSharp" Version="106.5.4" />
|
||||
<PackageReference Include="Serilog" Version="2.7.1" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
|
||||
<PackageReference Include="Serilog.Sinks.RollingFile" Version="3.3.0" />
|
||||
<PackageReference Include="SerilogTraceListener" Version="3.1.0" />
|
||||
<PackageReference Include="SixLabors.Core" Version="1.0.0-beta0006" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.0-beta0005" />
|
||||
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta0005" />
|
||||
|
|
Loading…
Reference in a new issue