From a3a3c3a7805877975cd285eedc14c76409ee5014 Mon Sep 17 00:00:00 2001 From: hak8or Date: Mon, 19 Feb 2018 23:57:14 -0500 Subject: [PATCH] Huge cleanup and rework pass, postgres now usable too --- YTManager/Controllers/Admin.cs | 45 ++++--- YTManager/Controllers/Channels.cs | 34 +++-- YTManager/Controllers/Videos.cs | 6 +- YTManager/MediaDB.cs | 5 +- ...180220032847_initiailmigration.Designer.cs | 100 ++++++++++++++ .../20180220032847_initiailmigration.cs | 85 ++++++++++++ YTManager/Migrations/MediaDBModelSnapshot.cs | 99 ++++++++++++++ YTManager/Models/Channel.cs | 4 +- YTManager/Models/Tag.cs | 8 +- YTManager/Models/Video.cs | 8 +- YTManager/Properties/launchSettings.json | 1 + YTManager/Startup.cs | 16 ++- YTManager/Tasks/FetchVideos.cs | 125 ++++++++++++------ YTManager/YTManager.csproj | 18 ++- YTManager/wwwroot/admin.js | 20 +-- YTManager/wwwroot/index.css | 4 +- YTManager/wwwroot/index.html | 2 +- YTManager/wwwroot/index.js | 2 +- 18 files changed, 472 insertions(+), 110 deletions(-) create mode 100644 YTManager/Migrations/20180220032847_initiailmigration.Designer.cs create mode 100644 YTManager/Migrations/20180220032847_initiailmigration.cs create mode 100644 YTManager/Migrations/MediaDBModelSnapshot.cs diff --git a/YTManager/Controllers/Admin.cs b/YTManager/Controllers/Admin.cs index 3c7faa5..48b9829 100644 --- a/YTManager/Controllers/Admin.cs +++ b/YTManager/Controllers/Admin.cs @@ -13,35 +13,40 @@ namespace YTManager.Controllers { [Produces("application/json")] [Route("api/Admin")] public class AdminController : Controller { - // POST api/Admin/refreshytvids - // Force a general youtube channel update. - [HttpPost("job_update")] - public void Post_forcejobupdate() { - Hangfire.RecurringJob.Trigger(Startup.periodicupdatejobID); + // ID for mass update job, used to tell if the job is running or not. + public static string Mass_Updater_ID { get; } = "2013066213"; + + // POST api/Admin/Trigger_Mass_Update + // Trigger a mass channel update. + [HttpPost("Trigger_Mass_Update")] + public IActionResult Trigger_Mass_Update() { + Hangfire.RecurringJob.Trigger(Mass_Updater_ID); + return Ok(); } - // POST api/Admin/job_periodicupdate/YTChannelID - // Force a YT Channel update. - [HttpPost("job_update/{id}")] - public void Post_forcejobupdateID([FromRoute] string id) { - Hangfire.BackgroundJob.Enqueue(() => YTManager.Tasks.FetchVideos.run(id)); + // POST api/Admin/Update/YTChannelID + // Update the videos for a specific channel. + [HttpPost("Update/{YoutubeID}")] + public IActionResult Update([FromRoute] string YoutubeID) { + Hangfire.BackgroundJob.Enqueue(() => Tasks.FetchVideos.ChannelUpdate(Startup.DBStr, YoutubeID)); + return Ok(); } - // POST api/Admin/job_periodicupdate + // POST api/Admin/Start_Updater // Ensures that the background YT Channel update API is running. - [HttpPost("job_periodicupdate")] - public void Post_periodicupdatejob() { + [HttpPost("Start_Updater")] + public IActionResult Start_Updater() { Hangfire.RecurringJob.AddOrUpdate( - Startup.periodicupdatejobID, - () => YTManager.Tasks.FetchVideos.run(""), - Hangfire.Cron.Hourly); + Mass_Updater_ID, + () => Tasks.FetchVideos.MassUpdate(Startup.DBStr), Hangfire.Cron.Hourly); + return Ok(); } - // GET api/Admin/job_periodicupdate + // GET api/Admin/Updater // Check if the periodic update job is enqued. - [HttpGet("job_periodicupdate")] - public IActionResult Get_periodicupdatejob() { - bool exists = Hangfire.JobStorage.Current.GetConnection().GetRecurringJobs().Count(j => j.Id == Startup.periodicupdatejobID) > 0; + [HttpGet("Update")] + public IActionResult Get_Update_Status() { + bool exists = Hangfire.JobStorage.Current.GetConnection().GetRecurringJobs().Any(j => j.Id == Mass_Updater_ID); return Ok(exists ? "true" : "false"); } } diff --git a/YTManager/Controllers/Channels.cs b/YTManager/Controllers/Channels.cs index c373bc6..ecf3fad 100644 --- a/YTManager/Controllers/Channels.cs +++ b/YTManager/Controllers/Channels.cs @@ -28,7 +28,7 @@ namespace YTManager.Controllers { // GET api/Channels/5 [HttpGet("{YTchannelID}")] public Task Get([FromQuery] string YTchannelID) { - return db.Channels.SingleOrDefaultAsync(c => c.YTChannelID == YTchannelID); + return db.Channels.SingleOrDefaultAsync(c => c.YoutubeID == YTchannelID); } // GET: api/Channels/sdfs6DFS65f/Videos (using YouTube channel ID) @@ -38,7 +38,7 @@ namespace YTManager.Controllers { return BadRequest(ModelState); // Attempt to get the video from the database. - var channel = await db.Channels.SingleOrDefaultAsync(m => m.YTChannelID == YTchannelID); + var channel = await db.Channels.SingleOrDefaultAsync(m => m.YoutubeID == YTchannelID); // If the channel wasn't found then send back not found. if (channel == null) @@ -48,6 +48,27 @@ namespace YTManager.Controllers { return Ok(db.Entry(channel).Collection(c => c.Videos).LoadAsync()); } + // POST api/Channels/sdfs6DFS65f + [HttpPost("{YTchannelID}")] + public async Task Post([FromRoute] string YTchannelID) { + // Check if we were able to parse. + if (!ModelState.IsValid) return BadRequest(ModelState); + + // Verify the channel doesn't already exist. + if (db.Channels.Any(c => c.YoutubeID == YTchannelID)) + return BadRequest(); + + // Get the channel info. + var ch = await Tasks.FetchVideos.Get_YTChannel(YTchannelID); + + // Seems good, so add it. + db.Channels.Add(ch); + await db.SaveChangesAsync(); + + // And all is well. + return Ok(); + } + // POST api/Channels [HttpPost] public async Task Post([FromBody] Channel channel) { @@ -55,28 +76,25 @@ namespace YTManager.Controllers { if (!ModelState.IsValid) return BadRequest(ModelState); // Verify the channel doesn't already exist. - if (db.Channels.Any(c => c.YTChannelID == channel.YTChannelID)) + if (db.Channels.Any(c => c.YoutubeID == channel.YoutubeID)) return BadRequest(); // Seems good, so add it. db.Channels.Add(channel); await db.SaveChangesAsync(); - // Get all new videos for the channel. - Hangfire.RecurringJob.Trigger(Startup.periodicupdatejobID); - // And all is well. return Ok(); } // DELETE api/Channels/5 [HttpDelete("{YTChannelID}")] - public async Task Delete([FromQuery] string YTChannelID) { + public async Task Delete([FromRoute] string YTChannelID) { // Check if we were able to parse. if (!ModelState.IsValid) return BadRequest(ModelState); // Attempt to find the channel. - var channel = await db.Channels.SingleOrDefaultAsync(c => c.YTChannelID == YTChannelID); + var channel = await db.Channels.SingleOrDefaultAsync(c => c.YoutubeID == YTChannelID); // Check if such an entry exists already. if (channel == null) diff --git a/YTManager/Controllers/Videos.cs b/YTManager/Controllers/Videos.cs index 301f6f5..bc19e8c 100644 --- a/YTManager/Controllers/Videos.cs +++ b/YTManager/Controllers/Videos.cs @@ -31,7 +31,7 @@ namespace YTManager.Controllers { if (!ModelState.IsValid) return BadRequest(ModelState); // Attempt to get the video from the database. - var video = await db.Videos.SingleOrDefaultAsync(m => m.key == id); + var video = await db.Videos.SingleOrDefaultAsync(m => m.PrimaryKey == id); // If the video wasn't found then send back not foud. if (video == null) @@ -47,7 +47,7 @@ namespace YTManager.Controllers { if (!ModelState.IsValid) return BadRequest(ModelState); // Check if such a database exists already. - if (await db.Videos.AnyAsync(d => d.YTVideoID == video.YTVideoID)) + if (await db.Videos.AnyAsync(d => d.YoutubeID == video.YoutubeID)) return BadRequest(); // Add our video to the database and tell db to update. @@ -65,7 +65,7 @@ namespace YTManager.Controllers { if (!ModelState.IsValid) return BadRequest(ModelState); // Attempt to find the video. - var video = await db.Videos.SingleOrDefaultAsync(m => m.YTVideoID == YTVideoID); + var video = await db.Videos.SingleOrDefaultAsync(m => m.YoutubeID == YTVideoID); // Check if such a database exists already. if (video == null) diff --git a/YTManager/MediaDB.cs b/YTManager/MediaDB.cs index 8489df7..7034931 100644 --- a/YTManager/MediaDB.cs +++ b/YTManager/MediaDB.cs @@ -12,10 +12,9 @@ namespace YTManager public DbSet Videos { get; set; } public DbSet Tags { get; set; } - public MediaDB(DbContextOptions options) :base(options){ } + public MediaDB(DbContextOptions options) : base(options){ } - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - { + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { base.OnConfiguring(optionsBuilder); } } diff --git a/YTManager/Migrations/20180220032847_initiailmigration.Designer.cs b/YTManager/Migrations/20180220032847_initiailmigration.Designer.cs new file mode 100644 index 0000000..ba71de5 --- /dev/null +++ b/YTManager/Migrations/20180220032847_initiailmigration.Designer.cs @@ -0,0 +1,100 @@ +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.Storage.Internal; +using System; +using YTManager; + +namespace YTManager.Migrations +{ + [DbContext(typeof(MediaDB))] + [Migration("20180220032847_initiailmigration")] + partial class initiailmigration + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn) + .HasAnnotation("ProductVersion", "2.0.1-rtm-125"); + + modelBuilder.Entity("YTManager.Models.Channel", b => + { + b.Property("PrimaryKey") + .ValueGeneratedOnAdd(); + + b.Property("AddedtoDB"); + + b.Property("Description") + .IsRequired(); + + b.Property("ThumbnailURL") + .IsRequired(); + + b.Property("Title") + .IsRequired(); + + b.Property("YoutubeID") + .IsRequired(); + + b.HasKey("PrimaryKey"); + + b.ToTable("Channels"); + }); + + modelBuilder.Entity("YTManager.Models.Tag", b => + { + b.Property("PrimaryKey") + .ValueGeneratedOnAdd(); + + b.Property("Name") + .IsRequired(); + + b.HasKey("PrimaryKey"); + + b.ToTable("Tags"); + }); + + modelBuilder.Entity("YTManager.Models.Video", b => + { + b.Property("PrimaryKey") + .ValueGeneratedOnAdd(); + + b.Property("AddedToYT"); + + b.Property("AddedtoDB"); + + b.Property("ChannelPrimaryKey"); + + b.Property("Description") + .IsRequired(); + + b.Property("ThumbnailURL") + .IsRequired(); + + b.Property("Title") + .IsRequired(); + + b.Property("YoutubeID") + .IsRequired(); + + b.HasKey("PrimaryKey"); + + b.HasIndex("ChannelPrimaryKey"); + + b.ToTable("Videos"); + }); + + modelBuilder.Entity("YTManager.Models.Video", b => + { + b.HasOne("YTManager.Models.Channel") + .WithMany("Videos") + .HasForeignKey("ChannelPrimaryKey"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/YTManager/Migrations/20180220032847_initiailmigration.cs b/YTManager/Migrations/20180220032847_initiailmigration.cs new file mode 100644 index 0000000..3fbeac9 --- /dev/null +++ b/YTManager/Migrations/20180220032847_initiailmigration.cs @@ -0,0 +1,85 @@ +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using System; +using System.Collections.Generic; + +namespace YTManager.Migrations +{ + public partial class initiailmigration : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Channels", + columns: table => new + { + PrimaryKey = table.Column(nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn), + AddedtoDB = table.Column(nullable: false), + Description = table.Column(nullable: false), + ThumbnailURL = table.Column(nullable: false), + Title = table.Column(nullable: false), + YoutubeID = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Channels", x => x.PrimaryKey); + }); + + migrationBuilder.CreateTable( + name: "Tags", + columns: table => new + { + PrimaryKey = table.Column(nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn), + Name = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Tags", x => x.PrimaryKey); + }); + + migrationBuilder.CreateTable( + name: "Videos", + columns: table => new + { + PrimaryKey = table.Column(nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn), + AddedToYT = table.Column(nullable: false), + AddedtoDB = table.Column(nullable: false), + ChannelPrimaryKey = table.Column(nullable: true), + Description = table.Column(nullable: false), + ThumbnailURL = table.Column(nullable: false), + Title = table.Column(nullable: false), + YoutubeID = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Videos", x => x.PrimaryKey); + table.ForeignKey( + name: "FK_Videos_Channels_ChannelPrimaryKey", + column: x => x.ChannelPrimaryKey, + principalTable: "Channels", + principalColumn: "PrimaryKey", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateIndex( + name: "IX_Videos_ChannelPrimaryKey", + table: "Videos", + column: "ChannelPrimaryKey"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Tags"); + + migrationBuilder.DropTable( + name: "Videos"); + + migrationBuilder.DropTable( + name: "Channels"); + } + } +} diff --git a/YTManager/Migrations/MediaDBModelSnapshot.cs b/YTManager/Migrations/MediaDBModelSnapshot.cs new file mode 100644 index 0000000..bd15502 --- /dev/null +++ b/YTManager/Migrations/MediaDBModelSnapshot.cs @@ -0,0 +1,99 @@ +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.Storage.Internal; +using System; +using YTManager; + +namespace YTManager.Migrations +{ + [DbContext(typeof(MediaDB))] + partial class MediaDBModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn) + .HasAnnotation("ProductVersion", "2.0.1-rtm-125"); + + modelBuilder.Entity("YTManager.Models.Channel", b => + { + b.Property("PrimaryKey") + .ValueGeneratedOnAdd(); + + b.Property("AddedtoDB"); + + b.Property("Description") + .IsRequired(); + + b.Property("ThumbnailURL") + .IsRequired(); + + b.Property("Title") + .IsRequired(); + + b.Property("YoutubeID") + .IsRequired(); + + b.HasKey("PrimaryKey"); + + b.ToTable("Channels"); + }); + + modelBuilder.Entity("YTManager.Models.Tag", b => + { + b.Property("PrimaryKey") + .ValueGeneratedOnAdd(); + + b.Property("Name") + .IsRequired(); + + b.HasKey("PrimaryKey"); + + b.ToTable("Tags"); + }); + + modelBuilder.Entity("YTManager.Models.Video", b => + { + b.Property("PrimaryKey") + .ValueGeneratedOnAdd(); + + b.Property("AddedToYT"); + + b.Property("AddedtoDB"); + + b.Property("ChannelPrimaryKey"); + + b.Property("Description") + .IsRequired(); + + b.Property("ThumbnailURL") + .IsRequired(); + + b.Property("Title") + .IsRequired(); + + b.Property("YoutubeID") + .IsRequired(); + + b.HasKey("PrimaryKey"); + + b.HasIndex("ChannelPrimaryKey"); + + b.ToTable("Videos"); + }); + + modelBuilder.Entity("YTManager.Models.Video", b => + { + b.HasOne("YTManager.Models.Channel") + .WithMany("Videos") + .HasForeignKey("ChannelPrimaryKey"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/YTManager/Models/Channel.cs b/YTManager/Models/Channel.cs index f32ed64..bca9469 100644 --- a/YTManager/Models/Channel.cs +++ b/YTManager/Models/Channel.cs @@ -8,7 +8,7 @@ namespace YTManager.Models { public class Channel { // Uniquie ID for this media type [Key] - public long key { get; set; } + public long PrimaryKey { get; set; } // Title of the media [Required] @@ -24,7 +24,7 @@ namespace YTManager.Models { // Youtube Channel ID [Required] - public string YTChannelID { get; set; } + public string YoutubeID { get; set; } // Added to this manager. [Required] diff --git a/YTManager/Models/Tag.cs b/YTManager/Models/Tag.cs index a481eb4..2915f02 100644 --- a/YTManager/Models/Tag.cs +++ b/YTManager/Models/Tag.cs @@ -10,16 +10,10 @@ namespace YTManager.Models { // Uniquie ID for this media type [Key] - public long key { get; set; } + public long PrimaryKey { get; set; } // Tag Name. [Required] public string Name { get; set; } - - // Videos this tag applies to. - public List