2018-11-17 02:14:32 +00:00
using Mapster ;
using Microsoft.AspNetCore.Http ;
2018-11-23 04:18:48 +00:00
using Microsoft.EntityFrameworkCore ;
2018-11-17 02:14:32 +00:00
using Microsoft.Extensions.Logging ;
2018-12-09 14:33:40 +00:00
using Newtonsoft.Json ;
2018-11-17 02:14:32 +00:00
using Roadie.Library ;
2018-11-12 00:28:37 +00:00
using Roadie.Library.Caching ;
using Roadie.Library.Configuration ;
using Roadie.Library.Encoding ;
2018-12-12 14:31:39 +00:00
using Roadie.Library.Enums ;
2018-11-17 02:14:32 +00:00
using Roadie.Library.Extensions ;
2019-06-30 22:14:36 +00:00
using Roadie.Library.Identity ;
2019-05-11 03:07:45 +00:00
using Roadie.Library.Imaging ;
2019-08-11 19:11:29 +00:00
using Roadie.Library.MetaData.Audio ;
2018-11-12 00:28:37 +00:00
using Roadie.Library.Models ;
using Roadie.Library.Models.Pagination ;
2018-12-07 21:02:38 +00:00
using Roadie.Library.Models.Releases ;
2019-06-30 22:14:36 +00:00
using Roadie.Library.Models.Statistics ;
2018-11-12 00:28:37 +00:00
using Roadie.Library.Models.Users ;
using Roadie.Library.Utility ;
using System ;
using System.Collections.Generic ;
using System.Diagnostics ;
2018-11-17 02:14:32 +00:00
using System.IO ;
2018-11-12 00:28:37 +00:00
using System.Linq ;
using System.Linq.Dynamic.Core ;
using System.Threading.Tasks ;
using data = Roadie . Library . Data ;
namespace Roadie.Api.Services
{
public class TrackService : ServiceBase , ITrackService
{
2019-02-25 02:26:54 +00:00
private IAdminService AdminService { get ; }
2019-06-30 22:14:36 +00:00
2019-08-11 19:11:29 +00:00
private IAudioMetaDataHelper AudioMetaDataHelper { get ; }
2019-06-30 22:14:36 +00:00
private IBookmarkService BookmarkService { get ; }
2018-12-12 14:31:39 +00:00
2019-08-22 20:33:07 +00:00
public TrackService ( IRoadieSettings configuration , IHttpEncoder httpEncoder , IHttpContext httpContext ,
data . IRoadieDbContext dbContext , ICacheManager cacheManager , ILogger < TrackService > logger ,
2019-08-11 19:11:29 +00:00
IBookmarkService bookmarkService , IAdminService adminService , IAudioMetaDataHelper audioMetaDataHelper )
2018-11-12 00:28:37 +00:00
: base ( configuration , httpEncoder , dbContext , cacheManager , logger , httpContext )
{
2019-06-30 22:14:36 +00:00
BookmarkService = bookmarkService ;
2019-08-11 19:11:29 +00:00
AudioMetaDataHelper = audioMetaDataHelper ;
2019-06-30 22:14:36 +00:00
AdminService = adminService ;
2018-11-12 00:28:37 +00:00
}
2019-09-05 02:04:20 +00:00
public TrackService ( IRoadieSettings configuration , data . IRoadieDbContext dbContext , ICacheManager cacheManager , ILogger logger )
: base ( configuration , null , dbContext , cacheManager , logger , null )
{
}
2018-11-17 02:14:32 +00:00
public static long DetermineByteEndFromHeaders ( IHeaderDictionary headers , long fileLength )
{
var defaultFileLength = fileLength - 1 ;
if ( headers = = null | | ! headers . Any ( x = > x . Key = = "Range" ) )
{
return defaultFileLength ;
}
2019-06-30 22:14:36 +00:00
2018-11-17 02:14:32 +00:00
long? result = null ;
var rangeHeader = headers [ "Range" ] ;
string rangeEnd = null ;
var rangeBegin = rangeHeader . FirstOrDefault ( ) ;
if ( ! string . IsNullOrEmpty ( rangeBegin ) )
{
//bytes=0-
rangeBegin = rangeBegin . Replace ( "bytes=" , "" ) ;
var parts = rangeBegin . Split ( '-' ) ;
rangeBegin = parts [ 0 ] ;
if ( parts . Length > 1 )
{
rangeEnd = parts [ 1 ] ;
}
2019-06-30 22:14:36 +00:00
2018-11-17 02:14:32 +00:00
if ( ! string . IsNullOrEmpty ( rangeEnd ) )
{
2019-06-30 22:14:36 +00:00
result = long . TryParse ( rangeEnd , out var outValue ) ? ( int? ) outValue : null ;
2018-11-17 02:14:32 +00:00
}
}
2019-06-30 22:14:36 +00:00
2018-11-17 02:14:32 +00:00
return result ? ? defaultFileLength ;
}
public static long DetermineByteStartFromHeaders ( IHeaderDictionary headers )
{
if ( headers = = null | | ! headers . Any ( x = > x . Key = = "Range" ) )
{
return 0 ;
}
2019-06-30 22:14:36 +00:00
2018-11-17 02:14:32 +00:00
long result = 0 ;
var rangeHeader = headers [ "Range" ] ;
var rangeBegin = rangeHeader . FirstOrDefault ( ) ;
if ( ! string . IsNullOrEmpty ( rangeBegin ) )
{
//bytes=0-
rangeBegin = rangeBegin . Replace ( "bytes=" , "" ) ;
var parts = rangeBegin . Split ( '-' ) ;
rangeBegin = parts [ 0 ] ;
if ( ! string . IsNullOrEmpty ( rangeBegin ) )
{
long . TryParse ( rangeBegin , out result ) ;
}
}
2019-06-30 22:14:36 +00:00
2018-11-17 02:14:32 +00:00
return result ;
}
2019-01-05 22:40:33 +00:00
public async Task < OperationResult < Track > > ById ( User roadieUser , Guid id , IEnumerable < string > includes )
{
2019-08-04 16:30:19 +00:00
var timings = new Dictionary < string , long > ( ) ;
var tsw = new Stopwatch ( ) ;
2019-01-05 22:40:33 +00:00
var sw = Stopwatch . StartNew ( ) ;
sw . Start ( ) ;
2019-08-04 16:30:19 +00:00
var cacheKey = string . Format ( "urn:track_by_id_operation:{0}:{1}" , id , includes = = null ? "0" : string . Join ( "|" , includes ) ) ;
2019-08-22 20:33:07 +00:00
var result = await CacheManager . GetAsync ( cacheKey , async ( ) = >
2019-08-04 16:30:19 +00:00
{
tsw . Restart ( ) ;
var rr = await TrackByIdAction ( id , includes ) ;
tsw . Stop ( ) ;
timings . Add ( "TrackByIdAction" , tsw . ElapsedMilliseconds ) ;
return rr ;
} , data . Track . CacheRegionUrn ( id ) ) ;
2019-01-05 22:40:33 +00:00
if ( result ? . Data ! = null & & roadieUser ! = null )
{
2019-08-04 16:30:19 +00:00
tsw . Restart ( ) ;
2019-06-30 22:14:36 +00:00
var user = GetUser ( roadieUser . UserId ) ;
2019-08-04 16:30:19 +00:00
tsw . Stop ( ) ;
timings . Add ( "getUser" , tsw . ElapsedMilliseconds ) ;
tsw . Restart ( ) ;
2019-06-30 22:14:36 +00:00
var track = GetTrack ( id ) ;
2019-08-04 16:30:19 +00:00
tsw . Stop ( ) ;
timings . Add ( "getTrack" , tsw . ElapsedMilliseconds ) ;
result . Data . TrackPlayUrl = MakeTrackPlayUrl ( user , HttpContext . BaseUrl , track . Id , track . RoadieId ) ;
tsw . Restart ( ) ;
var userBookmarkResult = await BookmarkService . List ( roadieUser , new PagedRequest ( ) , false , BookmarkType . Track ) ;
2019-01-05 22:40:33 +00:00
if ( userBookmarkResult . IsSuccess )
{
2019-06-30 22:14:36 +00:00
result . Data . UserBookmarked =
userBookmarkResult ? . Rows ? . FirstOrDefault ( x = > x . Bookmark . Value = = track . RoadieId . ToString ( ) ) ! =
null ;
2019-01-05 22:40:33 +00:00
}
2019-08-04 16:30:19 +00:00
tsw . Stop ( ) ;
timings . Add ( "userBookmarks" , tsw . ElapsedMilliseconds ) ;
2019-06-30 22:14:36 +00:00
2019-08-04 16:30:19 +00:00
tsw . Restart ( ) ;
var userTrack = DbContext . UserTracks . FirstOrDefault ( x = > x . TrackId = = track . Id & & x . UserId = = roadieUser . Id ) ;
2019-01-05 22:40:33 +00:00
if ( userTrack ! = null )
{
result . Data . UserRating = new UserTrack
{
Rating = userTrack . Rating ,
IsDisliked = userTrack . IsDisliked ? ? false ,
IsFavorite = userTrack . IsFavorite ? ? false ,
LastPlayed = userTrack . LastPlayed ,
PlayedCount = userTrack . PlayedCount
} ;
}
2019-08-04 16:30:19 +00:00
tsw . Stop ( ) ;
timings . Add ( "userTracks" , tsw . ElapsedMilliseconds ) ;
2019-06-28 21:24:32 +00:00
if ( result . Data . Comments . Any ( ) )
{
2019-08-04 16:30:19 +00:00
tsw . Restart ( ) ;
2019-06-28 21:24:32 +00:00
var commentIds = result . Data . Comments . Select ( x = > x . DatabaseId ) . ToArray ( ) ;
2019-06-30 22:14:36 +00:00
var userCommentReactions = ( from cr in DbContext . CommentReactions
2019-06-28 21:24:32 +00:00
where commentIds . Contains ( cr . CommentId )
where cr . UserId = = roadieUser . Id
select cr ) . ToArray ( ) ;
foreach ( var comment in result . Data . Comments )
{
2019-06-30 22:14:36 +00:00
var userCommentReaction =
userCommentReactions . FirstOrDefault ( x = > x . CommentId = = comment . DatabaseId ) ;
2019-06-28 21:24:32 +00:00
comment . IsDisliked = userCommentReaction ? . ReactionValue = = CommentReaction . Dislike ;
comment . IsLiked = userCommentReaction ? . ReactionValue = = CommentReaction . Like ;
}
2019-08-04 16:30:19 +00:00
tsw . Stop ( ) ;
timings . Add ( "userComments" , tsw . ElapsedMilliseconds ) ;
2019-06-28 21:24:32 +00:00
}
2019-01-05 22:40:33 +00:00
}
2019-06-30 22:14:36 +00:00
2019-01-05 22:40:33 +00:00
sw . Stop ( ) ;
2019-08-04 16:30:19 +00:00
Logger . LogInformation ( $"ById Track: `{ result?.Data }`, includes [{ includes.ToCSV() }], timings [{ timings.ToTimings() }]" ) ;
2019-01-05 22:40:33 +00:00
return new OperationResult < Track > ( result . Messages )
{
Data = result ? . Data ,
Errors = result ? . Errors ,
IsNotFoundResult = result ? . IsNotFoundResult ? ? false ,
IsSuccess = result ? . IsSuccess ? ? false ,
OperationTime = sw . ElapsedMilliseconds
} ;
}
2019-07-18 15:52:00 +00:00
public Task < Library . Models . Pagination . PagedResult < TrackList > > List ( PagedRequest request , User roadieUser , bool? doRandomize = false , Guid ? releaseId = null )
2018-11-12 00:28:37 +00:00
{
2018-12-09 14:33:40 +00:00
try
2018-11-23 04:18:48 +00:00
{
2018-12-09 14:33:40 +00:00
var sw = new Stopwatch ( ) ;
sw . Start ( ) ;
2018-12-09 17:58:31 +00:00
int? rowCount = null ;
2019-01-05 22:40:33 +00:00
if ( ! string . IsNullOrEmpty ( request . Sort ) )
2018-12-24 19:40:49 +00:00
{
request . Sort = request . Sort . Replace ( "Release.Text" , "Release.Release.Text" ) ;
}
2019-06-30 22:14:36 +00:00
var favoriteTrackIds = new int [ 0 ] . AsQueryable ( ) ;
2018-12-09 14:33:40 +00:00
if ( request . FilterFavoriteOnly )
{
2019-06-30 22:14:36 +00:00
favoriteTrackIds = from t in DbContext . Tracks
join ut in DbContext . UserTracks on t . Id equals ut . TrackId
where ut . UserId = = roadieUser . Id
where ut . IsFavorite ? ? false
select t . Id ;
2018-12-09 14:33:40 +00:00
}
2019-06-30 22:14:36 +00:00
var playListTrackPositions = new Dictionary < int , int > ( ) ;
var playlistTrackIds = new int [ 0 ] ;
2018-12-09 14:33:40 +00:00
if ( request . FilterToPlaylistId . HasValue )
2018-11-24 17:52:15 +00:00
{
2019-08-04 04:36:36 +00:00
var playlistTrackInfos = ( from plt in DbContext . PlaylistTracks
join p in DbContext . Playlists on plt . PlayListId equals p . Id
join t in DbContext . Tracks on plt . TrackId equals t . Id
where p . RoadieId = = request . FilterToPlaylistId . Value
orderby plt . ListNumber
select new
{
plt . ListNumber ,
t . Id
} ) . ToArray ( ) ;
2018-12-09 17:58:31 +00:00
rowCount = playlistTrackInfos . Count ( ) ;
2019-08-03 22:59:20 +00:00
playListTrackPositions = playlistTrackInfos
. Skip ( request . SkipValue )
. Take ( request . LimitValue )
. ToDictionary ( x = > x . Id , x = > x . ListNumber ) ;
2018-12-09 14:33:40 +00:00
playlistTrackIds = playListTrackPositions . Select ( x = > x . Key ) . ToArray ( ) ;
request . Sort = "TrackNumber" ;
request . Order = "ASC" ;
2018-12-09 20:31:02 +00:00
request . Page = 1 ; // Set back to first or it skips already paged tracks for playlist
request . SkipValue = 0 ;
2018-11-24 17:52:15 +00:00
}
2019-01-10 23:40:04 +00:00
2019-06-30 22:14:36 +00:00
var collectionTrackIds = new int [ 0 ] ;
2019-01-13 17:27:41 +00:00
if ( request . FilterToCollectionId . HasValue )
2019-01-10 23:40:04 +00:00
{
request . Limit = roadieUser ? . PlayerTrackLimit ? ? 50 ;
2019-06-30 22:14:36 +00:00
collectionTrackIds = ( from cr in DbContext . CollectionReleases
join c in DbContext . Collections on cr . CollectionId equals c . Id
join r in DbContext . Releases on cr . ReleaseId equals r . Id
join rm in DbContext . ReleaseMedias on r . Id equals rm . ReleaseId
join t in DbContext . Tracks on rm . Id equals t . ReleaseMediaId
2019-01-10 23:40:04 +00:00
where c . RoadieId = = request . FilterToCollectionId . Value
2019-01-13 17:27:41 +00:00
orderby cr . ListNumber , rm . MediaNumber , t . TrackNumber
2019-08-03 22:59:20 +00:00
select t . Id )
. Skip ( request . SkipValue )
. Take ( request . LimitValue )
. ToArray ( ) ;
2019-01-10 23:40:04 +00:00
}
2019-06-23 15:45:45 +00:00
IQueryable < int > topTrackids = null ;
2018-12-09 14:33:40 +00:00
if ( request . FilterTopPlayedOnly )
2018-11-24 17:52:15 +00:00
{
2018-12-09 14:33:40 +00:00
// Get request number of top played songs for artist
2019-06-30 22:14:36 +00:00
topTrackids = ( from t in DbContext . Tracks
join ut in DbContext . UserTracks on t . Id equals ut . TrackId
join rm in DbContext . ReleaseMedias on t . ReleaseMediaId equals rm . Id
join r in DbContext . Releases on rm . ReleaseId equals r . Id
join a in DbContext . Artists on r . ArtistId equals a . Id
2018-12-09 14:33:40 +00:00
where a . RoadieId = = request . FilterToArtistId
orderby ut . PlayedCount descending
select t . Id
2019-07-04 15:50:31 +00:00
) . Skip ( request . SkipValue )
. Take ( request . LimitValue ) ;
2018-12-09 14:33:40 +00:00
}
2019-06-30 22:14:36 +00:00
2018-12-09 14:33:40 +00:00
int [ ] randomTrackIds = null ;
2019-08-04 05:39:00 +00:00
2019-01-13 17:27:41 +00:00
if ( doRandomize ? ? false )
{
2019-08-04 05:39:00 +00:00
var randomLimit = roadieUser ? . RandomReleaseLimit ? ? request . LimitValue ;
2019-01-31 04:53:09 +00:00
var userId = roadieUser ? . Id ? ? - 1 ;
2019-01-09 04:43:19 +00:00
2019-08-04 05:39:00 +00:00
// Select random tracks that are not disliked Artist, Release or Track by user.
var dislikedArtistIds = ( from ua in DbContext . UserArtists
where ua . UserId = = userId
where ua . IsDisliked = = true
select ua . ArtistId ) . ToArray ( ) ;
var dislikedReleaseIds = ( from ur in DbContext . UserReleases
where ur . UserId = = userId
where ur . IsDisliked = = true
select ur . ReleaseId ) . ToArray ( ) ;
var dislikedTrackIds = ( from ut in DbContext . UserTracks
where ut . UserId = = userId
where ut . IsDisliked = = true
select ut . TrackId ) . ToArray ( ) ;
int [ ] favoritedTrackIds = null ;
if ( request . FilterFavoriteOnly )
{
favoritedTrackIds = ( from ut in DbContext . UserTracks
where ut . UserId = = userId
where ut . IsFavorite = = true
select ut . TrackId ) . ToArray ( ) ;
favoriteTrackIds = new int [ 0 ] . AsQueryable ( ) ;
request . FilterFavoriteOnly = false ;
}
2019-08-06 01:45:00 +00:00
randomTrackIds = ( from t in DbContext . Tracks
2019-08-22 20:33:07 +00:00
join rm in DbContext . ReleaseMedias on t . ReleaseMediaId equals rm . Id
join r in DbContext . Releases on rm . ReleaseId equals r . Id
join a in DbContext . Artists on r . ArtistId equals a . Id
where ! request . FilterRatedOnly | | request . FilterRatedOnly & & t . Rating > 0
where ! dislikedArtistIds . Contains ( r . ArtistId )
where ! dislikedArtistIds . Contains ( t . ArtistId ? ? 0 )
where ! dislikedReleaseIds . Contains ( r . Id )
where ! dislikedTrackIds . Contains ( t . Id )
where favoritedTrackIds = = null | | favoritedTrackIds . Contains ( t . Id )
where t . Hash ! = null
select new TrackList
{
DatabaseId = t . Id ,
Artist = new ArtistList
{
Artist = new DataToken { Value = a . RoadieId . ToString ( ) , Text = a . Name }
} ,
Release = new ReleaseList
{
Release = new DataToken { Value = r . RoadieId . ToString ( ) , Text = r . Title }
}
} )
2019-08-06 01:45:00 +00:00
. OrderBy ( x = > x . Artist . RandomSortId )
. ThenBy ( x = > x . RandomSortId )
. ThenBy ( x = > x . RandomSortId )
. Take ( randomLimit )
2019-08-04 05:39:00 +00:00
. Select ( x = > x . DatabaseId )
. ToArray ( ) ;
2018-12-09 14:33:40 +00:00
}
2019-06-30 22:14:36 +00:00
2018-12-09 14:33:40 +00:00
Guid ? [ ] filterToTrackIds = null ;
if ( request . FilterToTrackId . HasValue | | request . FilterToTrackIds ! = null )
{
var f = new List < Guid ? > ( ) ;
if ( request . FilterToTrackId . HasValue )
2018-11-24 17:52:15 +00:00
{
2018-12-09 14:33:40 +00:00
f . Add ( request . FilterToTrackId ) ;
}
2019-06-30 22:14:36 +00:00
2018-12-09 14:33:40 +00:00
if ( request . FilterToTrackIds ! = null )
{
foreach ( var ft in request . FilterToTrackIds )
2018-11-24 17:52:15 +00:00
{
2018-12-09 14:33:40 +00:00
if ( ! f . Contains ( ft ) )
{
f . Add ( ft ) ;
}
2018-11-24 17:52:15 +00:00
}
}
2019-06-30 22:14:36 +00:00
2018-12-09 14:33:40 +00:00
filterToTrackIds = f . ToArray ( ) ;
2018-11-24 17:52:15 +00:00
}
2019-06-30 22:14:36 +00:00
2019-07-04 15:50:31 +00:00
var normalizedFilterValue = ! string . IsNullOrEmpty ( request . FilterValue ) ? request . FilterValue . ToAlphanumericName ( ) : null ;
2019-03-10 16:55:21 +00:00
var isEqualFilter = false ;
if ( ! string . IsNullOrEmpty ( request . FilterValue ) )
{
var filter = request . FilterValue ;
// if filter string is wrapped in quotes then is an exact not like search, e.g. "Diana Ross" should not return "Diana Ross & The Supremes"
if ( filter . StartsWith ( '"' ) & & filter . EndsWith ( '"' ) )
{
isEqualFilter = true ;
request . Filter = filter . Substring ( 1 , filter . Length - 2 ) ;
}
}
2019-07-04 15:50:31 +00:00
// Did this for performance against the Track table, with just * selects the table scans are too much of a performance hit.
2019-06-30 22:14:36 +00:00
var resultQuery = from t in DbContext . Tracks
join rm in DbContext . ReleaseMedias on t . ReleaseMediaId equals rm . Id
join r in DbContext . Releases on rm . ReleaseId equals r . Id
join releaseArtist in DbContext . Artists on r . ArtistId equals releaseArtist . Id
join trackArtist in DbContext . Artists on t . ArtistId equals trackArtist . Id into tas
from trackArtist in tas . DefaultIfEmpty ( )
where t . Hash ! = null
2019-07-04 15:50:31 +00:00
where randomTrackIds = = null | | randomTrackIds . Contains ( t . Id )
2019-06-30 22:14:36 +00:00
where filterToTrackIds = = null | | filterToTrackIds . Contains ( t . RoadieId )
2019-08-25 20:38:07 +00:00
where releaseId = = null | | r . RoadieId = = releaseId
2019-06-30 22:14:36 +00:00
where request . FilterMinimumRating = = null | | t . Rating > = request . FilterMinimumRating . Value
2019-08-25 20:38:07 +00:00
where request . FilterValue = = "" | | ( trackArtist ! = null & & trackArtist . Name . Contains ( request . FilterValue ) ) | | t . Title . Contains ( request . FilterValue ) | | t . AlternateNames . Contains ( request . FilterValue ) | | t . AlternateNames . Contains ( normalizedFilterValue ) | | t . PartTitles . Contains ( request . FilterValue )
2019-07-18 15:52:00 +00:00
where ! isEqualFilter | | t . Title . Equals ( request . FilterValue ) | | t . AlternateNames . Equals ( request . FilterValue ) | | t . AlternateNames . Equals ( normalizedFilterValue ) | | t . PartTitles . Equals ( request . FilterValue )
2019-06-30 22:14:36 +00:00
where ! request . FilterFavoriteOnly | | favoriteTrackIds . Contains ( t . Id )
where request . FilterToPlaylistId = = null | | playlistTrackIds . Contains ( t . Id )
where ! request . FilterTopPlayedOnly | | topTrackids . Contains ( t . Id )
2019-09-05 02:04:20 +00:00
where request . FilterToArtistId = = null | | ( ( t . TrackArtist ! = null & & t . TrackArtist . RoadieId = = request . FilterToArtistId ) | | r . Artist . RoadieId = = request . FilterToArtistId )
2019-06-30 22:14:36 +00:00
where ! request . IsHistoryRequest | | t . PlayedCount > 0
where request . FilterToCollectionId = = null | | collectionTrackIds . Contains ( t . Id )
select new
{
ti = new
{
t . Id ,
t . RoadieId ,
t . CreatedDate ,
t . LastUpdated ,
t . LastPlayed ,
t . Duration ,
t . FileSize ,
t . PlayedCount ,
t . PartTitles ,
t . Rating ,
t . Tags ,
t . TrackNumber ,
2019-08-06 03:13:00 +00:00
t . Status ,
2019-06-30 22:14:36 +00:00
t . Title
} ,
rmi = new
{
rm . MediaNumber
} ,
rl = new ReleaseList
{
DatabaseId = r . Id ,
Id = r . RoadieId ,
Artist = new DataToken
{
Value = releaseArtist . RoadieId . ToString ( ) ,
Text = releaseArtist . Name
} ,
Release = new DataToken
{
Text = r . Title ,
Value = r . RoadieId . ToString ( )
} ,
ArtistThumbnail = MakeArtistThumbnailImage ( releaseArtist . RoadieId ) ,
CreatedDate = r . CreatedDate ,
Duration = r . Duration ,
LastPlayed = r . LastPlayed ,
LastUpdated = r . LastUpdated ,
LibraryStatus = r . LibraryStatus ,
MediaCount = r . MediaCount ,
Rating = r . Rating ,
Rank = r . Rank ,
ReleaseDateDateTime = r . ReleaseDate ,
ReleasePlayUrl = $"{HttpContext.BaseUrl}/play/release/{r.RoadieId}" ,
Status = r . Status ,
Thumbnail = MakeReleaseThumbnailImage ( r . RoadieId ) ,
TrackCount = r . TrackCount ,
TrackPlayedCount = r . PlayedCount
} ,
ta = trackArtist = = null
? null
: new ArtistList
{
DatabaseId = trackArtist . Id ,
Id = trackArtist . RoadieId ,
Artist = new DataToken
{ Text = trackArtist . Name , Value = trackArtist . RoadieId . ToString ( ) } ,
Rating = trackArtist . Rating ,
Rank = trackArtist . Rank ,
CreatedDate = trackArtist . CreatedDate ,
LastUpdated = trackArtist . LastUpdated ,
LastPlayed = trackArtist . LastPlayed ,
PlayedCount = trackArtist . PlayedCount ,
ReleaseCount = trackArtist . ReleaseCount ,
TrackCount = trackArtist . TrackCount ,
SortName = trackArtist . SortName ,
Thumbnail = MakeArtistThumbnailImage ( trackArtist . RoadieId )
} ,
ra = new ArtistList
{
DatabaseId = releaseArtist . Id ,
Id = releaseArtist . RoadieId ,
Artist = new DataToken
{ Text = releaseArtist . Name , Value = releaseArtist . RoadieId . ToString ( ) } ,
Rating = releaseArtist . Rating ,
Rank = releaseArtist . Rank ,
CreatedDate = releaseArtist . CreatedDate ,
LastUpdated = releaseArtist . LastUpdated ,
LastPlayed = releaseArtist . LastPlayed ,
PlayedCount = releaseArtist . PlayedCount ,
ReleaseCount = releaseArtist . ReleaseCount ,
TrackCount = releaseArtist . TrackCount ,
SortName = releaseArtist . SortName ,
Thumbnail = MakeArtistThumbnailImage ( releaseArtist . RoadieId )
}
} ;
2018-11-12 00:28:37 +00:00
2018-12-09 14:33:40 +00:00
if ( ! string . IsNullOrEmpty ( request . FilterValue ) )
2018-11-15 00:16:25 +00:00
{
2018-12-09 14:33:40 +00:00
if ( request . FilterValue . StartsWith ( "#" ) )
{
// Find any releases by tags
var tagValue = request . FilterValue . Replace ( "#" , "" ) ;
resultQuery = resultQuery . Where ( x = > x . ti . Tags ! = null & & x . ti . Tags . Contains ( tagValue ) ) ;
}
2018-11-15 00:16:25 +00:00
}
2019-06-30 22:14:36 +00:00
var user = GetUser ( roadieUser . UserId ) ;
2018-12-09 14:33:40 +00:00
var result = resultQuery . Select ( x = >
2019-06-30 22:14:36 +00:00
new TrackList
{
DatabaseId = x . ti . Id ,
Id = x . ti . RoadieId ,
Track = new DataToken
{
Text = x . ti . Title ,
Value = x . ti . RoadieId . ToString ( )
} ,
2019-08-06 03:13:00 +00:00
Status = x . ti . Status ,
2019-06-30 22:14:36 +00:00
Artist = x . ra ,
CreatedDate = x . ti . CreatedDate ,
Duration = x . ti . Duration ,
FileSize = x . ti . FileSize ,
LastPlayed = x . ti . LastPlayed ,
LastUpdated = x . ti . LastUpdated ,
MediaNumber = x . rmi . MediaNumber ,
PlayedCount = x . ti . PlayedCount ,
PartTitles = x . ti . PartTitles ,
Rating = x . ti . Rating ,
Release = x . rl ,
ReleaseDate = x . rl . ReleaseDateDateTime ,
Thumbnail = MakeTrackThumbnailImage ( x . ti . RoadieId ) ,
Title = x . ti . Title ,
TrackArtist = x . ta ,
TrackNumber = playListTrackPositions . ContainsKey ( x . ti . Id )
? playListTrackPositions [ x . ti . Id ]
: x . ti . TrackNumber ,
2019-08-04 16:30:19 +00:00
TrackPlayUrl = MakeTrackPlayUrl ( user , HttpContext . BaseUrl , x . ti . Id , x . ti . RoadieId )
2019-06-30 22:14:36 +00:00
} ) ;
2018-12-09 14:33:40 +00:00
string sortBy = null ;
2018-11-12 00:28:37 +00:00
2018-12-09 17:58:31 +00:00
rowCount = rowCount ? ? result . Count ( ) ;
2018-12-09 14:33:40 +00:00
TrackList [ ] rows = null ;
2018-11-15 00:16:25 +00:00
2018-12-09 14:33:40 +00:00
if ( request . Action = = User . ActionKeyUserRated )
{
2019-06-30 22:14:36 +00:00
sortBy = string . IsNullOrEmpty ( request . Sort )
2019-08-22 20:33:07 +00:00
? request . OrderValue ( new Dictionary < string , string > { { "UserTrack.Rating" , "DESC" } , { "MediaNumber" , "ASC" } , { "TrackNumber" , "ASC" } } )
2019-06-30 22:14:36 +00:00
: request . OrderValue ( ) ;
2018-12-09 14:33:40 +00:00
}
else
{
2019-07-18 15:52:00 +00:00
if ( request . Sort = = "Rating" )
{
// The request is to sort tracks by Rating if the artist only has a few tracks rated then order by those then order by played (put most popular after top rated)
sortBy = request . OrderValue ( new Dictionary < string , string > { { "Rating" , request . Order } , { "PlayedCount" , request . Order } } ) ;
}
else
{
sortBy = string . IsNullOrEmpty ( request . Sort )
? request . OrderValue ( new Dictionary < string , string > { { "Release.Release.Text" , "ASC" } , { "MediaNumber" , "ASC" } , { "TrackNumber" , "ASC" } } )
: request . OrderValue ( ) ;
}
2018-12-09 14:33:40 +00:00
}
2019-06-30 22:14:36 +00:00
2019-08-22 20:33:07 +00:00
if ( doRandomize ? ? false )
2019-03-06 01:18:21 +00:00
{
2019-08-06 01:45:00 +00:00
rows = TrackList . Shuffle ( result ) . ToArray ( ) ;
2019-03-06 01:18:21 +00:00
}
else
{
2019-08-03 22:59:20 +00:00
rows = result
. OrderBy ( sortBy )
. Skip ( request . SkipValue )
. Take ( request . LimitValue )
. ToArray ( ) ;
2019-05-29 22:25:40 +00:00
}
2019-06-30 22:14:36 +00:00
2018-12-09 14:33:40 +00:00
if ( rows . Any ( ) & & roadieUser ! = null )
2018-11-15 00:16:25 +00:00
{
2018-12-09 14:33:40 +00:00
var rowIds = rows . Select ( x = > x . DatabaseId ) . ToArray ( ) ;
2019-06-30 22:14:36 +00:00
var userTrackRatings = ( from ut in DbContext . UserTracks
2018-12-09 14:33:40 +00:00
where ut . UserId = = roadieUser . Id
where rowIds . Contains ( ut . TrackId )
select ut ) . ToArray ( ) ;
foreach ( var userTrackRating in userTrackRatings )
2018-11-15 00:16:25 +00:00
{
2018-12-09 14:33:40 +00:00
var row = rows . FirstOrDefault ( x = > x . DatabaseId = = userTrackRating . TrackId ) ;
if ( row ! = null )
2018-11-15 00:16:25 +00:00
{
2018-12-09 14:33:40 +00:00
row . UserRating = new UserTrack
{
IsDisliked = userTrackRating . IsDisliked ? ? false ,
IsFavorite = userTrackRating . IsFavorite ? ? false ,
Rating = userTrackRating . Rating ,
LastPlayed = userTrackRating . LastPlayed ,
PlayedCount = userTrackRating . PlayedCount
} ;
}
2018-11-15 00:16:25 +00:00
}
2018-12-26 01:28:36 +00:00
var releaseIds = rows . Select ( x = > x . Release . DatabaseId ) . Distinct ( ) . ToArray ( ) ;
2019-06-30 22:14:36 +00:00
var userReleaseRatings = ( from ur in DbContext . UserReleases
2019-07-04 15:50:31 +00:00
where ur . UserId = = roadieUser . Id
2018-12-26 01:28:36 +00:00
where releaseIds . Contains ( ur . ReleaseId )
select ur ) . ToArray ( ) ;
2019-01-05 22:40:33 +00:00
foreach ( var userReleaseRating in userReleaseRatings )
2018-12-26 01:28:36 +00:00
{
2019-01-05 22:40:33 +00:00
foreach ( var row in rows . Where ( x = > x . Release . DatabaseId = = userReleaseRating . ReleaseId ) )
2018-12-26 01:28:36 +00:00
{
row . Release . UserRating = userReleaseRating . Adapt < UserRelease > ( ) ;
}
}
var artistIds = rows . Select ( x = > x . Artist . DatabaseId ) . ToArray ( ) ;
if ( artistIds ! = null & & artistIds . Any ( ) )
{
2019-06-30 22:14:36 +00:00
var userArtistRatings = ( from ua in DbContext . UserArtists
2018-12-26 01:28:36 +00:00
where ua . UserId = = roadieUser . Id
where artistIds . Contains ( ua . ArtistId )
select ua ) . ToArray ( ) ;
foreach ( var userArtistRating in userArtistRatings )
{
2019-06-30 22:14:36 +00:00
foreach ( var artistTrack in rows . Where (
x = > x . Artist . DatabaseId = = userArtistRating . ArtistId ) )
2018-12-26 01:28:36 +00:00
{
artistTrack . Artist . UserRating = userArtistRating . Adapt < UserArtist > ( ) ;
}
}
}
2019-07-04 15:50:31 +00:00
var trackArtistIds = rows . Where ( x = > x . TrackArtist ! = null ) . Select ( x = > x . TrackArtist . DatabaseId ) . ToArray ( ) ;
2018-12-26 01:28:36 +00:00
if ( trackArtistIds ! = null & & trackArtistIds . Any ( ) )
{
2019-06-30 22:14:36 +00:00
var userTrackArtistRatings = ( from ua in DbContext . UserArtists
2018-12-26 01:28:36 +00:00
where ua . UserId = = roadieUser . Id
where trackArtistIds . Contains ( ua . ArtistId )
select ua ) . ToArray ( ) ;
2018-12-28 18:58:17 +00:00
if ( userTrackArtistRatings ! = null & & userTrackArtistRatings . Any ( ) )
2018-12-26 01:28:36 +00:00
{
2018-12-28 18:58:17 +00:00
foreach ( var userTrackArtistRating in userTrackArtistRatings )
2018-12-26 01:28:36 +00:00
{
2019-06-30 22:14:36 +00:00
foreach ( var artistTrack in rows . Where ( x = >
x . TrackArtist ! = null & &
x . TrackArtist . DatabaseId = = userTrackArtistRating . ArtistId ) )
2018-12-28 18:58:17 +00:00
{
artistTrack . Artist . UserRating = userTrackArtistRating . Adapt < UserArtist > ( ) ;
}
2018-12-26 01:28:36 +00:00
}
}
}
2018-11-15 00:16:25 +00:00
}
2018-12-09 14:33:40 +00:00
if ( rows . Any ( ) )
2018-11-15 00:16:25 +00:00
{
2019-07-04 15:50:31 +00:00
var rowIds = rows . Select ( x = > x . DatabaseId ) . ToArray ( ) ;
var favoriteUserTrackRatings = ( from ut in DbContext . UserTracks
where ut . IsFavorite ? ? false
where rowIds . Contains ( ut . TrackId )
select ut ) . ToArray ( ) ;
2018-12-09 14:33:40 +00:00
foreach ( var row in rows )
{
2019-07-04 15:50:31 +00:00
row . FavoriteCount = favoriteUserTrackRatings . Where ( x = > x . TrackId = = row . DatabaseId ) . Count ( ) ;
2018-12-09 14:33:40 +00:00
}
2018-11-15 00:16:25 +00:00
}
2018-12-09 14:33:40 +00:00
sw . Stop ( ) ;
2018-12-24 19:40:49 +00:00
return Task . FromResult ( new Library . Models . Pagination . PagedResult < TrackList >
2018-12-09 14:33:40 +00:00
{
2018-12-09 17:58:31 +00:00
TotalCount = rowCount ? ? 0 ,
2018-12-09 14:33:40 +00:00
CurrentPage = request . PageValue ,
TotalPages = ( int ) Math . Ceiling ( ( double ) rowCount / request . LimitValue ) ,
OperationTime = sw . ElapsedMilliseconds ,
Rows = rows
2018-12-24 19:40:49 +00:00
} ) ;
2018-12-09 14:33:40 +00:00
}
catch ( Exception ex )
2018-11-15 00:16:25 +00:00
{
2019-08-22 20:33:07 +00:00
Logger . LogError ( ex , "Error In List, Request [{0}], User [{1}]" , JsonConvert . SerializeObject ( request ) , roadieUser ) ;
2018-12-24 19:40:49 +00:00
return Task . FromResult ( new Library . Models . Pagination . PagedResult < TrackList >
2019-01-05 22:40:33 +00:00
{
Message = "An Error has occured"
2018-12-24 19:40:49 +00:00
} ) ;
2018-12-09 14:33:40 +00:00
}
2018-11-12 00:28:37 +00:00
}
2018-11-17 02:14:32 +00:00
2019-01-13 17:27:41 +00:00
/// <summary>
2019-06-30 22:14:36 +00:00
/// Fast as possible check if exists and return minimum information on Track
2019-01-13 17:27:41 +00:00
/// </summary>
public OperationResult < Track > StreamCheckAndInfo ( User roadieUser , Guid id )
{
2019-06-30 22:14:36 +00:00
var track = DbContext . Tracks . FirstOrDefault ( x = > x . RoadieId = = id ) ;
2019-01-13 17:27:41 +00:00
if ( track = = null )
{
return new OperationResult < Track > ( true , string . Format ( "Track Not Found [{0}]" , id ) ) ;
}
2019-06-30 22:14:36 +00:00
return new OperationResult < Track >
2019-01-13 17:27:41 +00:00
{
Data = track . Adapt < Track > ( ) ,
IsSuccess = true
} ;
}
2019-09-05 02:04:20 +00:00
public async Task < OperationResult < TrackStreamInfo > > TrackStreamInfo ( Guid trackId , long beginBytes , long endBytes , User roadieUser )
2018-11-17 02:14:32 +00:00
{
2019-06-30 22:14:36 +00:00
var track = DbContext . Tracks . FirstOrDefault ( x = > x . RoadieId = = trackId ) ;
2019-07-31 22:42:49 +00:00
if ( ! ( track ? . IsValid ? ? true ) )
2018-11-17 02:14:32 +00:00
{
2019-05-29 22:25:40 +00:00
// Not Found try recanning release
2019-06-30 22:14:36 +00:00
var release = ( from r in DbContext . Releases
join rm in DbContext . ReleaseMedias on r . Id equals rm . ReleaseId
2019-02-25 02:26:54 +00:00
where rm . Id = = track . ReleaseMediaId
select r ) . FirstOrDefault ( ) ;
2019-09-05 02:04:20 +00:00
if ( ! release . IsLocked ? ? false & & roadieUser ! = null )
2019-02-25 02:26:54 +00:00
{
2019-06-30 22:14:36 +00:00
await AdminService . ScanRelease ( new ApplicationUser
2019-02-25 02:26:54 +00:00
{
Id = roadieUser . Id . Value
} , release . RoadieId , false , true ) ;
2019-07-31 22:42:49 +00:00
track = DbContext . Tracks . FirstOrDefault ( x = > x . RoadieId = = trackId ) ;
}
else
{
Logger . LogWarning ( $"TrackStreamInfo: Track [{ trackId }] was invalid but release [{ release.RoadieId }] is locked, did not rescan." ) ;
2019-02-25 02:26:54 +00:00
}
2019-05-29 22:25:40 +00:00
if ( track = = null )
2019-02-25 02:26:54 +00:00
{
2019-06-30 22:14:36 +00:00
return new OperationResult < TrackStreamInfo > ( $"TrackStreamInfo: Unable To Find Track [{trackId}]" ) ;
2019-02-25 02:26:54 +00:00
}
2019-07-31 22:42:49 +00:00
if ( ! track . IsValid )
{
return new OperationResult < TrackStreamInfo > ( $"TrackStreamInfo: Invalid Track. Track Id [{trackId}], FilePath [{track.FilePath}], Filename [{track.FileName}]" ) ;
}
2018-11-17 02:14:32 +00:00
}
string trackPath = null ;
try
{
2019-07-07 03:16:33 +00:00
trackPath = track . PathToTrack ( Configuration ) ;
2018-11-17 02:14:32 +00:00
}
catch ( Exception ex )
{
return new OperationResult < TrackStreamInfo > ( ex ) ;
}
2019-06-30 22:14:36 +00:00
2018-11-17 02:14:32 +00:00
var trackFileInfo = new FileInfo ( trackPath ) ;
if ( ! trackFileInfo . Exists )
{
2019-05-29 22:25:40 +00:00
// Not Found try recanning release
2019-06-30 22:14:36 +00:00
var release = ( from r in DbContext . Releases
join rm in DbContext . ReleaseMedias on r . Id equals rm . ReleaseId
2019-03-02 20:18:41 +00:00
where rm . Id = = track . ReleaseMediaId
select r ) . FirstOrDefault ( ) ;
2019-09-05 02:04:20 +00:00
if ( ! release . IsLocked ? ? false & & roadieUser ! = null )
2019-03-02 20:18:41 +00:00
{
2019-06-30 22:14:36 +00:00
await AdminService . ScanRelease ( new ApplicationUser
2019-03-02 20:18:41 +00:00
{
Id = roadieUser . Id . Value
} , release . RoadieId , false , true ) ;
}
2019-06-30 22:14:36 +00:00
track = DbContext . Tracks . FirstOrDefault ( x = > x . RoadieId = = trackId ) ;
2019-03-02 20:18:41 +00:00
if ( track = = null )
{
2019-06-30 22:14:36 +00:00
return new OperationResult < TrackStreamInfo > ( $"TrackStreamInfo: Unable To Find Track [{trackId}]" ) ;
2019-03-02 20:18:41 +00:00
}
2019-06-30 22:14:36 +00:00
2019-03-02 20:18:41 +00:00
try
{
2019-07-07 03:16:33 +00:00
trackPath = track . PathToTrack ( Configuration ) ;
2019-03-02 20:18:41 +00:00
}
catch ( Exception ex )
{
return new OperationResult < TrackStreamInfo > ( ex ) ;
}
2019-06-30 22:14:36 +00:00
2019-03-02 20:18:41 +00:00
if ( ! trackFileInfo . Exists )
2019-05-29 22:25:40 +00:00
{
2019-03-02 20:18:41 +00:00
track . UpdateTrackMissingFile ( ) ;
2019-06-30 22:14:36 +00:00
await DbContext . SaveChangesAsync ( ) ;
return new OperationResult < TrackStreamInfo > (
$"TrackStreamInfo: TrackId [{trackId}] Unable to Find Track [{trackFileInfo.FullName}]" ) ;
2019-03-02 20:18:41 +00:00
}
2018-11-17 02:14:32 +00:00
}
2019-06-30 22:14:36 +00:00
2019-08-14 21:03:31 +00:00
var disableCaching = true ;
2019-06-30 22:14:36 +00:00
var contentDurationTimeSpan = TimeSpan . FromMilliseconds ( track . Duration ? ? 0 ) ;
2018-11-17 02:14:32 +00:00
var info = new TrackStreamInfo
{
2019-09-05 02:04:20 +00:00
FileName = HttpEncoder ? . UrlEncode ( track . FileName ) . ToContentDispositionFriendly ( ) ,
ContentDisposition = $"attachment; filename=\" { HttpEncoder ? . UrlEncode ( track . FileName ) . ToContentDispositionFriendly ( ) } \ "" ,
2019-06-30 22:14:36 +00:00
ContentDuration = contentDurationTimeSpan . TotalSeconds . ToString ( )
2018-11-17 02:14:32 +00:00
} ;
2019-06-30 22:14:36 +00:00
var contentLength = endBytes - beginBytes + 1 ;
2018-11-17 02:14:32 +00:00
info . Track = new DataToken
{
Text = track . Title ,
Value = track . RoadieId . ToString ( )
} ;
info . BeginBytes = beginBytes ;
info . EndBytes = endBytes ;
info . ContentRange = $"bytes {beginBytes}-{endBytes}/{contentLength}" ;
info . ContentLength = contentLength . ToString ( ) ;
2019-06-30 22:14:36 +00:00
info . IsFullRequest = beginBytes = = 0 & & endBytes = = trackFileInfo . Length - 1 ;
info . IsEndRangeRequest = beginBytes > 0 & & endBytes ! = trackFileInfo . Length - 1 ;
2018-11-17 02:14:32 +00:00
info . LastModified = ( track . LastUpdated ? ? track . CreatedDate ) . ToString ( "R" ) ;
2019-08-14 21:03:31 +00:00
if ( ! disableCaching )
{
var cacheTimeout = 86400 ; // 24 hours
info . CacheControl = $"public, max-age={cacheTimeout.ToString()} " ;
info . Expires = DateTime . UtcNow . AddMinutes ( cacheTimeout ) . ToString ( "R" ) ;
info . Etag = track . Etag ;
}
else
{
info . CacheControl = "no-store, must-revalidate, no-cache, max-age=0" ;
info . Pragma = "no-cache" ;
info . Expires = "Mon, 01 Jan 1990 00:00:00 GMT" ;
2019-08-22 20:33:07 +00:00
}
2019-06-30 22:14:36 +00:00
var bytesToRead = ( int ) ( endBytes - beginBytes ) + 1 ;
var trackBytes = new byte [ bytesToRead ] ;
2018-11-17 02:14:32 +00:00
using ( var fs = trackFileInfo . OpenRead ( ) )
{
try
{
fs . Seek ( beginBytes , SeekOrigin . Begin ) ;
var r = fs . Read ( trackBytes , 0 , bytesToRead ) ;
}
catch ( Exception ex )
{
return new OperationResult < TrackStreamInfo > ( ex ) ;
}
}
2019-06-30 22:14:36 +00:00
2018-11-17 02:14:32 +00:00
info . Bytes = trackBytes ;
return new OperationResult < TrackStreamInfo >
{
2018-11-24 01:46:12 +00:00
IsSuccess = true ,
2018-11-17 02:14:32 +00:00
Data = info
} ;
}
2019-01-05 22:40:33 +00:00
2019-05-29 22:25:40 +00:00
public async Task < OperationResult < bool > > UpdateTrack ( User user , Track model )
{
var didChangeTrack = false ;
var didChangeThumbnail = false ;
var sw = new Stopwatch ( ) ;
sw . Start ( ) ;
var errors = new List < Exception > ( ) ;
2019-06-30 22:14:36 +00:00
var track = DbContext . Tracks
. Include ( x = > x . ReleaseMedia )
. Include ( x = > x . ReleaseMedia . Release )
. Include ( x = > x . ReleaseMedia . Release . Artist )
. FirstOrDefault ( x = > x . RoadieId = = model . Id ) ;
2019-05-29 22:25:40 +00:00
if ( track = = null )
{
return new OperationResult < bool > ( true , string . Format ( "Track Not Found [{0}]" , model . Id ) ) ;
}
2019-06-30 22:14:36 +00:00
2019-05-29 22:25:40 +00:00
try
{
2019-08-11 19:11:29 +00:00
var originalTitle = track . Title ;
2019-08-22 20:33:07 +00:00
var originalTrackNumber = track . TrackNumber ;
2019-08-11 19:11:29 +00:00
var originalFilename = track . PathToTrack ( Configuration ) ;
2019-05-29 22:25:40 +00:00
var now = DateTime . UtcNow ;
track . IsLocked = model . IsLocked ;
track . Status = SafeParser . ToEnum < Statuses > ( model . Status ) ;
track . Title = model . Title ;
track . AlternateNames = model . AlternateNamesList . ToDelimitedList ( ) ;
track . Rating = model . Rating ;
track . AmgId = model . AmgId ;
track . LastFMId = model . LastFMId ;
track . MusicBrainzId = model . MusicBrainzId ;
track . SpotifyId = model . SpotifyId ;
track . Tags = model . TagsList . ToDelimitedList ( ) ;
2019-06-30 22:14:36 +00:00
track . PartTitles = model . PartTitlesList = = null | | ! model . PartTitlesList . Any ( )
? null
: string . Join ( "\n" , model . PartTitlesList ) ;
2019-05-29 22:25:40 +00:00
2019-08-11 19:11:29 +00:00
data . Artist trackArtist = null ;
2019-05-29 22:25:40 +00:00
if ( model . TrackArtistToken ! = null )
{
var artistId = SafeParser . ToGuid ( model . TrackArtistToken . Value ) ;
if ( artistId . HasValue )
{
2019-08-11 19:11:29 +00:00
trackArtist = GetArtist ( artistId . Value ) ;
if ( trackArtist ! = null )
2019-05-29 22:25:40 +00:00
{
2019-08-11 19:11:29 +00:00
track . ArtistId = trackArtist . Id ;
2019-05-29 22:25:40 +00:00
}
}
}
else
{
track . ArtistId = null ;
}
var trackImage = ImageHelper . ImageDataFromUrl ( model . NewThumbnailData ) ;
if ( trackImage ! = null )
{
// Save unaltered image to cover file
2019-07-07 03:16:33 +00:00
var trackThumbnailName = track . PathToTrackThumbnail ( Configuration ) ;
2019-07-25 15:43:11 +00:00
File . WriteAllBytes ( trackThumbnailName , ImageHelper . ConvertToJpegFormat ( trackImage ) ) ;
2019-05-29 22:25:40 +00:00
// Resize to store in database as thumbnail
2019-07-25 15:43:11 +00:00
track . Thumbnail = ImageHelper . ResizeToThumbnail ( trackImage , Configuration ) ;
2019-05-29 22:25:40 +00:00
didChangeThumbnail = true ;
}
2019-06-30 22:14:36 +00:00
2019-08-11 19:11:29 +00:00
// See if Title was changed if so then modify DB Filename and rename track
var shouldFileNameBeUpdated = originalTitle ! = track . Title | | originalTrackNumber ! = track . TrackNumber ;
2019-08-22 20:33:07 +00:00
if ( shouldFileNameBeUpdated )
2019-08-11 19:11:29 +00:00
{
track . FileName = FolderPathHelper . TrackFileName ( Configuration , track . Title , track . TrackNumber , track . ReleaseMedia . MediaNumber , track . ReleaseMedia . TrackCount ) ;
File . Move ( originalFilename , track . PathToTrack ( Configuration ) ) ;
}
2019-05-29 22:25:40 +00:00
track . LastUpdated = now ;
2019-08-22 20:33:07 +00:00
await DbContext . SaveChangesAsync ( ) ;
2019-08-11 19:11:29 +00:00
var trackFileInfo = new FileInfo ( track . PathToTrack ( Configuration ) ) ;
var audioMetaData = await AudioMetaDataHelper . GetInfo ( trackFileInfo ) ;
if ( audioMetaData ! = null )
{
audioMetaData . Title = track . Title ;
if ( trackArtist ! = null )
{
audioMetaData . Artist = trackArtist . Name ;
}
AudioMetaDataHelper . WriteTags ( audioMetaData , trackFileInfo ) ;
}
2019-06-30 22:14:36 +00:00
CacheManager . ClearRegion ( track . CacheRegion ) ;
2019-08-11 19:11:29 +00:00
Logger . LogInformation ( $"UpdateTrack `{track}` By User `{user}`: Edited Track [{didChangeTrack}], Uploaded new image [{didChangeThumbnail}]" ) ;
2019-05-29 22:25:40 +00:00
}
catch ( Exception ex )
{
2019-06-30 22:14:36 +00:00
Logger . LogError ( ex ) ;
2019-05-29 22:25:40 +00:00
errors . Add ( ex ) ;
}
2019-06-30 22:14:36 +00:00
2019-05-29 22:25:40 +00:00
sw . Stop ( ) ;
return new OperationResult < bool >
{
IsSuccess = ! errors . Any ( ) ,
Data = ! errors . Any ( ) ,
OperationTime = sw . ElapsedMilliseconds ,
Errors = errors
} ;
}
2019-01-05 22:40:33 +00:00
private Task < OperationResult < Track > > TrackByIdAction ( Guid id , IEnumerable < string > includes )
{
2019-08-04 16:30:19 +00:00
var timings = new Dictionary < string , long > ( ) ;
var tsw = new Stopwatch ( ) ;
2019-01-05 22:40:33 +00:00
var sw = Stopwatch . StartNew ( ) ;
sw . Start ( ) ;
2019-08-04 16:30:19 +00:00
tsw . Restart ( ) ;
2019-06-30 22:14:36 +00:00
var track = GetTrack ( id ) ;
2019-08-04 16:30:19 +00:00
tsw . Stop ( ) ;
timings . Add ( "getTrack" , tsw . ElapsedMilliseconds ) ;
2019-01-05 22:40:33 +00:00
if ( track = = null )
{
return Task . FromResult ( new OperationResult < Track > ( true , string . Format ( "Track Not Found [{0}]" , id ) ) ) ;
}
2019-08-04 16:30:19 +00:00
tsw . Restart ( ) ;
2019-01-05 22:40:33 +00:00
var result = track . Adapt < Track > ( ) ;
result . IsLocked = ( track . IsLocked ? ? false ) | |
( track . ReleaseMedia . IsLocked ? ? false ) | |
( track . ReleaseMedia . Release . IsLocked ? ? false ) | |
( track . ReleaseMedia . Release . Artist . IsLocked ? ? false ) ;
2019-06-30 22:14:36 +00:00
result . Thumbnail = MakeTrackThumbnailImage ( id ) ;
result . MediumThumbnail = MakeThumbnailImage ( id , "track" , Configuration . MediumImageSize . Width ,
Configuration . MediumImageSize . Height ) ;
2019-01-05 22:40:33 +00:00
result . ReleaseMediaId = track . ReleaseMedia . RoadieId . ToString ( ) ;
2019-06-30 22:14:36 +00:00
result . Artist = ArtistList . FromDataArtist ( track . ReleaseMedia . Release . Artist ,
MakeArtistThumbnailImage ( track . ReleaseMedia . Release . Artist . RoadieId ) ) ;
result . ArtistThumbnail = MakeArtistThumbnailImage ( track . ReleaseMedia . Release . Artist . RoadieId ) ;
result . Release = ReleaseList . FromDataRelease ( track . ReleaseMedia . Release , track . ReleaseMedia . Release . Artist ,
HttpContext . BaseUrl , MakeArtistThumbnailImage ( track . ReleaseMedia . Release . Artist . RoadieId ) ,
MakeReleaseThumbnailImage ( track . ReleaseMedia . Release . RoadieId ) ) ;
result . ReleaseThumbnail = MakeReleaseThumbnailImage ( track . ReleaseMedia . Release . RoadieId ) ;
2019-08-04 16:30:19 +00:00
tsw . Stop ( ) ;
timings . Add ( "adapt" , tsw . ElapsedMilliseconds ) ;
2019-01-05 22:40:33 +00:00
if ( track . ArtistId . HasValue )
{
2019-08-04 16:30:19 +00:00
tsw . Restart ( ) ;
2019-06-30 22:14:36 +00:00
var trackArtist = DbContext . Artists . FirstOrDefault ( x = > x . Id = = track . ArtistId ) ;
2019-01-05 22:40:33 +00:00
if ( trackArtist = = null )
{
2019-06-30 22:14:36 +00:00
Logger . LogWarning ( $"Unable to find Track Artist [{track.ArtistId}" ) ;
2019-01-05 22:40:33 +00:00
}
else
{
2019-06-30 22:14:36 +00:00
result . TrackArtist =
ArtistList . FromDataArtist ( trackArtist , MakeArtistThumbnailImage ( trackArtist . RoadieId ) ) ;
2019-05-11 15:18:09 +00:00
result . TrackArtistToken = result . TrackArtist . Artist ;
2019-06-30 22:14:36 +00:00
result . TrackArtistThumbnail = MakeArtistThumbnailImage ( trackArtist . RoadieId ) ;
2019-01-05 22:40:33 +00:00
}
2019-08-04 16:30:19 +00:00
tsw . Stop ( ) ;
timings . Add ( "trackArtist" , tsw . ElapsedMilliseconds ) ;
2019-01-05 22:40:33 +00:00
}
2019-06-30 22:14:36 +00:00
2019-01-05 22:40:33 +00:00
if ( includes ! = null & & includes . Any ( ) )
{
if ( includes . Contains ( "stats" ) )
{
2019-08-04 16:30:19 +00:00
tsw . Restart ( ) ;
2019-06-30 22:14:36 +00:00
result . Statistics = new TrackStatistics
2019-01-05 22:40:33 +00:00
{
FileSizeFormatted = ( ( long? ) track . FileSize ) . ToFileSize ( ) ,
Time = new TimeInfo ( ( decimal ) track . Duration ) . ToFullFormattedString ( ) ,
PlayedCount = track . PlayedCount
} ;
2019-06-30 22:14:36 +00:00
var userTracks = ( from t in DbContext . Tracks
join ut in DbContext . UserTracks on t . Id equals ut . TrackId
2019-01-05 22:40:33 +00:00
where t . Id = = track . Id
select ut ) . ToArray ( ) ;
if ( userTracks ! = null & & userTracks . Any ( ) )
{
result . Statistics . DislikedCount = userTracks . Count ( x = > x . IsDisliked ? ? false ) ;
result . Statistics . FavoriteCount = userTracks . Count ( x = > x . IsFavorite ? ? false ) ;
}
2019-08-04 16:30:19 +00:00
tsw . Stop ( ) ;
timings . Add ( "stats" , tsw . ElapsedMilliseconds ) ;
2019-01-05 22:40:33 +00:00
}
2019-06-30 22:14:36 +00:00
2019-06-28 21:24:32 +00:00
if ( includes . Contains ( "comments" ) )
{
2019-08-04 16:30:19 +00:00
tsw . Restart ( ) ;
2019-06-30 22:14:36 +00:00
var trackComments = DbContext . Comments . Include ( x = > x . User ) . Where ( x = > x . TrackId = = track . Id )
. OrderByDescending ( x = > x . CreatedDate ) . ToArray ( ) ;
2019-06-28 21:24:32 +00:00
if ( trackComments . Any ( ) )
{
var comments = new List < Comment > ( ) ;
var commentIds = trackComments . Select ( x = > x . Id ) . ToArray ( ) ;
2019-06-30 22:14:36 +00:00
var userCommentReactions = ( from cr in DbContext . CommentReactions
2019-06-28 21:24:32 +00:00
where commentIds . Contains ( cr . CommentId )
select cr ) . ToArray ( ) ;
foreach ( var trackComment in trackComments )
{
var comment = trackComment . Adapt < Comment > ( ) ;
comment . DatabaseId = trackComment . Id ;
2019-06-30 22:14:36 +00:00
comment . User = UserList . FromDataUser ( trackComment . User ,
MakeUserThumbnailImage ( trackComment . User . RoadieId ) ) ;
comment . DislikedCount = userCommentReactions . Count ( x = >
x . CommentId = = trackComment . Id & & x . ReactionValue = = CommentReaction . Dislike ) ;
comment . LikedCount = userCommentReactions . Count ( x = >
x . CommentId = = trackComment . Id & & x . ReactionValue = = CommentReaction . Like ) ;
2019-06-28 21:24:32 +00:00
comments . Add ( comment ) ;
}
2019-06-30 22:14:36 +00:00
2019-06-28 21:24:32 +00:00
result . Comments = comments ;
}
2019-08-04 16:30:19 +00:00
tsw . Stop ( ) ;
timings . Add ( "comments" , tsw . ElapsedMilliseconds ) ;
2019-06-28 21:24:32 +00:00
}
2019-01-05 22:40:33 +00:00
}
sw . Stop ( ) ;
2019-08-04 16:30:19 +00:00
Logger . LogInformation ( $"ByIdAction: Track `{ track }`: includes [{includes.ToCSV()}], timings: [{ timings.ToTimings() }]" ) ;
2019-01-05 22:40:33 +00:00
return Task . FromResult ( new OperationResult < Track >
{
Data = result ,
IsSuccess = result ! = null ,
OperationTime = sw . ElapsedMilliseconds
} ) ;
}
2018-11-12 00:28:37 +00:00
}
}