Revert "Resolved #13: Move play history recording for Roadie to a scrobbler integration and implemented LastFM integration."

This reverts commit 03ead41934.
This commit is contained in:
Steven Hildreth 2019-06-08 17:27:39 -05:00
parent 6ff4285987
commit 461719f826
52 changed files with 342 additions and 1028 deletions

View file

@ -12,24 +12,27 @@ namespace Roadie.Library.Configuration
private string _lastFMApiKey = null;
private bool _lastFmEnabled = true;
private string _lastFMSecret = null;
public List<ApiKey> ApiKeys { get; set; } = new List<ApiKey>();
public List<ApiKey> ApiKeys { get; set; }
public string DiscogsConsumerKey
{
get
{
var keySetting = this.ApiKeys.FirstOrDefault(x => x.ApiName == "DiscogsConsumerKey");
if (keySetting != null)
if (string.IsNullOrEmpty(this._discogsConsumerKey))
{
return keySetting.Key;
var keySetting = this.ApiKeys.FirstOrDefault(x => x.ApiName == "DiscogsConsumerKey");
if (keySetting != null)
{
this._discogsConsumerKey = keySetting.Key;
this._discogsConsumerSecret = keySetting.KeySecret;
}
else
{
Trace.WriteLine("Unable To Find Api Key with Key Name of 'DiscogsConsumerKey', Discogs Integration Disabled");
}
}
else
{
Trace.WriteLine("Unable To Find Api Key with Key Name of 'DiscogsConsumerKey', Discogs Integration Disabled");
}
return null;
return this._discogsConsumerKey;
}
}
@ -37,16 +40,20 @@ namespace Roadie.Library.Configuration
{
get
{
var keySetting = this.ApiKeys.FirstOrDefault(x => x.ApiName == "DiscogsConsumerKey");
if (keySetting != null)
if (string.IsNullOrEmpty(this._discogsConsumerSecret))
{
return keySetting.KeySecret;
var keySetting = this.ApiKeys.FirstOrDefault(x => x.ApiName == "DiscogsConsumerKey");
if (keySetting != null)
{
this._discogsConsumerKey = keySetting.Key;
this._discogsConsumerSecret = keySetting.KeySecret;
}
else
{
Trace.WriteLine("Unable To Find Api Key with Key Name of 'DiscogsConsumerKey', Discogs Integration Disabled");
}
}
else
{
Trace.WriteLine("Unable To Find Api Key with Key Name of 'DiscogsConsumerKey', Discogs Integration Disabled");
}
return null;
return this._discogsConsumerSecret;
}
}
@ -76,16 +83,20 @@ namespace Roadie.Library.Configuration
{
get
{
var keySetting = this.ApiKeys.FirstOrDefault(x => x.ApiName == "LastFMApiKey");
if (keySetting != null)
if (string.IsNullOrEmpty(this._lastFMApiKey))
{
return keySetting.Key;
var keySetting = this.ApiKeys.FirstOrDefault(x => x.ApiName == "LastFMApiKey");
if (keySetting != null)
{
this._lastFMApiKey = keySetting.Key;
this._lastFMSecret = keySetting.KeySecret;
}
else
{
Trace.WriteLine("Unable To Find Api Key with Key Name of 'LastFMApiKey', Last FM Integration Disabled");
}
}
else
{
Trace.WriteLine("Unable To Find Api Key with Key Name of 'LastFMApiKey', Last FM Integration Disabled");
}
return null;
return this._lastFMApiKey;
}
}
@ -93,16 +104,20 @@ namespace Roadie.Library.Configuration
{
get
{
var keySetting = this.ApiKeys.FirstOrDefault(x => x.ApiName == "LastFMApiKey");
if (keySetting != null)
if (string.IsNullOrEmpty(this._lastFMSecret))
{
return keySetting.KeySecret;
var keySetting = this.ApiKeys.FirstOrDefault(x => x.ApiName == "LastFMApiKey");
if (keySetting != null)
{
this._lastFMApiKey = keySetting.Key;
this._lastFMSecret = keySetting.KeySecret;
}
else
{
Trace.WriteLine("Unable To Find Api Key with Key Name of 'LastFMApiKey', Last FM Integration Disabled");
}
}
else
{
Trace.WriteLine("Unable To Find Api Key with Key Name of 'LastFMApiKey', Last FM Integration Disabled");
}
return null;
return this._lastFMSecret;
}
}

View file

@ -26,12 +26,12 @@ namespace Roadie.Library.Data
public int? UserId { get; set; }
[Column("duration")]
public int? Duration { get; set; }
public int? Duration { get; set; } // TODO update this on playlist edit
[Column("trackCount")]
public short TrackCount { get; set; }
public short TrackCount { get; set; } // TODO update this on playlist edit
[Column("releaseCount")]
public short ReleaseCount { get; set; }
public short ReleaseCount { get; set; } // TODO update this on playlist edit
}
}

View file

@ -51,7 +51,7 @@ namespace Roadie.Library.Engines
{
this.ITunesArtistSearchEngine = new ITunesSearchEngine(this.Configuration, this.CacheManager, this.Logger);
this.MusicBrainzArtistSearchEngine = new musicbrainz.MusicBrainzProvider(this.Configuration, this.CacheManager, this.Logger);
this.LastFmArtistSearchEngine = new lastfm.LastFmHelper(this.Configuration, this.CacheManager, this.Logger, context, httpEncoder);
this.LastFmArtistSearchEngine = new lastfm.LastFmHelper(this.Configuration, this.CacheManager, this.Logger);
this.SpotifyArtistSearchEngine = new spotify.SpotifyHelper(this.Configuration, this.CacheManager, this.Logger);
this.WikipediaArtistSearchEngine = new wikipedia.WikipediaHelper(this.Configuration, this.CacheManager, this.Logger, this.HttpEncoder);
this.DiscogsArtistSearchEngine = new discogs.DiscogsHelper(this.Configuration, this.CacheManager, this.Logger);

View file

@ -61,9 +61,7 @@ namespace Roadie.Library.Engines
public IReleaseSearchEngine SpotifyReleaseSearchEngine { get; }
public IReleaseSearchEngine WikipediaReleaseSearchEngine { get; }
public ReleaseLookupEngine(IRoadieSettings configuration, IHttpEncoder httpEncoder, IRoadieDbContext context,
ICacheManager cacheManager, ILogger logger, IArtistLookupEngine aristLookupEngine,
ILabelLookupEngine labelLookupEngine)
public ReleaseLookupEngine(IRoadieSettings configuration, IHttpEncoder httpEncoder, IRoadieDbContext context, ICacheManager cacheManager, ILogger logger, IArtistLookupEngine aristLookupEngine, ILabelLookupEngine labelLookupEngine)
: base(configuration, httpEncoder, context, cacheManager, logger)
{
this.ArtistLookupEngine = ArtistLookupEngine;
@ -71,7 +69,7 @@ namespace Roadie.Library.Engines
this.ITunesReleaseSearchEngine = new ITunesSearchEngine(this.Configuration, this.CacheManager, this.Logger);
this.MusicBrainzReleaseSearchEngine = new musicbrainz.MusicBrainzProvider(this.Configuration, this.CacheManager, this.Logger);
this.LastFmReleaseSearchEngine = new lastfm.LastFmHelper(this.Configuration, this.CacheManager, this.Logger, context, httpEncoder);
this.LastFmReleaseSearchEngine = new lastfm.LastFmHelper(this.Configuration, this.CacheManager, this.Logger);
this.DiscogsReleaseSearchEngine = new discogs.DiscogsHelper(this.Configuration, this.CacheManager, this.Logger);
this.SpotifyReleaseSearchEngine = new spotify.SpotifyHelper(this.Configuration, this.CacheManager, this.Logger);
this.WikipediaReleaseSearchEngine = new wikipedia.WikipediaHelper(this.Configuration, this.CacheManager, this.Logger, this.HttpEncoder);

View file

@ -28,14 +28,5 @@ namespace Roadie.Library.Extensions
var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
return Convert.ToInt64((date - epoch).TotalSeconds);
}
public static int ToUnixTimeSinceEpoch(this DateTime dateTime)
{
DateTime utcDateTime = dateTime.ToUniversalTime();
var jan1St1970 = new DateTime(1970, 1, 1, 0, 0, 0);
TimeSpan timeSinceJan1St1970 = utcDateTime.Subtract(jan1St1970);
return (int)timeSinceJan1St1970.TotalSeconds;
}
}
}

View file

@ -127,10 +127,6 @@ namespace Roadie.Library.Identity
[StringLength(50)]
public string Timezone { get; set; }
[Column("lastFMSessionKey")]
[StringLength(50)]
public string LastFMSessionKey { get; set; }
public ICollection<UserTrack> TrackRatings { get; set; }
public ICollection<UserQue> UserQues { get; set; }

View file

@ -34,8 +34,6 @@ namespace Roadie.Library
[XmlIgnore]
public Dictionary<string, object> AdditionalData { get; set; } = new Dictionary<string, object>();
public Dictionary<string, object> AdditionalClientData { get; set; } = new Dictionary<string, object>();
/// <summary>
/// Client friendly exceptions
/// </summary>

View file

@ -1,18 +0,0 @@
using Roadie.Library.Models.Users;
using System.Threading.Tasks;
namespace Roadie.Library.Scrobble
{
public interface IScrobbleHandler
{
/// <summary>
/// When a user starts playing a track.
/// </summary>
Task<OperationResult<bool>> NowPlaying(User user, ScrobbleInfo scrobble);
/// <summary>
/// When a user has either played more than 4 minutes of the track or the entire track.
/// </summary>
Task<OperationResult<bool>> Scrobble(User user, ScrobbleInfo scrobble);
}
}

View file

@ -1,12 +0,0 @@
using Roadie.Library.Models.Users;
using System.Threading.Tasks;
namespace Roadie.Library.Scrobble
{
public interface IScrobblerIntegration
{
Task<OperationResult<bool>> NowPlaying(User roadieUser, ScrobbleInfo scrobble);
Task<OperationResult<bool>> Scrobble(User roadieUser, ScrobbleInfo scrobble);
}
}

View file

@ -1,37 +0,0 @@
using Microsoft.Extensions.Logging;
using Roadie.Library.Caching;
using Roadie.Library.Configuration;
using Roadie.Library.MetaData.LastFm;
using Roadie.Library.Models.Users;
using System.Threading.Tasks;
using data = Roadie.Library.Data;
namespace Roadie.Library.Scrobble
{
/// <summary>
/// LastFM Scrobbler
/// <seealso cref="https://www.last.fm/api/scrobbling"/>
/// </summary>
public class LastFMScrobbler : ScrobblerIntegrationBase
{
private ILastFmHelper LastFmHelper { get; }
public LastFMScrobbler(IRoadieSettings configuration, ILogger logger, data.IRoadieDbContext dbContext, ICacheManager cacheManager, ILastFmHelper lastFmHelper)
: base(configuration, logger, dbContext, cacheManager)
{
LastFmHelper = lastFmHelper;
}
/// <summary>
/// Send a Now Playing Request.
/// <remark>The "Now Playing" service lets a client notify Last.fm that a user has started listening to a track. This does not affect a user's charts, but will feature the current track on their profile page, along with an indication of what music player they're using.</remark>
/// </summary>
public override async Task<OperationResult<bool>> NowPlaying(User roadieUser, ScrobbleInfo scrobble) => await LastFmHelper.NowPlaying(roadieUser, scrobble);
/// <summary>
/// Send a Scrobble Request
/// <remark>The scrobble service lets a client add a track-play to a user's profile. This data is used to show a user's listening history and generate personalised charts and recommendations (and more).</remark>
/// </summary>
public override async Task<OperationResult<bool>> Scrobble(User roadieUser, ScrobbleInfo scrobble) => await LastFmHelper.Scrobble(roadieUser, scrobble);
}
}

View file

@ -1,96 +0,0 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Roadie.Library.Caching;
using Roadie.Library.Configuration;
using Roadie.Library.Models.Users;
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using data = Roadie.Library.Data;
namespace Roadie.Library.Scrobble
{
public class RoadieScrobbler : ScrobblerIntegrationBase
{
public RoadieScrobbler(IRoadieSettings configuration, ILogger logger, data.IRoadieDbContext dbContext, ICacheManager cacheManager)
: base(configuration, logger, dbContext, cacheManager)
{
}
/// <summary>
/// The user has started playing a track.
/// </summary>
public override async Task<OperationResult<bool>> NowPlaying(User roadieUser, ScrobbleInfo scrobble) => await ScrobbleAction(roadieUser, scrobble, true);
/// <summary>
/// The user has played a track.
/// </summary>
public override async Task<OperationResult<bool>> Scrobble(User roadieUser, ScrobbleInfo scrobble) => await ScrobbleAction(roadieUser, scrobble, false);
private async Task<OperationResult<bool>> ScrobbleAction(User roadieUser, ScrobbleInfo scrobble, bool isNowPlaying)
{
try
{
var sw = Stopwatch.StartNew();
var track = this.DbContext.Tracks
.Include(x => x.ReleaseMedia)
.Include(x => x.ReleaseMedia.Release)
.Include(x => x.ReleaseMedia.Release.Artist)
.Include(x => x.TrackArtist)
.FirstOrDefault(x => x.RoadieId == scrobble.TrackId);
if (track == null)
{
return new OperationResult<bool>($"Scrobble: Unable To Find Track [{ scrobble.TrackId }]");
}
if (!track.IsValid)
{
return new OperationResult<bool>($"Scrobble: Invalid Track. Track Id [{scrobble.TrackId}], FilePath [{track.FilePath}], Filename [{track.FileName}]");
}
data.UserTrack userTrack = null;
var now = DateTime.UtcNow;
var success = false;
try
{
// Only create (or update) a user track activity record when the user has played the entire track.
if (!isNowPlaying)
{
var user = this.DbContext.Users.FirstOrDefault(x => x.RoadieId == roadieUser.UserId);
userTrack = this.DbContext.UserTracks.FirstOrDefault(x => x.UserId == roadieUser.Id && x.TrackId == track.Id);
if (userTrack == null)
{
userTrack = new data.UserTrack(now)
{
UserId = user.Id,
TrackId = track.Id
};
this.DbContext.UserTracks.Add(userTrack);
}
userTrack.LastPlayed = now;
userTrack.PlayedCount = (userTrack.PlayedCount ?? 0) + 1;
this.CacheManager.ClearRegion(user.CacheRegion);
await this.DbContext.SaveChangesAsync();
}
success = true;
}
catch (Exception ex)
{
this.Logger.LogError(ex, $"Error in Scrobble, Creating UserTrack: User `{ roadieUser}` TrackId [{ track.Id }");
}
sw.Stop();
this.Logger.LogInformation($"RoadieScrobbler: RoadieUser `{ roadieUser }` { (isNowPlaying ? "NowPlaying" : "Scrobble") } `{ scrobble }`");
return new OperationResult<bool>
{
Data = success,
IsSuccess = userTrack != null,
OperationTime = sw.ElapsedMilliseconds
};
}
catch (Exception ex)
{
this.Logger.LogError(ex, $"Scrobble RoadieUser `{ roadieUser }` Scrobble `{ scrobble }`");
}
return new OperationResult<bool>();
}
}
}

View file

@ -1,102 +0,0 @@
using Microsoft.Extensions.Logging;
using Roadie.Library.Caching;
using Roadie.Library.Configuration;
using Roadie.Library.Encoding;
using Roadie.Library.MetaData.LastFm;
using Roadie.Library.Models.Users;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using data = Roadie.Library.Data;
namespace Roadie.Library.Scrobble
{
/// <summary>
/// Handles NowPlaying and Scrobbling for all integrations
/// </summary>
public class ScrobbleHandler : IScrobbleHandler
{
private IRoadieSettings Configuration { get; }
private data.IRoadieDbContext DbContext { get; }
private ILogger Logger { get; }
private IHttpEncoder HttpEncoder { get; }
private IEnumerable<IScrobblerIntegration> Scrobblers { get; }
public ScrobbleHandler(IRoadieSettings configuration, ILogger<ScrobbleHandler> logger, data.IRoadieDbContext dbContext, ICacheManager cacheManager, IHttpEncoder httpEncoder)
{
Logger = logger;
Configuration = configuration;
DbContext = dbContext;
HttpEncoder = httpEncoder;
var scrobblers = new List<IScrobblerIntegration>
{
new RoadieScrobbler(configuration, logger, dbContext, cacheManager)
};
if (configuration.Integrations.LastFmProviderEnabled)
{
scrobblers.Add(new LastFmHelper(configuration, cacheManager, logger, dbContext, httpEncoder));
}
Scrobblers = scrobblers;
}
/// <summary>
/// Send Now Playing Requests
/// </summary>
public async Task<OperationResult<bool>> NowPlaying(User user, ScrobbleInfo scrobble)
{
var s = GetScrobbleInfoDetails(scrobble);
foreach (var scrobbler in Scrobblers)
{
await Task.Run(async () => await scrobbler.NowPlaying(user, s));
}
return new OperationResult<bool>
{
Data = true,
IsSuccess = true
};
}
/// <summary>
/// Send any Scrobble Requests
/// </summary>
public async Task<OperationResult<bool>> Scrobble(User user, ScrobbleInfo scrobble)
{
var s = GetScrobbleInfoDetails(scrobble);
foreach (var scrobbler in Scrobblers)
{
await Task.Run(async () => await scrobbler.Scrobble(user, s));
}
return new OperationResult<bool>
{
Data = true,
IsSuccess = true
};
}
private ScrobbleInfo GetScrobbleInfoDetails(ScrobbleInfo scrobble)
{
var scrobbleInfo = (from t in this.DbContext.Tracks
join rm in this.DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
join r in this.DbContext.Releases on rm.ReleaseId equals r.Id
join a in this.DbContext.Artists on r.ArtistId equals a.Id
where t.RoadieId == scrobble.TrackId
select new
{
ArtistName = a.Name,
ReleaseTitle = r.Title,
TrackTitle = t.Title,
t.TrackNumber,
t.Duration
}).FirstOrDefault();
scrobble.ArtistName = scrobbleInfo.ArtistName;
scrobble.ReleaseTitle = scrobbleInfo.ReleaseTitle;
scrobble.TrackTitle = scrobbleInfo.TrackTitle;
scrobble.TrackNumber = scrobbleInfo.TrackNumber.ToString();
scrobble.TrackDuration = TimeSpan.FromMilliseconds((double)(scrobbleInfo.Duration ?? 0));
return scrobble;
}
}
}

View file

@ -1,28 +0,0 @@
using System;
namespace Roadie.Library.Scrobble
{
[Serializable]
public class ScrobbleInfo
{
public string ArtistName { get; set; }
public bool IsRandomizedScrobble { get; set; }
public string ReleaseTitle { get; set; }
public DateTime TimePlayed { get; set; }
public Guid TrackId { get; set; }
public string TrackNumber { get; set; }
public string TrackTitle { get; set; }
public TimeSpan TrackDuration { get; set; }
public TimeSpan ElapsedTimeOfTrackPlayed
{
get
{
return DateTime.UtcNow.Subtract(TimePlayed);
}
}
public override string ToString() => $"Artist: [{ ArtistName }], Release: [{ ReleaseTitle}], Track# [{ TrackNumber }], Track [{ TrackTitle }]";
}
}

View file

@ -1,29 +0,0 @@
using Microsoft.Extensions.Logging;
using Roadie.Library.Caching;
using Roadie.Library.Configuration;
using Roadie.Library.Models.Users;
using System.Threading.Tasks;
using data = Roadie.Library.Data;
namespace Roadie.Library.Scrobble
{
public abstract class ScrobblerIntegrationBase : IScrobblerIntegration
{
protected ICacheManager CacheManager { get; }
protected IRoadieSettings Configuration { get; }
protected data.IRoadieDbContext DbContext { get; }
protected ILogger Logger { get; }
public ScrobblerIntegrationBase(IRoadieSettings configuration, ILogger logger, data.IRoadieDbContext dbContext, ICacheManager cacheManager)
{
Logger = logger;
Configuration = configuration;
DbContext = dbContext;
CacheManager = cacheManager;
}
public abstract Task<OperationResult<bool>> NowPlaying(User roadieUser, ScrobbleInfo scrobble);
public abstract Task<OperationResult<bool>> Scrobble(User roadieUser, ScrobbleInfo scrobble);
}
}

View file

@ -20,7 +20,10 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
{
get
{
return this.Configuration.Integrations.DiscogsProviderEnabled;
// TODO
//return this.Configuration.Integrations.dis.GetValue<bool>("Integrations:DiscogsProviderEnabled", true) &&
// !string.IsNullOrEmpty(this.ApiKey.Key);
return false;
}
}

View file

@ -1,19 +1,16 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Roadie.Library.MetaData.Audio;
using Roadie.Library.Scrobble;
using Roadie.Library.SearchEngines.MetaData;
namespace Roadie.Library.MetaData.LastFm
{
public interface ILastFmHelper : IScrobblerIntegration
public interface ILastFmHelper
{
bool IsEnabled { get; }
Task<OperationResult<IEnumerable<ArtistSearchResult>>> PerformArtistSearch(string query, int resultsCount);
Task<OperationResult<IEnumerable<ReleaseSearchResult>>> PerformReleaseSearch(string artistName, string query, int resultsCount);
Task<IEnumerable<AudioMetaData>> TracksForRelease(string artist, string Release);
Task<OperationResult<string>> GetSessionKeyForUserToken(string token);
}
}

View file

@ -1,25 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Roadie.Library.SearchEngines.MetaData.LastFm
{
public class LastFmApiException : Exception
{
/// <summary>
/// Instantiates a Last.fm API exception
/// </summary>
public LastFmApiException(string message)
: base(message)
{
}
/// <summary>
/// Instantiates a Last.fm API exception
/// </summary>
public LastFmApiException(string message, Exception innerException)
: base(message, innerException)
{
}
}
}

View file

@ -1,59 +1,37 @@
using IF.Lastfm.Core.Api;
using IF.Lastfm.Core.Objects;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using RestSharp;
using Roadie.Library.Caching;
using Roadie.Library.Configuration;
using Roadie.Library.Encoding;
using Roadie.Library.Extensions;
using Roadie.Library.Identity;
using Roadie.Library.MetaData.Audio;
using Roadie.Library.Models.Users;
using Roadie.Library.Scrobble;
using Roadie.Library.SearchEngines.MetaData;
using Roadie.Library.SearchEngines.MetaData.LastFm;
using Roadie.Library.Utility;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;
using System.Xml.XPath;
using data = Roadie.Library.Data;
namespace Roadie.Library.MetaData.LastFm
{
public class LastFmHelper : MetaDataProviderBase, IArtistSearchEngine, IReleaseSearchEngine, ILastFmHelper
{
const string LastFmStatusOk = "ok";
const string LastFmErrorXPath = "/lfm/error";
const string LastFmErrorCodeXPath = "/lfm/error/@code";
const string LastFmStatusXPath = "/lfm/@status";
public override bool IsEnabled
{
get
{
return this.Configuration.Integrations.LastFmProviderEnabled;
// TODO
// return this.Configuration.GetValue<bool>("Integrations:LastFmProviderEnabled", true) &&
// !string.IsNullOrEmpty(this.ApiKey.Key);
return false;
}
}
private data.IRoadieDbContext DbContext { get; }
private IHttpEncoder HttpEncoder { get; }
public LastFmHelper(IRoadieSettings configuration, ICacheManager cacheManager, ILogger logger,
data.IRoadieDbContext dbContext, IHttpEncoder httpEncoder)
: base(configuration, cacheManager, logger)
public LastFmHelper(IRoadieSettings configuration, ICacheManager cacheManager, ILogger logger) : base(configuration, cacheManager, logger)
{
this._apiKey = configuration.Integrations.ApiKeys.FirstOrDefault(x => x.ApiName == "LastFMApiKey") ?? new ApiKey();
DbContext = dbContext;
HttpEncoder = httpEncoder;
}
public async Task<OperationResult<IEnumerable<ArtistSearchResult>>> PerformArtistSearch(string query, int resultsCount)
@ -80,7 +58,10 @@ namespace Roadie.Library.MetaData.LastFm
{
result.Tags = lastFmArtist.Tags.Select(x => x.Name).ToList();
}
// No longer fetching/consuming images LastFm says is violation of ToS ; https://getsatisfaction.com/lastfm/topics/api-announcement-dac8oefw5vrxq
if (lastFmArtist.MainImage != null && (lastFmArtist.MainImage.ExtraLarge != null || lastFmArtist.MainImage.Large != null))
{
result.ArtistThumbnailUrl = (lastFmArtist.MainImage.ExtraLarge ?? lastFmArtist.MainImage.Large).ToString();
}
if (lastFmArtist.Url != null)
{
result.Urls = new string[] { lastFmArtist.Url.ToString() };
@ -116,8 +97,10 @@ namespace Roadie.Library.MetaData.LastFm
MusicBrainzId = lastFmAlbum.mbid
};
// No longer fetching/consuming images LastFm says is violation of ToS ; https://getsatisfaction.com/lastfm/topics/api-announcement-dac8oefw5vrxq
if (lastFmAlbum.image != null)
{
result.ImageUrls = lastFmAlbum.image.Where(x => x.size == "extralarge").Select(x => x.Value).ToList();
}
if (lastFmAlbum.tags != null)
{
result.Tags = lastFmAlbum.tags.Select(x => x.name).ToList();
@ -152,132 +135,6 @@ namespace Roadie.Library.MetaData.LastFm
};
}
public async Task<OperationResult<bool>> NowPlaying(User roadieUser, ScrobbleInfo scrobble)
{
var result = false;
try
{
if (!IsEnabled)
{
return new OperationResult<bool>("LastFM Integation Disabled");
}
var user = this.DbContext.Users.FirstOrDefault(x => x.RoadieId == roadieUser.UserId);
if (user == null || string.IsNullOrEmpty(user.LastFMSessionKey))
{
return new OperationResult<bool>("User does not have LastFM Integration setup");
}
var method = "track.updateNowPlaying";
var parameters = new RequestParameters
{
{ "artist", scrobble.ArtistName },
{ "track", scrobble.TrackTitle},
{ "album", scrobble.ReleaseTitle },
{ "duration", ((int)scrobble.TrackDuration.TotalSeconds).ToString() }
};
var url = "http://ws.audioscrobbler.com/2.0/";
var signature = GenerateMethodSignature(method, parameters, user.LastFMSessionKey);
parameters.Add("api_sig", signature);
ServicePointManager.Expect100Continue = false;
var request = WebRequest.Create(url);
request.Method = "POST";
var postData = parameters.ToString();
byte[] byteArray = System.Text.Encoding.UTF8.GetBytes(postData);
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = byteArray.Length;
using (Stream dataStream = request.GetRequestStream())
{
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
}
var xp = GetResponseAsXml(request);
this.Logger.LogInformation($"LastFmHelper: RoadieUser `{ roadieUser }` NowPlaying `{ scrobble }` LastFmResult [{ xp.InnerXml }]");
result = true;
}
catch (Exception ex)
{
this.Logger.LogError(ex, $"Error in LastFmHelper NowPlaying: RoadieUser `{ roadieUser }` Scrobble `{ scrobble }`");
}
return new OperationResult<bool>
{
IsSuccess = result,
Data = result
};
}
public async Task<OperationResult<bool>> Scrobble(User roadieUser, ScrobbleInfo scrobble)
{
var result = false;
try
{
if (!IsEnabled)
{
return new OperationResult<bool>("LastFM Integation Disabled");
}
// LastFM Rules on scrobbling:
// * The track must be longer than 30 seconds.
// * And the track has been played for at least half its duration, or for 4 minutes(whichever occurs earlier.)
if (scrobble.TrackDuration.TotalSeconds < 30)
{
return new OperationResult<bool>("Track duration or elapsed time does not qualify for LastFM Scrobbling");
}
// If less than half of duration then create a NowPlaying
if (scrobble.ElapsedTimeOfTrackPlayed.TotalMinutes < 4 ||
scrobble.ElapsedTimeOfTrackPlayed.TotalSeconds < (scrobble.TrackDuration.TotalSeconds / 2))
{
return await NowPlaying(roadieUser, scrobble);
}
var user = this.DbContext.Users.FirstOrDefault(x => x.RoadieId == roadieUser.UserId);
if (user == null || string.IsNullOrEmpty(user.LastFMSessionKey))
{
return new OperationResult<bool>("User does not have LastFM Integration setup");
}
var parameters = new RequestParameters
{
{ "artist", scrobble.ArtistName },
{ "track", scrobble.TrackTitle },
{ "timestamp", scrobble.TimePlayed.ToUnixTimeSinceEpoch().ToString() },
{ "album", scrobble.ReleaseTitle },
{ "chosenByUser", scrobble.IsRandomizedScrobble ? "1" : "0" },
{ "duration", ((int)scrobble.TrackDuration.TotalSeconds).ToString() }
};
var method = "track.scrobble";
var url = "http://ws.audioscrobbler.com/2.0/";
var signature = GenerateMethodSignature(method, parameters, user.LastFMSessionKey);
parameters.Add("api_sig", signature);
ServicePointManager.Expect100Continue = false;
var request = WebRequest.Create(url);
request.Method = "POST";
var postData = parameters.ToString();
byte[] byteArray = System.Text.Encoding.UTF8.GetBytes(postData);
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = byteArray.Length;
using (Stream dataStream = request.GetRequestStream())
{
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
}
var xp = GetResponseAsXml(request);
this.Logger.LogInformation($"LastFmHelper: RoadieUser `{ roadieUser }` Scrobble `{ scrobble }` LastFmResult [{ xp.InnerXml }]");
result = true;
}
catch (Exception ex)
{
this.Logger.LogError(ex, $"Error in LastFmHelper Scrobble: RoadieUser `{ roadieUser }` Scrobble `{ scrobble }`");
}
return new OperationResult<bool>
{
IsSuccess = result,
Data = result
};
}
public async Task<IEnumerable<AudioMetaData>> TracksForRelease(string artist, string Release)
{
if (string.IsNullOrEmpty(artist) || string.IsNullOrEmpty(Release))
@ -346,166 +203,5 @@ namespace Roadie.Library.MetaData.LastFm
}
return result;
}
public async Task<OperationResult<string>> GetSessionKeyForUserToken(string token)
{
var parameters = new Dictionary<string, string>
{
{ "token", token }
};
var request = new RestRequest(Method.GET);
var client = new RestClient(BuildUrl("auth.getSession", parameters));
var responseXML = await client.ExecuteTaskAsync<string>(request);
XmlDocument doc = new XmlDocument();
doc.LoadXml(responseXML.Content);
var sessionKey = doc.GetElementsByTagName("key")[0].InnerText;
return new OperationResult<string>
{
Data = sessionKey,
IsSuccess = true
};
}
private string BuildUrl(string method, IDictionary<string, string> parameters = null)
{
var builder = new StringBuilder($"http://ws.audioscrobbler.com/2.0?method={ method }");
if (parameters != null)
{
parameters.Add("api_key", this._apiKey.Key);
foreach (var kv in parameters.OrderBy(kv => kv.Key, StringComparer.Ordinal))
{
builder.Append($"&{kv.Key}={kv.Value }");
}
var signature = GenerateMethodSignature(method, parameters);
builder.Append($"&api_sig={ signature } ");
}
return builder.ToString();
}
private string GenerateMethodSignature(string method, IDictionary<string, string> parameters = null, string sk = null)
{
if (parameters == null)
{
parameters = new Dictionary<string, string>();
}
parameters.Add("method", method);
parameters.Add("api_key", this._apiKey.Key);
if (!string.IsNullOrEmpty(sk))
{
parameters.Add("sk", sk);
}
var builder = new StringBuilder();
foreach (var kv in parameters.OrderBy(kv => kv.Key, StringComparer.Ordinal))
{
builder.Append($"{kv.Key}{kv.Value}");
}
builder.Append(this._apiKey.KeySecret);
return Hash(builder.ToString());
}
// http://msdn.microsoft.com/en-us/library/system.security.cryptography.md5.aspx
// Hash an input string and return the hash as
// a 32 character hexadecimal string.
public static string Hash(string input)
{
// Create a new instance of the MD5CryptoServiceProvider object.
using (MD5 md5Hasher = MD5.Create())
{
byte[] data = md5Hasher.ComputeHash(System.Text.Encoding.ASCII.GetBytes(input));
var sb = new StringBuilder();
foreach (byte b in data)
{
sb.Append(b.ToString("X2"));
}
return sb.ToString();
}
}
protected internal virtual XPathNavigator GetResponseAsXml(WebRequest request)
{
WebResponse response;
XPathNavigator navigator;
try
{
response = request.GetResponse();
navigator = GetXpathDocumentFromResponse(response);
CheckLastFmStatus(navigator);
}
catch (WebException exception)
{
response = exception.Response;
XPathNavigator document;
TryGetXpathDocumentFromResponse(response, out document);
if (document != null) CheckLastFmStatus(document, exception);
throw; // throw even if Last.fm status is OK
}
return navigator;
}
protected virtual bool TryGetXpathDocumentFromResponse(WebResponse response, out XPathNavigator document)
{
bool parsed;
try
{
document = GetXpathDocumentFromResponse(response);
parsed = true;
}
catch (Exception)
{
document = null;
parsed = false;
}
return parsed;
}
protected virtual XPathNavigator GetXpathDocumentFromResponse(WebResponse response)
{
using (var stream = response.GetResponseStream())
{
if (stream == null) throw new InvalidOperationException("Response Stream is null");
try
{
return new XPathDocument(stream).CreateNavigator();
}
catch (XmlException exception)
{
throw new XmlException("Could not read HTTP Response as XML", exception);
}
finally
{
response.Close();
}
}
}
public static void CheckLastFmStatus(XPathNavigator navigator)
{
CheckLastFmStatus(navigator, null);
}
public static void CheckLastFmStatus(XPathNavigator navigator, WebException webException)
{
var node = SelectSingleNode(navigator, LastFmStatusXPath);
if (node.Value == LastFmStatusOk) return;
throw new LastFmApiException(string.Format("LastFm status = \"{0}\". Error code = {1}. {2}",
node.Value,
SelectSingleNode(navigator, LastFmErrorCodeXPath),
SelectSingleNode(navigator, LastFmErrorXPath)), webException);
}
public static XPathNavigator SelectSingleNode(XPathNavigator navigator, string xpath)
{
var node = navigator.SelectSingleNode(xpath);
if (node == null) throw new InvalidOperationException("Node is null. Cannot select single node. XML response may be mal-formed");
return node;
}
}
}

View file

@ -1,66 +0,0 @@
using System.Collections.Generic;
using System.Text;
using System.Web;
namespace Roadie.Library.SearchEngines.MetaData.LastFm
{
internal class RequestParameters : SortedDictionary<string, string>
{
/// <summary>
/// The Name Value Pair Format String used by this object
/// </summary>
public const string NameValuePairStringFormat = "{0}={1}";
/// <summary>
/// The Name-value pair seperator used by this object
/// </summary>
public const string NameValuePairStringSeperator = "&";
public RequestParameters()
: base()
{
}
internal RequestParameters(string serialization)
: base()
{
string[] values = serialization.Split('\t');
for (int i = 0; i < values.Length - 1; i++)
{
if ((i % 2) == 0)
{
this[values[i]] = values[i + 1];
}
}
}
public override string ToString()
{
var builder = new StringBuilder();
int count = 0;
foreach (string key in this.Keys)
{
if (count > 0) builder.Append(NameValuePairStringSeperator);
builder.AppendFormat(NameValuePairStringFormat, key, HttpUtility.UrlEncode(this[key]));
count++;
}
return builder.ToString();
}
internal string serialize()
{
string line = "";
foreach (string key in Keys)
line += key + "\t" + this[key] + "\t";
return line;
}
internal byte[] ToBytes()
{
return System.Text.Encoding.UTF8.GetBytes(ToString());
}
}
}

View file

@ -34,8 +34,6 @@ namespace Roadie.Library.SearchEngines.MetaData.Spotify
ArtistSearchResult data = null;
try
{
// TODO update this to use https://github.com/JohnnyCrazy/SpotifyAPI-NET
this.Logger.LogTrace("SpotifyHelper:PerformArtistSearch:{0}", query);
var request = this.BuildSearchRequest(query, 1, "artist");

View file

@ -0,0 +1,42 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Roadie.Library.Utility
{
public class LookupSerializer : JsonConverter
{
public override bool CanConvert(Type objectType)
{
var result = objectType.GetInterfaces().Any(a => a.IsGenericType
&& a.GetGenericTypeDefinition() == typeof(ILookup<,>));
return result;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var obj = new JObject();
var enumerable = (IEnumerable)value;
foreach (object kvp in enumerable)
{
// TODO: caching
var keyProp = kvp.GetType().GetProperty("Key");
var keyValue = keyProp.GetValue(kvp, null);
obj.Add(keyValue.ToString(), JArray.FromObject((IEnumerable)kvp));
}
obj.WriteTo(writer);
}
}
}

View file

@ -73,7 +73,7 @@ namespace Roadie.Api.Services
this.EventMessageLogger.Messages += EventMessageLogger_Messages;
this.MusicBrainzProvider = new MusicBrainzProvider(configuration, cacheManager, MessageLogger);
this.LastFmHelper = new LastFmHelper(configuration, cacheManager, MessageLogger, context, httpEncoder);
this.LastFmHelper = new LastFmHelper(configuration, cacheManager, MessageLogger);
this.FileNameHelper = new FileNameHelper(configuration, cacheManager, MessageLogger);
this.ID3TagsHelper = new ID3TagsHelper(configuration, cacheManager, MessageLogger);

View file

@ -70,7 +70,7 @@ namespace Roadie.Api.Services
this.BookmarkService = bookmarkService;
this.MusicBrainzProvider = new mb.MusicBrainzProvider(configuration, cacheManager, logger);
this.LastFmHelper = new LastFmHelper(configuration, cacheManager, logger, dbContext, httpEncoder);
this.LastFmHelper = new LastFmHelper(configuration, cacheManager, logger);
this.FileNameHelper = new FileNameHelper(configuration, cacheManager, logger);
this.ID3TagsHelper = new ID3TagsHelper(configuration, cacheManager, logger);
this.ArtistLookupEngine = new ArtistLookupEngine(configuration, httpEncoder, dbContext, cacheManager, logger);

View file

@ -9,6 +9,8 @@ namespace Roadie.Api.Services
{
public interface IPlayActivityService
{
Task<OperationResult<PlayActivityList>> CreatePlayActivity(User roadieUser, TrackStreamInfo streamInfo);
Task<PagedResult<PlayActivityList>> List(PagedRequest request, User roadieUser = null, DateTime? newerThan = null);
}
}

View file

@ -44,7 +44,5 @@ namespace Roadie.Api.Services
Task<OperationResult<short>> SetTrackRating(Guid trackId, User roadieUser, short rating);
Task<OperationResult<bool>> UpdateProfile(User userPerformingUpdate, User userBeingUpdatedModel);
Task<OperationResult<bool>> UpdateIntegrationGrant(Guid userId, string integrationName, string token);
}
}

View file

@ -36,6 +36,143 @@ namespace Roadie.Api.Services
this.PlayActivityHub = playHubContext;
}
public async Task<OperationResult<PlayActivityList>> CreatePlayActivity(User roadieUser, TrackStreamInfo streamInfo)
{
try
{
var sw = Stopwatch.StartNew();
var track = this.DbContext.Tracks
.Include(x => x.ReleaseMedia)
.Include(x => x.ReleaseMedia.Release)
.Include(x => x.ReleaseMedia.Release.Artist)
.Include(x => x.TrackArtist)
.FirstOrDefault(x => x.RoadieId == SafeParser.ToGuid(streamInfo.Track.Value));
if (track == null)
{
return new OperationResult<PlayActivityList>($"CreatePlayActivity: Unable To Find Track [{ streamInfo.Track.Value }]");
}
if (!track.IsValid)
{
return new OperationResult<PlayActivityList>($"CreatePlayActivity: Invalid Track. Track Id [{streamInfo.Track.Value}], FilePath [{track.FilePath}], Filename [{track.FileName}]");
}
data.UserTrack userTrack = null;
var now = DateTime.UtcNow;
try
{
var user = roadieUser != null ? this.DbContext.Users.FirstOrDefault(x => x.RoadieId == roadieUser.UserId) : null;
if (user != null)
{
userTrack = this.DbContext.UserTracks.FirstOrDefault(x => x.UserId == user.Id && x.TrackId == track.Id);
if (userTrack == null)
{
userTrack = new data.UserTrack(now)
{
UserId = user.Id,
TrackId = track.Id
};
this.DbContext.UserTracks.Add(userTrack);
}
userTrack.LastPlayed = now;
userTrack.PlayedCount = (userTrack.PlayedCount ?? 0) + 1;
this.CacheManager.ClearRegion(user.CacheRegion);
await this.DbContext.SaveChangesAsync();
}
}
catch (Exception ex)
{
this.Logger.LogError(ex, $"Error in CreatePlayActivity, Creating UserTrack: User `{ roadieUser}` TrackId [{ track.Id }");
}
track.PlayedCount = (track.PlayedCount ?? 0) + 1;
track.LastPlayed = now;
var release = this.DbContext.Releases.Include(x => x.Artist).FirstOrDefault(x => x.RoadieId == track.ReleaseMedia.Release.RoadieId);
release.LastPlayed = now;
release.PlayedCount = (release.PlayedCount ?? 0) + 1;
var artist = this.DbContext.Artists.FirstOrDefault(x => x.RoadieId == release.Artist.RoadieId);
artist.LastPlayed = now;
artist.PlayedCount = (artist.PlayedCount ?? 0) + 1;
data.Artist trackArtist = null;
if (track.ArtistId.HasValue)
{
trackArtist = this.DbContext.Artists.FirstOrDefault(x => x.Id == track.ArtistId);
trackArtist.LastPlayed = now;
trackArtist.PlayedCount = (trackArtist.PlayedCount ?? 0) + 1;
this.CacheManager.ClearRegion(trackArtist.CacheRegion);
}
this.CacheManager.ClearRegion(track.CacheRegion);
this.CacheManager.ClearRegion(track.ReleaseMedia.Release.CacheRegion);
this.CacheManager.ClearRegion(track.ReleaseMedia.Release.Artist.CacheRegion);
var pl = new PlayActivityList
{
Artist = new DataToken
{
Text = track.ReleaseMedia.Release.Artist.Name,
Value = track.ReleaseMedia.Release.Artist.RoadieId.ToString()
},
TrackArtist = track.TrackArtist == null ? null : new DataToken
{
Text = track.TrackArtist.Name,
Value = track.TrackArtist.RoadieId.ToString()
},
Release = new DataToken
{
Text = track.ReleaseMedia.Release.Title,
Value = track.ReleaseMedia.Release.RoadieId.ToString()
},
Track = new DataToken
{
Text = track.Title,
Value = track.RoadieId.ToString()
},
User = new DataToken
{
Text = roadieUser.UserName,
Value = roadieUser.UserId.ToString()
},
PlayedDateDateTime = userTrack?.LastPlayed,
ReleasePlayUrl = $"{ this.HttpContext.BaseUrl }/play/release/{ track.ReleaseMedia.Release.RoadieId}",
Rating = track.Rating,
UserRating = userTrack?.Rating,
TrackPlayUrl = $"{ this.HttpContext.BaseUrl }/play/track/{ track.RoadieId}.mp3",
ArtistThumbnail = this.MakeArtistThumbnailImage(track.TrackArtist != null ? track.TrackArtist.RoadieId : track.ReleaseMedia.Release.Artist.RoadieId),
ReleaseThumbnail = this.MakeReleaseThumbnailImage(track.ReleaseMedia.Release.RoadieId),
UserThumbnail = this.MakeUserThumbnailImage(roadieUser.UserId)
};
if (!roadieUser.IsPrivate)
{
try
{
await this.PlayActivityHub.Clients.All.SendAsync("SendActivity", pl);
}
catch (Exception ex)
{
this.Logger.LogError(ex);
}
}
await this.DbContext.SaveChangesAsync();
sw.Stop();
return new OperationResult<PlayActivityList>
{
Data = pl,
IsSuccess = userTrack != null,
OperationTime = sw.ElapsedMilliseconds
};
}
catch (Exception ex)
{
this.Logger.LogError(ex, $"CreatePlayActivity RoadieUser `{ roadieUser }` StreamInfo `{ streamInfo }`");
}
return new OperationResult<PlayActivityList>();
}
public Task<Library.Models.Pagination.PagedResult<PlayActivityList>> List(PagedRequest request, User roadieUser = null, DateTime? newerThan = null)
{
try

View file

@ -68,7 +68,7 @@ namespace Roadie.Api.Services
this.BookmarkService = bookmarkService;
this.MusicBrainzProvider = new MusicBrainzProvider(configuration, cacheManager, logger);
this.LastFmHelper = new LastFmHelper(configuration, cacheManager, logger, dbContext, httpEncoder);
this.LastFmHelper = new LastFmHelper(configuration, cacheManager, logger);
this.FileNameHelper = new FileNameHelper(configuration, cacheManager, logger);
this.ID3TagsHelper = new ID3TagsHelper(configuration, cacheManager, logger);

View file

@ -9,7 +9,6 @@ using Roadie.Library.Configuration;
using Roadie.Library.Encoding;
using Roadie.Library.Identity;
using Roadie.Library.Imaging;
using Roadie.Library.MetaData.LastFm;
using Roadie.Library.Models;
using Roadie.Library.Models.Pagination;
using Roadie.Library.Models.Statistics;
@ -22,14 +21,13 @@ using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using data = Roadie.Library.Data;
using models = Roadie.Library.Models;
namespace Roadie.Api.Services
{
public class UserService : ServiceBase, IUserService
{
private ILastFmHelper LastFmHelper { get; }
private UserManager<ApplicationUser> UserManager { get; }
public UserService(IRoadieSettings configuration,
@ -38,12 +36,10 @@ namespace Roadie.Api.Services
data.IRoadieDbContext context,
ICacheManager cacheManager,
ILogger<ArtistService> logger,
UserManager<ApplicationUser> userManager
)
UserManager<ApplicationUser> userManager)
: base(configuration, httpEncoder, context, cacheManager, logger, httpContext)
{
this.UserManager = userManager;
this.LastFmHelper = new LastFmHelper(this.Configuration, this.CacheManager, this.Logger, context, httpEncoder); ;
}
public async Task<OperationResult<User>> ById(User user, Guid id, IEnumerable<string> includes)
@ -388,51 +384,6 @@ namespace Roadie.Api.Services
return result;
}
private async Task<OperationResult<bool>> UpdateLastFMSessionKey(ApplicationUser user, string token)
{
var lastFmSessionKeyResult = await this.LastFmHelper.GetSessionKeyForUserToken(token);
if(!lastFmSessionKeyResult.IsSuccess)
{
return new OperationResult<bool>(false, $"Unable to Get LastFM Session Key For Token [{ token }]");
}
// Check concurrency stamp
if (user.ConcurrencyStamp != user.ConcurrencyStamp)
{
return new OperationResult<bool>
{
Errors = new List<Exception> { new Exception("User data is stale.") }
};
}
user.LastFMSessionKey = lastFmSessionKeyResult.Data;
user.LastUpdated = DateTime.UtcNow;
user.ConcurrencyStamp = Guid.NewGuid().ToString();
await this.DbContext.SaveChangesAsync();
this.CacheManager.ClearRegion(ApplicationUser.CacheRegionUrn(user.RoadieId));
this.Logger.LogInformation($"User `{ user }` Updated LastFm SessionKey");
return new OperationResult<bool>
{
IsSuccess = true,
Data = true
};
}
public async Task<OperationResult<bool>> UpdateIntegrationGrant(Guid userId, string integrationName, string token)
{
var user = this.DbContext.Users.FirstOrDefault(x => x.RoadieId == userId);
if (user == null)
{
return new OperationResult<bool>(true, $"User Not Found [{ userId }]");
}
if (integrationName == "lastfm")
{
return await this.UpdateLastFMSessionKey(user, token);
}
throw new NotImplementedException();
}
public async Task<OperationResult<bool>> UpdateProfile(User userPerformingUpdate, User userBeingUpdatedModel)
{
var user = this.DbContext.Users.FirstOrDefault(x => x.RoadieId == userBeingUpdatedModel.UserId);

View file

@ -5,7 +5,6 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Roadie.Api.Services;
using Roadie.Library.Caching;
using Roadie.Library.Configuration;
using Roadie.Library.Identity;
using System;
using System.Net;
@ -20,9 +19,8 @@ namespace Roadie.Api.Controllers
{
private IAdminService AdminService { get; }
public AdminController(IAdminService adminService, ILoggerFactory logger, ICacheManager cacheManager,
UserManager<ApplicationUser> userManager, IRoadieSettings roadieSettings)
: base(cacheManager, roadieSettings, userManager)
public AdminController(IAdminService adminService, ILoggerFactory logger, ICacheManager cacheManager, IConfiguration configuration, UserManager<ApplicationUser> userManager)
: base(cacheManager, configuration, userManager)
{
this.Logger = logger.CreateLogger("RoadieApi.Controllers.AdminController");
this.AdminService = adminService;

View file

@ -6,7 +6,6 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Roadie.Api.Services;
using Roadie.Library.Caching;
using Roadie.Library.Configuration;
using Roadie.Library.Identity;
using Roadie.Library.Models.Pagination;
using System;
@ -25,9 +24,8 @@ namespace Roadie.Api.Controllers
{
private IArtistService ArtistService { get; }
public ArtistController(IArtistService artistService, ILoggerFactory logger, ICacheManager cacheManager,
UserManager<ApplicationUser> userManager, IRoadieSettings roadieSettings)
: base(cacheManager, roadieSettings, userManager)
public ArtistController(IArtistService artistService, ILoggerFactory logger, ICacheManager cacheManager, IConfiguration configuration, UserManager<ApplicationUser> userManager)
: base(cacheManager, configuration, userManager)
{
this.Logger = logger.CreateLogger("RoadieApi.Controllers.ArtistController");
this.ArtistService = artistService;

View file

@ -5,7 +5,6 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Roadie.Api.Services;
using Roadie.Library.Caching;
using Roadie.Library.Configuration;
using Roadie.Library.Identity;
using Roadie.Library.Models.Pagination;
using System;
@ -22,9 +21,8 @@ namespace Roadie.Api.Controllers
{
private IBookmarkService BookmarkService { get; }
public BookmarkController(IBookmarkService bookmarkService, ILoggerFactory logger, ICacheManager cacheManager,
UserManager<ApplicationUser> userManager, IRoadieSettings roadieSettings)
: base(cacheManager, roadieSettings, userManager)
public BookmarkController(IBookmarkService bookmarkService, ILoggerFactory logger, ICacheManager cacheManager, IConfiguration configuration, UserManager<ApplicationUser> userManager)
: base(cacheManager, configuration, userManager)
{
this.Logger = logger.CreateLogger("RoadieApi.Controllers.BookmarkController");
this.BookmarkService = bookmarkService;

View file

@ -5,7 +5,6 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Roadie.Api.Services;
using Roadie.Library.Caching;
using Roadie.Library.Configuration;
using Roadie.Library.Identity;
using Roadie.Library.Models.Pagination;
using System;
@ -23,9 +22,8 @@ namespace Roadie.Api.Controllers
{
private ICollectionService CollectionService { get; }
public CollectionController(ICollectionService collectionService, ILoggerFactory logger, ICacheManager cacheManager,
UserManager<ApplicationUser> userManager, IRoadieSettings roadieSettings)
: base(cacheManager, roadieSettings, userManager)
public CollectionController(ICollectionService collectionService, ILoggerFactory logger, ICacheManager cacheManager, IConfiguration configuration, UserManager<ApplicationUser> userManager)
: base(cacheManager, configuration, userManager)
{
this.Logger = logger.CreateLogger("RoadieApi.Controllers.CollectionController");
this.CollectionService = collectionService;

View file

@ -9,7 +9,6 @@ using Roadie.Api.Services;
using Roadie.Library.Caching;
using Roadie.Library.Configuration;
using Roadie.Library.Identity;
using Roadie.Library.Scrobble;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@ -27,14 +26,18 @@ namespace Roadie.Api.Controllers
private models.User _currentUser = null;
protected ICacheManager CacheManager { get; }
protected IConfiguration Configuration { get; }
protected ILogger Logger { get; set; }
protected IRoadieSettings RoadieSettings { get; }
protected UserManager<ApplicationUser> UserManager { get; }
public EntityControllerBase(ICacheManager cacheManager, IRoadieSettings roadieSettings, UserManager<ApplicationUser> userManager)
public EntityControllerBase(ICacheManager cacheManager, IConfiguration configuration, UserManager<ApplicationUser> userManager)
{
this.CacheManager = cacheManager;
this.RoadieSettings = roadieSettings;
this.Configuration = configuration;
this.RoadieSettings = new RoadieSettings();
this.Configuration.GetSection("RoadieSettings").Bind(this.RoadieSettings);
this.UserManager = userManager;
}
@ -57,7 +60,7 @@ namespace Roadie.Api.Controllers
return this._currentUser;
}
protected async Task<IActionResult> StreamTrack(Guid id, ITrackService trackService, IScrobbleHandler scrobbleHandler, models.User currentUser = null)
protected async Task<IActionResult> StreamTrack(Guid id, ITrackService trackService, IPlayActivityService playActivityService, models.User currentUser = null)
{
var sw = Stopwatch.StartNew();
var timings = new Dictionary<string, long>();
@ -118,25 +121,12 @@ namespace Roadie.Api.Controllers
Response.Headers.Add("Cache-Control", info.Data.CacheControl);
Response.Headers.Add("Expires", info.Data.Expires);
var stream = new MemoryStream(info.Data.Bytes);
await Response.Body.WriteAsync(info.Data.Bytes, 0, info.Data.Bytes.Length);
var scrobble = new ScrobbleInfo
{
IsRandomizedScrobble = false,
TimePlayed = DateTime.UtcNow,
TrackId = id
};
if(!info.Data.IsFullRequest)
{
await scrobbleHandler.NowPlaying(user, scrobble);
}
else
{
await scrobbleHandler.Scrobble(user, scrobble);
}
var playListUser = await playActivityService.CreatePlayActivity(user, info?.Data);
sw.Stop();
this.Logger.LogInformation($"StreamTrack ElapsedTime [{ sw.ElapsedMilliseconds }], Timings [{ JsonConvert.SerializeObject(timings) }], StreamInfo `{ info?.Data.ToString() }`");
this.Logger.LogInformation($"StreamTrack ElapsedTime [{ sw.ElapsedMilliseconds }], Timings [{ JsonConvert.SerializeObject(timings) }] PlayActivity `{ playListUser?.Data.ToString() }`, StreamInfo `{ info?.Data.ToString() }`");
return new EmptyResult();
}

View file

@ -5,7 +5,6 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Roadie.Api.Services;
using Roadie.Library.Caching;
using Roadie.Library.Configuration;
using Roadie.Library.Identity;
using Roadie.Library.Models.Pagination;
using System;
@ -22,9 +21,8 @@ namespace Roadie.Api.Controllers
{
private IGenreService GenreService { get; }
public GenreController(IGenreService genreService, ILoggerFactory logger, ICacheManager cacheManager,
UserManager<ApplicationUser> userManager, IRoadieSettings roadieSettings)
: base(cacheManager, roadieSettings, userManager)
public GenreController(IGenreService genreService, ILoggerFactory logger, ICacheManager cacheManager, IConfiguration configuration, UserManager<ApplicationUser> userManager)
: base(cacheManager, configuration, userManager)
{
this.Logger = logger.CreateLogger("RoadieApi.Controllers.GenreController");
this.GenreService = genreService;

View file

@ -5,7 +5,6 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Roadie.Api.Services;
using Roadie.Library.Caching;
using Roadie.Library.Configuration;
using Roadie.Library.Identity;
using System;
using System.Net;
@ -21,14 +20,19 @@ namespace Roadie.Api.Controllers
{
private IImageService ImageService { get; }
public ImageController(IImageService imageService, ILoggerFactory logger, ICacheManager cacheManager,
UserManager<ApplicationUser> userManager, IRoadieSettings roadieSettings)
: base(cacheManager, roadieSettings, userManager)
public ImageController(IImageService imageService, ILoggerFactory logger, ICacheManager cacheManager, IConfiguration configuration, UserManager<ApplicationUser> userManager)
: base(cacheManager, configuration, userManager)
{
this.Logger = logger.CreateLogger("RoadieApi.Controllers.ImageController");
this.ImageService = imageService;
}
//[EnableQuery]
//public IActionResult Get()
//{
// return Ok(this._RoadieDbContext.Tracks.ProjectToType<models.Image>());
//}
[HttpGet("artist/{id}/{width:int?}/{height:int?}/{cacheBuster?}")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]

View file

@ -6,7 +6,6 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Roadie.Api.Services;
using Roadie.Library.Caching;
using Roadie.Library.Configuration;
using Roadie.Library.Identity;
using Roadie.Library.Models.Pagination;
using System;
@ -25,9 +24,8 @@ namespace Roadie.Api.Controllers
{
private ILabelService LabelService { get; }
public LabelController(ILabelService labelService, ILoggerFactory logger, ICacheManager cacheManager,
UserManager<ApplicationUser> userManager, IRoadieSettings roadieSettings)
: base(cacheManager, roadieSettings, userManager)
public LabelController(ILabelService labelService, ILoggerFactory logger, ICacheManager cacheManager, IConfiguration configuration, UserManager<ApplicationUser> userManager)
: base(cacheManager, configuration, userManager)
{
this.Logger = logger.CreateLogger("RoadieApi.Controllers.LabelController");
this.LabelService = labelService;

View file

@ -5,7 +5,6 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Roadie.Api.Services;
using Roadie.Library.Caching;
using Roadie.Library.Configuration;
using Roadie.Library.Identity;
using System;
using System.Net;
@ -21,9 +20,8 @@ namespace Roadie.Api.Controllers
{
private ILookupService LookupService { get; }
public LookupController(ILabelService labelService, ILoggerFactory logger, ICacheManager cacheManager,
UserManager<ApplicationUser> userManager, ILookupService lookupService, IRoadieSettings roadieSettings)
: base(cacheManager, roadieSettings, userManager)
public LookupController(ILabelService labelService, ILoggerFactory logger, ICacheManager cacheManager, IConfiguration configuration, UserManager<ApplicationUser> userManager, ILookupService lookupService)
: base(cacheManager, configuration, userManager)
{
this.Logger = logger.CreateLogger("RoadieApi.Controllers.LookupController");
this.LookupService = lookupService;

View file

@ -5,7 +5,6 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Roadie.Api.Services;
using Roadie.Library.Caching;
using Roadie.Library.Configuration;
using Roadie.Library.Identity;
using Roadie.Library.Models.Pagination;
using System;
@ -23,9 +22,8 @@ namespace Roadie.Api.Controllers
{
private IPlayActivityService PlayActivityService { get; }
public PlayActivityController(IPlayActivityService playActivityService, ILoggerFactory logger, ICacheManager cacheManager,
UserManager<ApplicationUser> userManager, IRoadieSettings roadieSettings)
: base(cacheManager, roadieSettings, userManager)
public PlayActivityController(IPlayActivityService playActivityService, ILoggerFactory logger, ICacheManager cacheManager, IConfiguration configuration, UserManager<ApplicationUser> userManager)
: base(cacheManager, configuration, userManager)
{
this.Logger = logger.CreateLogger("RoadieApi.Controllers.PlayActivityController");
this.PlayActivityService = playActivityService;

View file

@ -5,9 +5,7 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Roadie.Api.Services;
using Roadie.Library.Caching;
using Roadie.Library.Configuration;
using Roadie.Library.Identity;
using Roadie.Library.Scrobble;
using Roadie.Library.Utility;
using System;
using System.Linq;
@ -22,18 +20,16 @@ namespace Roadie.Api.Controllers
[Authorize]
public class PlayController : EntityControllerBase
{
private IScrobbleHandler ScrobbleHandler { get; }
private IPlayActivityService PlayActivityService { get; }
private IReleaseService ReleaseService { get; }
private ITrackService TrackService { get; }
public PlayController(ITrackService trackService, IReleaseService releaseService, IScrobbleHandler scrobblerHandler,
ILoggerFactory logger, ICacheManager cacheManager, UserManager<ApplicationUser> userManager,
IRoadieSettings roadieSettings)
: base(cacheManager, roadieSettings, userManager)
public PlayController(ITrackService trackService, IReleaseService releaseService, IPlayActivityService playActivityService, ILoggerFactory logger, ICacheManager cacheManager, IConfiguration configuration, UserManager<ApplicationUser> userManager)
: base(cacheManager, configuration, userManager)
{
this.Logger = logger.CreateLogger("RoadieApi.Controllers.PlayController");
this.TrackService = trackService;
this.ScrobbleHandler = scrobblerHandler;
this.PlayActivityService = playActivityService;
this.ReleaseService = releaseService;
}
@ -68,31 +64,6 @@ namespace Roadie.Api.Controllers
return File(System.Text.Encoding.Default.GetBytes(m3u), "audio/mpeg-url");
}
/// <summary>
/// A scrobble is done at the end of a Track being played and is not exactly the same as a track activity (user can fetch a track and not play it in its entirety).
/// </summary>
[HttpPost("track/scrobble/{id}/{startedPlaying}/{isRandom}")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public async Task<IActionResult> Scrobble(Guid id, string startedPlaying, bool isRandom)
{
var result = await this.ScrobbleHandler.Scrobble(await this.CurrentUserModel(), new ScrobbleInfo
{
TrackId = id,
TimePlayed = SafeParser.ToDateTime(startedPlaying) ?? DateTime.UtcNow,
IsRandomizedScrobble = isRandom
});
if (result == null || result.IsNotFoundResult)
{
return NotFound();
}
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
/// <summary>
/// This was done to use a URL based token as many clients don't support adding Auth Bearer tokens to audio requests.
/// </summary>
@ -109,7 +80,7 @@ namespace Roadie.Api.Controllers
{
return StatusCode((int)HttpStatusCode.Unauthorized);
}
return await base.StreamTrack(id, this.TrackService, this.ScrobbleHandler, this.UserModelForUser(user));
return await base.StreamTrack(id, this.TrackService, this.PlayActivityService, this.UserModelForUser(user));
}
}
}

View file

@ -5,7 +5,6 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Roadie.Api.Services;
using Roadie.Library.Caching;
using Roadie.Library.Configuration;
using Roadie.Library.Identity;
using Roadie.Library.Models.Pagination;
using Roadie.Library.Models.Playlists;
@ -24,9 +23,8 @@ namespace Roadie.Api.Controllers
{
private IPlaylistService PlaylistService { get; }
public PlaylistController(IPlaylistService playlistService, ILoggerFactory logger, ICacheManager cacheManager,
UserManager<ApplicationUser> userManager, IRoadieSettings roadieSettings)
: base(cacheManager, roadieSettings, userManager)
public PlaylistController(IPlaylistService playlistService, ILoggerFactory logger, ICacheManager cacheManager, IConfiguration configuration, UserManager<ApplicationUser> userManager)
: base(cacheManager, configuration, userManager)
{
this.Logger = logger.CreateLogger("RoadieApi.Controllers.PlaylistController");
this.PlaylistService = playlistService;

View file

@ -6,7 +6,6 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Roadie.Api.Services;
using Roadie.Library.Caching;
using Roadie.Library.Configuration;
using Roadie.Library.Identity;
using Roadie.Library.Models.Pagination;
using System;
@ -25,9 +24,8 @@ namespace Roadie.Api.Controllers
{
private IReleaseService ReleaseService { get; }
public ReleaseController(IReleaseService releaseService, ILoggerFactory logger, ICacheManager cacheManager,
UserManager<ApplicationUser> userManager, IRoadieSettings roadieSettings)
: base(cacheManager, roadieSettings, userManager)
public ReleaseController(IReleaseService releaseService, ILoggerFactory logger, ICacheManager cacheManager, IConfiguration configuration, UserManager<ApplicationUser> userManager)
: base(cacheManager, configuration, userManager)
{
this.Logger = logger.CreateLogger("RoadieApi.Controllers.ReleaseController"); ;
this.ReleaseService = releaseService;

View file

@ -5,7 +5,6 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Roadie.Api.Services;
using Roadie.Library.Caching;
using Roadie.Library.Configuration;
using Roadie.Library.Identity;
using System.Collections.Generic;
using System.Diagnostics;
@ -21,9 +20,8 @@ namespace Roadie.Api.Controllers
{
private IStatisticsService StatisticsService { get; }
public StatsController(IStatisticsService statisticsService, ILoggerFactory logger, ICacheManager cacheManager,
UserManager<ApplicationUser> userManager, IRoadieSettings roadieSettings)
: base(cacheManager, roadieSettings, userManager)
public StatsController(IStatisticsService statisticsService, ILoggerFactory logger, ICacheManager cacheManager, IConfiguration configuration, UserManager<ApplicationUser> userManager)
: base(cacheManager, configuration, userManager)
{
this.Logger = logger.CreateLogger("RoadieApi.Controllers.StatsController");
this.StatisticsService = statisticsService;

View file

@ -7,11 +7,9 @@ using Newtonsoft.Json;
using Roadie.Api.ModelBinding;
using Roadie.Api.Services;
using Roadie.Library.Caching;
using Roadie.Library.Configuration;
using Roadie.Library.Extensions;
using Roadie.Library.Identity;
using Roadie.Library.Models.ThirdPartyApi.Subsonic;
using Roadie.Library.Scrobble;
using System;
using System.Collections.Generic;
using System.Linq;
@ -24,7 +22,7 @@ namespace Roadie.Api.Controllers
[ApiController]
public class SubsonicController : EntityControllerBase
{
private IScrobbleHandler ScrobbleHandler { get; }
private IPlayActivityService PlayActivityService { get; }
private IReleaseService ReleaseService { get; }
private ISubsonicService SubsonicService { get; }
@ -35,16 +33,14 @@ namespace Roadie.Api.Controllers
private ITrackService TrackService { get; }
public SubsonicController(ISubsonicService subsonicService, ITrackService trackService, IReleaseService releaseService,
IScrobbleHandler scrobbleHandler, ILoggerFactory logger, ICacheManager cacheManager,
UserManager<ApplicationUser> userManager, IRoadieSettings roadieSettings)
: base(cacheManager, roadieSettings, userManager)
public SubsonicController(ISubsonicService subsonicService, ITrackService trackService, IReleaseService releaseService, IPlayActivityService playActivityService, ILoggerFactory logger, ICacheManager cacheManager, IConfiguration configuration, UserManager<ApplicationUser> userManager)
: base(cacheManager, configuration, userManager)
{
this.Logger = logger.CreateLogger("RoadieApi.Controllers.SubsonicController");
this.SubsonicService = subsonicService;
this.TrackService = trackService;
this.ReleaseService = releaseService;
this.ScrobbleHandler = scrobbleHandler;
this.PlayActivityService = playActivityService;
}
[HttpGet("addChatMessage.view")]
@ -130,7 +126,7 @@ namespace Roadie.Api.Controllers
var trackId = request.TrackId;
if (trackId != null)
{
return await base.StreamTrack(trackId.Value, this.TrackService, this.ScrobbleHandler, this.SubsonicUser);
return await base.StreamTrack(trackId.Value, this.TrackService, this.PlayActivityService, this.SubsonicUser);
}
var releaseId = request.ReleaseId;
if (releaseId != null)
@ -723,7 +719,7 @@ namespace Roadie.Api.Controllers
{
return NotFound("Invalid TrackId");
}
return await base.StreamTrack(trackId.Value, this.TrackService, this.ScrobbleHandler, this.SubsonicUser);
return await base.StreamTrack(trackId.Value, this.TrackService, this.PlayActivityService, this.SubsonicUser);
}
[HttpGet("unstar.view")]

View file

@ -5,7 +5,6 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Roadie.Api.Services;
using Roadie.Library.Caching;
using Roadie.Library.Configuration;
using Roadie.Library.Identity;
using Roadie.Library.Models;
using Roadie.Library.Models.Pagination;
@ -25,9 +24,8 @@ namespace Roadie.Api.Controllers
{
private ITrackService TrackService { get; }
public TrackController(ITrackService trackService, ILoggerFactory logger, ICacheManager cacheManager,
UserManager<ApplicationUser> userManager, IRoadieSettings roadieSettings)
: base(cacheManager, roadieSettings, userManager)
public TrackController(ITrackService trackService, ILoggerFactory logger, ICacheManager cacheManager, IConfiguration configuration, UserManager<ApplicationUser> userManager)
: base(cacheManager, configuration, userManager)
{
this.Logger = logger.CreateLogger("RoadieApi.Controllers.TrackController");
this.TrackService = trackService;

View file

@ -5,7 +5,6 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Roadie.Api.Services;
using Roadie.Library.Caching;
using Roadie.Library.Configuration;
using Roadie.Library.Identity;
using Roadie.Library.Models.Pagination;
using Roadie.Library.Models.Users;
@ -27,10 +26,8 @@ namespace Roadie.Api.Controllers
private IHttpContext RoadieHttpContext { get; }
private IUserService UserService { get; }
public UserController(IUserService userService, ILoggerFactory logger, ICacheManager cacheManager,
IConfiguration configuration, ITokenService tokenService, UserManager<ApplicationUser> userManager,
IHttpContext httpContext, IRoadieSettings roadieSettings)
: base(cacheManager, roadieSettings, userManager)
public UserController(IUserService userService, ILoggerFactory logger, ICacheManager cacheManager, IConfiguration configuration, ITokenService tokenService, UserManager<ApplicationUser> userManager, IHttpContext httpContext)
: base(cacheManager, configuration, userManager)
{
this.Logger = logger.CreateLogger("RoadieApi.Controllers.UserController");
this.UserService = userService;
@ -57,12 +54,6 @@ namespace Roadie.Api.Controllers
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
result.AdditionalClientData = new System.Collections.Generic.Dictionary<string, object>();
if (RoadieSettings.Integrations.LastFmProviderEnabled)
{
var lastFmCallBackUrl = $"{ this.RoadieHttpContext.BaseUrl}/users/integration/grant?userId={ user.UserId }&iname=lastfm";
result.AdditionalClientData.Add("lastFMIntegrationUrl", $"http://www.last.fm/api/auth/?api_key={ RoadieSettings.Integrations.LastFMApiKey }&cb={ WebUtility.UrlEncode(lastFmCallBackUrl) }");
}
return Ok(result);
}
@ -273,19 +264,6 @@ namespace Roadie.Api.Controllers
return Ok(result);
}
[AllowAnonymous]
[HttpGet("integration/grant")]
[ProducesResponseType(200)]
public async Task<IActionResult> IntegrationGrant(Guid userId, string iname, string token)
{
var result = await this.UserService.UpdateIntegrationGrant(userId, iname, token);
if (!result.IsSuccess)
{
return Content($"Error while attempting to enable integration");
}
return Content($"Successfully enabled integration!");
}
[HttpPost("profile/edit")]
[ProducesResponseType(200)]
public async Task<IActionResult> UpdateProfile(User model)

View file

@ -3,7 +3,7 @@
"Roadie.Api": {
"commandName": "Project",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Production"
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:5123/"
}

View file

@ -22,8 +22,6 @@ using Roadie.Library.Data;
using Roadie.Library.Encoding;
using Roadie.Library.Identity;
using Roadie.Library.Imaging;
using Roadie.Library.MetaData.LastFm;
using Roadie.Library.Scrobble;
using Roadie.Library.Utility;
using System;
using System.Diagnostics;
@ -156,29 +154,28 @@ namespace Roadie.Api
if (integrationKeys != null)
{
settings.Integrations.ApiKeys = new System.Collections.Generic.List<ApiKey>
{
new ApiKey
{
new ApiKey
{
ApiName = "LastFMApiKey",
Key = integrationKeys.LastFMApiKey,
KeySecret = integrationKeys.LastFMSecret
},
new ApiKey
{
ApiName = "DiscogsConsumerKey",
Key = integrationKeys.DiscogsConsumerKey,
KeySecret = integrationKeys.DiscogsConsumerSecret
},
new ApiKey
{
ApiName = "BingImageSearch",
Key = integrationKeys.BingImageSearch
}
};
ApiName = "LastFMApiKey",
Key = integrationKeys.LastFMApiKey,
KeySecret = integrationKeys.LastFMSecret
},
new ApiKey
{
ApiName = "DiscogsConsumerKey",
Key = integrationKeys.DiscogsConsumerKey,
KeySecret = integrationKeys.DiscogsConsumerSecret
},
new ApiKey
{
ApiName = "BingImageSearch",
Key = integrationKeys.BingImageSearch
}
};
}
return settings;
});
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
services.AddSingleton<IDefaultNotFoundImages, DefaultNotFoundImages>();
services.AddScoped<IStatisticsService, StatisticsService>();
@ -192,7 +189,6 @@ namespace Roadie.Api
services.AddScoped<ILabelService, LabelService>();
services.AddScoped<IPlaylistService, PlaylistService>();
services.AddScoped<IPlayActivityService, PlayActivityService>();
services.AddScoped<IScrobbleHandler, ScrobbleHandler>();
services.AddScoped<IGenreService, GenreService>();
services.AddScoped<ISubsonicService, SubsonicService>();
services.AddScoped<IUserService, UserService>();

View file

@ -80,7 +80,6 @@
"Integrations": {
"ITunesProviderEnabled": true,
"MusicBrainzProviderEnabled": true,
"LastFmProviderEnabled": true,
"SpotifyProviderEnabled": true
},
"Processing": {

View file

@ -83,7 +83,7 @@
"OGGConvertCommand": "ffmpeg -i \"{0}\" -acodec libmp3lame -q:a 0 \"{1}\"\"",
"APEConvertCommand": "ffmpeg -i \"{0}\" \"{1}\""
},
"SmtpFromAddress": "roadie@roadie.rocks",
"SmtpFromAddress": "roadie@roadie.net",
"SmtpPort": 2525,
"SmtpUsername": "apikey",
"SmtpHost": "smtp.sendgrid.net",
@ -91,22 +91,21 @@
"Integrations": {
"ITunesProviderEnabled": true,
"MusicBrainzProviderEnabled": true,
"LastFmProviderEnabled": true,
"SpotifyProviderEnabled": true,
"ApiKeys": [
{
"ApiName": "BingImageSearch",
"Key": "629eb0b425ff4cbfb926b262ccd2e313"
"Key": "<KEY HERE>"
},
{
"ApiName": "LastFMApiKey",
"Key": "5175afa1b9ec99789f4e4e8955c1a19b",
"KeySecret": "38dd80ade64bd094e82a690046fce1d1"
"Key": "<KEY HERE>",
"KeySecret": "<SECRET HERE>"
},
{
"ApiName": "DiscogsConsumerKey",
"Key": "qLhWWShjypNgLDDkpPTB",
"KeySecret": "fPzsROOQvvqBtuVsqEFnASLnRumaMDvh"
"Key": "<KEY HERE>",
"KeySecret": "<SECRET HERE>"
}
]
},

View file

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29001.49
# Visual Studio 15
VisualStudioVersion = 15.0.27130.2010
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Roadie.Api", "Roadie.Api\Roadie.Api.csproj", "{68C80416-0D72-409D-B727-3FEA7AB7FD2C}"
EndProject
@ -12,14 +12,13 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Scripts", "Scripts", "{1BA7115B-6E37-4546-BBD6-C8B0787A3FE0}"
ProjectSection(SolutionItems) = preProject
roadie.sql = roadie.sql
Upgrade0001.sql = Upgrade0001.sql
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Roadie.Api.Services", "Roadie.Api.Services\Roadie.Api.Services.csproj", "{7B37031E-F2AE-4BE2-9F6F-005CA7A6FDF1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Roadie.Api.Hubs", "Roadie.Api.Hubs\Roadie.Api.Hubs.csproj", "{E740C89E-3363-4577-873B-0871823E252C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Inspector", "Inspector\Inspector.csproj", "{9A0831DC-343A-4E0C-8617-AF62426F3BA8}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Inspector", "Inspector\Inspector.csproj", "{9A0831DC-343A-4E0C-8617-AF62426F3BA8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution

View file

@ -1,2 +0,0 @@
-- Add new table to existing user table if not already added
ALTER TABLE `user` ADD COLUMN IF NOT EXISTS `lastFMSessionKey` varchar(50) NULL;

View file

@ -658,7 +658,6 @@ CREATE TABLE `user` (
`PhoneNumber` varchar(100) DEFAULT NULL,
`PhoneNumberConfirmed` bit(1) DEFAULT NULL,
`removeTrackFromQueAfterPlayed` bit(1) DEFAULT NULL,
`lastFMSessionKey` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `email` (`email`),
UNIQUE KEY `ix_user_username` (`username`),