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
e893532680
commit
aaba240a53
10 changed files with 455 additions and 33 deletions
|
@ -7,6 +7,7 @@ using Roadie.Api.Services;
|
|||
using Roadie.Library.Caching;
|
||||
using Roadie.Library.Identity;
|
||||
using Roadie.Library.Models.ThirdPartyApi.Subsonic;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Roadie.Api.Controllers
|
||||
|
@ -42,6 +43,15 @@ namespace Roadie.Api.Controllers
|
|||
return this.BuildResponse(request, result.Data, "musicFolders");
|
||||
}
|
||||
|
||||
[HttpGet("getMusicDirectory.view")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> GetMusicDirectory([FromQuery]Request request, string id)
|
||||
{
|
||||
var result = await this.SubsonicService.GetMusicDirectory(request, null, id);
|
||||
return this.BuildResponse(request, result.Data, "directory");
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("getPlaylists.view")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> GetPlaylists([FromQuery]Request request, string username)
|
||||
|
@ -50,6 +60,43 @@ namespace Roadie.Api.Controllers
|
|||
return this.BuildResponse(request, result.Data, "playlists");
|
||||
}
|
||||
|
||||
[HttpGet("getGenres.view")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> GetGenres([FromQuery]Request request)
|
||||
{
|
||||
var result = await this.SubsonicService.GetGenres(request);
|
||||
return this.BuildResponse(request, result.Data, "genres");
|
||||
}
|
||||
|
||||
[HttpGet("getPodcasts.view")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> GetPodcasts([FromQuery]Request request, bool includeEpisodes)
|
||||
{
|
||||
var result = await this.SubsonicService.GetPodcasts(request);
|
||||
return this.BuildResponse(request, result.Data, "podcasts");
|
||||
}
|
||||
|
||||
[HttpGet("getCoverArt.view")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> GetCoverArt([FromQuery]Request request, int? size)
|
||||
{
|
||||
var result = await this.SubsonicService.GetCoverArt(request, size);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return File(fileContents: result.Data.Bytes,
|
||||
contentType: result.ContentType,
|
||||
fileDownloadName: $"{ result.Data.Caption ?? request.id.ToString()}.jpg",
|
||||
lastModified: result.LastModified,
|
||||
entityTag: result.ETag);
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("ping.view")]
|
||||
[HttpPost("ping.view")]
|
||||
[ProducesResponseType(200)]
|
||||
|
|
|
@ -16,6 +16,10 @@ namespace Roadie.Api.Services
|
|||
|
||||
Task<OperationResult<Response>> GetPodcasts(Request request);
|
||||
|
||||
Task<OperationResult<Response>> GetMusicDirectory(Request request, Roadie.Library.Models.Users.User roadieUser, string id);
|
||||
|
||||
Task<FileOperationResult<Roadie.Library.Models.Image>> GetCoverArt(Request request, int? size);
|
||||
|
||||
OperationResult<Response> Ping(Request request);
|
||||
}
|
||||
}
|
|
@ -60,7 +60,7 @@ namespace Roadie.Api.Services
|
|||
},
|
||||
User = new DataToken
|
||||
{
|
||||
Text = u.Username,
|
||||
Text = u.UserName,
|
||||
Value = u.RoadieId.ToString()
|
||||
},
|
||||
PlaylistCount = this.DbContext.PlaylistTracks.Where(x => x.PlayListId == pl.Id).Count(),
|
||||
|
|
|
@ -1,17 +1,10 @@
|
|||
using Mapster;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Roadie.Library;
|
||||
using Roadie.Library.Caching;
|
||||
using Roadie.Library.Configuration;
|
||||
using Roadie.Library.Encoding;
|
||||
using Roadie.Library.Enums;
|
||||
using Roadie.Library.Extensions;
|
||||
using Roadie.Library.Models;
|
||||
using Roadie.Library.Models.Pagination;
|
||||
using Roadie.Library.Models.Releases;
|
||||
using Roadie.Library.Models.Statistics;
|
||||
using subsonic = Roadie.Library.Models.ThirdPartyApi.Subsonic;
|
||||
using Roadie.Library.Imaging;
|
||||
using Roadie.Library.Models.Users;
|
||||
using Roadie.Library.Utility;
|
||||
using System;
|
||||
|
@ -21,6 +14,7 @@ using System.Linq;
|
|||
using System.Linq.Dynamic.Core;
|
||||
using System.Threading.Tasks;
|
||||
using data = Roadie.Library.Data;
|
||||
using subsonic = Roadie.Library.Models.ThirdPartyApi.Subsonic;
|
||||
|
||||
namespace Roadie.Api.Services
|
||||
{
|
||||
|
@ -32,8 +26,6 @@ namespace Roadie.Api.Services
|
|||
/// </summary>
|
||||
public class SubsonicService : ServiceBase, ISubsonicService
|
||||
{
|
||||
public const string ArtistIdIdentifier = "A:";
|
||||
public const string CollectionIdentifier = "C:";
|
||||
public const string SubsonicVersion = "1.16.1";
|
||||
|
||||
public SubsonicService(IRoadieSettings configuration,
|
||||
|
@ -58,7 +50,7 @@ namespace Roadie.Api.Services
|
|||
version = SubsonicService.SubsonicVersion,
|
||||
status = subsonic.ResponseStatus.ok
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -104,12 +96,12 @@ namespace Roadie.Api.Services
|
|||
/// <param name="ifModifiedSince">If specified, only return a result if the artist collection has changed since the given time (in milliseconds since 1 Jan 1970).</param>
|
||||
public async Task<OperationResult<subsonic.Response>> GetIndexes(subsonic.Request request, string musicFolderId = null, long? ifModifiedSince = null)
|
||||
{
|
||||
|
||||
|
||||
var modifiedSinceFilter = ifModifiedSince.HasValue ? (DateTime?)ifModifiedSince.Value.FromUnixTime() : null;
|
||||
subsonic.MusicFolder musicFolderFilter = string.IsNullOrEmpty(musicFolderId) ? null : this.MusicFolders().FirstOrDefault(x => x.id == SafeParser.ToNumber<int>(musicFolderId));
|
||||
subsonic.MusicFolder musicFolderFilter = string.IsNullOrEmpty(musicFolderId) ? new subsonic.MusicFolder() : this.MusicFolders().FirstOrDefault(x => x.id == SafeParser.ToNumber<int>(musicFolderId));
|
||||
var indexes = new List<subsonic.Index>();
|
||||
|
||||
if (musicFolderFilter == this.CollectionMusicFolder())
|
||||
if (musicFolderFilter.id == this.CollectionMusicFolder().id)
|
||||
{
|
||||
// Collections for Music Folders by Alpha First
|
||||
foreach (var collectionFirstLetter in (from c in this.DbContext.Collections
|
||||
|
@ -126,7 +118,7 @@ namespace Roadie.Api.Services
|
|||
orderby c.SortName, c.Name
|
||||
select new subsonic.Artist
|
||||
{
|
||||
id = SubsonicService.CollectionIdentifier + c.RoadieId.ToString(),
|
||||
id = subsonic.Request.CollectionIdentifier + c.RoadieId.ToString(),
|
||||
name = c.Name,
|
||||
artistImageUrl = this.MakeCollectionThumbnailImage(c.RoadieId).Url,
|
||||
averageRating = 0,
|
||||
|
@ -152,7 +144,7 @@ namespace Roadie.Api.Services
|
|||
orderby c.SortName, c.Name
|
||||
select new subsonic.Artist
|
||||
{
|
||||
id = SubsonicService.ArtistIdIdentifier + c.RoadieId.ToString(),
|
||||
id = subsonic.Request.ArtistIdIdentifier + c.RoadieId.ToString(),
|
||||
name = c.Name,
|
||||
artistImageUrl = this.MakeArtistThumbnailImage(c.RoadieId).Url,
|
||||
averageRating = 0,
|
||||
|
@ -194,7 +186,7 @@ namespace Roadie.Api.Services
|
|||
id = playlist.RoadieId.ToString(),
|
||||
name = playlist.Name,
|
||||
comment = playlist.Description,
|
||||
owner = u.Username,
|
||||
owner = u.UserName,
|
||||
songCount = trackCount,
|
||||
duration = playListDuration ?? 0,
|
||||
created = playlist.CreatedDate,
|
||||
|
@ -223,7 +215,36 @@ namespace Roadie.Api.Services
|
|||
|
||||
public async Task<OperationResult<subsonic.Response>> GetGenres(subsonic.Request request)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var genres = (from g in this.DbContext.Genres
|
||||
let albumCount = (from rg in this.DbContext.ReleaseGenres
|
||||
where rg.GenreId == g.Id
|
||||
select rg.Id).Count()
|
||||
let songCount = (from rg in this.DbContext.ReleaseGenres
|
||||
join rm in this.DbContext.ReleaseMedias on rg.ReleaseId equals rm.ReleaseId
|
||||
join t in this.DbContext.Tracks on rm.ReleaseId equals t.ReleaseMediaId
|
||||
where rg.GenreId == g.Id
|
||||
select t.Id).Count()
|
||||
select new subsonic.Genre
|
||||
{
|
||||
songCount = songCount,
|
||||
albumCount = albumCount,
|
||||
value = g.Name
|
||||
}).OrderBy(x => x.value).ToArray();
|
||||
|
||||
return new OperationResult<subsonic.Response>
|
||||
{
|
||||
IsSuccess = true,
|
||||
Data = new subsonic.Response
|
||||
{
|
||||
version = SubsonicService.SubsonicVersion,
|
||||
status = subsonic.ResponseStatus.ok,
|
||||
ItemElementName = subsonic.ItemChoiceType.genres,
|
||||
Item = new subsonic.Genres
|
||||
{
|
||||
genre = genres.ToArray()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<subsonic.Response>> GetPodcasts(subsonic.Request request)
|
||||
|
@ -241,5 +262,251 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a listing of all files in a music directory. Typically used to get list of albums for an artist, or list of songs for an album.
|
||||
/// </summary>
|
||||
/// <param name="request">Query from application.</param>
|
||||
/// <param name="id">A string which uniquely identifies the music folder. Obtained by calls to getIndexes or getMusicDirectory.</param>
|
||||
/// <returns></returns>
|
||||
public async Task<OperationResult<subsonic.Response>> GetMusicDirectory(subsonic.Request request, User roadieUser, string id)
|
||||
{
|
||||
var directory = new subsonic.Directory();
|
||||
var user = this.GetUser(roadieUser?.UserId);
|
||||
|
||||
// Request to get albums for an Artist
|
||||
if (request.ArtistId != null)
|
||||
{
|
||||
var artist = this.GetArtist(request.ArtistId.Value);
|
||||
if (artist == null)
|
||||
{
|
||||
return new OperationResult<subsonic.Response>(true, $"Invalid ArtistId [{ request.ArtistId}]");
|
||||
}
|
||||
directory.id = subsonic.Request.ArtistIdIdentifier + artist.RoadieId.ToString();
|
||||
directory.name = artist.Name;
|
||||
var artistRating = user?.ArtistRatings?.FirstOrDefault(x => x.ArtistId == artist.Id);
|
||||
directory.starred = artistRating != null ? (DateTime?)(artistRating.LastUpdated ?? artistRating.CreatedDate) : null;
|
||||
directory.child = (from r in this.DbContext.Releases
|
||||
join ur in this.DbContext.UserReleases on r.Id equals ur.ReleaseId into urr
|
||||
from ur in urr.DefaultIfEmpty()
|
||||
let genre = r.Genres.FirstOrDefault()
|
||||
where r.ArtistId == artist.Id
|
||||
select new subsonic.Child
|
||||
{
|
||||
id = subsonic.Request.ReleaseIdIdentifier + r.RoadieId.ToString(),
|
||||
parent = subsonic.Request.ArtistIdIdentifier + artist.RoadieId.ToString(),
|
||||
isDir = true,
|
||||
title = r.Title,
|
||||
album = r.Title,
|
||||
albumId = subsonic.Request.ReleaseIdIdentifier + r.RoadieId.ToString(),
|
||||
artist = artist.Name,
|
||||
year = (r.ReleaseDate ?? r.CreatedDate).Year,
|
||||
genre = genre != null ? genre.Genre.Name : null,
|
||||
coverArt = subsonic.Request.ReleaseIdIdentifier + r.RoadieId.ToString(),
|
||||
averageRating = artist.Rating ?? 0,
|
||||
created = artist.CreatedDate,
|
||||
playCount = (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
|
||||
where rm.ReleaseId == r.Id
|
||||
where ut.PlayedCount != null
|
||||
select ut.PlayedCount ?? 0).Sum(),
|
||||
starred = ur != null ? (ur.IsFavorite ?? false ? (DateTime?)(ur.LastUpdated ?? ur.CreatedDate) : null) : null,
|
||||
}).ToArray();
|
||||
}
|
||||
// Request to get albums for in a Collection
|
||||
else if (request.CollectionId != null)
|
||||
{
|
||||
var collection = this.GetCollection(request.CollectionId.Value);
|
||||
if (collection == null)
|
||||
{
|
||||
return new OperationResult<subsonic.Response>(true, $"Invalid CollectionId [{ request.CollectionId}]");
|
||||
}
|
||||
directory.id = subsonic.Request.CollectionIdentifier + collection.RoadieId.ToString();
|
||||
directory.name = collection.Name;
|
||||
directory.child = (from cr in this.DbContext.CollectionReleases
|
||||
join r in this.DbContext.Releases on cr.ReleaseId equals r.Id
|
||||
join a in this.DbContext.Artists on r.ArtistId equals a.Id
|
||||
join ur in this.DbContext.UserReleases on r.Id equals ur.ReleaseId into urr
|
||||
from ur in urr.DefaultIfEmpty()
|
||||
let genre = r.Genres.FirstOrDefault()
|
||||
let playCount = (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
|
||||
where rm.ReleaseId == r.Id
|
||||
select ut.PlayedCount).Sum()
|
||||
where cr.CollectionId == collection.Id
|
||||
select new subsonic.Child
|
||||
{
|
||||
id = subsonic.Request.ReleaseIdIdentifier + r.RoadieId.ToString(),
|
||||
parent = subsonic.Request.CollectionIdentifier + collection.RoadieId.ToString(),
|
||||
isDir = true,
|
||||
title = r.Title,
|
||||
album = r.Title,
|
||||
albumId = subsonic.Request.ReleaseIdIdentifier + r.RoadieId.ToString(),
|
||||
artist = a.Name,
|
||||
year = (r.ReleaseDate ?? r.CreatedDate).Year,
|
||||
genre = genre != null ? genre.Genre.Name : null,
|
||||
coverArt = subsonic.Request.ReleaseIdIdentifier + r.RoadieId.ToString(),
|
||||
created = collection.CreatedDate,
|
||||
playCount = playCount ?? 0
|
||||
}).ToArray();
|
||||
|
||||
}
|
||||
// Request to get Tracks for an Album
|
||||
else
|
||||
{
|
||||
var release = this.GetRelease(request.ReleaseId.Value);
|
||||
if (release == null)
|
||||
{
|
||||
return new OperationResult<subsonic.Response>(true, $"Invalid ReleaseId [{ request.ReleaseId}]");
|
||||
}
|
||||
directory.id = subsonic.Request.ReleaseIdIdentifier + release.RoadieId.ToString();
|
||||
directory.name = release.Title;
|
||||
var releaseRating = user?.ReleaseRatings?.FirstOrDefault(x => x.ReleaseId == release.Id);
|
||||
directory.averageRating = release.Rating ?? 0;
|
||||
directory.parent = subsonic.Request.ArtistIdIdentifier + release.Artist.RoadieId.ToString();
|
||||
directory.starred = releaseRating != null ? (releaseRating.IsFavorite ?? false ? (DateTime?)(releaseRating.LastUpdated ?? releaseRating.CreatedDate) : null) : null;
|
||||
var releaseTracks = release.Medias.SelectMany(x => x.Tracks);
|
||||
var genre = release.Genres.FirstOrDefault();
|
||||
directory.child = (from t in releaseTracks
|
||||
join ut in this.DbContext.UserTracks on t.Id equals ut.TrackId into utg
|
||||
from ut in utg.DefaultIfEmpty()
|
||||
join rm in this.DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||
let playCount = (from ut in this.DbContext.UserTracks
|
||||
where ut.TrackId == t.Id
|
||||
select ut.PlayedCount).Sum()
|
||||
select new subsonic.Child
|
||||
{
|
||||
id = subsonic.Request.TrackIdIdentifier + t.RoadieId.ToString(),
|
||||
album = release.Title,
|
||||
albumId = subsonic.Request.ReleaseIdIdentifier + release.RoadieId.ToString(),
|
||||
artist = release.Artist.Name,
|
||||
artistId = subsonic.Request.ArtistIdIdentifier + release.Artist.RoadieId.ToString(),
|
||||
averageRating = release.Rating ?? 0,
|
||||
averageRatingSpecified= true,
|
||||
bitRate = 320,
|
||||
bitRateSpecified = true,
|
||||
contentType = "audio/mpeg",
|
||||
coverArt = subsonic.Request.ReleaseIdIdentifier + release.RoadieId.ToString(),
|
||||
created = release.CreatedDate,
|
||||
createdSpecified = true,
|
||||
discNumber = rm.MediaNumber,
|
||||
discNumberSpecified = true,
|
||||
duration = t.Duration.ToSecondsFromMilliseconds(),
|
||||
durationSpecified = true,
|
||||
genre = genre != null ? genre.Genre.Name : null,
|
||||
parent = subsonic.Request.ReleaseIdIdentifier + release.RoadieId.ToString(),
|
||||
path = $"{ release.Artist.Name}/{ release.Title}/{ t.TrackNumber } - { t.Title }.mp3",
|
||||
playCountSpecified = true,
|
||||
size = t.FileSize ?? 0,
|
||||
sizeSpecified = true,
|
||||
starred = ut != null ? (ut.IsFavorite ?? false ? (DateTime?)(ut.LastUpdated ?? ut.CreatedDate) : null) : null,
|
||||
starredSpecified = ut != null,
|
||||
suffix = "mp3",
|
||||
title = t.Title,
|
||||
track = t.TrackNumber,
|
||||
trackSpecified = true,
|
||||
type = subsonic.MediaType.music,
|
||||
typeSpecified = true,
|
||||
userRating = ut != null ? ut.Rating : 0,
|
||||
userRatingSpecified = ut != null,
|
||||
year = (release.ReleaseDate ?? release.CreatedDate).Year,
|
||||
yearSpecified = true,
|
||||
playCount = (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
|
||||
where rm.ReleaseId == release.Id
|
||||
where ut.PlayedCount != null
|
||||
select ut.PlayedCount ?? 0).Sum(),
|
||||
}).ToArray();
|
||||
directory.playCount = directory.child.Select(x => x.playCount).Sum();
|
||||
}
|
||||
return new OperationResult<subsonic.Response>
|
||||
{
|
||||
IsSuccess = true,
|
||||
Data = new subsonic.Response
|
||||
{
|
||||
version = SubsonicService.SubsonicVersion,
|
||||
status = subsonic.ResponseStatus.ok,
|
||||
ItemElementName = subsonic.ItemChoiceType.directory,
|
||||
Item = directory
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<FileOperationResult<Roadie.Library.Models.Image>> GetCoverArt(subsonic.Request request, int? size)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
var result = new FileOperationResult<Roadie.Library.Models.Image>
|
||||
{
|
||||
Data = new Roadie.Library.Models.Image()
|
||||
};
|
||||
|
||||
if (request.ArtistId != null)
|
||||
{
|
||||
var artist = this.GetArtist(request.ArtistId.Value);
|
||||
if (artist == null)
|
||||
{
|
||||
return new FileOperationResult<Roadie.Library.Models.Image>(true, $"Invalid ArtistId [{ request.ArtistId}]");
|
||||
}
|
||||
result.Data.Bytes = artist.Thumbnail;
|
||||
}
|
||||
else if(request.CollectionId != null)
|
||||
{
|
||||
var collection = this.GetCollection(request.CollectionId.Value);
|
||||
if (collection == null)
|
||||
{
|
||||
return new FileOperationResult<Roadie.Library.Models.Image>(true, $"Invalid CollectionId [{ request.CollectionId}]");
|
||||
}
|
||||
result.Data.Bytes = collection.Thumbnail;
|
||||
}
|
||||
else if(request.ReleaseId != null)
|
||||
{
|
||||
var release = this.GetRelease(request.ReleaseId.Value);
|
||||
if (release == null)
|
||||
{
|
||||
return new FileOperationResult<Roadie.Library.Models.Image>(true, $"Invalid ReleaseId [{ request.ReleaseId}]");
|
||||
}
|
||||
result.Data.Bytes = release.Thumbnail;
|
||||
}
|
||||
else if (request.PlaylistId != null)
|
||||
{
|
||||
var playlist = this.GetPlaylist(request.PlaylistId.Value);
|
||||
if (playlist == null)
|
||||
{
|
||||
return new FileOperationResult<Roadie.Library.Models.Image>(true, $"Invalid PlaylistId [{ request.PlaylistId}]");
|
||||
}
|
||||
result.Data.Bytes = playlist.Thumbnail;
|
||||
}
|
||||
else if(!string.IsNullOrEmpty(request.u))
|
||||
{
|
||||
var userByUsername = this.DbContext.Users.FirstOrDefault(x => x.UserName == request.u);
|
||||
if(userByUsername == null)
|
||||
{
|
||||
return new FileOperationResult<Roadie.Library.Models.Image>(true, $"Invalid Username [{ request.u}]");
|
||||
}
|
||||
result.Data.Bytes = userByUsername.Avatar;
|
||||
}
|
||||
|
||||
if (size.HasValue && result.Data.Bytes != null)
|
||||
{
|
||||
result.Data.Bytes = ImageHelper.ResizeImage(result.Data.Bytes, size.Value, size.Value);
|
||||
result.ETag = EtagHelper.GenerateETag(this.HttpEncoder, result.Data.Bytes);
|
||||
result.LastModified = DateTime.UtcNow;
|
||||
}
|
||||
result.IsSuccess = true;
|
||||
sw.Stop();
|
||||
return new FileOperationResult<Roadie.Library.Models.Image>(result.Messages)
|
||||
{
|
||||
Data = result.Data,
|
||||
ETag = result.ETag,
|
||||
LastModified = result.LastModified,
|
||||
ContentType = "image/jpeg",
|
||||
Errors = result?.Errors,
|
||||
IsSuccess = result?.IsSuccess ?? false,
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -46,7 +46,7 @@ namespace Roadie.Api.Services
|
|||
}
|
||||
|
||||
var result = (from u in this.DbContext.Users
|
||||
where (request.FilterValue.Length == 0 || (request.FilterValue.Length > 0 && (u.Username.Contains(request.FilterValue))))
|
||||
where (request.FilterValue.Length == 0 || (request.FilterValue.Length > 0 && (u.UserName.Contains(request.FilterValue))))
|
||||
select new UserList
|
||||
{
|
||||
DatabaseId = u.Id,
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
namespace Roadie.Library.Extensions
|
||||
using System;
|
||||
|
||||
namespace Roadie.Library.Extensions
|
||||
{
|
||||
public static class IntEx
|
||||
{
|
||||
|
@ -10,5 +12,15 @@
|
|||
}
|
||||
return value.HasValue ? value : alternative;
|
||||
}
|
||||
|
||||
public static int ToSecondsFromMilliseconds(this int? value)
|
||||
{
|
||||
if (value > 0)
|
||||
{
|
||||
var contentDurationTimeSpan = TimeSpan.FromMilliseconds((double)(value ?? 0));
|
||||
return (int)contentDurationTimeSpan.TotalSeconds;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -120,10 +120,10 @@ namespace Roadie.Library.Identity
|
|||
|
||||
public ICollection<UserTrack> TrackRatings { get; set; }
|
||||
|
||||
[Column("username")]
|
||||
[Required]
|
||||
[StringLength(20)]
|
||||
public string Username { get; set; }
|
||||
//[Column("username")]
|
||||
//[Required]
|
||||
//[StringLength(20)]
|
||||
//public string UserName { get; set; }
|
||||
|
||||
public virtual ICollection<ApplicationUserRole> UserRoles { get; set; }
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Roadie.Library.Extensions;
|
||||
using Roadie.Library.Utility;
|
||||
using System;
|
||||
|
||||
namespace Roadie.Library.Models.ThirdPartyApi.Subsonic
|
||||
|
@ -6,6 +7,12 @@ namespace Roadie.Library.Models.ThirdPartyApi.Subsonic
|
|||
[Serializable]
|
||||
public class Request
|
||||
{
|
||||
public const string ArtistIdIdentifier = "A:";
|
||||
public const string CollectionIdentifier = "C:";
|
||||
public const string ReleaseIdIdentifier = "R:";
|
||||
public const string TrackIdIdentifier = "T:";
|
||||
public const string PlaylistdIdentifier = "P:";
|
||||
|
||||
/// <summary>
|
||||
/// A unique string identifying the client application.
|
||||
/// </summary>
|
||||
|
@ -83,6 +90,77 @@ namespace Roadie.Library.Models.ThirdPartyApi.Subsonic
|
|||
/// </summary>
|
||||
public string v { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A string which uniquely identifies the music folder. Obtained by calls to getIndexes or getMusicDirectory.
|
||||
/// </summary>
|
||||
public string id { get; set; }
|
||||
|
||||
public Guid? ArtistId
|
||||
{
|
||||
get
|
||||
{
|
||||
if(string.IsNullOrEmpty(this.id))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if(this.id.StartsWith(Request.ArtistIdIdentifier))
|
||||
{
|
||||
return SafeParser.ToGuid(this.id.Replace(Request.ArtistIdIdentifier, ""));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Guid? CollectionId
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(this.id))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (this.id.StartsWith(Request.CollectionIdentifier))
|
||||
{
|
||||
return SafeParser.ToGuid(this.id.Replace(Request.CollectionIdentifier, ""));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Guid? ReleaseId
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(this.id))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (this.id.StartsWith(Request.ReleaseIdIdentifier))
|
||||
{
|
||||
return SafeParser.ToGuid(this.id.Replace(Request.ReleaseIdIdentifier, ""));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Guid? PlaylistId
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(this.id))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (this.id.StartsWith(Request.PlaylistdIdentifier))
|
||||
{
|
||||
return SafeParser.ToGuid(this.id.Replace(Request.PlaylistdIdentifier, ""));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//public user CheckPasswordGetUser(ICacheManager<object> cacheManager, RoadieDbContext context)
|
||||
//{
|
||||
// user user = null;
|
||||
|
|
|
@ -161,7 +161,7 @@ namespace Roadie.Library.Models.ThirdPartyApi.Subsonic
|
|||
|
||||
/// <remarks/>
|
||||
[System.Xml.Serialization.XmlAttributeAttribute()]
|
||||
public long size;
|
||||
public int size;
|
||||
|
||||
/// <remarks/>
|
||||
[System.Xml.Serialization.XmlIgnoreAttribute()]
|
||||
|
@ -221,7 +221,7 @@ namespace Roadie.Library.Models.ThirdPartyApi.Subsonic
|
|||
|
||||
/// <remarks/>
|
||||
[System.Xml.Serialization.XmlAttributeAttribute()]
|
||||
public double averageRating;
|
||||
public short averageRating;
|
||||
|
||||
/// <remarks/>
|
||||
[System.Xml.Serialization.XmlIgnoreAttribute()]
|
||||
|
@ -229,7 +229,7 @@ namespace Roadie.Library.Models.ThirdPartyApi.Subsonic
|
|||
|
||||
/// <remarks/>
|
||||
[System.Xml.Serialization.XmlAttributeAttribute()]
|
||||
public long playCount;
|
||||
public int playCount;
|
||||
|
||||
/// <remarks/>
|
||||
[System.Xml.Serialization.XmlIgnoreAttribute()]
|
||||
|
@ -253,7 +253,7 @@ namespace Roadie.Library.Models.ThirdPartyApi.Subsonic
|
|||
|
||||
/// <remarks/>
|
||||
[System.Xml.Serialization.XmlAttributeAttribute()]
|
||||
public System.DateTime starred;
|
||||
public System.DateTime? starred;
|
||||
|
||||
/// <remarks/>
|
||||
[System.Xml.Serialization.XmlIgnoreAttribute()]
|
||||
|
@ -1688,7 +1688,7 @@ namespace Roadie.Library.Models.ThirdPartyApi.Subsonic
|
|||
|
||||
/// <remarks/>
|
||||
[System.Xml.Serialization.XmlTextAttribute()]
|
||||
public string[] Text;
|
||||
public string value;
|
||||
}
|
||||
|
||||
/// <remarks/>
|
||||
|
@ -1718,7 +1718,7 @@ namespace Roadie.Library.Models.ThirdPartyApi.Subsonic
|
|||
|
||||
/// <remarks/>
|
||||
[System.Xml.Serialization.XmlAttributeAttribute()]
|
||||
public System.DateTime starred;
|
||||
public System.DateTime? starred;
|
||||
|
||||
/// <remarks/>
|
||||
[System.Xml.Serialization.XmlIgnoreAttribute()]
|
||||
|
@ -1734,7 +1734,7 @@ namespace Roadie.Library.Models.ThirdPartyApi.Subsonic
|
|||
|
||||
/// <remarks/>
|
||||
[System.Xml.Serialization.XmlAttributeAttribute()]
|
||||
public double averageRating;
|
||||
public short averageRating;
|
||||
|
||||
/// <remarks/>
|
||||
[System.Xml.Serialization.XmlIgnoreAttribute()]
|
||||
|
|
|
@ -59,6 +59,20 @@ namespace Roadie.Library.Utility
|
|||
}
|
||||
}
|
||||
|
||||
public static Guid? ToGuid(object input)
|
||||
{
|
||||
if(input == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (!Guid.TryParse(input.ToString(), out Guid result))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public static DateTime? ToDateTime(object input)
|
||||
{
|
||||
if (input == null)
|
||||
|
|
Loading…
Reference in a new issue