mirror of
https://github.com/sphildreth/roadie
synced 2024-11-22 12:13:10 +00:00
Work for collection and redo of timeinfo
This commit is contained in:
parent
6242831067
commit
e59a3195a8
24 changed files with 469 additions and 52 deletions
|
@ -7,8 +7,10 @@ using Roadie.Api.Services;
|
|||
using Roadie.Library.Caching;
|
||||
using Roadie.Library.Identity;
|
||||
using Roadie.Library.Models.Pagination;
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using models = Roadie.Library.Models;
|
||||
|
||||
namespace Roadie.Api.Controllers
|
||||
{
|
||||
|
@ -27,33 +29,22 @@ namespace Roadie.Api.Controllers
|
|||
this.CollectionService = collectionService;
|
||||
}
|
||||
|
||||
//[EnableQuery]
|
||||
//public IActionResult Get()
|
||||
//{
|
||||
// return Ok(this._RoadieDbContext.Labels.ProjectToType<models.Label>());
|
||||
//}
|
||||
|
||||
//[HttpGet("{id}")]
|
||||
//[ProducesResponseType(200)]
|
||||
//[ProducesResponseType(404)]
|
||||
//public IActionResult Get(Guid id)
|
||||
//{
|
||||
// var key = id.ToString();
|
||||
// var result = this._cacheManager.Get<models.Label>(key, () =>
|
||||
// {
|
||||
// var d = this._RoadieDbContext.Labels.FirstOrDefault(x => x.RoadieId == id);
|
||||
// if (d != null)
|
||||
// {
|
||||
// return d.Adapt<models.Label>();
|
||||
// }
|
||||
// return null;
|
||||
// }, key);
|
||||
// if (result == null)
|
||||
// {
|
||||
// return NotFound();
|
||||
// }
|
||||
// return Ok(result);
|
||||
//}
|
||||
[HttpGet("{id}")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> Get(Guid id, string inc = null)
|
||||
{
|
||||
var result = await this.CollectionService.ById(await this.CurrentUserModel(), id, (inc ?? models.Collections.Collection.DefaultIncludes).ToLower().Split(","));
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[ProducesResponseType(200)]
|
||||
|
|
|
@ -206,7 +206,7 @@ namespace Roadie.Api.Services
|
|||
join rm in this.DbContext.ReleaseMedias on r.Id equals rm.ReleaseId
|
||||
where r.ArtistId == artist.Id
|
||||
select rm.Id).Count(),
|
||||
TrackTime = validCartistTracks.Any() ? TimeSpan.FromSeconds(Math.Floor((double)trackTime / 1000)).ToString(@"dd\:hh\:mm\:ss") : "--:--",
|
||||
TrackTime = validCartistTracks.Any() ? new TimeInfo((decimal)trackTime).ToFullFormattedString() : "--:--",
|
||||
TrackCount = validCartistTracks.Count(),
|
||||
TrackPlayedCount = artist.PlayedCount
|
||||
};
|
||||
|
|
|
@ -24,8 +24,7 @@ namespace Roadie.Api.Services
|
|||
IHttpContext httpContext,
|
||||
data.IRoadieDbContext context,
|
||||
ICacheManager cacheManager,
|
||||
ILogger<BookmarkService> logger,
|
||||
ICollectionService collectionService)
|
||||
ILogger<BookmarkService> logger)
|
||||
: base(configuration, httpEncoder, context, cacheManager, logger, httpContext)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
using Microsoft.EntityFrameworkCore;
|
||||
using Mapster;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
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.Collections;
|
||||
using Roadie.Library.Models.Pagination;
|
||||
using Roadie.Library.Models.Statistics;
|
||||
using Roadie.Library.Models.Users;
|
||||
using Roadie.Library.Utility;
|
||||
using System;
|
||||
|
@ -21,16 +25,134 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
public class CollectionService : ServiceBase, ICollectionService
|
||||
{
|
||||
private IBookmarkService BookmarkService { get; } = null;
|
||||
|
||||
public CollectionService(IRoadieSettings configuration,
|
||||
IHttpEncoder httpEncoder,
|
||||
IHttpContext httpContext,
|
||||
data.IRoadieDbContext dbContext,
|
||||
ICacheManager cacheManager,
|
||||
ILogger<CollectionService> logger)
|
||||
ILogger<CollectionService> logger,
|
||||
IBookmarkService bookmarkService)
|
||||
: base(configuration, httpEncoder, dbContext, cacheManager, logger, httpContext)
|
||||
{
|
||||
this.BookmarkService = bookmarkService;
|
||||
}
|
||||
|
||||
public async Task<OperationResult<Collection>> ById(User roadieUser, Guid id, IEnumerable<string> includes = null)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
sw.Start();
|
||||
var cacheKey = string.Format("urn:collection_by_id_operation:{0}:{1}", id, includes == null ? "0" : string.Join("|", includes));
|
||||
var result = await this.CacheManager.GetAsync<OperationResult<Collection>>(cacheKey, async () =>
|
||||
{
|
||||
return await this.CollectionByIdAction(id, includes);
|
||||
}, data.Artist.CacheRegionUrn(id));
|
||||
sw.Stop();
|
||||
if (result?.Data != null && roadieUser != null)
|
||||
{
|
||||
var userBookmarkResult = await this.BookmarkService.List(roadieUser, new PagedRequest(), false, BookmarkType.Collection);
|
||||
if (userBookmarkResult.IsSuccess)
|
||||
{
|
||||
result.Data.UserBookmarked = userBookmarkResult?.Rows?.FirstOrDefault(x => x.Bookmark.Text == result.Data.Id.ToString()) != null;
|
||||
}
|
||||
}
|
||||
return new OperationResult<Collection>(result.Messages)
|
||||
{
|
||||
Data = result?.Data,
|
||||
IsNotFoundResult = result?.IsNotFoundResult ?? false,
|
||||
Errors = result?.Errors,
|
||||
IsSuccess = result?.IsSuccess ?? false,
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<OperationResult<Collection>> CollectionByIdAction(Guid id, IEnumerable<string> includes = null)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
sw.Start();
|
||||
|
||||
var collection = this.GetCollection(id);
|
||||
|
||||
if (collection == null)
|
||||
{
|
||||
return new OperationResult<Collection>(true, string.Format("Collection Not Found [{0}]", id));
|
||||
}
|
||||
|
||||
var result = collection.Adapt<Collection>();
|
||||
result.AlternateNames = collection.AlternateNames;
|
||||
result.Tags = collection.Tags;
|
||||
result.URLs = collection.URLs;
|
||||
result.Thumbnail = this.MakeCollectionThumbnailImage(collection.RoadieId);
|
||||
result.MediumThumbnail = base.MakeThumbnailImage(id, "collection", this.Configuration.MediumImageSize.Width, this.Configuration.MediumImageSize.Height);
|
||||
result.CollectionFoundCount = (from crc in this.DbContext.CollectionReleases
|
||||
where crc.CollectionId == collection.Id
|
||||
select crc.Id).Count();
|
||||
if (includes != null && includes.Any())
|
||||
{
|
||||
if (includes.Contains("list"))
|
||||
{
|
||||
result.ListInCSVFormat = collection.ListInCSVFormat;
|
||||
result.ListInCSV = collection.ListInCSV;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.ListInCSV = null;
|
||||
result.ListInCSVFormat = null;
|
||||
}
|
||||
|
||||
if (includes.Contains("releases"))
|
||||
{
|
||||
result.Releases = (from crc in this.DbContext.CollectionReleases
|
||||
join r in this.DbContext.Releases.Include(x => x.Artist) on crc.ReleaseId equals r.Id
|
||||
where crc.CollectionId == collection.Id
|
||||
orderby crc.ListNumber
|
||||
select new CollectionRelease
|
||||
{
|
||||
ListNumber = crc.ListNumber,
|
||||
Release = Library.Models.Releases.ReleaseList.FromDataRelease(r, r.Artist, this.HttpContext.BaseUrl, this.MakeArtistThumbnailImage(r.Artist.RoadieId), this.MakeReleaseThumbnailImage(r.RoadieId))
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
if (includes.Contains("stats"))
|
||||
{
|
||||
var collectionReleases = (from crc in this.DbContext.CollectionReleases
|
||||
join r in this.DbContext.Releases.Include(x => x.Artist) on crc.ReleaseId equals r.Id
|
||||
where crc.CollectionId == collection.Id
|
||||
select r);
|
||||
|
||||
var collectionTracks = (from crc in this.DbContext.CollectionReleases
|
||||
join r in this.DbContext.Releases.Include(x => x.Artist) on crc.ReleaseId equals r.Id
|
||||
join rm in this.DbContext.ReleaseMedias on r.Id equals rm.ReleaseId
|
||||
join t in this.DbContext.Tracks on rm.Id equals t.ReleaseMediaId
|
||||
where crc.CollectionId == collection.Id
|
||||
select t);
|
||||
|
||||
result.Statistics = new CollectionStatistics
|
||||
{
|
||||
FileSize = collectionTracks.Sum(x => (long?)x.FileSize).ToFileSize(),
|
||||
MissingTrackCount = collectionTracks.Count(x => x.Hash != null),
|
||||
ReleaseCount = collectionReleases.Count(),
|
||||
ReleaseMediaCount = collectionReleases.Sum(x => x.MediaCount),
|
||||
Duration = collectionReleases.Sum(x => (long?)x.Duration),
|
||||
TrackCount = collectionReleases.Sum(x => x.TrackCount),
|
||||
TrackPlayedCount = collectionReleases.Sum(x => x.PlayedCount)
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
return new OperationResult<Collection>
|
||||
{
|
||||
Data = result,
|
||||
IsSuccess = result != null,
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
public async Task<Library.Models.Pagination.PagedResult<CollectionList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false, Guid? releaseId = null, Guid? artistId = null)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
using Roadie.Library.Models.Collections;
|
||||
using Roadie.Library;
|
||||
using Roadie.Library.Models.Collections;
|
||||
using Roadie.Library.Models.Pagination;
|
||||
using Roadie.Library.Models.Users;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Roadie.Api.Services
|
||||
{
|
||||
public interface ICollectionService
|
||||
{
|
||||
Task<OperationResult<Collection>> ById(User roadieUser, Guid id, IEnumerable<string> includes = null);
|
||||
|
||||
Task<PagedResult<CollectionList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false, Guid? releaseId = null, Guid? artistId = null);
|
||||
}
|
||||
}
|
|
@ -135,6 +135,7 @@ namespace Roadie.Api.Services
|
|||
join r in this.DbContext.Releases on cr.ReleaseId equals r.Id
|
||||
where c.RoadieId == request.FilterToCollectionId.Value
|
||||
select r.Id).ToArray();
|
||||
|
||||
}
|
||||
int[] favoriteReleaseIds = new int[0];
|
||||
if (request.FilterFavoriteOnly)
|
||||
|
@ -271,6 +272,52 @@ namespace Roadie.Api.Services
|
|||
release.Genre = genre?.dt ?? new DataToken();
|
||||
}
|
||||
|
||||
if (request.FilterToCollectionId.HasValue)
|
||||
{
|
||||
// Get and number the releases found for the Collection
|
||||
var collectionReleases = (from c in this.DbContext.Collections
|
||||
join cr in this.DbContext.CollectionReleases on c.Id equals cr.CollectionId
|
||||
where collectionReleaseIds.Contains(cr.ReleaseId)
|
||||
orderby cr.ListNumber
|
||||
select cr);
|
||||
foreach (var release in rows)
|
||||
{
|
||||
var cr = collectionReleases.FirstOrDefault(x => x.ReleaseId == release.DatabaseId);
|
||||
if (cr != null)
|
||||
{
|
||||
release.ListNumber = cr.ListNumber;
|
||||
}
|
||||
}
|
||||
// For the missing releases create a dummy release list item
|
||||
var resultListNumbers = (from x in rows select x.ListNumber).ToList();
|
||||
var collection = this.GetCollection(request.FilterToCollectionId.Value);
|
||||
var missingReleases = (from par in collection.PositionArtistReleases()
|
||||
where !resultListNumbers.Contains(par.Position)
|
||||
select par);
|
||||
var newRows = new List<ReleaseList>(rows);
|
||||
foreach(var missingRelease in missingReleases)
|
||||
{
|
||||
newRows.Add(new ReleaseList
|
||||
{
|
||||
Artist = new DataToken
|
||||
{
|
||||
Text = missingRelease.Artist
|
||||
},
|
||||
Release = new DataToken
|
||||
{
|
||||
Text = missingRelease.Release
|
||||
},
|
||||
CssClass = "missing",
|
||||
ArtistThumbnail = new Image($"{this.HttpContext.ImageBaseUrl }/unknown.jpg"),
|
||||
Thumbnail = new Image($"{this.HttpContext.ImageBaseUrl }/unknown.jpg"),
|
||||
ListNumber = missingRelease.Position
|
||||
});
|
||||
}
|
||||
// Resort the list for the collection by listNumber
|
||||
rows = newRows.OrderBy(x => x.ListNumber).Skip(request.SkipValue).Take(request.LimitValue).ToArray();
|
||||
rowCount = newRows.Count();
|
||||
}
|
||||
|
||||
if (roadieUser != null)
|
||||
{
|
||||
var userReleaseRatings = (from ur in this.DbContext.UserReleases
|
||||
|
@ -507,7 +554,7 @@ namespace Roadie.Api.Services
|
|||
TrackCount = release.TrackCount,
|
||||
TrackPlayedCount = release.PlayedCount,
|
||||
TrackSize = releaseTracks.Sum(x => (long?)x.size).ToFileSize(),
|
||||
TrackTime = releaseTracks.Any() ? TimeSpan.FromSeconds(Math.Floor((double)releaseTime / 1000)).ToString(@"hh\:mm\:ss") : "--:--"
|
||||
TrackTime = releaseTracks.Any() ? new TimeInfo((decimal)releaseTime).ToFullFormattedString() : "--:--"
|
||||
};
|
||||
result.MaxMediaNumber = releaseMedias.Max(x => x.MediaNumber);
|
||||
result.Statistics = releaseStats;
|
||||
|
|
|
@ -518,6 +518,7 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
|
||||
private Image MakeImage(Guid id, string type, int? width, int? height, string caption = null)
|
||||
{
|
||||
if (width.HasValue && height.HasValue && (width.Value != this.Configuration.ThumbnailImageSize.Width || height.Value != this.Configuration.ThumbnailImageSize.Height))
|
||||
|
@ -526,5 +527,7 @@ namespace Roadie.Api.Services
|
|||
}
|
||||
return new Image($"{this.HttpContext.ImageBaseUrl }/{type}/{id}", caption, null);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -150,9 +150,9 @@ namespace Roadie.Api.Services
|
|||
FavoriteCount = userTracks.Count(x => x.IsFavorite ?? false),
|
||||
PlayedCount = userTracks.Sum(x => x.PlayedCount),
|
||||
FileSizeFormatted = ((long?)track.FileSize).ToFileSize(),
|
||||
Time = TimeSpan.FromSeconds(Math.Floor((double)track.Duration / 1000)).ToString(@"hh\:mm\:ss")
|
||||
Time = new TimeInfo((decimal)track.Duration).ToFullFormattedString()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -71,6 +71,9 @@ namespace Roadie.Api
|
|||
// c.SwaggerEndpoint("/swagger/swagger.json", "Roadie API");
|
||||
// c.RoutePrefix = string.Empty;
|
||||
//});
|
||||
|
||||
app.UseStaticFiles();
|
||||
|
||||
app.UseSignalR(routes =>
|
||||
{
|
||||
routes.MapHub<PlayActivityHub>("/playActivityHub");
|
||||
|
|
BIN
RoadieApi/wwwroot/Images/unknown.jpg
Normal file
BIN
RoadieApi/wwwroot/Images/unknown.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
|
@ -1,4 +1,5 @@
|
|||
using Roadie.Library.Enums;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
using System;
|
||||
using CsvHelper;
|
||||
using Newtonsoft.Json;
|
||||
using Roadie.Library.Enums;
|
||||
using Roadie.Library.Utility;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Roadie.Library.Data
|
||||
|
@ -23,5 +28,129 @@ namespace Roadie.Library.Data
|
|||
return Collection.CacheUrn(this.RoadieId);
|
||||
}
|
||||
}
|
||||
|
||||
public int? _positionColumn = null;
|
||||
public int PositionColumn
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._positionColumn == null)
|
||||
{
|
||||
var looper = -1;
|
||||
foreach (var pos in this.ListInCSVFormat.Split(','))
|
||||
{
|
||||
looper++;
|
||||
if (pos.ToLower().Equals("position"))
|
||||
{
|
||||
this._positionColumn = looper;
|
||||
}
|
||||
}
|
||||
}
|
||||
return this._positionColumn.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public int? _artistColumn = null;
|
||||
public int ArtistColumn
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._artistColumn == null)
|
||||
{
|
||||
var looper = -1;
|
||||
foreach (var pos in this.ListInCSVFormat.Split(','))
|
||||
{
|
||||
looper++;
|
||||
if (pos.ToLower().Equals("artist"))
|
||||
{
|
||||
this._artistColumn = looper;
|
||||
}
|
||||
}
|
||||
}
|
||||
return this._artistColumn.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public int? _releaseColumn = null;
|
||||
public int ReleaseColumn
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._releaseColumn == null)
|
||||
{
|
||||
var looper = -1;
|
||||
foreach (var pos in this.ListInCSVFormat.Split(','))
|
||||
{
|
||||
looper++;
|
||||
if (pos.ToLower().Equals("release"))
|
||||
{
|
||||
this._releaseColumn = looper;
|
||||
}
|
||||
}
|
||||
}
|
||||
return this._releaseColumn.Value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private IEnumerable<PositionAristRelease> _positionAristReleases = null;
|
||||
|
||||
public IEnumerable<PositionAristRelease> PositionArtistReleases()
|
||||
{
|
||||
if (this._positionAristReleases == null)
|
||||
{
|
||||
var rows = new List<PositionAristRelease>();
|
||||
using (var sr = new StringReader(this.ListInCSV))
|
||||
{
|
||||
var index = 0;
|
||||
var csv = new CsvReader(sr, new CsvHelper.Configuration.Configuration { MissingFieldFound = null, HasHeaderRecord = false });
|
||||
while (csv.Read())
|
||||
{
|
||||
index++;
|
||||
rows.Add(new PositionAristRelease
|
||||
{
|
||||
Index = index,
|
||||
Position = csv.GetField<int>(this.PositionColumn),
|
||||
Artist = SafeParser.ToString(csv.GetField<string>(this.ArtistColumn)),
|
||||
Release = SafeParser.ToString(csv.GetField<string>(this.ReleaseColumn)),
|
||||
});
|
||||
}
|
||||
}
|
||||
this._positionAristReleases = rows;
|
||||
}
|
||||
return this._positionAristReleases;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class PositionAristRelease
|
||||
{
|
||||
[JsonIgnore]
|
||||
public Statuses Status { get; set; }
|
||||
|
||||
[JsonProperty("Status")]
|
||||
public string StatusVerbose
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.Status.ToString();
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// This is the index (position in the list regardless of the position number)
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public int Index { get; set; }
|
||||
/// <summary>
|
||||
/// This is the position number for the list (can be a year "1984" can be a number "14")
|
||||
/// </summary>
|
||||
public int Position { get; set; }
|
||||
public string Artist { get; set; }
|
||||
public string Release { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("Position [{0}], Artist [{1}], Release [{2}]", this.Position, this.Artist, this.Release);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
19
RoadieLibrary/Extensions/DecimalExt.cs
Normal file
19
RoadieLibrary/Extensions/DecimalExt.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
using Roadie.Library.Utility;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Roadie.Library.Extensions
|
||||
{
|
||||
public static class DecimalExt
|
||||
{
|
||||
public static int ToSecondsFromMilliseconds(this decimal? value)
|
||||
{
|
||||
if (value > 0)
|
||||
{
|
||||
return (int)new TimeInfo(value.Value).Seconds;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
18
RoadieLibrary/Extensions/TimeSpanExt.cs
Normal file
18
RoadieLibrary/Extensions/TimeSpanExt.cs
Normal file
|
@ -0,0 +1,18 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Roadie.Library.Extensions
|
||||
{
|
||||
public static class TimeSpanExt
|
||||
{
|
||||
public static string ToDuration(this TimeSpan input)
|
||||
{
|
||||
if(input == null || input.TotalMilliseconds == 0)
|
||||
{
|
||||
return "--/--/--";
|
||||
}
|
||||
return input.ToString(@"ddd\.hh\:mm\:ss");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Roadie.Library.Models.Statistics;
|
||||
|
||||
namespace Roadie.Library.Models.Collections
|
||||
{
|
||||
[Serializable]
|
||||
public class Collection : EntityModelBase
|
||||
{
|
||||
public const string DefaultIncludes = "stats";
|
||||
|
||||
public int CollectionCount { get; set; }
|
||||
|
||||
public string CollectionType { get; set; }
|
||||
|
@ -17,10 +20,44 @@ namespace Roadie.Library.Models.Collections
|
|||
[MaxLength(200)]
|
||||
public string Edition { get; set; }
|
||||
|
||||
[MaxLength(100)]
|
||||
public string Name { get; set; }
|
||||
|
||||
public DataToken Maintainer { get; set; }
|
||||
|
||||
public IEnumerable<CollectionRelease> Releases { get; set; }
|
||||
|
||||
public Image Thumbnail { get; set; }
|
||||
public Image MediumThumbnail { get; set; }
|
||||
public string ListInCSVFormat { get; set; }
|
||||
public string ListInCSV { get; set; }
|
||||
|
||||
public int PercentComplete
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.CollectionCount == 0 || this.CollectionFoundCount == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return (int)Math.Floor((decimal)this.CollectionFoundCount / (decimal)this.CollectionCount * 100);
|
||||
}
|
||||
}
|
||||
|
||||
public int? MissingReleaseCount
|
||||
{
|
||||
get
|
||||
{
|
||||
if(this.CollectionCount == this.CollectionFoundCount)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return this.CollectionCount - this.CollectionFoundCount;
|
||||
}
|
||||
}
|
||||
|
||||
public int? CollectionFoundCount { get; set; }
|
||||
public CollectionStatistics Statistics { get; set; }
|
||||
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@ namespace Roadie.Library.Models.Collections
|
|||
[Serializable]
|
||||
public class CollectionRelease
|
||||
{
|
||||
public Release Release { get; set; }
|
||||
public ReleaseList Release { get; set; }
|
||||
public int ListNumber { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Roadie.Library.Models.Statistics;
|
||||
using Roadie.Library.Utility;
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
|
@ -32,7 +33,7 @@ namespace Roadie.Library.Models
|
|||
|
||||
public ReleaseGroupingStatistics Statistics { get; set; }
|
||||
|
||||
public int? Duration { get; set; }
|
||||
public decimal? Duration { get; set; }
|
||||
public string DurationTime
|
||||
{
|
||||
get
|
||||
|
@ -41,7 +42,7 @@ namespace Roadie.Library.Models
|
|||
{
|
||||
return "--:--";
|
||||
}
|
||||
return TimeSpan.FromSeconds(this.Duration.Value / 1000).ToString(@"dd\.hh\:mm\:ss");
|
||||
return new TimeInfo(this.Duration.Value).ToFullFormattedString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using Mapster;
|
||||
using Roadie.Library.Models.Statistics;
|
||||
using Roadie.Library.Models.Users;
|
||||
using Roadie.Library.Utility;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
@ -28,7 +29,7 @@ namespace Roadie.Library.Models.Playlists
|
|||
public Image MediumThumbnail { get; set; }
|
||||
public short? TrackCount { get; set; }
|
||||
public short? ReleaseCount { get; set; }
|
||||
public int? Duration { get; set; }
|
||||
public decimal? Duration { get; set; }
|
||||
public string DurationTime
|
||||
{
|
||||
get
|
||||
|
@ -37,7 +38,7 @@ namespace Roadie.Library.Models.Playlists
|
|||
{
|
||||
return "--:--";
|
||||
}
|
||||
return TimeSpan.FromSeconds(this.Duration.Value / 1000).ToString(@"dd\.hh\:mm\:ss");
|
||||
return new TimeInfo(this.Duration.Value).ToFullFormattedString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using Roadie.Library.Utility;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
|
@ -13,7 +14,7 @@ namespace Roadie.Library.Models.Playlists
|
|||
public int? PlaylistCount { get; set; }
|
||||
public Image UserThumbnail { get; set; }
|
||||
public bool IsPublic { get; set; }
|
||||
public int? Duration { get; set; }
|
||||
public decimal? Duration { get; set; }
|
||||
public string DurationTime
|
||||
{
|
||||
get
|
||||
|
@ -22,7 +23,7 @@ namespace Roadie.Library.Models.Playlists
|
|||
{
|
||||
return "--:--";
|
||||
}
|
||||
return TimeSpan.FromSeconds(this.Duration.Value / 1000).ToString(@"hh\:mm\:ss");
|
||||
return new TimeInfo(this.Duration.Value).ToFullFormattedString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ using Newtonsoft.Json;
|
|||
using Roadie.Library.Enums;
|
||||
using Roadie.Library.Extensions;
|
||||
using Roadie.Library.Models.Users;
|
||||
using Roadie.Library.Utility;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
@ -47,7 +48,7 @@ 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; }
|
||||
public decimal? Duration { get; set; }
|
||||
public string DurationTime
|
||||
{
|
||||
get
|
||||
|
@ -56,12 +57,25 @@ namespace Roadie.Library.Models.Releases
|
|||
{
|
||||
return "--:--";
|
||||
}
|
||||
return TimeSpan.FromSeconds(this.Duration.Value / 1000).ToString(@"hh\:mm\:ss");
|
||||
return new TimeInfo(this.Duration.Value).ToFullFormattedString();
|
||||
}
|
||||
|
||||
}
|
||||
public int? MediaCount { get; set; }
|
||||
|
||||
public bool IsValid
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.Id != Guid.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is populated on a request to get the list of releases for a collection.
|
||||
/// </summary>
|
||||
public int? ListNumber { get; set; }
|
||||
|
||||
public static ReleaseList FromDataRelease(Data.Release release, Data.Artist artist, string baseUrl, Image artistThumbnail, Image thumbnail)
|
||||
{
|
||||
return new ReleaseList
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using Roadie.Library.Utility;
|
||||
using System;
|
||||
|
||||
namespace Roadie.Library.Models.Statistics
|
||||
{
|
||||
|
@ -13,5 +14,19 @@ namespace Roadie.Library.Models.Statistics
|
|||
public int? TrackCount { get; set; }
|
||||
public int? TrackPlayedCount { get; set; }
|
||||
public string TrackTime { get; set; }
|
||||
public decimal? Duration { get; set; }
|
||||
|
||||
public string DurationTime
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!this.Duration.HasValue)
|
||||
{
|
||||
return "--:--";
|
||||
}
|
||||
return new TimeInfo(this.Duration.Value).ToFullFormattedString();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
using Newtonsoft.Json;
|
||||
using Roadie.Library.Models.Releases;
|
||||
using Roadie.Library.Models.Users;
|
||||
using Roadie.Library.Utility;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
@ -24,14 +25,14 @@ namespace Roadie.Library.Models
|
|||
{
|
||||
get
|
||||
{
|
||||
return this.Duration.HasValue ? TimeSpan.FromSeconds(this.Duration.Value / 1000).ToString(@"hh\:mm\:ss") : "--:--";
|
||||
return this.Duration.HasValue ? new TimeInfo((decimal)this.Duration.Value).ToFullFormattedString() : "--:--";
|
||||
}
|
||||
}
|
||||
public string DurationTimeShort
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.Duration.HasValue ? TimeSpan.FromSeconds(this.Duration.Value / 1000).ToString(@"mm\:ss") : "--:--";
|
||||
return this.Duration.HasValue ? new TimeInfo((decimal)this.Duration.Value).ToShortFormattedString() : "--:--";
|
||||
}
|
||||
}
|
||||
public DateTime? LastPlayed { get; set; }
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CsvHelper" Version="12.0.1" />
|
||||
<PackageReference Include="FluentFTP" Version="19.2.2" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.8.10" />
|
||||
<PackageReference Include="ID3" Version="0.5.0-beta.1" />
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace Roadie.Library.Utility
|
|||
|
||||
public decimal Hours { get; set; }
|
||||
|
||||
public string HoursForamtted
|
||||
public string HoursFormatted
|
||||
{
|
||||
get
|
||||
{
|
||||
|
@ -77,6 +77,7 @@ namespace Roadie.Library.Utility
|
|||
|
||||
public TimeInfo(decimal milliseconds)
|
||||
{
|
||||
|
||||
var secondsTotal = milliseconds / 1000;
|
||||
var minutesTotal = Math.Floor(secondsTotal / 60);
|
||||
var hoursTotal = Math.Floor(minutesTotal / 60);
|
||||
|
@ -96,9 +97,18 @@ namespace Roadie.Library.Utility
|
|||
return $"{ (string.IsNullOrEmpty(yearsFormatted) ? string.Empty : yearsFormatted + ":") }{ this.ToString() }";
|
||||
}
|
||||
|
||||
public string ToShortFormattedString()
|
||||
{
|
||||
return $"{ MinutesFormatted }:{ SecondsFormatted }";
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{ DaysFormatted}:{ HoursForamtted}:{ MinutesFormatted }";
|
||||
if(this.Days > 0)
|
||||
{
|
||||
return $"{ DaysFormatted}:{ HoursFormatted}:{ MinutesFormatted}:{ SecondsFormatted }";
|
||||
}
|
||||
return $"{ HoursFormatted}:{ MinutesFormatted }:{ SecondsFormatted }";
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue