Changed image handling added more Subsonic work.

This commit is contained in:
Steven Hildreth 2018-11-21 09:22:55 -06:00
parent 7655d16561
commit 0fdff8ea10
19 changed files with 292 additions and 93 deletions

View file

@ -5,18 +5,22 @@
"DiagnosticsPassword": "RoadieDiagPassword",
"InboundFolder": "Z:/incoming/",
"LibraryFolder": "Z:/library/",
"Thumbnails": {
"ThumbnailImageSize": {
"Height": 80,
"Width": 80
},
"MediumThumbnails": {
"SmallImageSize": {
"Height": 160,
"Width": 160
},
"LargeThumbnails": {
"MediumImageSize": {
"Height": 320,
"Width": 320
},
"LargeImageSize": {
"Height": 500,
"Width": 500
},
"DontDoMetaDataProvidersSearchArtists": [ "Various Artists", "Sound Tracks" ],
"FileExtenionsToDelete": [ ".cue", ".db", ".gif", ".html", ".ini", ".jpg", ".jpeg", ".log", ".mpg", ".m3u", ".png", ".nfo", ".nzb", ".sfv", ".srr", ".txt", ".url" ],
"RecordNoResultSearches": true,
@ -63,7 +67,7 @@
"DoParseFromLastFM": true,
"MaximumArtistImagesToAdd": 12,
"MaximumReleaseImagesToAdd": 12,
"MaxImageWidth": 800,
"MaxImageWidth": 800,
"RemoveStringsRegex": "\\b[0-9]+\\s#\\s\\b",
"ReplaceStrings": [
{

View file

@ -33,12 +33,12 @@ namespace Roadie.Api.Controllers
// return Ok(this._RoadieDbContext.Tracks.ProjectToType<models.Image>());
//}
[HttpGet("thumbnail/artist/{id}/{width:int?}/{height:int?}")]
[HttpGet("artist/{id}/{width:int?}/{height:int?}")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public async Task<IActionResult> ArtistThumbnail(Guid id, int? width, int? height)
{
var result = await this.ImageService.ArtistThumbnail(id, width ?? this.RoadieSettings.Thumbnails.Width, height ?? this.RoadieSettings.Thumbnails.Height);
var result = await this.ImageService.ArtistImage(id, width ?? this.RoadieSettings.ThumbnailImageSize.Width, height ?? this.RoadieSettings.ThumbnailImageSize.Height);
if (result == null || result.IsNotFoundResult)
{
return NotFound();
@ -54,12 +54,13 @@ namespace Roadie.Api.Controllers
entityTag: result.ETag);
}
[HttpGet("thumbnail/collection/{id}/{width:int?}/{height:int?}")]
[HttpGet("collection/{id}/{width:int?}/{height:int?}")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public async Task<IActionResult> CollectionThumbnail(Guid id, int? width, int? height)
{
var result = await this.ImageService.CollectionThumbnail(id, width ?? this.RoadieSettings.Thumbnails.Width, height ?? this.RoadieSettings.Thumbnails.Height);
var result = await this.ImageService.CollectionImage(id, width ?? this.RoadieSettings.ThumbnailImageSize.Width, height ?? this.RoadieSettings.ThumbnailImageSize.Height);
if (result == null || result.IsNotFoundResult)
{
return NotFound();
@ -113,12 +114,12 @@ namespace Roadie.Api.Controllers
entityTag: result.ETag);
}
[HttpGet("thumbnail/label/{id}/{width:int?}/{height:int?}")]
[HttpGet("label/{id}/{width:int?}/{height:int?}")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public async Task<IActionResult> LabelThumbnail(Guid id, int? width, int? height)
{
var result = await this.ImageService.LabelThumbnail(id, width ?? this.RoadieSettings.Thumbnails.Width, height ?? this.RoadieSettings.Thumbnails.Height);
var result = await this.ImageService.LabelImage(id, width ?? this.RoadieSettings.ThumbnailImageSize.Width, height ?? this.RoadieSettings.ThumbnailImageSize.Height);
if (result == null || result.IsNotFoundResult)
{
return NotFound();
@ -134,12 +135,12 @@ namespace Roadie.Api.Controllers
entityTag: result.ETag);
}
[HttpGet("thumbnail/playlist/{id}/{width:int?}/{height:int?}")]
[HttpGet("playlist/{id}/{width:int?}/{height:int?}")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public async Task<IActionResult> PlaylistThumbnail(Guid id, int? width, int? height)
{
var result = await this.ImageService.PlaylistThumbnail(id, width ?? this.RoadieSettings.Thumbnails.Width, height ?? this.RoadieSettings.Thumbnails.Height);
var result = await this.ImageService.PlaylistImage(id, width ?? this.RoadieSettings.ThumbnailImageSize.Width, height ?? this.RoadieSettings.ThumbnailImageSize.Height);
if (result == null || result.IsNotFoundResult)
{
return NotFound();
@ -155,12 +156,12 @@ namespace Roadie.Api.Controllers
entityTag: result.ETag);
}
[HttpGet("thumbnail/release/{id}/{width:int?}/{height:int?}")]
[HttpGet("release/{id}/{width:int?}/{height:int?}")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public async Task<IActionResult> ReleaseThumbnail(Guid id, int? width, int? height)
{
var result = await this.ImageService.ReleaseThumbnail(id, width ?? this.RoadieSettings.Thumbnails.Width, height ?? this.RoadieSettings.Thumbnails.Height);
var result = await this.ImageService.ReleaseImage(id, width ?? this.RoadieSettings.ThumbnailImageSize.Width, height ?? this.RoadieSettings.ThumbnailImageSize.Height);
if (result == null || result.IsNotFoundResult)
{
return NotFound();
@ -176,12 +177,12 @@ namespace Roadie.Api.Controllers
entityTag: result.ETag);
}
[HttpGet("thumbnail/track/{id}/{width:int?}/{height:int?}")]
[HttpGet("track/{id}/{width:int?}/{height:int?}")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public async Task<IActionResult> TrackThumbnail(Guid id, int? width, int? height)
{
var result = await this.ImageService.TrackThumbnail(id, width ?? this.RoadieSettings.Thumbnails.Width, height ?? this.RoadieSettings.Thumbnails.Height);
var result = await this.ImageService.TrackImage(id, width ?? this.RoadieSettings.ThumbnailImageSize.Width, height ?? this.RoadieSettings.ThumbnailImageSize.Height);
if (result == null || result.IsNotFoundResult)
{
return NotFound();
@ -197,12 +198,12 @@ namespace Roadie.Api.Controllers
entityTag: result.ETag);
}
[HttpGet("thumbnail/user/{id}/{width:int?}/{height:int?}")]
[HttpGet("user/{id}/{width:int?}/{height:int?}")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public async Task<IActionResult> UserThumbnail(Guid id, int? width, int? height)
{
var result = await this.ImageService.UserThumbnail(id, width ?? this.RoadieSettings.Thumbnails.Width, height ?? this.RoadieSettings.Thumbnails.Height);
var result = await this.ImageService.UserImage(id, width ?? this.RoadieSettings.ThumbnailImageSize.Width, height ?? this.RoadieSettings.ThumbnailImageSize.Height);
if (result == null || result.IsNotFoundResult)
{
return NotFound();

View file

@ -37,7 +37,7 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(200)]
public async Task<IActionResult> GetAlbumList([FromQuery]Request request)
{
var result = await this.SubsonicService.GetAlbumList(request, null, "1");
var result = await this.SubsonicService.GetAlbumList(request, null, AlbumListVersions.One);
return this.BuildResponse(request, result.Data, "albumList");
}
@ -46,10 +46,28 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(200)]
public async Task<IActionResult> GetAlbumList2([FromQuery]Request request)
{
var result = await this.SubsonicService.GetAlbumList(request, null, "2");
var result = await this.SubsonicService.GetAlbumList(request, null, AlbumListVersions.Two);
return this.BuildResponse(request, result.Data, "albumList");
}
[HttpGet("getArtistInfo.view")]
[HttpPost("getArtistInfo.view")]
[ProducesResponseType(200)]
public async Task<IActionResult> GetArtistInfo([FromQuery]Request request, string id, int? count, bool? includeNotPresent)
{
var result = await this.SubsonicService.GetArtistInfo(request, id, count, includeNotPresent ?? false, ArtistInfoVersion.One);
return this.BuildResponse(request, result.Data, "artistInfo");
}
[HttpGet("getArtistInfo2.view")]
[HttpPost("getArtistInfo2.view")]
[ProducesResponseType(200)]
public async Task<IActionResult> GetArtistInfo2([FromQuery]Request request, string id, int? count, bool? includeNotPresent)
{
var result = await this.SubsonicService.GetArtistInfo(request, id, count, includeNotPresent ?? false, ArtistInfoVersion.Two);
return this.BuildResponse(request, result.Data, "artistInfo2");
}
[HttpGet("getCoverArt.view")]
[HttpPost("getCoverArt.view")]
[ProducesResponseType(200)]

View file

@ -171,7 +171,7 @@ namespace Roadie.Api.Services
}
if (includes.Contains("images"))
{
result.Images = this.DbContext.Images.Where(x => x.ArtistId == artist.Id).Select(x => MakeImage(x.RoadieId, this.Configuration.LargeThumbnails.Width, this.Configuration.LargeThumbnails.Height)).ToArray();
result.Images = this.DbContext.Images.Where(x => x.ArtistId == artist.Id).Select(x => MakeImage(x.RoadieId, this.Configuration.LargeImageSize.Width, this.Configuration.LargeImageSize.Height)).ToArray();
}
if (includes.Contains("associatedartists"))
{

View file

@ -10,24 +10,24 @@ namespace Roadie.Api.Services
{
public interface IImageService
{
Task<FileOperationResult<Library.Models.Image>> ArtistThumbnail(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<Library.Models.Image>> ArtistImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<Library.Models.Image>> ById(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<Library.Models.Image>> CollectionThumbnail(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<Library.Models.Image>> CollectionImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<OperationResult<bool>> Delete(User user, Guid id);
Task<OperationResult<IEnumerable<ImageSearchResult>>> ImageProvidersSearch(string query);
Task<FileOperationResult<Library.Models.Image>> LabelThumbnail(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<Library.Models.Image>> LabelImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<Library.Models.Image>> PlaylistThumbnail(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<Library.Models.Image>> PlaylistImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<Library.Models.Image>> ReleaseThumbnail(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<Library.Models.Image>> ReleaseImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<Library.Models.Image>> TrackThumbnail(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<Library.Models.Image>> TrackImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<Library.Models.Image>> UserThumbnail(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<Library.Models.Image>> UserImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
}
}

View file

@ -6,7 +6,7 @@ namespace Roadie.Api.Services
{
public interface ISubsonicService
{
Task<OperationResult<Response>> GetAlbumList(Request request, Roadie.Library.Models.Users.User roadieUser, string version);
Task<OperationResult<Response>> GetAlbumList(Request request, Roadie.Library.Models.Users.User roadieUser, AlbumListVersions version);
Task<FileOperationResult<Roadie.Library.Models.Image>> GetCoverArt(Request request, int? size);
@ -28,5 +28,6 @@ namespace Roadie.Api.Services
Task<OperationResult<Response>> Search(Request request, Roadie.Library.Models.Users.User roadieUser);
Task<OperationResult<Response>> GetAlbum(Request request, Roadie.Library.Models.Users.User roadieUser);
Task<OperationResult<Response>> GetArtistInfo(Request request, string id, int? count, bool includeNotPresent, ArtistInfoVersion version);
}
}

View file

@ -37,20 +37,21 @@ namespace Roadie.Api.Services
this.DefaultNotFoundImages = defaultNotFoundImages;
}
public async Task<FileOperationResult<Image>> ArtistThumbnail(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
public async Task<FileOperationResult<Image>> ArtistImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
{
return await this.GetImageFileOperation(type: "ArtistThumbnail",
return await this.GetImageFileOperation(type: "ArtistImage",
regionUrn: data.Artist.CacheRegionUrn(id),
id: id,
width: width,
height: height,
action: async () =>
{
return await this.ArtistThumbnailAction(id, etag);
return await this.ArtistImageAction(id, etag);
},
etag: etag);
}
public async Task<FileOperationResult<Image>> ById(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
{
return await this.GetImageFileOperation(type: "ImageById",
@ -65,7 +66,7 @@ namespace Roadie.Api.Services
etag: etag);
}
public async Task<FileOperationResult<Image>> CollectionThumbnail(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
public async Task<FileOperationResult<Image>> CollectionImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
{
return await this.GetImageFileOperation(type: "CollectionThumbnail",
regionUrn: data.Collection.CacheRegionUrn(id),
@ -74,7 +75,7 @@ namespace Roadie.Api.Services
height: height,
action: async () =>
{
return await this.CollectionThumbnailAction(id, etag);
return await this.CollectionImageAction(id, etag);
},
etag: etag);
}
@ -137,7 +138,7 @@ namespace Roadie.Api.Services
};
}
public async Task<FileOperationResult<Image>> LabelThumbnail(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
public async Task<FileOperationResult<Image>> LabelImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
{
return await this.GetImageFileOperation(type: "LabelThumbnail",
regionUrn: data.Label.CacheRegionUrn(id),
@ -146,12 +147,12 @@ namespace Roadie.Api.Services
height: height,
action: async () =>
{
return await this.LabelThumbnailAction(id, etag);
return await this.LabelImageAction(id, etag);
},
etag: etag);
}
public async Task<FileOperationResult<Image>> PlaylistThumbnail(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
public async Task<FileOperationResult<Image>> PlaylistImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
{
return await this.GetImageFileOperation(type: "PlaylistThumbnail",
regionUrn: data.Playlist.CacheRegionUrn(id),
@ -160,12 +161,12 @@ namespace Roadie.Api.Services
height: height,
action: async () =>
{
return await this.PlaylistThumbnailAction(id, etag);
return await this.PlaylistImageAction(id, etag);
},
etag: etag);
}
public async Task<FileOperationResult<Image>> ReleaseThumbnail(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
public async Task<FileOperationResult<Image>> ReleaseImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
{
return await this.GetImageFileOperation(type: "ReleaseThumbnail",
regionUrn: data.Release.CacheRegionUrn(id),
@ -174,12 +175,12 @@ namespace Roadie.Api.Services
height: height,
action: async () =>
{
return await this.ReleaseThumbnailAction(id, etag);
return await this.ReleaseImageAction(id, etag);
},
etag: etag);
}
public async Task<FileOperationResult<Image>> TrackThumbnail(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
public async Task<FileOperationResult<Image>> TrackImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
{
return await this.GetImageFileOperation(type: "TrackThumbnail",
regionUrn: data.Track.CacheRegionUrn(id),
@ -188,12 +189,12 @@ namespace Roadie.Api.Services
height: height,
action: async () =>
{
return await this.TrackThumbnailAction(id, etag);
return await this.TrackImageAction(id, etag);
},
etag: etag);
}
public async Task<FileOperationResult<Image>> UserThumbnail(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
public async Task<FileOperationResult<Image>> UserImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
{
return await this.GetImageFileOperation(type: "UserById",
regionUrn: ApplicationUser.CacheRegionUrn(id),
@ -202,12 +203,12 @@ namespace Roadie.Api.Services
height: height,
action: async () =>
{
return await this.UserThumbnailAction(id, etag);
return await this.UserImageAction(id, etag);
},
etag: etag);
}
private async Task<FileOperationResult<Image>> ArtistThumbnailAction(Guid id, EntityTagHeaderValue etag = null)
private async Task<FileOperationResult<Image>> ArtistImageAction(Guid id, EntityTagHeaderValue etag = null)
{
try
{
@ -235,7 +236,7 @@ namespace Roadie.Api.Services
return new FileOperationResult<Image>(OperationMessages.ErrorOccured);
}
private async Task<FileOperationResult<Image>> CollectionThumbnailAction(Guid id, EntityTagHeaderValue etag = null)
private async Task<FileOperationResult<Image>> CollectionImageAction(Guid id, EntityTagHeaderValue etag = null)
{
try
{
@ -301,7 +302,7 @@ namespace Roadie.Api.Services
result.Data.Bytes = ImageHelper.ResizeImage(result?.Data?.Bytes, width.Value, height.Value);
result.ETag = EtagHelper.GenerateETag(this.HttpEncoder, result.Data.Bytes);
result.LastModified = DateTime.UtcNow;
if (width.Value != this.Configuration.Thumbnails.Width || height.Value != this.Configuration.Thumbnails.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 }]");
}
@ -340,7 +341,7 @@ namespace Roadie.Api.Services
return new FileOperationResult<Image>(OperationMessages.ErrorOccured);
}
private async Task<FileOperationResult<Image>> LabelThumbnailAction(Guid id, EntityTagHeaderValue etag = null)
private async Task<FileOperationResult<Image>> LabelImageAction(Guid id, EntityTagHeaderValue etag = null)
{
try
{
@ -368,7 +369,7 @@ namespace Roadie.Api.Services
return new FileOperationResult<Image>(OperationMessages.ErrorOccured);
}
private async Task<FileOperationResult<Image>> PlaylistThumbnailAction(Guid id, EntityTagHeaderValue etag = null)
private async Task<FileOperationResult<Image>> PlaylistImageAction(Guid id, EntityTagHeaderValue etag = null)
{
try
{
@ -396,7 +397,7 @@ namespace Roadie.Api.Services
return new FileOperationResult<Image>(OperationMessages.ErrorOccured);
}
private async Task<FileOperationResult<Image>> ReleaseThumbnailAction(Guid id, EntityTagHeaderValue etag = null)
private async Task<FileOperationResult<Image>> ReleaseImageAction(Guid id, EntityTagHeaderValue etag = null)
{
try
{
@ -424,7 +425,7 @@ namespace Roadie.Api.Services
return new FileOperationResult<Image>(OperationMessages.ErrorOccured);
}
private async Task<FileOperationResult<Image>> TrackThumbnailAction(Guid id, EntityTagHeaderValue etag = null)
private async Task<FileOperationResult<Image>> TrackImageAction(Guid id, EntityTagHeaderValue etag = null)
{
try
{
@ -442,7 +443,7 @@ namespace Roadie.Api.Services
if (track.Thumbnail == null || !track.Thumbnail.Any())
{
// If no track image is found then return image for release
return await this.ReleaseThumbnailAction(track.ReleaseMedia.Release.RoadieId, etag);
return await this.ReleaseImageAction(track.ReleaseMedia.Release.RoadieId, etag);
}
return GenerateFileOperationResult(id, image, etag);
}
@ -453,7 +454,7 @@ namespace Roadie.Api.Services
return new FileOperationResult<Image>(OperationMessages.ErrorOccured);
}
private async Task<FileOperationResult<Image>> UserThumbnailAction(Guid id, EntityTagHeaderValue etag = null)
private async Task<FileOperationResult<Image>> UserImageAction(Guid id, EntityTagHeaderValue etag = null)
{
try
{
@ -480,5 +481,7 @@ namespace Roadie.Api.Services
}
return new FileOperationResult<Image>(OperationMessages.ErrorOccured);
}
}
}

View file

@ -382,7 +382,7 @@ namespace Roadie.Api.Services
}
if (includes.Contains("images"))
{
var releaseImages = this.DbContext.Images.Where(x => x.ReleaseId == release.Id).Select(x => MakeImage(x.RoadieId, this.Configuration.LargeThumbnails.Width, this.Configuration.LargeThumbnails.Height)).ToArray();
var releaseImages = this.DbContext.Images.Where(x => x.ReleaseId == release.Id).Select(x => MakeImage(x.RoadieId, this.Configuration.LargeImageSize.Width, this.Configuration.LargeImageSize.Height)).ToArray();
if (releaseImages != null && releaseImages.Any())
{
result.Images = releaseImages;

View file

@ -304,6 +304,7 @@ namespace Roadie.Api.Services
return MakeThumbnailImage(id, "collection");
}
protected Image MakeImage(Guid id, int width = 200, int height = 200)
{
return new Image($"{this.HttpContext.ImageBaseUrl }/{id}/{ width }/{ height }");
@ -336,7 +337,22 @@ namespace Roadie.Api.Services
private Image MakeThumbnailImage(Guid id, string type)
{
return new Image($"{this.HttpContext.ImageBaseUrl }/thumbnail/{ type }/{id}");
return this.MakeImage(id, type, this.Configuration.ThumbnailImageSize.Width, this.Configuration.ThumbnailImageSize.Height);
}
protected Image MakeImage(Guid id, string type, ImageSize imageSize)
{
return this.MakeImage(id, type, imageSize.Width, imageSize.Height);
}
private Image MakeImage(Guid id, string type, int? width, int? height)
{
if (width.HasValue && height.HasValue)
{
return new Image($"{this.HttpContext.ImageBaseUrl }/{type}/{id}/{width}/{height}");
}
return new Image($"{this.HttpContext.ImageBaseUrl }/{type}/{id}");
}
}

View file

@ -59,7 +59,7 @@ namespace Roadie.Api.Services
/// <summary>
/// Returns a list of random, newest, highest rated etc. albums. Similar to the album lists on the home page of the Subsonic web interface.
/// </summary>
public async Task<OperationResult<subsonic.Response>> GetAlbumList(subsonic.Request request, User roadieUser, string version)
public async Task<OperationResult<subsonic.Response>> GetAlbumList(subsonic.Request request, User roadieUser, subsonic.AlbumListVersions version)
{
var releaseResult = new Library.Models.Pagination.PagedResult<ReleaseList>();
@ -90,22 +90,44 @@ namespace Roadie.Api.Services
return new OperationResult<subsonic.Response>(releaseResult.Message);
}
var albums = this.SubsonicChildrenForReleases(releaseResult.Rows, null);
return new OperationResult<subsonic.Response>
switch (version)
{
IsSuccess = true,
Data = new subsonic.Response
{
version = SubsonicService.SubsonicVersion,
status = subsonic.ResponseStatus.ok,
ItemElementName = subsonic.ItemChoiceType.albumList,
Item = new subsonic.AlbumList
case subsonic.AlbumListVersions.One:
return new OperationResult<subsonic.Response>
{
album = albums
}
}
};
IsSuccess = true,
Data = new subsonic.Response
{
version = SubsonicService.SubsonicVersion,
status = subsonic.ResponseStatus.ok,
ItemElementName = subsonic.ItemChoiceType.albumList,
Item = new subsonic.AlbumList
{
album = this.SubsonicChildrenForReleases(releaseResult.Rows, null)
}
}
};
case subsonic.AlbumListVersions.Two:
return new OperationResult<subsonic.Response>
{
IsSuccess = true,
Data = new subsonic.Response
{
version = SubsonicService.SubsonicVersion,
status = subsonic.ResponseStatus.ok,
ItemElementName = subsonic.ItemChoiceType.albumList2,
Item = new subsonic.AlbumList2
{
album = this.SubsonicAlbumID3ForReleases(releaseResult.Rows, null)
}
}
};
default:
return new OperationResult<subsonic.Response>($"Unknown AlbumListVersions [{ version }]");
}
}
@ -122,7 +144,7 @@ namespace Roadie.Api.Services
if (request.ArtistId != null)
{
var artistImage = await this.ImageService.ArtistThumbnail(request.ArtistId.Value, size, size);
var artistImage = await this.ImageService.ArtistImage(request.ArtistId.Value, size, size);
if (!artistImage.IsSuccess)
{
return artistImage;
@ -131,7 +153,7 @@ namespace Roadie.Api.Services
}
else if (request.TrackId != null)
{
var trackimage = await this.ImageService.TrackThumbnail(request.TrackId.Value, size, size);
var trackimage = await this.ImageService.TrackImage(request.TrackId.Value, size, size);
if (!trackimage.IsSuccess)
{
return trackimage;
@ -433,7 +455,7 @@ namespace Roadie.Api.Services
comment = playlist.Description,
owner = u.UserName,
songCount = trackCount,
duration = playListDuration ?? 0,
duration = playListDuration.ToSecondsFromMilliseconds(),
created = playlist.CreatedDate,
changed = playlist.LastUpdated ?? playlist.CreatedDate,
coverArt = this.MakePlaylistThumbnailImage(playlist.RoadieId).Url,
@ -573,7 +595,7 @@ namespace Roadie.Api.Services
artistId = subsonic.Request.ArtistIdIdentifier + release.Artist.RoadieId.ToString(),
coverArt = subsonic.Request.ReleaseIdIdentifier + release.RoadieId.ToString(),
created = release.CreatedDate,
duration = releaseTracks.Rows.Sum(x => x.Duration) ?? 0,
duration = release.Duration.ToSecondsFromMilliseconds(),
genre = genre == null ? null : genre.Genre.Name,
id = subsonic.Request.ReleaseIdIdentifier + release.RoadieId.ToString(),
name = release.Title,
@ -590,6 +612,9 @@ namespace Roadie.Api.Services
};
}
/// <summary>
/// Get details about the software license. Takes no extra parameters. Roadies gives everyone a premium 1 year license everytime they ask :)
/// </summary>
public OperationResult<subsonic.Response> GetLicense(subsonic.Request request)
{
return new OperationResult<subsonic.Response>
@ -612,12 +637,80 @@ namespace Roadie.Api.Services
}
public subsonic.ArtistInfo SubsonicArtistInfoForArtist(data.Artist artist)
{
return new subsonic.ArtistInfo
{
biography = artist.BioContext,
largeImageUrl = this.MakeImage(artist.RoadieId, "artist", this.Configuration.LargeImageSize).Url,
mediumImageUrl = this.MakeImage(artist.RoadieId, "artist", this.Configuration.MediumImageSize).Url,
musicBrainzId = artist.MusicBrainzId,
similarArtist = new subsonic.Artist[0],
smallImageUrl = this.MakeImage(artist.RoadieId, "artist", this.Configuration.SmallImageSize).Url
};
}
public subsonic.ArtistInfo2 SubsonicArtistInfo2InfoForArtist(data.Artist artist)
{
return new subsonic.ArtistInfo2
{
biography = artist.BioContext,
largeImageUrl = this.MakeImage(artist.RoadieId, "artist", this.Configuration.LargeImageSize).Url,
mediumImageUrl = this.MakeImage(artist.RoadieId, "artist", this.Configuration.MediumImageSize).Url,
musicBrainzId = artist.MusicBrainzId,
similarArtist = new subsonic.ArtistID3[0],
smallImageUrl = this.MakeImage(artist.RoadieId, "artist", this.Configuration.SmallImageSize).Url
};
}
/// <summary>
/// Returns artist info with biography, image URLs and similar artists, using data from last.fm.
/// </summary>
public OperationResult<subsonic.Response> GetArtistInfo(subsonic.Request request, string id, int? count, bool includeNotPresent)
public async Task<OperationResult<subsonic.Response>> GetArtistInfo(subsonic.Request request, string id, int? count, bool includeNotPresent, subsonic.ArtistInfoVersion version)
{
throw new NotImplementedException();
var artistId = SafeParser.ToGuid(id);
if(!artistId.HasValue)
{
return new OperationResult<subsonic.Response>(true, $"Invalid ArtistId [{ id }]");
}
var artist = this.GetArtist(artistId.Value);
if(artist == null)
{
return new OperationResult<subsonic.Response>(true, $"Invalid ArtistId [{ id }]");
}
switch (version)
{
case subsonic.ArtistInfoVersion.One:
return new OperationResult<subsonic.Response>
{
IsSuccess = true,
Data = new subsonic.Response
{
version = SubsonicService.SubsonicVersion,
status = subsonic.ResponseStatus.ok,
ItemElementName = subsonic.ItemChoiceType.artistInfo,
Item = this.SubsonicArtistInfoForArtist(artist)
}
};
case subsonic.ArtistInfoVersion.Two:
return new OperationResult<subsonic.Response>
{
IsSuccess = true,
Data = new subsonic.Response
{
version = SubsonicService.SubsonicVersion,
status = subsonic.ResponseStatus.ok,
ItemElementName = subsonic.ItemChoiceType.artistInfo2,
Item = this.SubsonicArtistInfo2InfoForArtist(artist)
}
};
default:
return new OperationResult<subsonic.Response>($"Unknown ArtistInfoVersion [{ version }]");
}
}
/// <summary>
@ -644,7 +737,6 @@ namespace Roadie.Api.Services
throw new NotImplementedException();
}
//getAlbumList2
//getArtists
//getStarred2
//search3
@ -718,6 +810,28 @@ namespace Roadie.Api.Services
};
}
private subsonic.AlbumID3 SubsonicAlbumID3ForRelease(ReleaseList r, string parent, string path)
{
return new subsonic.AlbumID3
{
id = subsonic.Request.ReleaseIdIdentifier + r.Id.ToString(),
artistId = r.Artist.Value,
name = r.Release.Text,
songCount = r.TrackCount ?? 0,
duration = r.Duration.ToSecondsFromMilliseconds(),
artist = r.Artist.Text,
coverArt = subsonic.Request.ReleaseIdIdentifier + r.Id.ToString(),
created = r.CreatedDate.Value,
genre = r.Genre.Text,
playCount = r.TrackPlayedCount ?? 0,
playCountSpecified = true,
starred = r.UserRating?.RatedDate ?? DateTime.UtcNow,
starredSpecified = r.UserRating?.IsFavorite ?? false,
year = SafeParser.ToNumber<int>(r.ReleaseYear),
yearSpecified = true
};
}
private subsonic.Child SubsonicChildForTrack(TrackList t)
{
return new subsonic.Child
@ -774,6 +888,15 @@ namespace Roadie.Api.Services
return r.Select(x => this.SubsonicChildForRelease(x, parent, $"{ x.Artist.Text}/{ x.Release.Text}/")).ToArray();
}
private subsonic.AlbumID3[] SubsonicAlbumID3ForReleases(IEnumerable<ReleaseList> r, string parent)
{
if (r == null || !r.Any())
{
return new subsonic.AlbumID3[0];
}
return r.Select(x => this.SubsonicAlbumID3ForRelease(x, parent, $"{ x.Artist.Text}/{ x.Release.Text}/")).ToArray();
}
private subsonic.Child[] SubsonicChildrenForTracks(IEnumerable<TrackList> tracks)
{
if (tracks == null || !tracks.Any())

View file

@ -15,10 +15,11 @@ namespace Roadie.Library.Configuration
FilePlugins FilePlugins { get; set; }
string InboundFolder { get; set; }
Integrations Integrations { get; set; }
Thumbnails LargeThumbnails { get; set; }
ImageSize LargeImageSize { get; set; }
string LibraryFolder { get; set; }
string ListenAddress { get; set; }
Thumbnails MediumThumbnails { get; set; }
ImageSize SmallImageSize { get; set; }
ImageSize MediumImageSize { get; set; }
Processing Processing { get; set; }
bool RecordNoResultSearches { get; set; }
RedisCache Redis { get; set; }
@ -31,7 +32,7 @@ namespace Roadie.Library.Configuration
int SmtpPort { get; set; }
string SmtpUsername { get; set; }
bool SmtpUseSSl { get; set; }
Thumbnails Thumbnails { get; set; }
ImageSize ThumbnailImageSize { get; set; }
Dictionary<string, string> TrackPathReplace { get; set; }
bool UseSSLBehindProxy { get; set; }
string WebsocketAddress { get; set; }

View file

@ -6,19 +6,22 @@ namespace Roadie.Library.Configuration
[Serializable]
public sealed class RoadieSettings : IRoadieSettings
{
/// <summary>
/// Set to the Roadie Database for DbDataReader operations
/// </summary>
public string ConnectionString { get; set; }
/// <summary>
/// If the artist name is found in the values then use the key.
/// <remark>This was desgined to handle 'AC/DC' type names as they contain the ID3 v2.3 spec artist seperator</remark>
/// </summary>
public Dictionary<string, List<string>> ArtistNameReplace { get; set; }
/// <summary>
/// Set to the Roadie Database for DbDataReader operations
/// </summary>
public string ConnectionString { get; set; }
/// <summary>
/// This is the phsycial path to the content folder (which holds among other things place-holder images)
/// </summary>
public string ContentPath { get; set; }
public Converting Converting { get; set; }
public string DefaultTimeZone { get; set; }
public string DiagnosticsPassword { get; set; }
@ -27,13 +30,14 @@ namespace Roadie.Library.Configuration
public FilePlugins FilePlugins { get; set; }
public string InboundFolder { get; set; }
public Integrations Integrations { get; set; }
public Thumbnails LargeThumbnails { get; set; }
public ImageSize LargeImageSize { get; set; }
public string LibraryFolder { get; set; }
public string ListenAddress { get; set; }
public Thumbnails MediumThumbnails { get; set; }
public ImageSize MediumImageSize { get; set; }
public Processing Processing { get; set; }
public bool RecordNoResultSearches { get; set; }
public RedisCache Redis { get; set; }
public ImageSize SmallImageSize { get; set; }
public string SecretKey { get; set; }
public string SingleArtistHoldingFolder { get; set; }
public string SiteName { get; set; }
@ -43,7 +47,7 @@ namespace Roadie.Library.Configuration
public int SmtpPort { get; set; }
public string SmtpUsername { get; set; }
public bool SmtpUseSSl { get; set; }
public Thumbnails Thumbnails { get; set; }
public ImageSize ThumbnailImageSize { get; set; }
public Dictionary<string, string> TrackPathReplace { get; set; }
public bool UseSSLBehindProxy { get; set; }
public string WebsocketAddress { get; set; }

View file

@ -3,12 +3,12 @@
namespace Roadie.Library.Configuration
{
[Serializable]
public class Thumbnails
public class ImageSize
{
public short Height { get; set; }
public short Width { get; set; }
public Thumbnails()
public ImageSize()
{
this.Height = 80;
this.Width = 80;

View file

@ -25,6 +25,9 @@ namespace Roadie.Library.Data
public ICollection<CollectionRelease> Collections { get; set; }
[Column("duration")]
public int? Duration { get; set; }
[Column("discogsId")]
[MaxLength(50)]
public string DiscogsId { get; set; }

View file

@ -71,7 +71,7 @@ namespace Roadie.Library.Factories
artist.Thumbnail = firstImageWithNotNullBytes.Bytes;
if (artist.Thumbnail != null)
{
artist.Thumbnail = ImageHelper.ResizeImage(artist.Thumbnail, this.Configuration.Thumbnails.Width, this.Configuration.Thumbnails.Height);
artist.Thumbnail = ImageHelper.ResizeImage(artist.Thumbnail, this.Configuration.ThumbnailImageSize.Width, this.Configuration.ThumbnailImageSize.Height);
artist.Thumbnail = ImageHelper.ConvertToJpegFormat(artist.Thumbnail);
}
}
@ -751,7 +751,7 @@ namespace Roadie.Library.Factories
}
if (result.Thumbnail != null)
{
result.Thumbnail = ImageHelper.ResizeImage(result.Thumbnail, this.Configuration.Thumbnails.Width, this.Configuration.Thumbnails.Height);
result.Thumbnail = ImageHelper.ResizeImage(result.Thumbnail, this.Configuration.ThumbnailImageSize.Width, this.Configuration.ThumbnailImageSize.Height);
result.Thumbnail = ImageHelper.ConvertToJpegFormat(result.Thumbnail);
}
}

View file

@ -1326,7 +1326,7 @@ namespace Roadie.Library.Factories
if (result.Thumbnail != null)
{
result.Thumbnail = ImageHelper.ResizeImage(result.Thumbnail, this.Configuration.Thumbnails.Width, this.Configuration.Thumbnails.Height);
result.Thumbnail = ImageHelper.ResizeImage(result.Thumbnail, this.Configuration.ThumbnailImageSize.Width, this.Configuration.ThumbnailImageSize.Height);
result.Thumbnail = ImageHelper.ConvertToJpegFormat(result.Thumbnail);
}
sw.Stop();
@ -1622,7 +1622,7 @@ namespace Roadie.Library.Factories
{
// Read image and convert to jpeg
release.Thumbnail = File.ReadAllBytes(coverFileName);
release.Thumbnail = ImageHelper.ResizeImage(release.Thumbnail, this.Configuration.Thumbnails.Width, this.Configuration.Thumbnails.Height);
release.Thumbnail = ImageHelper.ResizeImage(release.Thumbnail, this.Configuration.ThumbnailImageSize.Width, this.Configuration.ThumbnailImageSize.Height);
release.Thumbnail = ImageHelper.ConvertToJpegFormat(release.Thumbnail);
release.LastUpdated = now;
await this.DbContext.SaveChangesAsync();

View file

@ -46,5 +46,6 @@ namespace Roadie.Library.Models.Releases
public Statuses? Status { get; set; }
public DataToken Genre { get; set; }
public DateTime? LastPlayed { get; set; }
public int? Duration { get; set; }
}
}

View file

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Roadie.Library.Models.ThirdPartyApi.Subsonic
{
public enum AlbumListVersions
{
One,
Two
}
}

View file

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Roadie.Library.Models.ThirdPartyApi.Subsonic
{
public enum ArtistInfoVersion
{
One,
Two
}
}