Huge cleanup and rework pass, postgres now usable too

This commit is contained in:
hak8or 2018-02-19 23:57:14 -05:00
parent d996f7a2cb
commit a3a3c3a780
18 changed files with 472 additions and 110 deletions

View File

@ -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");
}
}

View File

@ -28,7 +28,7 @@ namespace YTManager.Controllers {
// GET api/Channels/5
[HttpGet("{YTchannelID}")]
public Task<Models.Channel> 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<IActionResult> 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<IActionResult> 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<IActionResult> Delete([FromQuery] string YTChannelID) {
public async Task<IActionResult> 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)

View File

@ -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)

View File

@ -12,10 +12,9 @@ namespace YTManager
public DbSet<Models.Video> Videos { get; set; }
public DbSet<Models.Tag> Tags { get; set; }
public MediaDB(DbContextOptions<MediaDB> options) :base(options){ }
public MediaDB(DbContextOptions<MediaDB> options) : base(options){ }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
base.OnConfiguring(optionsBuilder);
}
}

View File

@ -0,0 +1,100 @@
// <auto-generated />
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<long>("PrimaryKey")
.ValueGeneratedOnAdd();
b.Property<DateTime>("AddedtoDB");
b.Property<string>("Description")
.IsRequired();
b.Property<string>("ThumbnailURL")
.IsRequired();
b.Property<string>("Title")
.IsRequired();
b.Property<string>("YoutubeID")
.IsRequired();
b.HasKey("PrimaryKey");
b.ToTable("Channels");
});
modelBuilder.Entity("YTManager.Models.Tag", b =>
{
b.Property<long>("PrimaryKey")
.ValueGeneratedOnAdd();
b.Property<string>("Name")
.IsRequired();
b.HasKey("PrimaryKey");
b.ToTable("Tags");
});
modelBuilder.Entity("YTManager.Models.Video", b =>
{
b.Property<long>("PrimaryKey")
.ValueGeneratedOnAdd();
b.Property<DateTime>("AddedToYT");
b.Property<DateTime>("AddedtoDB");
b.Property<long?>("ChannelPrimaryKey");
b.Property<string>("Description")
.IsRequired();
b.Property<string>("ThumbnailURL")
.IsRequired();
b.Property<string>("Title")
.IsRequired();
b.Property<string>("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
}
}
}

View File

@ -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<long>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn),
AddedtoDB = table.Column<DateTime>(nullable: false),
Description = table.Column<string>(nullable: false),
ThumbnailURL = table.Column<string>(nullable: false),
Title = table.Column<string>(nullable: false),
YoutubeID = table.Column<string>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Channels", x => x.PrimaryKey);
});
migrationBuilder.CreateTable(
name: "Tags",
columns: table => new
{
PrimaryKey = table.Column<long>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn),
Name = table.Column<string>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Tags", x => x.PrimaryKey);
});
migrationBuilder.CreateTable(
name: "Videos",
columns: table => new
{
PrimaryKey = table.Column<long>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn),
AddedToYT = table.Column<DateTime>(nullable: false),
AddedtoDB = table.Column<DateTime>(nullable: false),
ChannelPrimaryKey = table.Column<long>(nullable: true),
Description = table.Column<string>(nullable: false),
ThumbnailURL = table.Column<string>(nullable: false),
Title = table.Column<string>(nullable: false),
YoutubeID = table.Column<string>(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");
}
}
}

View File

@ -0,0 +1,99 @@
// <auto-generated />
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<long>("PrimaryKey")
.ValueGeneratedOnAdd();
b.Property<DateTime>("AddedtoDB");
b.Property<string>("Description")
.IsRequired();
b.Property<string>("ThumbnailURL")
.IsRequired();
b.Property<string>("Title")
.IsRequired();
b.Property<string>("YoutubeID")
.IsRequired();
b.HasKey("PrimaryKey");
b.ToTable("Channels");
});
modelBuilder.Entity("YTManager.Models.Tag", b =>
{
b.Property<long>("PrimaryKey")
.ValueGeneratedOnAdd();
b.Property<string>("Name")
.IsRequired();
b.HasKey("PrimaryKey");
b.ToTable("Tags");
});
modelBuilder.Entity("YTManager.Models.Video", b =>
{
b.Property<long>("PrimaryKey")
.ValueGeneratedOnAdd();
b.Property<DateTime>("AddedToYT");
b.Property<DateTime>("AddedtoDB");
b.Property<long?>("ChannelPrimaryKey");
b.Property<string>("Description")
.IsRequired();
b.Property<string>("ThumbnailURL")
.IsRequired();
b.Property<string>("Title")
.IsRequired();
b.Property<string>("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
}
}
}

View File

@ -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]

View File

@ -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<Video> Videos { get; set; }
// Channels this tag applies to.
public List<Channel> Channels { get; set; }
}
}

View File

@ -8,7 +8,7 @@ namespace YTManager.Models {
public class Video {
// Uniquie ID for this media type
[Key]
public long key { get; set; }
public long PrimaryKey { get; set; }
// Title of the media
[Required]
@ -20,7 +20,7 @@ namespace YTManager.Models {
// Youtube Video ID
[Required]
public string YTVideoID { get; set; }
public string YoutubeID { get; set; }
// Thumbnail link
[Required]
@ -34,8 +34,8 @@ namespace YTManager.Models {
[Required]
public DateTime AddedtoDB { get; set; }
// Channel this video comes from.
// Tag this video applies to.
[Required]
public Channel channel;
public List<Tag> Tags;
}
}

View File

@ -20,6 +20,7 @@
"commandName": "Project",
"launchUrl": "api/values",
"environmentVariables": {
"POSTGRESQL_DBSTR": "Server=192.168.1.211;Port=32768;Database=postgres;User Id=postgres;",
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:62214/"

View File

@ -9,7 +9,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Hangfire;
using Hangfire.MemoryStorage;
using Hangfire.PostgreSql;
using Microsoft.EntityFrameworkCore;
namespace YTManager {
@ -20,14 +20,20 @@ namespace YTManager {
public IConfiguration Configuration { get; }
// ID for periodic job to update all channels.
public static string periodicupdatejobID { get; } = "2013066213";
public static string DBStr {
get {
string s = Environment.GetEnvironmentVariable("POSTGRESQL_DBSTR");
s = s ?? "Server=localhost;Port=32768;Database=postgres;User Id=postgres;";
return s;
}
}
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services) {
Console.WriteLine("Using db string of: " + DBStr);
services.AddMvc();
services.AddHangfire(x => x.UseMemoryStorage());
services.AddDbContext<MediaDB>(options => options.UseInMemoryDatabase(databaseName: "testdb"));
services.AddDbContext<MediaDB>(x => x.UseNpgsql(DBStr));
services.AddHangfire(x => x.UsePostgreSqlStorage(DBStr));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.

View File

@ -5,12 +5,10 @@ using System.Threading.Tasks;
using Google.Apis.YouTube.v3;
using Microsoft.EntityFrameworkCore;
namespace YTManager.Tasks
{
public class FetchVideos
{
public static void run(string youtubechannelIDstr = "")
{
namespace YTManager.Tasks {
public class FetchVideos {
// Get a bunch of videos from youtube that the channel generated.
private static async Task<List<Models.Video>> Get_YTVideos(string channelID) {
// YT API access key
var youtubeService = new YouTubeService(new Google.Apis.Services.BaseClientService.Initializer()
{
@ -18,49 +16,92 @@ namespace YTManager.Tasks
ApplicationName = "testingapppp"
});
// Search youtube for all the relevant data of the channel.
var query = youtubeService.Search.List("snippet");
query.ChannelId = channelID;
query.Order = SearchResource.ListRequest.OrderEnum.Date;
query.MaxResults = 50;
var response = await query.ExecuteAsync();
// Convert the response into models.
return response.Items?
.Where(i => i.Id.Kind == "youtube#video")
.Select(newvid => new Models.Video
{
Title = newvid.Snippet.Title,
Description = newvid.Snippet.Description,
YoutubeID = newvid.Id.VideoId,
AddedToYT = newvid.Snippet.PublishedAt.GetValueOrDefault(),
AddedtoDB = DateTime.Now,
ThumbnailURL = newvid.Snippet.Thumbnails.Medium.Url
}).ToList();
}
public static async Task<Models.Channel> Get_YTChannel(string channelID) {
// YT API access key
var youtubeService = new YouTubeService(new Google.Apis.Services.BaseClientService.Initializer()
{
ApiKey = "AIzaSyCuIYkMc5SktlnXRXNaDf2ObX-fQvtWCnQ",
ApplicationName = "testingapppp"
});
// Search youtube for all the relevant data of the channel.
var query = youtubeService.Channels.List("snippet");
query.Id = channelID;
query.MaxResults = 1;
var response = await query.ExecuteAsync();
// Parse the response into a channel.
return new Models.Channel {
Description = response.Items.First().Snippet.Description,
Title = response.Items.First().Snippet.Title,
ThumbnailURL = response.Items.First().Snippet.Thumbnails.Medium.Url,
YoutubeID = channelID,
AddedtoDB = DateTime.Now
};
}
// Update videos for all our channels.
public static async Task MassUpdate(string dbstr) {
// Get the interface to the database.
var ops = new DbContextOptionsBuilder<MediaDB>();
ops.UseInMemoryDatabase(databaseName: "testdb");
ops.UseNpgsql(dbstr);
// Get all the channels to update.
using (var dbcontext = new MediaDB(ops.Options)) {
// Get all the potential relevant channels.
List<Models.Channel> channels;
if (youtubechannelIDstr == "")
channels = dbcontext.Channels.ToList();
else
channels = dbcontext.Channels.Where(c => c.YTChannelID == youtubechannelIDstr).ToList();
// Get all the channels from the db.
var channels = await (new MediaDB(ops.Options)).Channels.ToListAsync();
// Get all the most recent videos for each channel.
channels.ForEach(ch => {
// Get channel videos from youtube.
var query = youtubeService.Search.List("snippet");
query.ChannelId = ch.YTChannelID;
query.Order = SearchResource.ListRequest.OrderEnum.Date;
query.MaxResults = 50;
var response = query.Execute();
// For each channel, do an update.
channels.ForEach(async ch => await ChannelUpdate(dbstr, ch.YoutubeID));
}
// Get all videos which aren't already in the DB based on the ytid.
var notindb = response.Items
.Where(i => i.Id.Kind == "youtube#video")
.Where(i => !dbcontext.Videos.Any(dbvid => dbvid.YTVideoID == i.Id.VideoId))
.Select(newvid =>
new Models.Video {
Title = newvid.Snippet.Title,
Description = newvid.Snippet.Description,
YTVideoID = newvid.Id.VideoId,
AddedToYT = newvid.Snippet.PublishedAt.GetValueOrDefault(),
AddedtoDB = DateTime.Now,
channel = ch,
ThumbnailURL = newvid.Snippet.Thumbnails.Medium.Url
}).ToList();
// Update videos for just one channel.
public static async Task ChannelUpdate(string dbstr, string youtubechannelIDstr) {
// Get the interface to the database.
var ops = new DbContextOptionsBuilder<MediaDB>();
ops.UseNpgsql(dbstr);
var db = new MediaDB(ops.Options);
// Add all videos not already in the database over.
notindb.ForEach(newvid => dbcontext.Videos.Add(newvid));
// Get the channel from the db when including it's videos.
var channel = await db.Channels
.Include(c => c.Videos)
.SingleOrDefaultAsync(ch => ch.YoutubeID == youtubechannelIDstr);
// And save since we are done.
dbcontext.SaveChanges();
});
// Update the channel if it was found.
if (channel != null) {
// Get all the new videos for the channel.
var Videos = await Get_YTVideos(channel.YoutubeID);
// Get all the videos which haven't been put into this channels videos.
var newvids = Videos.Where(nv => !channel.Videos.Any(cv => cv.YoutubeID == nv.YoutubeID));
// Add all the videos to the databse.
await db.Videos.AddRangeAsync(newvids);
// Update the videos this channel refers to.
channel.Videos.AddRange(newvids);
// And say the database should be changed.
await db.SaveChangesAsync();
}
}
}

View File

@ -4,11 +4,22 @@
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<!-- Job System -->
<ItemGroup>
<PackageReference Include="Hangfire" Version="1.6.17" />
<PackageReference Include="Hangfire.AspNetCore" Version="1.6.17" />
<PackageReference Include="Hangfire.PostgreSql" Version="1.4.8.1" />
</ItemGroup>
<!-- Database -->
<ItemGroup>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="2.0.0" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL.Design" Version="1.1.1" />
</ItemGroup>
<!-- Backend Website -->
<ItemGroup>
<PackageReference Include="Google.Apis.YouTube.v3" Version="1.32.2.1131" />
<PackageReference Include="Hangfire" Version="1.6.17"/>
<PackageReference Include="Hangfire.AspNetCore" Version="1.6.17" />
<PackageReference Include="Hangfire.MemoryStorage.Core" Version="1.4.0"/>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="2.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.0.1" />
@ -17,6 +28,7 @@
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.0.2" />
</ItemGroup>
<!-- So we can run dotnet migration ... -->
<ItemGroup>
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.2" />
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.1" />

View File

@ -59,7 +59,7 @@ var addchanel0 = new Vue({
submit: function (event) {
// Send the channel to our API and request tables be updated.
var d = this.entry;
axios.post('/api/Channels', d)
axios.post('/api/Channels/' + this.entry.yTChannelID)
.then(function (response) {
this.entry.title = "";
this.entry.description = "";
@ -132,13 +132,13 @@ var tbody0 = new Vue({
</thead>
<tbody>
<tr v-cloak v-for="entry in entries">
<td class="tinytext12px">{{entry.ytChannelID}}</td>
<td class="tinytext12px">{{entry.youtubeID}}</td>
<td class="tinytext12px">{{entry.title}}</td>
<td class="tinytext12px">{{entry.description}}</td>
<td class="tinytext12px">{{entry.channelId}}</td>
<td class="tinytext12px">{{entry.primaryKey}}</td>
<td>
<a href="#"><i class="fa fa-refresh" aria-hidden="true" :id="entry.ytChannelID" @click="forcerefresh"/></a>
<a href="#"><i class="fa fa-trash-o" aria-hidden="true" :id="entry.ytChannelID" @click="deletechannel"/></a>
<a href="#"><i class="fa fa-refresh" aria-hidden="true" :id="entry.youtubeID" @click="forcerefresh"/></a>
<a href="#"><i class="fa fa-trash-o" aria-hidden="true" :id="entry.youtubeID" @click="deletechannel"/></a>
</td>
</tr>
</tbody>
@ -165,7 +165,7 @@ var tbody0 = new Vue({
},
forcerefresh: function (event) {
axios
.post('/api/Admin/job_update/' + event.target.id)
.post('/api/Admin/Update/' + event.target.id)
.catch(function (error) { console.log(error); });
},
deletechannel: function (event) {
@ -200,7 +200,7 @@ var apistatus = new Vue({
`,
methods: {
update: function (event) {
axios.get('/api/Admin/job_periodicupdate')
axios.get('/api/Admin/Update')
.then(function (response) {
this.apiaccessible = (response.status == 200);
this.updatingjobactive = (response.data != "false")
@ -213,7 +213,7 @@ var apistatus = new Vue({
}
});
// Grid if images.
// Grid of images.
var videostb = new Vue({
el: '#videosindbtable-0',
data: {
@ -234,9 +234,9 @@ var videostb = new Vue({
<tr v-cloak v-for="video in Videos">
<td class="tinytext12px">{{video.title}}</td>
<td class="tinytext12px">{{video.description}}</td>
<td class="tinytext12px">{{video.ytVideoID}}</td>
<td class="tinytext12px">{{video.youtubeID}}</td>
<td class="tinytext12px">{{video.uploaded}}</td>
<td class="tinytext12px">{{video.videoId}}</td>
<td class="tinytext12px">{{video.primaryKey}}</td>
</tr>
</tbody>
</table>

View File

@ -5,10 +5,12 @@
font-size: 18px;
color: #003636;
background-color: #F8F8F8;
max-width: 1024px;
margin: auto;
}
.pageheader {
max-width: 1280px;
max-width: 960px;
margin: auto;
}

View File

@ -15,7 +15,7 @@
</div>
<hr />
<h2>Most Recent Videos</h2>
<div v-cloak id="vidholder-0"></div>
<!-- Compressed JavaScript -->

View File

@ -40,7 +40,7 @@ var vidholder = new Vue({
}
// Generate a new URL by adding the YT ID.
x.url = "https://www.youtube.com/watch?v=" + x.ytVideoID
x.url = "https://www.youtube.com/watch?v=" + x.youtubeID;
// Add it to our array
this.Videos.push(x);