integrated and first working
This commit is contained in:
parent
2b8e0a2735
commit
75415b4db4
@ -52,7 +52,6 @@ namespace Selector.CLI
|
|||||||
var directoryContents = Directory.EnumerateFiles(path);
|
var directoryContents = Directory.EnumerateFiles(path);
|
||||||
var endSongs = directoryContents.Where(f => f.Contains("endsong_")).ToArray();
|
var endSongs = directoryContents.Where(f => f.Contains("endsong_")).ToArray();
|
||||||
|
|
||||||
|
|
||||||
foreach(var file in endSongs)
|
foreach(var file in endSongs)
|
||||||
{
|
{
|
||||||
streams.Add(File.OpenRead(file));
|
streams.Add(File.OpenRead(file));
|
||||||
|
@ -118,8 +118,12 @@ namespace Selector.CLI.Extensions
|
|||||||
options.UseNpgsql(config.DatabaseOptions.ConnectionString)
|
options.UseNpgsql(config.DatabaseOptions.ConnectionString)
|
||||||
);
|
);
|
||||||
|
|
||||||
services.AddTransient<IScrobbleRepository, ScrobbleRepository>();
|
services.AddTransient<IScrobbleRepository, ScrobbleRepository>()
|
||||||
services.AddTransient<ISpotifyListenRepository, SpotifyListenRepository>();
|
.AddTransient<ISpotifyListenRepository, SpotifyListenRepository>();
|
||||||
|
|
||||||
|
//services.AddTransient<IListenRepository, MetaListenRepository>();
|
||||||
|
services.AddTransient<IListenRepository, SpotifyListenRepository>();
|
||||||
|
|
||||||
services.AddTransient<IScrobbleMappingRepository, ScrobbleMappingRepository>();
|
services.AddTransient<IScrobbleMappingRepository, ScrobbleMappingRepository>();
|
||||||
|
|
||||||
services.AddHostedService<MigratorService>();
|
services.AddHostedService<MigratorService>();
|
||||||
|
@ -112,7 +112,7 @@ namespace Selector
|
|||||||
logger.LogDebug("Identifying difference sets");
|
logger.LogDebug("Identifying difference sets");
|
||||||
var time = Stopwatch.StartNew();
|
var time = Stopwatch.StartNew();
|
||||||
|
|
||||||
(var toAdd, var toRemove) = ScrobbleMatcher.IdentifyDiffs(currentScrobbles, nativeScrobbles);
|
(var toAdd, var toRemove) = ListenMatcher.IdentifyDiffs(currentScrobbles, nativeScrobbles);
|
||||||
|
|
||||||
time.Stop();
|
time.Stop();
|
||||||
logger.LogTrace("Finished diffing: {:n}ms", time.ElapsedMilliseconds);
|
logger.LogTrace("Finished diffing: {:n}ms", time.ElapsedMilliseconds);
|
||||||
|
@ -50,7 +50,7 @@ public class HistoryPersister
|
|||||||
var parsed = await JsonSerializer.DeserializeAsync(singleInput, Json.EndSongArray);
|
var parsed = await JsonSerializer.DeserializeAsync(singleInput, Json.EndSongArray);
|
||||||
songs = songs.Concat(parsed);
|
songs = songs.Concat(parsed);
|
||||||
|
|
||||||
Logger?.LogDebug("Parsed {} items for {}", parsed.Length, Config.Username);
|
Logger?.LogDebug("Parsed {.2f} items for {}", parsed.Length, Config.Username);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Process(songs);
|
await Process(songs);
|
||||||
@ -67,7 +67,13 @@ public class HistoryPersister
|
|||||||
|
|
||||||
var counter = 0;
|
var counter = 0;
|
||||||
|
|
||||||
foreach(var item in input)
|
var filtered = input.Where(x => x.ms_played > 20000)
|
||||||
|
.DistinctBy(x => (x.offline_timestamp, x.ts, x.spotify_track_uri))
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
Logger.LogInformation("{.2f} items after filtering", filtered.Length);
|
||||||
|
|
||||||
|
foreach (var item in filtered)
|
||||||
{
|
{
|
||||||
if(!string.IsNullOrWhiteSpace(item.master_metadata_track_name))
|
if(!string.IsNullOrWhiteSpace(item.master_metadata_track_name))
|
||||||
{
|
{
|
||||||
|
@ -87,7 +87,12 @@ namespace Selector.Model
|
|||||||
.Property(s => s.LastfmArtistName)
|
.Property(s => s.LastfmArtistName)
|
||||||
.UseCollation("case_insensitive");
|
.UseCollation("case_insensitive");
|
||||||
|
|
||||||
modelBuilder.Entity<SpotifyListen>().HasKey(s => s.Timestamp);
|
modelBuilder.Entity<ArtistLastfmSpotifyMapping>().HasKey(s => s.SpotifyUri);
|
||||||
|
modelBuilder.Entity<ArtistLastfmSpotifyMapping>()
|
||||||
|
.Property(s => s.LastfmArtistName)
|
||||||
|
.UseCollation("case_insensitive");
|
||||||
|
|
||||||
|
modelBuilder.Entity<SpotifyListen>().HasKey(s => s.Id);
|
||||||
modelBuilder.Entity<SpotifyListen>()
|
modelBuilder.Entity<SpotifyListen>()
|
||||||
.Property(s => s.TrackName)
|
.Property(s => s.TrackName)
|
||||||
.UseCollation("case_insensitive");
|
.UseCollation("case_insensitive");
|
||||||
|
12
Selector.Model/Listen/IListenRepository.cs
Normal file
12
Selector.Model/Listen/IListenRepository.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Selector.Model
|
||||||
|
{
|
||||||
|
public interface IListenRepository
|
||||||
|
{
|
||||||
|
IEnumerable<IListen> GetAll(string include = null, string userId = null, string username = null, string trackName = null, string albumName = null, string artistName = null, DateTime? from = null, DateTime? to = null);
|
||||||
|
int Count(string userId = null, string username = null, string trackName = null, string albumName = null, string artistName = null, DateTime? from = null, DateTime? to = null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,18 +4,18 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace Selector.Model
|
namespace Selector.Model
|
||||||
{
|
{
|
||||||
public interface ISpotifyListenRepository
|
public interface ISpotifyListenRepository: IListenRepository
|
||||||
{
|
{
|
||||||
void Add(SpotifyListen item);
|
void Add(SpotifyListen item);
|
||||||
void AddRange(IEnumerable<SpotifyListen> item);
|
void AddRange(IEnumerable<SpotifyListen> item);
|
||||||
IEnumerable<SpotifyListen> GetAll(string include = null, string userId = null, string username = null, string trackName = null, string albumName = null, string artistName = null, DateTime? from = null, DateTime? to = null);
|
//IEnumerable<SpotifyListen> GetAll(string include = null, string userId = null, string username = null, string trackName = null, string albumName = null, string artistName = null, DateTime? from = null, DateTime? to = null);
|
||||||
SpotifyListen Find(DateTime key, string include = null);
|
SpotifyListen Find(DateTime key, string include = null);
|
||||||
void Remove(DateTime key);
|
void Remove(DateTime key);
|
||||||
public void Remove(SpotifyListen scrobble);
|
public void Remove(SpotifyListen scrobble);
|
||||||
public void RemoveRange(IEnumerable<SpotifyListen> scrobbles);
|
public void RemoveRange(IEnumerable<SpotifyListen> scrobbles);
|
||||||
void Update(SpotifyListen item);
|
void Update(SpotifyListen item);
|
||||||
Task<int> Save();
|
Task<int> Save();
|
||||||
int Count(string include = null, string userId = null, string username = null, string trackName = null, string albumName = null, string artistName = null, DateTime? from = null, DateTime? to = null);
|
//int Count(string userId = null, string username = null, string trackName = null, string albumName = null, string artistName = null, DateTime? from = null, DateTime? to = null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
10
Selector.Model/Listen/IUserListen.cs
Normal file
10
Selector.Model/Listen/IUserListen.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Selector.Model;
|
||||||
|
|
||||||
|
public interface IUserListen: IListen
|
||||||
|
{
|
||||||
|
string UserId { get; set; }
|
||||||
|
ApplicationUser User { get; set; }
|
||||||
|
}
|
||||||
|
|
75
Selector.Model/Listen/MetaListenRepository.cs
Normal file
75
Selector.Model/Listen/MetaListenRepository.cs
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Selector.Model;
|
||||||
|
|
||||||
|
public enum PreferenceMode
|
||||||
|
{
|
||||||
|
Greedy, LastFm, Spotify
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MetaListenRepository: IListenRepository
|
||||||
|
{
|
||||||
|
private readonly IScrobbleRepository scrobbleRepository;
|
||||||
|
private readonly ISpotifyListenRepository spotifyRepository;
|
||||||
|
|
||||||
|
public MetaListenRepository(IScrobbleRepository scrobbleRepository, ISpotifyListenRepository listenRepository)
|
||||||
|
{
|
||||||
|
this.scrobbleRepository = scrobbleRepository;
|
||||||
|
spotifyRepository = listenRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Count(
|
||||||
|
string userId = null,
|
||||||
|
string username = null,
|
||||||
|
string trackName = null,
|
||||||
|
string albumName = null,
|
||||||
|
string artistName = null,
|
||||||
|
DateTime? from = null,
|
||||||
|
DateTime? to = null)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<IListen> GetAll(
|
||||||
|
string includes = null,
|
||||||
|
string userId = null,
|
||||||
|
string username = null,
|
||||||
|
string trackName = null,
|
||||||
|
string albumName = null,
|
||||||
|
string artistName = null,
|
||||||
|
DateTime? from = null,
|
||||||
|
DateTime? to = null)
|
||||||
|
{
|
||||||
|
var scrobbles = scrobbleRepository.GetAll(
|
||||||
|
include: includes,
|
||||||
|
userId: userId,
|
||||||
|
username: username,
|
||||||
|
trackName: trackName,
|
||||||
|
albumName: albumName,
|
||||||
|
artistName: artistName,
|
||||||
|
from: from,
|
||||||
|
to: to)
|
||||||
|
.OrderBy(x => x.Timestamp)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
var spotListens = spotifyRepository.GetAll(
|
||||||
|
include: includes,
|
||||||
|
userId: userId,
|
||||||
|
username: username,
|
||||||
|
trackName: trackName,
|
||||||
|
albumName: albumName,
|
||||||
|
artistName: artistName,
|
||||||
|
from: from,
|
||||||
|
to: to)
|
||||||
|
.OrderBy(x => x.Timestamp)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
var scrobbleIter = scrobbles.GetEnumerator();
|
||||||
|
var spotIter = spotListens.GetEnumerator();
|
||||||
|
|
||||||
|
return scrobbles;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,8 +2,10 @@
|
|||||||
|
|
||||||
namespace Selector.Model;
|
namespace Selector.Model;
|
||||||
|
|
||||||
public class SpotifyListen: Listen
|
public class SpotifyListen: Listen, IUserListen
|
||||||
{
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
public int? PlayedDuration { get; set; }
|
public int? PlayedDuration { get; set; }
|
||||||
|
|
||||||
public string TrackUri { get; set; }
|
public string TrackUri { get; set; }
|
||||||
|
@ -95,7 +95,7 @@ namespace Selector.Model
|
|||||||
return listens;
|
return listens;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<SpotifyListen> GetAll(string include = null, string userId = null, string username = null, string trackName = null, string albumName = null, string artistName = null, DateTime? from = null, DateTime? to = null)
|
public IEnumerable<IListen> GetAll(string include = null, string userId = null, string username = null, string trackName = null, string albumName = null, string artistName = null, DateTime? from = null, DateTime? to = null)
|
||||||
=> GetAllQueryable(include: include, userId: userId, username: username, trackName: trackName, albumName: albumName, artistName: artistName, from: from, to: to).AsEnumerable();
|
=> GetAllQueryable(include: include, userId: userId, username: username, trackName: trackName, albumName: albumName, artistName: artistName, from: from, to: to).AsEnumerable();
|
||||||
|
|
||||||
public void Remove(DateTime key)
|
public void Remove(DateTime key)
|
||||||
@ -123,7 +123,7 @@ namespace Selector.Model
|
|||||||
return db.SaveChangesAsync();
|
return db.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Count(string include = null, string userId = null, string username = null, string trackName = null, string albumName = null, string artistName = null, DateTime? from = null, DateTime? to = null)
|
public int Count(string userId = null, string username = null, string trackName = null, string albumName = null, string artistName = null, DateTime? from = null, DateTime? to = null)
|
||||||
=> GetAllQueryable(include: include, userId: userId, username: username, trackName: trackName, albumName: albumName, artistName: artistName, from: from, to: to).Count();
|
=> GetAllQueryable(userId: userId, username: username, trackName: trackName, albumName: albumName, artistName: artistName, from: from, to: to).Count();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
491
Selector.Model/Migrations/20221007214100_SpotifyHistory.Designer.cs
generated
Normal file
491
Selector.Model/Migrations/20221007214100_SpotifyHistory.Designer.cs
generated
Normal file
@ -0,0 +1,491 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
using Selector.Model;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Selector.Model.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(ApplicationDbContext))]
|
||||||
|
[Migration("20221007214100_SpotifyHistory")]
|
||||||
|
partial class SpotifyHistory
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("Npgsql:CollationDefinition:case_insensitive", "en-u-ks-primary,en-u-ks-primary,icu,False")
|
||||||
|
.HasAnnotation("ProductVersion", "6.0.9")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("ConcurrencyStamp")
|
||||||
|
.IsConcurrencyToken()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("character varying(256)");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedName")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("character varying(256)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedName")
|
||||||
|
.IsUnique()
|
||||||
|
.HasDatabaseName("RoleNameIndex");
|
||||||
|
|
||||||
|
b.ToTable("AspNetRoles", (string)null);
|
||||||
|
|
||||||
|
b.HasData(
|
||||||
|
new
|
||||||
|
{
|
||||||
|
Id = "00c64c0a-3387-4933-9575-83443fa9092b",
|
||||||
|
ConcurrencyStamp = "4b4a37c7-cc65-485a-ac0e-d88ef6dede78",
|
||||||
|
Name = "Admin",
|
||||||
|
NormalizedName = "ADMIN"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("ClaimType")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("ClaimValue")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("RoleId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("RoleId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetRoleClaims", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("ClaimType")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("ClaimValue")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserClaims", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("LoginProvider")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("ProviderKey")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("ProviderDisplayName")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("LoginProvider", "ProviderKey");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserLogins", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("RoleId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("UserId", "RoleId");
|
||||||
|
|
||||||
|
b.HasIndex("RoleId");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserRoles", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("LoginProvider")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Value")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("UserId", "LoginProvider", "Name");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUserTokens", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Selector.Model.AlbumLastfmSpotifyMapping", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("SpotifyUri")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("LastfmAlbumName")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.UseCollation("case_insensitive");
|
||||||
|
|
||||||
|
b.Property<string>("LastfmArtistName")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.UseCollation("case_insensitive");
|
||||||
|
|
||||||
|
b.HasKey("SpotifyUri");
|
||||||
|
|
||||||
|
b.ToTable("AlbumMapping");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Selector.Model.ApplicationUser", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("AccessFailedCount")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<string>("ConcurrencyStamp")
|
||||||
|
.IsConcurrencyToken()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("character varying(256)");
|
||||||
|
|
||||||
|
b.Property<bool>("EmailConfirmed")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<string>("LastFmUsername")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.UseCollation("case_insensitive");
|
||||||
|
|
||||||
|
b.Property<bool>("LockoutEnabled")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset?>("LockoutEnd")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedEmail")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("character varying(256)");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedUserName")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("character varying(256)");
|
||||||
|
|
||||||
|
b.Property<string>("PasswordHash")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("PhoneNumber")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<bool>("PhoneNumberConfirmed")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<bool>("SaveScrobbles")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<string>("SecurityStamp")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("SpotifyAccessToken")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<bool>("SpotifyIsLinked")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<DateTime>("SpotifyLastRefresh")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("SpotifyRefreshToken")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("SpotifyTokenExpiry")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<bool>("TwoFactorEnabled")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<string>("UserName")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("character varying(256)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedEmail")
|
||||||
|
.HasDatabaseName("EmailIndex");
|
||||||
|
|
||||||
|
b.HasIndex("NormalizedUserName")
|
||||||
|
.IsUnique()
|
||||||
|
.HasDatabaseName("UserNameIndex");
|
||||||
|
|
||||||
|
b.ToTable("AspNetUsers", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Selector.Model.ArtistLastfmSpotifyMapping", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("SpotifyUri")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("LastfmArtistName")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.UseCollation("case_insensitive");
|
||||||
|
|
||||||
|
b.HasKey("SpotifyUri");
|
||||||
|
|
||||||
|
b.ToTable("ArtistMapping");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Selector.Model.SpotifyListen", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("AlbumName")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.UseCollation("case_insensitive");
|
||||||
|
|
||||||
|
b.Property<string>("ArtistName")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.UseCollation("case_insensitive");
|
||||||
|
|
||||||
|
b.Property<int?>("PlayedDuration")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Timestamp")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("TrackName")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.UseCollation("case_insensitive");
|
||||||
|
|
||||||
|
b.Property<string>("TrackUri")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("SpotifyListen");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Selector.Model.TrackLastfmSpotifyMapping", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("SpotifyUri")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("LastfmArtistName")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.UseCollation("case_insensitive");
|
||||||
|
|
||||||
|
b.Property<string>("LastfmTrackName")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.UseCollation("case_insensitive");
|
||||||
|
|
||||||
|
b.HasKey("SpotifyUri");
|
||||||
|
|
||||||
|
b.ToTable("TrackMapping");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Selector.Model.UserScrobble", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("AlbumArtistName")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("AlbumName")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.UseCollation("case_insensitive");
|
||||||
|
|
||||||
|
b.Property<string>("ArtistName")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.UseCollation("case_insensitive");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Timestamp")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("TrackName")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.UseCollation("case_insensitive");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("Scrobble");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Selector.Model.Watcher", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("Watcher");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("RoleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Selector.Model.ApplicationUser", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Selector.Model.ApplicationUser", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("RoleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Selector.Model.ApplicationUser", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Selector.Model.ApplicationUser", null)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Selector.Model.SpotifyListen", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Selector.Model.ApplicationUser", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId");
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Selector.Model.UserScrobble", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Selector.Model.ApplicationUser", "User")
|
||||||
|
.WithMany("Scrobbles")
|
||||||
|
.HasForeignKey("UserId");
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Selector.Model.Watcher", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Selector.Model.ApplicationUser", "User")
|
||||||
|
.WithMany("Watchers")
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Selector.Model.ApplicationUser", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Scrobbles");
|
||||||
|
|
||||||
|
b.Navigation("Watchers");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
63
Selector.Model/Migrations/20221007214100_SpotifyHistory.cs
Normal file
63
Selector.Model/Migrations/20221007214100_SpotifyHistory.cs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Selector.Model.Migrations
|
||||||
|
{
|
||||||
|
public partial class SpotifyHistory : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "SpotifyListen",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
PlayedDuration = table.Column<int>(type: "integer", nullable: true),
|
||||||
|
TrackUri = table.Column<string>(type: "text", nullable: true),
|
||||||
|
UserId = table.Column<string>(type: "text", nullable: true),
|
||||||
|
TrackName = table.Column<string>(type: "text", nullable: true, collation: "case_insensitive"),
|
||||||
|
AlbumName = table.Column<string>(type: "text", nullable: true, collation: "case_insensitive"),
|
||||||
|
ArtistName = table.Column<string>(type: "text", nullable: true, collation: "case_insensitive"),
|
||||||
|
Timestamp = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_SpotifyListen", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_SpotifyListen_AspNetUsers_UserId",
|
||||||
|
column: x => x.UserId,
|
||||||
|
principalTable: "AspNetUsers",
|
||||||
|
principalColumn: "Id");
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.UpdateData(
|
||||||
|
table: "AspNetRoles",
|
||||||
|
keyColumn: "Id",
|
||||||
|
keyValue: "00c64c0a-3387-4933-9575-83443fa9092b",
|
||||||
|
column: "ConcurrencyStamp",
|
||||||
|
value: "4b4a37c7-cc65-485a-ac0e-d88ef6dede78");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_SpotifyListen_UserId",
|
||||||
|
table: "SpotifyListen",
|
||||||
|
column: "UserId");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "SpotifyListen");
|
||||||
|
|
||||||
|
migrationBuilder.UpdateData(
|
||||||
|
table: "AspNetRoles",
|
||||||
|
keyColumn: "Id",
|
||||||
|
keyValue: "00c64c0a-3387-4933-9575-83443fa9092b",
|
||||||
|
column: "ConcurrencyStamp",
|
||||||
|
value: "ec454f56-2b26-4bd8-be8e-a7fd34981ac2");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -18,7 +18,7 @@ namespace Selector.Model.Migrations
|
|||||||
#pragma warning disable 612, 618
|
#pragma warning disable 612, 618
|
||||||
modelBuilder
|
modelBuilder
|
||||||
.HasAnnotation("Npgsql:CollationDefinition:case_insensitive", "en-u-ks-primary,en-u-ks-primary,icu,False")
|
.HasAnnotation("Npgsql:CollationDefinition:case_insensitive", "en-u-ks-primary,en-u-ks-primary,icu,False")
|
||||||
.HasAnnotation("ProductVersion", "6.0.2")
|
.HasAnnotation("ProductVersion", "6.0.9")
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
@ -52,7 +52,7 @@ namespace Selector.Model.Migrations
|
|||||||
new
|
new
|
||||||
{
|
{
|
||||||
Id = "00c64c0a-3387-4933-9575-83443fa9092b",
|
Id = "00c64c0a-3387-4933-9575-83443fa9092b",
|
||||||
ConcurrencyStamp = "ec454f56-2b26-4bd8-be8e-a7fd34981ac2",
|
ConcurrencyStamp = "4b4a37c7-cc65-485a-ac0e-d88ef6dede78",
|
||||||
Name = "Admin",
|
Name = "Admin",
|
||||||
NormalizedName = "ADMIN"
|
NormalizedName = "ADMIN"
|
||||||
});
|
});
|
||||||
@ -282,6 +282,45 @@ namespace Selector.Model.Migrations
|
|||||||
b.ToTable("ArtistMapping");
|
b.ToTable("ArtistMapping");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Selector.Model.SpotifyListen", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("AlbumName")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.UseCollation("case_insensitive");
|
||||||
|
|
||||||
|
b.Property<string>("ArtistName")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.UseCollation("case_insensitive");
|
||||||
|
|
||||||
|
b.Property<int?>("PlayedDuration")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Timestamp")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("TrackName")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.UseCollation("case_insensitive");
|
||||||
|
|
||||||
|
b.Property<string>("TrackUri")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("SpotifyListen");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Selector.Model.TrackLastfmSpotifyMapping", b =>
|
modelBuilder.Entity("Selector.Model.TrackLastfmSpotifyMapping", b =>
|
||||||
{
|
{
|
||||||
b.Property<string>("SpotifyUri")
|
b.Property<string>("SpotifyUri")
|
||||||
@ -409,6 +448,15 @@ namespace Selector.Model.Migrations
|
|||||||
.IsRequired();
|
.IsRequired();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Selector.Model.SpotifyListen", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Selector.Model.ApplicationUser", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId");
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Selector.Model.UserScrobble", b =>
|
modelBuilder.Entity("Selector.Model.UserScrobble", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("Selector.Model.ApplicationUser", "User")
|
b.HasOne("Selector.Model.ApplicationUser", "User")
|
||||||
|
@ -9,12 +9,12 @@ namespace Selector.Cache
|
|||||||
{
|
{
|
||||||
public class DBPlayCountPuller
|
public class DBPlayCountPuller
|
||||||
{
|
{
|
||||||
protected readonly IScrobbleRepository ScrobbleRepository;
|
protected readonly IListenRepository ScrobbleRepository;
|
||||||
private readonly IOptions<NowPlayingOptions> nowOptions;
|
private readonly IOptions<NowPlayingOptions> nowOptions;
|
||||||
|
|
||||||
public DBPlayCountPuller(
|
public DBPlayCountPuller(
|
||||||
IOptions<NowPlayingOptions> options,
|
IOptions<NowPlayingOptions> options,
|
||||||
IScrobbleRepository scrobbleRepository
|
IListenRepository scrobbleRepository
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
ScrobbleRepository = scrobbleRepository;
|
ScrobbleRepository = scrobbleRepository;
|
||||||
|
@ -6,17 +6,17 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace Selector.Model
|
namespace Selector.Model
|
||||||
{
|
{
|
||||||
public interface IScrobbleRepository
|
public interface IScrobbleRepository: IListenRepository
|
||||||
{
|
{
|
||||||
void Add(UserScrobble item);
|
void Add(UserScrobble item);
|
||||||
void AddRange(IEnumerable<UserScrobble> item);
|
void AddRange(IEnumerable<UserScrobble> item);
|
||||||
IEnumerable<UserScrobble> GetAll(string include = null, string userId = null, string username = null, string trackName = null, string albumName = null, string artistName = null, DateTime? from = null, DateTime? to = null);
|
//IEnumerable<UserScrobble> GetAll(string include = null, string userId = null, string username = null, string trackName = null, string albumName = null, string artistName = null, DateTime? from = null, DateTime? to = null);
|
||||||
UserScrobble Find(int key, string include = null);
|
UserScrobble Find(int key, string include = null);
|
||||||
void Remove(int key);
|
void Remove(int key);
|
||||||
public void Remove(UserScrobble scrobble);
|
public void Remove(UserScrobble scrobble);
|
||||||
public void RemoveRange(IEnumerable<UserScrobble> scrobbles);
|
public void RemoveRange(IEnumerable<UserScrobble> scrobbles);
|
||||||
void Update(UserScrobble item);
|
void Update(UserScrobble item);
|
||||||
Task<int> Save();
|
Task<int> Save();
|
||||||
int Count(string include = null, string userId = null, string username = null, string trackName = null, string albumName = null, string artistName = null, DateTime? from = null, DateTime? to = null);
|
//int Count(string userId = null, string username = null, string trackName = null, string albumName = null, string artistName = null, DateTime? from = null, DateTime? to = null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,7 +95,7 @@ namespace Selector.Model
|
|||||||
return scrobbles;
|
return scrobbles;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<UserScrobble> GetAll(string include = null, string userId = null, string username = null, string trackName = null, string albumName = null, string artistName = null, DateTime? from = null, DateTime? to = null)
|
public IEnumerable<IListen> GetAll(string include = null, string userId = null, string username = null, string trackName = null, string albumName = null, string artistName = null, DateTime? from = null, DateTime? to = null)
|
||||||
=> GetAllQueryable(include: include, userId: userId, username: username, trackName: trackName, albumName: albumName, artistName: artistName, from: from, to: to).AsEnumerable();
|
=> GetAllQueryable(include: include, userId: userId, username: username, trackName: trackName, albumName: albumName, artistName: artistName, from: from, to: to).AsEnumerable();
|
||||||
|
|
||||||
public void Remove(int key)
|
public void Remove(int key)
|
||||||
@ -123,7 +123,7 @@ namespace Selector.Model
|
|||||||
return db.SaveChangesAsync();
|
return db.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Count(string include = null, string userId = null, string username = null, string trackName = null, string albumName = null, string artistName = null, DateTime? from = null, DateTime? to = null)
|
public int Count(string userId = null, string username = null, string trackName = null, string albumName = null, string artistName = null, DateTime? from = null, DateTime? to = null)
|
||||||
=> GetAllQueryable(include: include, userId: userId, username: username, trackName: trackName, albumName: albumName, artistName: artistName, from: from, to: to).Count();
|
=> GetAllQueryable(userId: userId, username: username, trackName: trackName, albumName: albumName, artistName: artistName, from: from, to: to).Count();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace Selector.Model
|
namespace Selector.Model
|
||||||
{
|
{
|
||||||
public class UserScrobble: Scrobble
|
public class UserScrobble: Scrobble, IUserListen
|
||||||
{
|
{
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public string UserId { get; set; }
|
public string UserId { get; set; }
|
||||||
|
@ -64,7 +64,11 @@ namespace Selector.Web
|
|||||||
options.UseNpgsql(Configuration.GetConnectionString("Default"))
|
options.UseNpgsql(Configuration.GetConnectionString("Default"))
|
||||||
);
|
);
|
||||||
services.AddDBPlayCountPuller();
|
services.AddDBPlayCountPuller();
|
||||||
services.AddTransient<IScrobbleRepository, ScrobbleRepository>();
|
services.AddTransient<IScrobbleRepository, ScrobbleRepository>()
|
||||||
|
.AddTransient<ISpotifyListenRepository, SpotifyListenRepository>();
|
||||||
|
|
||||||
|
//services.AddTransient<IListenRepository, MetaListenRepository>();
|
||||||
|
services.AddTransient<IListenRepository, SpotifyListenRepository>();
|
||||||
|
|
||||||
services.AddIdentity<ApplicationUser, IdentityRole>()
|
services.AddIdentity<ApplicationUser, IdentityRole>()
|
||||||
.AddEntityFrameworkStores<ApplicationDbContext>()
|
.AddEntityFrameworkStores<ApplicationDbContext>()
|
||||||
|
@ -6,9 +6,9 @@ namespace Selector
|
|||||||
{
|
{
|
||||||
public static class PlayDensity
|
public static class PlayDensity
|
||||||
{
|
{
|
||||||
public static decimal Density(this IEnumerable<Scrobble> scrobbles, TimeSpan window) => scrobbles.Density(DateTime.UtcNow - window, DateTime.UtcNow);
|
public static decimal Density(this IEnumerable<IListen> scrobbles, TimeSpan window) => scrobbles.Density(DateTime.UtcNow - window, DateTime.UtcNow);
|
||||||
|
|
||||||
public static decimal Density(this IEnumerable<Scrobble> scrobbles, DateTime from, DateTime to)
|
public static decimal Density(this IEnumerable<IListen> scrobbles, DateTime from, DateTime to)
|
||||||
{
|
{
|
||||||
var filteredScrobbles = scrobbles.Where(s => s.Timestamp > from && s.Timestamp < to);
|
var filteredScrobbles = scrobbles.Where(s => s.Timestamp > from && s.Timestamp < to);
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ namespace Selector
|
|||||||
return filteredScrobbles.Count() / dayDelta;
|
return filteredScrobbles.Count() / dayDelta;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static decimal Density(this IEnumerable<Scrobble> scrobbles)
|
public static decimal Density(this IEnumerable<IListen> scrobbles)
|
||||||
{
|
{
|
||||||
var minDate = scrobbles.Select(s => s.Timestamp).Min();
|
var minDate = scrobbles.Select(s => s.Timestamp).Min();
|
||||||
var maxDate = scrobbles.Select(s => s.Timestamp).Max();
|
var maxDate = scrobbles.Select(s => s.Timestamp).Max();
|
||||||
|
@ -6,22 +6,22 @@ using System.Linq;
|
|||||||
|
|
||||||
namespace Selector
|
namespace Selector
|
||||||
{
|
{
|
||||||
public static class ScrobbleMatcher
|
public static class ListenMatcher
|
||||||
{
|
{
|
||||||
public static bool MatchTime(Scrobble nativeScrobble, LastTrack serviceScrobble)
|
public static bool MatchTime(IListen nativeScrobble, LastTrack serviceScrobble)
|
||||||
=> serviceScrobble.TimePlayed.Equals(nativeScrobble);
|
=> serviceScrobble.TimePlayed.Equals(nativeScrobble);
|
||||||
|
|
||||||
public static bool MatchTime(Scrobble nativeScrobble, Scrobble serviceScrobble)
|
public static bool MatchTime(IListen nativeScrobble, IListen serviceScrobble)
|
||||||
=> serviceScrobble.Timestamp.Equals(nativeScrobble.Timestamp);
|
=> serviceScrobble.Timestamp.Equals(nativeScrobble.Timestamp);
|
||||||
|
|
||||||
public static (IEnumerable<Scrobble>, IEnumerable<Scrobble>) IdentifyDiffs(IEnumerable<Scrobble> existing, IEnumerable<Scrobble> toApply, bool matchContents = true)
|
public static (IEnumerable<IListen>, IEnumerable<IListen>) IdentifyDiffs(IEnumerable<IListen> existing, IEnumerable<IListen> toApply, bool matchContents = true)
|
||||||
{
|
{
|
||||||
existing = existing.OrderBy(s => s.Timestamp);
|
existing = existing.OrderBy(s => s.Timestamp);
|
||||||
toApply = toApply.OrderBy(s => s.Timestamp);
|
toApply = toApply.OrderBy(s => s.Timestamp);
|
||||||
var toApplyIter = toApply.GetEnumerator();
|
var toApplyIter = toApply.GetEnumerator();
|
||||||
|
|
||||||
var toAdd = new List<Scrobble>();
|
var toAdd = new List<IListen>();
|
||||||
var toRemove = new List<Scrobble>();
|
var toRemove = new List<IListen>();
|
||||||
|
|
||||||
var toApplyOverrun = false;
|
var toApplyOverrun = false;
|
||||||
|
|
||||||
@ -79,7 +79,7 @@ namespace Selector
|
|||||||
return (toAdd, toRemove);
|
return (toAdd, toRemove);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void MatchData(Scrobble currentExisting, Scrobble toApply)
|
public static void MatchData(IListen currentExisting, IListen toApply)
|
||||||
{
|
{
|
||||||
if (!currentExisting.TrackName.Equals(toApply.TrackName, StringComparison.InvariantCultureIgnoreCase))
|
if (!currentExisting.TrackName.Equals(toApply.TrackName, StringComparison.InvariantCultureIgnoreCase))
|
||||||
{
|
{
|
||||||
@ -97,19 +97,19 @@ namespace Selector
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static (IEnumerable<Scrobble>, IEnumerable<Scrobble>) IdentifyDiffsContains(IEnumerable<Scrobble> existing, IEnumerable<Scrobble> toApply)
|
public static (IEnumerable<IListen>, IEnumerable<IListen>) IdentifyDiffsContains(IEnumerable<IListen> existing, IEnumerable<IListen> toApply)
|
||||||
{
|
{
|
||||||
var toAdd = toApply.Where(s => !existing.Contains(s, new ScrobbleComp()));
|
var toAdd = toApply.Where(s => !existing.Contains(s, new ListenComp()));
|
||||||
var toRemove = existing.Where(s => !toApply.Contains(s, new ScrobbleComp()));
|
var toRemove = existing.Where(s => !toApply.Contains(s, new ListenComp()));
|
||||||
|
|
||||||
return (toAdd, toRemove);
|
return (toAdd, toRemove);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ScrobbleComp : IEqualityComparer<Scrobble>
|
public class ListenComp : IEqualityComparer<IListen>
|
||||||
{
|
{
|
||||||
public bool Equals(Scrobble x, Scrobble y) => x.Timestamp == y.Timestamp;
|
public bool Equals(IListen x, IListen y) => x.Timestamp == y.Timestamp;
|
||||||
|
|
||||||
public int GetHashCode([DisallowNull] Scrobble obj) => obj.Timestamp.GetHashCode();
|
public int GetHashCode([DisallowNull] IListen obj) => obj.Timestamp.GetHashCode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user