mirror of
https://github.com/sphildreth/roadie
synced 2024-11-22 20:23:16 +00:00
Subsonic API work
This commit is contained in:
parent
aaba240a53
commit
f34f428143
13 changed files with 348 additions and 51 deletions
|
@ -1,11 +1,16 @@
|
|||
using Mapster;
|
||||
using Microsoft.AspNet.OData;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Roadie.Api.Services;
|
||||
using Roadie.Library.Caching;
|
||||
using Roadie.Library.Configuration;
|
||||
using Roadie.Library.Identity;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using models = Roadie.Library.Models.Users;
|
||||
|
||||
|
@ -50,5 +55,43 @@ namespace Roadie.Api.Controllers
|
|||
result.IsEditor = User.IsInRole("Editor");
|
||||
return result;
|
||||
}
|
||||
|
||||
protected async Task<FileStreamResult> StreamTrack(Guid id, ITrackService trackService, IPlayActivityService playActivityService)
|
||||
{
|
||||
var user = await this.CurrentUserModel();
|
||||
var track = await trackService.ById(user, id, null);
|
||||
if (track == null || track.IsNotFoundResult)
|
||||
{
|
||||
Response.StatusCode = (int)HttpStatusCode.NotFound;
|
||||
}
|
||||
var info = await trackService.TrackStreamInfo(id,
|
||||
Services.TrackService.DetermineByteStartFromHeaders(this.Request.Headers),
|
||||
Services.TrackService.DetermineByteEndFromHeaders(this.Request.Headers, track.Data.FileSize));
|
||||
if (!info.IsSuccess)
|
||||
{
|
||||
Response.StatusCode = (int)HttpStatusCode.InternalServerError;
|
||||
}
|
||||
Response.Headers.Add("Content-Disposition", info.Data.ContentDisposition);
|
||||
Response.Headers.Add("X-Content-Duration", info.Data.ContentDuration);
|
||||
if (!info.Data.IsFullRequest)
|
||||
{
|
||||
Response.Headers.Add("Accept-Ranges", info.Data.AcceptRanges);
|
||||
Response.Headers.Add("Content-Range", info.Data.ContentRange);
|
||||
}
|
||||
Response.Headers.Add("Content-Length", info.Data.ContentLength);
|
||||
Response.ContentType = info.Data.ContentType;
|
||||
Response.StatusCode = info.Data.IsFullRequest ? (int)HttpStatusCode.OK : (int)HttpStatusCode.PartialContent;
|
||||
Response.Headers.Add("Last-Modified", info.Data.LastModified);
|
||||
Response.Headers.Add("ETag", info.Data.Etag);
|
||||
Response.Headers.Add("Cache-Control", info.Data.CacheControl);
|
||||
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() }`");
|
||||
return new FileStreamResult(stream, info.Data.ContentType)
|
||||
{
|
||||
FileDownloadName = info.Data.FileName
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -68,40 +68,7 @@ namespace Roadie.Api.Controllers
|
|||
[HttpGet("track/{id}.{mp3?}")]
|
||||
public async Task<FileStreamResult> StreamTrack(Guid id)
|
||||
{
|
||||
var user = await this.CurrentUserModel();
|
||||
var track = await this.TrackService.ById(user, id, null);
|
||||
if (track == null || track.IsNotFoundResult)
|
||||
{
|
||||
Response.StatusCode = (int)HttpStatusCode.NotFound;
|
||||
}
|
||||
var info = await this.TrackService.TrackStreamInfo(id,
|
||||
Services.TrackService.DetermineByteStartFromHeaders(this.Request.Headers),
|
||||
Services.TrackService.DetermineByteEndFromHeaders(this.Request.Headers, track.Data.FileSize));
|
||||
if (!info.IsSuccess)
|
||||
{
|
||||
Response.StatusCode = (int)HttpStatusCode.InternalServerError;
|
||||
}
|
||||
Response.Headers.Add("Content-Disposition", info.Data.ContentDisposition);
|
||||
Response.Headers.Add("X-Content-Duration", info.Data.ContentDuration);
|
||||
if (!info.Data.IsFullRequest)
|
||||
{
|
||||
Response.Headers.Add("Accept-Ranges", info.Data.AcceptRanges);
|
||||
Response.Headers.Add("Content-Range", info.Data.ContentRange);
|
||||
}
|
||||
Response.Headers.Add("Content-Length", info.Data.ContentLength);
|
||||
Response.ContentType = info.Data.ContentType;
|
||||
Response.StatusCode = info.Data.IsFullRequest ? (int)HttpStatusCode.OK : (int)HttpStatusCode.PartialContent;
|
||||
Response.Headers.Add("Last-Modified", info.Data.LastModified);
|
||||
Response.Headers.Add("ETag", info.Data.Etag);
|
||||
Response.Headers.Add("Cache-Control", info.Data.CacheControl);
|
||||
Response.Headers.Add("Expires", info.Data.Expires);
|
||||
var stream = new MemoryStream(info.Data.Bytes);
|
||||
var playListUser = await this.PlayActivityService.CreatePlayActivity(user, info.Data);
|
||||
this._logger.LogInformation($"StreamTrack PlayActivity `{ playListUser?.ToString() }`, StreamInfo `{ info.Data.ToString() }`");
|
||||
return new FileStreamResult(stream, info.Data.ContentType)
|
||||
{
|
||||
FileDownloadName = info.Data.FileName
|
||||
};
|
||||
return await base.StreamTrack(id, this.TrackService, this.PlayActivityService);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,12 +19,16 @@ namespace Roadie.Api.Controllers
|
|||
public class SubsonicController : EntityControllerBase
|
||||
{
|
||||
private ISubsonicService SubsonicService { get; }
|
||||
private IPlayActivityService PlayActivityService { get; }
|
||||
private ITrackService TrackService { get; }
|
||||
|
||||
public SubsonicController(ISubsonicService subsonicService, ILoggerFactory logger, ICacheManager cacheManager, IConfiguration configuration, UserManager<ApplicationUser> userManager)
|
||||
public SubsonicController(ISubsonicService subsonicService, ITrackService trackService, IPlayActivityService playActivityService, ILoggerFactory logger, ICacheManager cacheManager, IConfiguration configuration, UserManager<ApplicationUser> userManager)
|
||||
: base(cacheManager, configuration, userManager)
|
||||
{
|
||||
this._logger = logger.CreateLogger("RoadieApi.Controllers.SubsonicController");
|
||||
this.SubsonicService = subsonicService;
|
||||
this.TrackService = trackService;
|
||||
this.PlayActivityService = playActivityService;
|
||||
}
|
||||
|
||||
[HttpGet("getIndexes.view")]
|
||||
|
@ -76,6 +80,27 @@ namespace Roadie.Api.Controllers
|
|||
return this.BuildResponse(request, result.Data, "podcasts");
|
||||
}
|
||||
|
||||
[HttpGet("getAlbumList.view")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> GetAlbumList([FromQuery]Request request)
|
||||
{
|
||||
var result = await this.SubsonicService.GetAlbumList(request, null);
|
||||
return this.BuildResponse(request, result.Data, "albumList");
|
||||
}
|
||||
|
||||
[HttpGet("stream.view")]
|
||||
[HttpPost("stream.view")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<FileStreamResult> StreamTrack([FromQuery]Request request)
|
||||
{
|
||||
var trackId = request.TrackId;
|
||||
if (trackId == null)
|
||||
{
|
||||
Response.StatusCode = (int)HttpStatusCode.InternalServerError;
|
||||
}
|
||||
return await base.StreamTrack(trackId.Value, this.TrackService, this.PlayActivityService);
|
||||
}
|
||||
|
||||
[HttpGet("getCoverArt.view")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> GetCoverArt([FromQuery]Request request, int? size)
|
||||
|
@ -106,6 +131,9 @@ namespace Roadie.Api.Controllers
|
|||
return this.BuildResponse(request, result.Data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#region Response Builder Methods
|
||||
|
||||
private string BuildJsonResult(Response response, string responseType)
|
||||
|
|
|
@ -18,6 +18,8 @@ namespace Roadie.Api.Services
|
|||
|
||||
Task<OperationResult<Response>> GetMusicDirectory(Request request, Roadie.Library.Models.Users.User roadieUser, string id);
|
||||
|
||||
Task<OperationResult<Response>> GetAlbumList(Request request, Roadie.Library.Models.Users.User roadieUser);
|
||||
|
||||
Task<FileOperationResult<Roadie.Library.Models.Image>> GetCoverArt(Request request, int? size);
|
||||
|
||||
OperationResult<Response> Ping(Request request);
|
||||
|
|
|
@ -110,16 +110,16 @@ namespace Roadie.Api.Services
|
|||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
if (!string.IsNullOrEmpty(request.Sort))
|
||||
{
|
||||
request.Sort = request.Sort.Replace("createdDate", "createdDateTime");
|
||||
request.Sort = request.Sort.Replace("lastUpdated", "lastUpdatedDateTime");
|
||||
request.Sort = request.Sort.Replace("ReleaseDate", "ReleaseDateDateTime");
|
||||
request.Sort = request.Sort.Replace("releaseYear", "ReleaseDateDateTime");
|
||||
}
|
||||
|
||||
var result = (from r in this.DbContext.Releases.Include("Artist")
|
||||
join a in this.DbContext.Artists on r.ArtistId equals a.Id
|
||||
let lastPlayed = (from ut in this.DbContext.UserTracks
|
||||
join t in this.DbContext.Tracks on ut.TrackId equals t.Id
|
||||
join rm in this.DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||
join rl in this.DbContext.Releases on rm.ReleaseId equals rl.Id
|
||||
where rl.Id == r.Id
|
||||
orderby ut.LastPlayed descending
|
||||
select ut.LastPlayed
|
||||
).FirstOrDefault()
|
||||
where (request.FilterMinimumRating == null || r.Rating >= request.FilterMinimumRating.Value)
|
||||
where (request.FilterToArtistId == null || r.Artist.RoadieId == request.FilterToArtistId)
|
||||
where (request.FilterValue == "" || (r.Title.Contains(request.FilterValue) || r.AlternateNames.Contains(request.FilterValue)))
|
||||
|
@ -146,6 +146,7 @@ namespace Roadie.Api.Services
|
|||
TrackCount = r.TrackCount,
|
||||
CreatedDate = r.CreatedDate,
|
||||
LastUpdated = r.LastUpdated,
|
||||
LastPlayed = lastPlayed != null ? lastPlayed : null,
|
||||
TrackPlayedCount = (from ut in this.DbContext.UserTracks
|
||||
join t in this.DbContext.Tracks on ut.TrackId equals t.Id
|
||||
join rm in this.DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||
|
@ -161,7 +162,8 @@ namespace Roadie.Api.Services
|
|||
|
||||
if (doRandomize ?? false)
|
||||
{
|
||||
request.Limit = request.LimitValue > roadieUser.RandomReleaseLimit ? roadieUser.RandomReleaseLimit : request.LimitValue;
|
||||
var randomLimit = roadieUser?.RandomReleaseLimit ?? 100;
|
||||
request.Limit = request.LimitValue > randomLimit ? randomLimit : request.LimitValue;
|
||||
rows = result.OrderBy(x => Guid.NewGuid()).Skip(request.SkipValue).Take(request.LimitValue).ToArray();
|
||||
}
|
||||
else
|
||||
|
@ -175,6 +177,14 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
sortBy = string.IsNullOrEmpty(request.Sort) ? request.OrderValue(new Dictionary<string, string> { { "Release.Text", "ASC" } }) : request.OrderValue(null);
|
||||
}
|
||||
if(request.FilterRatedOnly)
|
||||
{
|
||||
result = result.Where(x => x.Rating.HasValue);
|
||||
}
|
||||
if(request.FilterMinimumRating.HasValue)
|
||||
{
|
||||
result = result.Where(x => x.Rating.HasValue && x.Rating.Value >= request.FilterMinimumRating.Value);
|
||||
}
|
||||
rows = result.OrderBy(sortBy).Skip(request.SkipValue).Take(request.LimitValue).ToArray();
|
||||
}
|
||||
if (rows.Any() && roadieUser != null)
|
||||
|
@ -184,11 +194,14 @@ namespace Roadie.Api.Services
|
|||
var row = rows.FirstOrDefault(x => x.DatabaseId == userReleaseRatings.ReleaseId);
|
||||
if (row != null)
|
||||
{
|
||||
var isDisliked = userReleaseRatings.IsDisliked ?? false;
|
||||
var isFavorite = userReleaseRatings.IsFavorite ?? false;
|
||||
row.UserRating = new UserRelease
|
||||
{
|
||||
IsDisliked = userReleaseRatings.IsDisliked ?? false,
|
||||
IsFavorite = userReleaseRatings.IsFavorite ?? false,
|
||||
Rating = userReleaseRatings.Rating
|
||||
IsDisliked = isDisliked,
|
||||
IsFavorite = isFavorite,
|
||||
Rating = userReleaseRatings.Rating,
|
||||
RatedDate = isDisliked || isFavorite ? (DateTime?)(userReleaseRatings.LastUpdated ?? userReleaseRatings.CreatedDate) : null
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -159,6 +159,21 @@ namespace Roadie.Api.Services
|
|||
}, data.Track.CacheRegionUrn(id));
|
||||
}
|
||||
|
||||
protected ApplicationUser GetUser(string username)
|
||||
{
|
||||
if (string.IsNullOrEmpty(username))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var userByUsername = this.CacheManager.Get(ApplicationUser.CacheUrnByUsername(username), () =>
|
||||
{
|
||||
return this.DbContext.Users
|
||||
.FirstOrDefault(x => x.UserName == username);
|
||||
|
||||
}, null);
|
||||
return this.GetUser(userByUsername?.RoadieId);
|
||||
}
|
||||
|
||||
protected ApplicationUser GetUser(Guid? id)
|
||||
{
|
||||
if(!id.HasValue)
|
||||
|
|
|
@ -5,6 +5,7 @@ using Roadie.Library.Configuration;
|
|||
using Roadie.Library.Encoding;
|
||||
using Roadie.Library.Extensions;
|
||||
using Roadie.Library.Imaging;
|
||||
using Roadie.Library.Models.Releases;
|
||||
using Roadie.Library.Models.Users;
|
||||
using Roadie.Library.Utility;
|
||||
using System;
|
||||
|
@ -28,6 +29,8 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
public const string SubsonicVersion = "1.16.1";
|
||||
|
||||
private IReleaseService ReleaseService { get; }
|
||||
|
||||
public SubsonicService(IRoadieSettings configuration,
|
||||
IHttpEncoder httpEncoder,
|
||||
IHttpContext httpContext,
|
||||
|
@ -35,9 +38,11 @@ namespace Roadie.Api.Services
|
|||
ICacheManager cacheManager,
|
||||
ILogger<SubsonicService> logger,
|
||||
ICollectionService collectionService,
|
||||
IPlaylistService playlistService)
|
||||
IPlaylistService playlistService,
|
||||
IReleaseService releaseService)
|
||||
: base(configuration, httpEncoder, context, cacheManager, logger, httpContext)
|
||||
{
|
||||
this.ReleaseService = releaseService;
|
||||
}
|
||||
|
||||
public OperationResult<subsonic.Response> Ping(subsonic.Request request)
|
||||
|
@ -348,6 +353,7 @@ namespace Roadie.Api.Services
|
|||
genre = genre != null ? genre.Genre.Name : null,
|
||||
coverArt = subsonic.Request.ReleaseIdIdentifier + r.RoadieId.ToString(),
|
||||
created = collection.CreatedDate,
|
||||
path = $"{ r.Artist.Name}/{ r.Title}/",
|
||||
playCount = playCount ?? 0
|
||||
}).ToArray();
|
||||
|
||||
|
@ -480,12 +486,12 @@ namespace Roadie.Api.Services
|
|||
}
|
||||
else if(!string.IsNullOrEmpty(request.u))
|
||||
{
|
||||
var userByUsername = this.DbContext.Users.FirstOrDefault(x => x.UserName == request.u);
|
||||
if(userByUsername == null)
|
||||
var user = this.GetUser(request.u);
|
||||
if(user == null)
|
||||
{
|
||||
return new FileOperationResult<Roadie.Library.Models.Image>(true, $"Invalid Username [{ request.u}]");
|
||||
}
|
||||
result.Data.Bytes = userByUsername.Avatar;
|
||||
result.Data.Bytes = user.Avatar;
|
||||
}
|
||||
|
||||
if (size.HasValue && result.Data.Bytes != null)
|
||||
|
@ -508,5 +514,82 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<subsonic.Response>> GetAlbumList(subsonic.Request request, User roadieUser)
|
||||
{
|
||||
var releaseResult = new Library.Models.Pagination.PagedResult<ReleaseList>();
|
||||
|
||||
switch (request.Type)
|
||||
{
|
||||
case subsonic.ListType.Random:
|
||||
releaseResult = await this.ReleaseService.List(roadieUser, request.PagedRequest, true);
|
||||
break;
|
||||
case subsonic.ListType.Highest:
|
||||
case subsonic.ListType.Recent:
|
||||
case subsonic.ListType.Newest:
|
||||
case subsonic.ListType.Frequent:
|
||||
releaseResult = await this.ReleaseService.List(roadieUser, request.PagedRequest);
|
||||
break;
|
||||
break;
|
||||
case subsonic.ListType.AlphabeticalByName:
|
||||
break;
|
||||
case subsonic.ListType.AlphabeticalByArtist:
|
||||
break;
|
||||
case subsonic.ListType.Starred:
|
||||
releaseResult = await this.ReleaseService.List(roadieUser, request.PagedRequest);
|
||||
break;
|
||||
case subsonic.ListType.ByYear:
|
||||
break;
|
||||
case subsonic.ListType.ByGenre:
|
||||
break;
|
||||
default:
|
||||
return new OperationResult<subsonic.Response>($"Unknown Album List Type [{ request.Type}]");
|
||||
}
|
||||
|
||||
if(!releaseResult.IsSuccess)
|
||||
{
|
||||
return new OperationResult<subsonic.Response>(releaseResult.Message);
|
||||
}
|
||||
|
||||
var albums = releaseResult.Rows.Select(r => new subsonic.Child
|
||||
{
|
||||
id = subsonic.Request.ReleaseIdIdentifier + r.Id.ToString(),
|
||||
parent = subsonic.Request.ArtistIdIdentifier + r.Artist.Value,
|
||||
isDir = true,
|
||||
title = r.Release.Text,
|
||||
album = r.Release.Text,
|
||||
albumId = subsonic.Request.ReleaseIdIdentifier + r.Id.ToString(),
|
||||
artist = r.Artist.Text,
|
||||
year = SafeParser.ToNumber<int>(r.ReleaseYear),
|
||||
// genre = r.Genre.Text,
|
||||
coverArt = subsonic.Request.ReleaseIdIdentifier + r.Id.ToString(),
|
||||
averageRating = r.Rating ?? 0,
|
||||
averageRatingSpecified = true,
|
||||
created = r.CreatedDate.Value,
|
||||
createdSpecified = true,
|
||||
path = $"{ r.Artist.Text}/{ r.Release.Text}/",
|
||||
playCount = r.TrackPlayedCount ?? 0,
|
||||
playCountSpecified = true,
|
||||
starred = r.UserRating != null ? (r.UserRating.IsFavorite ? r.UserRating.RatedDate : null) : null,
|
||||
userRating = r.UserRating != null ? r.UserRating.Rating ?? 0 : 0,
|
||||
userRatingSpecified = r.UserRating != null && r.UserRating.Rating != null
|
||||
}).ToArray();
|
||||
|
||||
return new OperationResult<subsonic.Response>
|
||||
{
|
||||
IsSuccess = true,
|
||||
Data = new subsonic.Response
|
||||
{
|
||||
version = SubsonicService.SubsonicVersion,
|
||||
status = subsonic.ResponseStatus.ok,
|
||||
ItemElementName = subsonic.ItemChoiceType.albumList,
|
||||
Item = new subsonic.AlbumList
|
||||
{
|
||||
album = albums
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -16,6 +16,11 @@ namespace Roadie.Library.Identity
|
|||
return $"urn:user_by_id:{ Id }";
|
||||
}
|
||||
|
||||
public static string CacheUrnByUsername(string Username)
|
||||
{
|
||||
return $"urn:user_by_username:{ Username }";
|
||||
}
|
||||
|
||||
public string CacheRegion
|
||||
{
|
||||
get
|
||||
|
@ -24,6 +29,14 @@ namespace Roadie.Library.Identity
|
|||
}
|
||||
}
|
||||
|
||||
public string CacheKeyByUsername
|
||||
{
|
||||
get
|
||||
{
|
||||
return ApplicationUser.CacheUrnByUsername(this.UserName);
|
||||
}
|
||||
}
|
||||
|
||||
public string CacheKey
|
||||
{
|
||||
get
|
||||
|
|
|
@ -89,6 +89,7 @@ namespace Roadie.Library.Models.Pagination
|
|||
public Guid? FilterToArtistId { get; set; }
|
||||
|
||||
public int? FilterMinimumRating { get; set; }
|
||||
public bool FilterRatedOnly { get; internal set; }
|
||||
|
||||
public PagedRequest()
|
||||
{ }
|
||||
|
|
|
@ -44,5 +44,7 @@ namespace Roadie.Library.Models.Releases
|
|||
public int? TrackPlayedCount { get; set; }
|
||||
public UserRelease UserRating { get; set; }
|
||||
public Statuses? Status { get; set; }
|
||||
public DataToken Genre { get; set; }
|
||||
public DateTime? LastPlayed { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
21
RoadieLibrary/Models/ThirdPartyApi/Subsonic/ListType.cs
Normal file
21
RoadieLibrary/Models/ThirdPartyApi/Subsonic/ListType.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Roadie.Library.Models.ThirdPartyApi.Subsonic
|
||||
{
|
||||
public enum ListType : short
|
||||
{
|
||||
Unknown = 0,
|
||||
Random,
|
||||
Newest,
|
||||
Highest,
|
||||
Frequent,
|
||||
Recent,
|
||||
AlphabeticalByName,
|
||||
AlphabeticalByArtist,
|
||||
Starred,
|
||||
ByYear,
|
||||
ByGenre
|
||||
}
|
||||
}
|
|
@ -7,6 +7,8 @@ namespace Roadie.Library.Models.ThirdPartyApi.Subsonic
|
|||
[Serializable]
|
||||
public class Request
|
||||
{
|
||||
public const int MaxPageSize = 500;
|
||||
|
||||
public const string ArtistIdIdentifier = "A:";
|
||||
public const string CollectionIdentifier = "C:";
|
||||
public const string ReleaseIdIdentifier = "R:";
|
||||
|
@ -159,6 +161,112 @@ namespace Roadie.Library.Models.ThirdPartyApi.Subsonic
|
|||
}
|
||||
}
|
||||
|
||||
public Guid? TrackId
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(this.id))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (this.id.StartsWith(Request.TrackIdIdentifier))
|
||||
{
|
||||
return SafeParser.ToGuid(this.id.Replace(Request.TrackIdIdentifier, ""));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#region Paging and List Related
|
||||
|
||||
/// <summary>
|
||||
/// The number of albums to return. Max 500.
|
||||
/// </summary>
|
||||
public int? Size { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list offset. Useful if you for example want to page through the list of newest albums.
|
||||
/// </summary>
|
||||
public int? Offset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The first year in the range. If fromYear > toYear a reverse chronological list is returned.
|
||||
/// </summary>
|
||||
public int? FromYear { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The last year in the range.
|
||||
/// </summary>
|
||||
public int? ToYear { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of the genre, e.g., "Rock".
|
||||
/// </summary>
|
||||
public string Genre { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Only return albums in the music folder with the given ID. See getMusicFolders.
|
||||
/// </summary>
|
||||
public int? MusicFolderId { get; set; }
|
||||
|
||||
public ListType Type { get; set; }
|
||||
|
||||
//var pagedRequest = new Library.Models.Pagination.PagedRequest
|
||||
//{
|
||||
|
||||
//};
|
||||
|
||||
private Library.Models.Pagination.PagedRequest _pagedRequest;
|
||||
|
||||
public Library.Models.Pagination.PagedRequest PagedRequest
|
||||
{
|
||||
get
|
||||
{
|
||||
if(this._pagedRequest == null)
|
||||
{
|
||||
var limit = this.Size ?? Request.MaxPageSize;
|
||||
var page = this.Offset > 0 ? (int)Math.Ceiling((decimal)this.Offset.Value / (decimal)limit) : 1;
|
||||
var pagedRequest = new Pagination.PagedRequest();
|
||||
switch (this.Type)
|
||||
{
|
||||
case ListType.Newest:
|
||||
pagedRequest.Sort = "CreatedDate";
|
||||
pagedRequest.Order = "DESC";
|
||||
break;
|
||||
case ListType.Highest:
|
||||
pagedRequest.Sort = "Rating";
|
||||
pagedRequest.Order = "DESC";
|
||||
pagedRequest.FilterRatedOnly = true;
|
||||
break;
|
||||
case ListType.Frequent:
|
||||
pagedRequest.Sort = "TrackPlayedCount";
|
||||
pagedRequest.Order = "DESC";
|
||||
break;
|
||||
case ListType.Recent:
|
||||
pagedRequest.Sort = "LastPlayed";
|
||||
pagedRequest.Order = "DESC";
|
||||
break;
|
||||
case ListType.AlphabeticalByName:
|
||||
break;
|
||||
case ListType.AlphabeticalByArtist:
|
||||
break;
|
||||
case ListType.Starred:
|
||||
pagedRequest.FilterRatedOnly = true;
|
||||
break;
|
||||
case ListType.ByGenre:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
pagedRequest.Limit = limit;
|
||||
pagedRequest.Page = page;
|
||||
this._pagedRequest = pagedRequest;
|
||||
}
|
||||
return this._pagedRequest;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
//public user CheckPasswordGetUser(ICacheManager<object> cacheManager, RoadieDbContext context)
|
||||
|
|
|
@ -8,5 +8,6 @@ namespace Roadie.Library.Models.Users
|
|||
public bool IsDisliked { get; set; }
|
||||
public bool IsFavorite { get; set; }
|
||||
public short? Rating { get; set; }
|
||||
public DateTime? RatedDate { get; set; }
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue