diff --git a/Tv7Playlist.Data/Migrations/20190124221302_AddedEnabledAvailableNameOverride.Designer.cs b/Tv7Playlist.Data/Migrations/20190124221302_AddedEnabledAvailableNameOverride.Designer.cs new file mode 100644 index 0000000..220e9b1 --- /dev/null +++ b/Tv7Playlist.Data/Migrations/20190124221302_AddedEnabledAvailableNameOverride.Designer.cs @@ -0,0 +1,50 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Tv7Playlist.Data; + +namespace Tv7Playlist.Data.Migrations +{ + [DbContext(typeof(PlaylistContext))] + [Migration("20190124221302_AddedEnabledAvailableNameOverride")] + partial class AddedEnabledAvailableNameOverride + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.2.0-rtm-35687"); + + modelBuilder.Entity("Tv7Playlist.Data.PlaylistEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("IsAvailable"); + + b.Property("IsEnabled"); + + b.Property("Name"); + + b.Property("NameOverride"); + + b.Property("TrackNumber"); + + b.Property("Url"); + + b.HasKey("Id"); + + b.HasIndex("Name"); + + b.HasIndex("TrackNumber") + .IsUnique(); + + b.ToTable("PlaylistEntries"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Tv7Playlist.Data/Migrations/20190124221302_AddedEnabledAvailableNameOverride.cs b/Tv7Playlist.Data/Migrations/20190124221302_AddedEnabledAvailableNameOverride.cs new file mode 100644 index 0000000..f11796b --- /dev/null +++ b/Tv7Playlist.Data/Migrations/20190124221302_AddedEnabledAvailableNameOverride.cs @@ -0,0 +1,70 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Tv7Playlist.Data.Migrations +{ + public partial class AddedEnabledAvailableNameOverride : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropUniqueConstraint( + name: "AK_PlaylistEntries_TrackNumber", + table: "PlaylistEntries"); + + migrationBuilder.AddColumn( + name: "IsAvailable", + table: "PlaylistEntries", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "IsEnabled", + table: "PlaylistEntries", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "NameOverride", + table: "PlaylistEntries", + nullable: true); + + migrationBuilder.CreateIndex( + name: "IX_PlaylistEntries_Name", + table: "PlaylistEntries", + column: "Name"); + + migrationBuilder.CreateIndex( + name: "IX_PlaylistEntries_TrackNumber", + table: "PlaylistEntries", + column: "TrackNumber", + unique: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_PlaylistEntries_Name", + table: "PlaylistEntries"); + + migrationBuilder.DropIndex( + name: "IX_PlaylistEntries_TrackNumber", + table: "PlaylistEntries"); + + migrationBuilder.DropColumn( + name: "IsAvailable", + table: "PlaylistEntries"); + + migrationBuilder.DropColumn( + name: "IsEnabled", + table: "PlaylistEntries"); + + migrationBuilder.DropColumn( + name: "NameOverride", + table: "PlaylistEntries"); + + migrationBuilder.AddUniqueConstraint( + name: "AK_PlaylistEntries_TrackNumber", + table: "PlaylistEntries", + column: "TrackNumber"); + } + } +} diff --git a/Tv7Playlist.Data/Migrations/PlaylistContextModelSnapshot.cs b/Tv7Playlist.Data/Migrations/PlaylistContextModelSnapshot.cs index 996c02a..d434f9a 100644 --- a/Tv7Playlist.Data/Migrations/PlaylistContextModelSnapshot.cs +++ b/Tv7Playlist.Data/Migrations/PlaylistContextModelSnapshot.cs @@ -21,15 +21,24 @@ namespace Tv7Playlist.Data.Migrations b.Property("Id") .ValueGeneratedOnAdd(); + b.Property("IsAvailable"); + + b.Property("IsEnabled"); + b.Property("Name"); + b.Property("NameOverride"); + b.Property("TrackNumber"); b.Property("Url"); b.HasKey("Id"); - b.HasAlternateKey("TrackNumber"); + b.HasIndex("Name"); + + b.HasIndex("TrackNumber") + .IsUnique(); b.ToTable("PlaylistEntries"); }); diff --git a/Tv7Playlist.Data/PlaylistContext.cs b/Tv7Playlist.Data/PlaylistContext.cs index 0921675..416fd27 100644 --- a/Tv7Playlist.Data/PlaylistContext.cs +++ b/Tv7Playlist.Data/PlaylistContext.cs @@ -17,7 +17,8 @@ namespace Tv7Playlist.Data var entityTypeBuilder = modelBuilder.Entity(); entityTypeBuilder.HasKey(e => e.Id); - entityTypeBuilder.HasAlternateKey(e => e.TrackNumber); + entityTypeBuilder.HasIndex(e => e.TrackNumber).IsUnique(); + entityTypeBuilder.HasIndex(e => e.Name); } } } \ No newline at end of file diff --git a/Tv7Playlist.Data/PlaylistEntry.cs b/Tv7Playlist.Data/PlaylistEntry.cs index d1ba666..f6728fd 100644 --- a/Tv7Playlist.Data/PlaylistEntry.cs +++ b/Tv7Playlist.Data/PlaylistEntry.cs @@ -9,7 +9,13 @@ namespace Tv7Playlist.Data public int TrackNumber { get; set; } public string Name { get; set; } + + public string NameOverride { get; set; } public string Url { get; set; } + + public bool IsAvailable { get; set; } + + public bool IsEnabled { get; set; } } } \ No newline at end of file diff --git a/Tv7Playlist/Controllers/HomeController.cs b/Tv7Playlist/Controllers/HomeController.cs index 617e533..8c6e23a 100644 --- a/Tv7Playlist/Controllers/HomeController.cs +++ b/Tv7Playlist/Controllers/HomeController.cs @@ -1,7 +1,6 @@ using System; -using System.Collections.Generic; using System.Diagnostics; -using System.Linq; +using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; @@ -28,14 +27,14 @@ namespace Tv7Playlist.Controllers { var tracks = await _playlistLoader.LoadPlaylistFromUrl(_appConfig.TV7Url); var model = new HomeModel(tracks); - + return View(model); } [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] public IActionResult Error() { - return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); + return View(new ErrorViewModel {RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier}); } } } diff --git a/Tv7Playlist/Controllers/PlayListController.cs b/Tv7Playlist/Controllers/PlayListController.cs index dec146b..72dbfb4 100644 --- a/Tv7Playlist/Controllers/PlayListController.cs +++ b/Tv7Playlist/Controllers/PlayListController.cs @@ -10,7 +10,7 @@ using Tv7Playlist.Core; namespace Tv7Playlist.Controllers { - [Route("api/playlist")] + [Route("api/playlist-old")] [ApiController] public class PlayListController : ControllerBase { diff --git a/Tv7Playlist/Controllers/PlaylistApiController.cs b/Tv7Playlist/Controllers/PlaylistApiController.cs new file mode 100644 index 0000000..e23533a --- /dev/null +++ b/Tv7Playlist/Controllers/PlaylistApiController.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using Tv7Playlist.Core; +using Tv7Playlist.Core.Parsers; +using Tv7Playlist.Data; + +namespace Tv7Playlist.Controllers +{ + [Route("api/playlist")] + [ApiController] + public class PlaylistApiController : Controller + { + private readonly IAppConfig _appConfig; + private readonly ILogger _logger; + private readonly PlaylistContext _playlistContext; + private readonly IPlaylistLoader _playlistLoader; + + public PlaylistApiController(ILogger logger, PlaylistContext playlistContext, + IPlaylistLoader playlistLoader, IAppConfig appConfig) + { + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _playlistContext = playlistContext ?? throw new ArgumentNullException(nameof(playlistContext)); + _playlistLoader = playlistLoader ?? throw new ArgumentNullException(nameof(playlistLoader)); + _appConfig = appConfig ?? throw new ArgumentNullException(nameof(appConfig)); + } + + [HttpGet] + [Route("synchronize")] + public async Task Synchronize() + { + //TODO: Refactor to post method + _logger.LogDebug("Synchronizing playlist from server..."); + + var tracks = await _playlistLoader.LoadPlaylistFromUrl(_appConfig.TV7Url); + await MarkNotAvailableEntriesAsync(tracks); + await AddOrUpdateEntriesAsync(tracks); + _logger.LogDebug("Synchronizing playlist completed saving changes..."); + + await _playlistContext.SaveChangesAsync(); + _logger.LogDebug("Playlist changes saved successfully..."); + + return Ok(); + } + + private async Task AddOrUpdateEntriesAsync(IEnumerable tracks) + { + foreach (var track in tracks) + { + var entry = await _playlistContext.PlaylistEntries.Where(e => e.TrackNumber == track.Id).FirstOrDefaultAsync(); + if (entry == null) + { + _logger.LogInformation($"Adding playlist entry {track.Id} - {track.Name}"); + entry = new PlaylistEntry {Id = Guid.NewGuid(), TrackNumber = track.Id, IsEnabled = true}; + _playlistContext.PlaylistEntries.Add(entry); + } + + entry.IsAvailable = true; + entry.Name = track.Name; + entry.Url = track.Url; + } + } + + private async Task MarkNotAvailableEntriesAsync(IReadOnlyCollection tracks) + { + var unavailableEntries = + await _playlistContext.PlaylistEntries.Where(e => tracks.All(t => t.Id != e.TrackNumber)).ToListAsync(); + foreach (var entry in unavailableEntries) + { + _logger.LogInformation($"Channel {entry.TrackNumber} - {entry.Name} is no longer available."); + entry.IsAvailable = false; + } + } + } +} \ No newline at end of file