mirror of
https://github.com/fergalmoran/podnoms.git
synced 2025-12-22 09:18:08 +00:00
YouTube working, Mixcloud is a cunt
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
<div class="block-content">
|
||||
<button class="btn btn-primary" (click)="processOrphans()">Process Orphans</button>
|
||||
<button class="btn btn-primary" (click)="processPlaylists()">Process Playlists</button>
|
||||
<button class="btn btn-primary" (click)="processPlaylistItems()">Process Playlist Items</button>
|
||||
<button class="btn btn-primary" (click)="updateYouTubeDl()">Update Youtube Downloader</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -54,6 +54,13 @@ export class DebugComponent implements OnInit {
|
||||
console.log('debug.component.ts', 'processPlaylists', e)
|
||||
);
|
||||
}
|
||||
processPlaylistItems() {
|
||||
this._jobsService
|
||||
.processPlaylistItems()
|
||||
.subscribe((e) =>
|
||||
console.log('debug.component.ts', 'processPlaylists', e)
|
||||
);
|
||||
}
|
||||
updateYouTubeDl() {
|
||||
this._jobsService
|
||||
.updateYouTubeDl()
|
||||
|
||||
@@ -18,6 +18,11 @@ export class JobsService {
|
||||
environment.API_HOST + '/job/processplaylists'
|
||||
);
|
||||
}
|
||||
processPlaylistItems(): Observable<Response> {
|
||||
return this._http.get<Response>(
|
||||
environment.API_HOST + '/job/processplaylistitems'
|
||||
);
|
||||
}
|
||||
updateYouTubeDl(): Observable<Response> {
|
||||
return this._http.get<Response>(
|
||||
environment.API_HOST + '/job/updateyoutubedl'
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using AutoMapper;
|
||||
using Hangfire;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
@@ -32,6 +33,7 @@ namespace PodNoms.Api.Controllers {
|
||||
private readonly IUnitOfWork _unitOfWork;
|
||||
private readonly IMapper _mapper;
|
||||
private readonly IUrlProcessService _processor;
|
||||
private readonly IHostingEnvironment _hostingEnvironment;
|
||||
private readonly ILogger _logger;
|
||||
private readonly AudioFileStorageSettings _audioFileStorageSettings;
|
||||
private readonly StorageSettings _storageSettings;
|
||||
@@ -43,6 +45,7 @@ namespace PodNoms.Api.Controllers {
|
||||
IConfiguration options,
|
||||
IUrlProcessService processor, ILoggerFactory logger,
|
||||
UserManager<ApplicationUser> userManager,
|
||||
IHostingEnvironment hostingEnvironment,
|
||||
IHttpContextAccessor contextAccessor) : base(contextAccessor, userManager) {
|
||||
this._logger = logger.CreateLogger<EntryController>();
|
||||
this._podcastRepository = podcastRepository;
|
||||
@@ -53,6 +56,7 @@ namespace PodNoms.Api.Controllers {
|
||||
this._audioFileStorageSettings = audioFileStorageSettings.Value;
|
||||
this._mapper = mapper;
|
||||
this._processor = processor;
|
||||
this._hostingEnvironment = hostingEnvironment;
|
||||
}
|
||||
|
||||
private void _processEntry(PodcastEntry entry) {
|
||||
@@ -111,7 +115,7 @@ namespace PodNoms.Api.Controllers {
|
||||
var result = _mapper.Map<PodcastEntry, PodcastEntryViewModel>(entry);
|
||||
return result;
|
||||
}
|
||||
} else if (status == AudioType.Playlist) {
|
||||
} else if (status == AudioType.Playlist && _hostingEnvironment.IsDevelopment()) {
|
||||
entry.ProcessingStatus = ProcessingStatus.Deferred;
|
||||
return Accepted(entry);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,11 @@ namespace PodNoms.Api.Controllers {
|
||||
var infoJobId = BackgroundJob.Enqueue<ProcessPlaylistsJob>(service => service.Execute());
|
||||
return Ok();
|
||||
}
|
||||
[HttpGet("processplaylistitems")]
|
||||
public IActionResult ProcessPlaylistItems() {
|
||||
var infoJobId = BackgroundJob.Enqueue<ProcessPlaylistItemJob>(service => service.Execute());
|
||||
return Ok();
|
||||
}
|
||||
[HttpGet("updateyoutubedl")]
|
||||
public IActionResult UpdateYouTubeDl() {
|
||||
var infoJobId = BackgroundJob.Enqueue<UpdateYouTubeDlJob>(service => service.Execute());
|
||||
|
||||
390
server/Migrations/20180507153433_ParsedPlaylistVideos.Designer.cs
generated
Normal file
390
server/Migrations/20180507153433_ParsedPlaylistVideos.Designer.cs
generated
Normal file
@@ -0,0 +1,390 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Internal;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using PodNoms.Api.Persistence;
|
||||
|
||||
namespace PodNoms.Api.Migrations
|
||||
{
|
||||
[DbContext(typeof(PodnomsDbContext))]
|
||||
[Migration("20180507153433_ParsedPlaylistVideos")]
|
||||
partial class ParsedPlaylistVideos
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "2.1.0-preview2-30571")
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique()
|
||||
.HasName("RoleNameIndex")
|
||||
.HasFilter("[NormalizedName] IS NOT NULL");
|
||||
|
||||
b.ToTable("AspNetRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClaimType");
|
||||
|
||||
b.Property<string>("ClaimValue");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClaimType");
|
||||
|
||||
b.Property<string>("ClaimValue");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
b.Property<string>("ProviderKey");
|
||||
|
||||
b.Property<string>("ProviderDisplayName");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.Property<string>("RoleId");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
b.Property<string>("Name");
|
||||
|
||||
b.Property<string>("Value");
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("AspNetUserTokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.ParsedPlaylistVideo", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("CreateDate");
|
||||
|
||||
b.Property<bool>("IsProcessed");
|
||||
|
||||
b.Property<int>("PlaylistId");
|
||||
|
||||
b.Property<DateTime>("UpdateDate");
|
||||
|
||||
b.Property<string>("VideoId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("PlaylistId");
|
||||
|
||||
b.ToTable("ParsedPlaylistVideos");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.Playlist", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("CreateDate");
|
||||
|
||||
b.Property<int>("PodcastId");
|
||||
|
||||
b.Property<string>("SourceUrl");
|
||||
|
||||
b.Property<DateTime>("UpdateDate");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("PodcastId");
|
||||
|
||||
b.ToTable("Playlists");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.Podcast", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("AppUserId");
|
||||
|
||||
b.Property<DateTime>("CreateDate");
|
||||
|
||||
b.Property<string>("Description");
|
||||
|
||||
b.Property<string>("Slug");
|
||||
|
||||
b.Property<string>("TemporaryImageUrl");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("Uid");
|
||||
|
||||
b.Property<DateTime>("UpdateDate");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AppUserId");
|
||||
|
||||
b.ToTable("Podcasts");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.PodcastEntry", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<long>("AudioFileSize");
|
||||
|
||||
b.Property<float>("AudioLength");
|
||||
|
||||
b.Property<string>("AudioUrl");
|
||||
|
||||
b.Property<string>("Author");
|
||||
|
||||
b.Property<DateTime>("CreateDate");
|
||||
|
||||
b.Property<string>("Description");
|
||||
|
||||
b.Property<string>("ImageUrl");
|
||||
|
||||
b.Property<int?>("PlaylistId");
|
||||
|
||||
b.Property<int>("PodcastId");
|
||||
|
||||
b.Property<bool>("Processed");
|
||||
|
||||
b.Property<string>("ProcessingPayload");
|
||||
|
||||
b.Property<int>("ProcessingStatus");
|
||||
|
||||
b.Property<string>("SourceUrl");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("Uid");
|
||||
|
||||
b.Property<DateTime>("UpdateDate");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("PlaylistId");
|
||||
|
||||
b.HasIndex("PodcastId");
|
||||
|
||||
b.ToTable("PodcastEntries");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Services.Auth.ApplicationUser", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("AccessFailedCount");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<bool>("EmailConfirmed");
|
||||
|
||||
b.Property<long?>("FacebookId");
|
||||
|
||||
b.Property<string>("FirstName");
|
||||
|
||||
b.Property<string>("LastName");
|
||||
|
||||
b.Property<bool>("LockoutEnabled");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("PasswordHash");
|
||||
|
||||
b.Property<string>("PhoneNumber");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed");
|
||||
|
||||
b.Property<string>("PictureUrl");
|
||||
|
||||
b.Property<string>("SecurityStamp");
|
||||
|
||||
b.Property<string>("Slug");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasName("UserNameIndex")
|
||||
.HasFilter("[NormalizedUserName] IS NOT NULL");
|
||||
|
||||
b.ToTable("AspNetUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.ParsedPlaylistVideo", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Models.Playlist", "Playlist")
|
||||
.WithMany("ParsedPlaylistVideos")
|
||||
.HasForeignKey("PlaylistId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.Playlist", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Models.Podcast", "Podcast")
|
||||
.WithMany()
|
||||
.HasForeignKey("PodcastId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.Podcast", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser", "AppUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("AppUserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.PodcastEntry", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Models.Playlist")
|
||||
.WithMany("PodcastEntries")
|
||||
.HasForeignKey("PlaylistId");
|
||||
|
||||
b.HasOne("PodNoms.Api.Models.Podcast", "Podcast")
|
||||
.WithMany("PodcastEntries")
|
||||
.HasForeignKey("PodcastId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
75
server/Migrations/20180507153433_ParsedPlaylistVideos.cs
Normal file
75
server/Migrations/20180507153433_ParsedPlaylistVideos.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace PodNoms.Api.Migrations
|
||||
{
|
||||
public partial class ParsedPlaylistVideos : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
name: "CreateDate",
|
||||
table: "Podcasts",
|
||||
nullable: false,
|
||||
oldClrType: typeof(DateTime),
|
||||
oldDefaultValueSql: "getdate()");
|
||||
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
name: "CreateDate",
|
||||
table: "PodcastEntries",
|
||||
nullable: false,
|
||||
oldClrType: typeof(DateTime),
|
||||
oldDefaultValueSql: "getdate()");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "ParsedPlaylistVideos",
|
||||
columns: table => new
|
||||
{
|
||||
CreateDate = table.Column<DateTime>(nullable: false),
|
||||
UpdateDate = table.Column<DateTime>(nullable: false),
|
||||
Id = table.Column<int>(nullable: false)
|
||||
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
|
||||
VideoId = table.Column<string>(nullable: true),
|
||||
IsProcessed = table.Column<bool>(nullable: false),
|
||||
PlaylistId = table.Column<int>(nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_ParsedPlaylistVideos", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_ParsedPlaylistVideos_Playlists_PlaylistId",
|
||||
column: x => x.PlaylistId,
|
||||
principalTable: "Playlists",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ParsedPlaylistVideos_PlaylistId",
|
||||
table: "ParsedPlaylistVideos",
|
||||
column: "PlaylistId");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "ParsedPlaylistVideos");
|
||||
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
name: "CreateDate",
|
||||
table: "Podcasts",
|
||||
nullable: false,
|
||||
defaultValueSql: "getdate()",
|
||||
oldClrType: typeof(DateTime));
|
||||
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
name: "CreateDate",
|
||||
table: "PodcastEntries",
|
||||
nullable: false,
|
||||
defaultValueSql: "getdate()",
|
||||
oldClrType: typeof(DateTime));
|
||||
}
|
||||
}
|
||||
}
|
||||
390
server/Migrations/20180507155436_Rename_ParsedPlaylistVideos.Designer.cs
generated
Normal file
390
server/Migrations/20180507155436_Rename_ParsedPlaylistVideos.Designer.cs
generated
Normal file
@@ -0,0 +1,390 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Internal;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using PodNoms.Api.Persistence;
|
||||
|
||||
namespace PodNoms.Api.Migrations
|
||||
{
|
||||
[DbContext(typeof(PodnomsDbContext))]
|
||||
[Migration("20180507155436_Rename_ParsedPlaylistVideos")]
|
||||
partial class Rename_ParsedPlaylistVideos
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "2.1.0-preview2-30571")
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique()
|
||||
.HasName("RoleNameIndex")
|
||||
.HasFilter("[NormalizedName] IS NOT NULL");
|
||||
|
||||
b.ToTable("AspNetRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClaimType");
|
||||
|
||||
b.Property<string>("ClaimValue");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClaimType");
|
||||
|
||||
b.Property<string>("ClaimValue");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
b.Property<string>("ProviderKey");
|
||||
|
||||
b.Property<string>("ProviderDisplayName");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.Property<string>("RoleId");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
b.Property<string>("Name");
|
||||
|
||||
b.Property<string>("Value");
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("AspNetUserTokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.ParsedPlaylistItem", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("CreateDate");
|
||||
|
||||
b.Property<bool>("IsProcessed");
|
||||
|
||||
b.Property<int>("PlaylistId");
|
||||
|
||||
b.Property<DateTime>("UpdateDate");
|
||||
|
||||
b.Property<string>("VideoId");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("PlaylistId");
|
||||
|
||||
b.ToTable("ParsedPlaylistItems");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.Playlist", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("CreateDate");
|
||||
|
||||
b.Property<int>("PodcastId");
|
||||
|
||||
b.Property<string>("SourceUrl");
|
||||
|
||||
b.Property<DateTime>("UpdateDate");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("PodcastId");
|
||||
|
||||
b.ToTable("Playlists");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.Podcast", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("AppUserId");
|
||||
|
||||
b.Property<DateTime>("CreateDate");
|
||||
|
||||
b.Property<string>("Description");
|
||||
|
||||
b.Property<string>("Slug");
|
||||
|
||||
b.Property<string>("TemporaryImageUrl");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("Uid");
|
||||
|
||||
b.Property<DateTime>("UpdateDate");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AppUserId");
|
||||
|
||||
b.ToTable("Podcasts");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.PodcastEntry", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<long>("AudioFileSize");
|
||||
|
||||
b.Property<float>("AudioLength");
|
||||
|
||||
b.Property<string>("AudioUrl");
|
||||
|
||||
b.Property<string>("Author");
|
||||
|
||||
b.Property<DateTime>("CreateDate");
|
||||
|
||||
b.Property<string>("Description");
|
||||
|
||||
b.Property<string>("ImageUrl");
|
||||
|
||||
b.Property<int?>("PlaylistId");
|
||||
|
||||
b.Property<int>("PodcastId");
|
||||
|
||||
b.Property<bool>("Processed");
|
||||
|
||||
b.Property<string>("ProcessingPayload");
|
||||
|
||||
b.Property<int>("ProcessingStatus");
|
||||
|
||||
b.Property<string>("SourceUrl");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("Uid");
|
||||
|
||||
b.Property<DateTime>("UpdateDate");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("PlaylistId");
|
||||
|
||||
b.HasIndex("PodcastId");
|
||||
|
||||
b.ToTable("PodcastEntries");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Services.Auth.ApplicationUser", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("AccessFailedCount");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<bool>("EmailConfirmed");
|
||||
|
||||
b.Property<long?>("FacebookId");
|
||||
|
||||
b.Property<string>("FirstName");
|
||||
|
||||
b.Property<string>("LastName");
|
||||
|
||||
b.Property<bool>("LockoutEnabled");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("PasswordHash");
|
||||
|
||||
b.Property<string>("PhoneNumber");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed");
|
||||
|
||||
b.Property<string>("PictureUrl");
|
||||
|
||||
b.Property<string>("SecurityStamp");
|
||||
|
||||
b.Property<string>("Slug");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasName("UserNameIndex")
|
||||
.HasFilter("[NormalizedUserName] IS NOT NULL");
|
||||
|
||||
b.ToTable("AspNetUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.ParsedPlaylistItem", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Models.Playlist", "Playlist")
|
||||
.WithMany("ParsedPlaylistItems")
|
||||
.HasForeignKey("PlaylistId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.Playlist", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Models.Podcast", "Podcast")
|
||||
.WithMany()
|
||||
.HasForeignKey("PodcastId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.Podcast", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser", "AppUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("AppUserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.PodcastEntry", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Models.Playlist")
|
||||
.WithMany("PodcastEntries")
|
||||
.HasForeignKey("PlaylistId");
|
||||
|
||||
b.HasOne("PodNoms.Api.Models.Podcast", "Podcast")
|
||||
.WithMany("PodcastEntries")
|
||||
.HasForeignKey("PodcastId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace PodNoms.Api.Migrations
|
||||
{
|
||||
public partial class Rename_ParsedPlaylistVideos : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "ParsedPlaylistVideos");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "ParsedPlaylistItems",
|
||||
columns: table => new
|
||||
{
|
||||
CreateDate = table.Column<DateTime>(nullable: false),
|
||||
UpdateDate = table.Column<DateTime>(nullable: false),
|
||||
Id = table.Column<int>(nullable: false)
|
||||
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
|
||||
VideoId = table.Column<string>(nullable: true),
|
||||
IsProcessed = table.Column<bool>(nullable: false),
|
||||
PlaylistId = table.Column<int>(nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_ParsedPlaylistItems", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_ParsedPlaylistItems_Playlists_PlaylistId",
|
||||
column: x => x.PlaylistId,
|
||||
principalTable: "Playlists",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ParsedPlaylistItems_PlaylistId",
|
||||
table: "ParsedPlaylistItems",
|
||||
column: "PlaylistId");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "ParsedPlaylistItems");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "ParsedPlaylistVideos",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(nullable: false)
|
||||
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
|
||||
CreateDate = table.Column<DateTime>(nullable: false),
|
||||
IsProcessed = table.Column<bool>(nullable: false),
|
||||
PlaylistId = table.Column<int>(nullable: false),
|
||||
UpdateDate = table.Column<DateTime>(nullable: false),
|
||||
VideoId = table.Column<string>(nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_ParsedPlaylistVideos", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_ParsedPlaylistVideos_Playlists_PlaylistId",
|
||||
column: x => x.PlaylistId,
|
||||
principalTable: "Playlists",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ParsedPlaylistVideos_PlaylistId",
|
||||
table: "ParsedPlaylistVideos",
|
||||
column: "PlaylistId");
|
||||
}
|
||||
}
|
||||
}
|
||||
392
server/Migrations/20180507162159_AddVideoTypeToPlaylistItem.Designer.cs
generated
Normal file
392
server/Migrations/20180507162159_AddVideoTypeToPlaylistItem.Designer.cs
generated
Normal file
@@ -0,0 +1,392 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Internal;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using PodNoms.Api.Persistence;
|
||||
|
||||
namespace PodNoms.Api.Migrations
|
||||
{
|
||||
[DbContext(typeof(PodnomsDbContext))]
|
||||
[Migration("20180507162159_AddVideoTypeToPlaylistItem")]
|
||||
partial class AddVideoTypeToPlaylistItem
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "2.1.0-preview2-30571")
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique()
|
||||
.HasName("RoleNameIndex")
|
||||
.HasFilter("[NormalizedName] IS NOT NULL");
|
||||
|
||||
b.ToTable("AspNetRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClaimType");
|
||||
|
||||
b.Property<string>("ClaimValue");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("ClaimType");
|
||||
|
||||
b.Property<string>("ClaimValue");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
b.Property<string>("ProviderKey");
|
||||
|
||||
b.Property<string>("ProviderDisplayName");
|
||||
|
||||
b.Property<string>("UserId")
|
||||
.IsRequired();
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.Property<string>("RoleId");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.Property<string>("UserId");
|
||||
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
b.Property<string>("Name");
|
||||
|
||||
b.Property<string>("Value");
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("AspNetUserTokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.ParsedPlaylistItem", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("CreateDate");
|
||||
|
||||
b.Property<bool>("IsProcessed");
|
||||
|
||||
b.Property<int>("PlaylistId");
|
||||
|
||||
b.Property<DateTime>("UpdateDate");
|
||||
|
||||
b.Property<string>("VideoId");
|
||||
|
||||
b.Property<string>("VideoType");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("PlaylistId");
|
||||
|
||||
b.ToTable("ParsedPlaylistItems");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.Playlist", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("CreateDate");
|
||||
|
||||
b.Property<int>("PodcastId");
|
||||
|
||||
b.Property<string>("SourceUrl");
|
||||
|
||||
b.Property<DateTime>("UpdateDate");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("PodcastId");
|
||||
|
||||
b.ToTable("Playlists");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.Podcast", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<string>("AppUserId");
|
||||
|
||||
b.Property<DateTime>("CreateDate");
|
||||
|
||||
b.Property<string>("Description");
|
||||
|
||||
b.Property<string>("Slug");
|
||||
|
||||
b.Property<string>("TemporaryImageUrl");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("Uid");
|
||||
|
||||
b.Property<DateTime>("UpdateDate");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AppUserId");
|
||||
|
||||
b.ToTable("Podcasts");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.PodcastEntry", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<long>("AudioFileSize");
|
||||
|
||||
b.Property<float>("AudioLength");
|
||||
|
||||
b.Property<string>("AudioUrl");
|
||||
|
||||
b.Property<string>("Author");
|
||||
|
||||
b.Property<DateTime>("CreateDate");
|
||||
|
||||
b.Property<string>("Description");
|
||||
|
||||
b.Property<string>("ImageUrl");
|
||||
|
||||
b.Property<int?>("PlaylistId");
|
||||
|
||||
b.Property<int>("PodcastId");
|
||||
|
||||
b.Property<bool>("Processed");
|
||||
|
||||
b.Property<string>("ProcessingPayload");
|
||||
|
||||
b.Property<int>("ProcessingStatus");
|
||||
|
||||
b.Property<string>("SourceUrl");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("Uid");
|
||||
|
||||
b.Property<DateTime>("UpdateDate");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("PlaylistId");
|
||||
|
||||
b.HasIndex("PodcastId");
|
||||
|
||||
b.ToTable("PodcastEntries");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Services.Auth.ApplicationUser", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<int>("AccessFailedCount");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken();
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<bool>("EmailConfirmed");
|
||||
|
||||
b.Property<long?>("FacebookId");
|
||||
|
||||
b.Property<string>("FirstName");
|
||||
|
||||
b.Property<string>("LastName");
|
||||
|
||||
b.Property<bool>("LockoutEnabled");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.Property<string>("PasswordHash");
|
||||
|
||||
b.Property<string>("PhoneNumber");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed");
|
||||
|
||||
b.Property<string>("PictureUrl");
|
||||
|
||||
b.Property<string>("SecurityStamp");
|
||||
|
||||
b.Property<string>("Slug");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256);
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasName("UserNameIndex")
|
||||
.HasFilter("[NormalizedUserName] IS NOT NULL");
|
||||
|
||||
b.ToTable("AspNetUsers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
|
||||
{
|
||||
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.ParsedPlaylistItem", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Models.Playlist", "Playlist")
|
||||
.WithMany("ParsedPlaylistItems")
|
||||
.HasForeignKey("PlaylistId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.Playlist", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Models.Podcast", "Podcast")
|
||||
.WithMany()
|
||||
.HasForeignKey("PodcastId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.Podcast", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Services.Auth.ApplicationUser", "AppUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("AppUserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.PodcastEntry", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Models.Playlist")
|
||||
.WithMany("PodcastEntries")
|
||||
.HasForeignKey("PlaylistId");
|
||||
|
||||
b.HasOne("PodNoms.Api.Models.Podcast", "Podcast")
|
||||
.WithMany("PodcastEntries")
|
||||
.HasForeignKey("PodcastId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace PodNoms.Api.Migrations
|
||||
{
|
||||
public partial class AddVideoTypeToPlaylistItem : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "VideoType",
|
||||
table: "ParsedPlaylistItems",
|
||||
nullable: true);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "VideoType",
|
||||
table: "ParsedPlaylistItems");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -127,6 +127,30 @@ namespace PodNoms.Api.Migrations
|
||||
b.ToTable("AspNetUserTokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.ParsedPlaylistItem", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<DateTime>("CreateDate");
|
||||
|
||||
b.Property<bool>("IsProcessed");
|
||||
|
||||
b.Property<int>("PlaylistId");
|
||||
|
||||
b.Property<DateTime>("UpdateDate");
|
||||
|
||||
b.Property<string>("VideoId");
|
||||
|
||||
b.Property<string>("VideoType");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("PlaylistId");
|
||||
|
||||
b.ToTable("ParsedPlaylistItems");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.Playlist", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@@ -154,14 +178,11 @@ namespace PodNoms.Api.Migrations
|
||||
|
||||
b.Property<string>("AppUserId");
|
||||
|
||||
b.Property<DateTime>("CreateDate")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasDefaultValueSql("getdate()");
|
||||
b.Property<DateTime>("CreateDate");
|
||||
|
||||
b.Property<string>("Description");
|
||||
|
||||
b.Property<string>("Slug")
|
||||
.IsUnicode(true);
|
||||
b.Property<string>("Slug");
|
||||
|
||||
b.Property<string>("TemporaryImageUrl");
|
||||
|
||||
@@ -191,9 +212,7 @@ namespace PodNoms.Api.Migrations
|
||||
|
||||
b.Property<string>("Author");
|
||||
|
||||
b.Property<DateTime>("CreateDate")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasDefaultValueSql("getdate()");
|
||||
b.Property<DateTime>("CreateDate");
|
||||
|
||||
b.Property<string>("Description");
|
||||
|
||||
@@ -332,6 +351,14 @@ namespace PodNoms.Api.Migrations
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.ParsedPlaylistItem", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Models.Playlist", "Playlist")
|
||||
.WithMany("ParsedPlaylistItems")
|
||||
.HasForeignKey("PlaylistId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PodNoms.Api.Models.Playlist", b =>
|
||||
{
|
||||
b.HasOne("PodNoms.Api.Models.Podcast", "Podcast")
|
||||
|
||||
@@ -3,5 +3,6 @@ namespace PodNoms.Api.Models {
|
||||
public string Version { get; set; }
|
||||
public string SiteUrl { get; set; }
|
||||
public string RssUrl { get; set; }
|
||||
public string GoogleApiKey { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -7,5 +7,17 @@ namespace PodNoms.Api.Models {
|
||||
public string SourceUrl { get; set; }
|
||||
public Podcast Podcast { get; set; }
|
||||
public List<PodcastEntry> PodcastEntries { get; set; }
|
||||
public List<ParsedPlaylistItem> ParsedPlaylistItems { get; set; }
|
||||
public Playlist() {
|
||||
ParsedPlaylistItems = new List<ParsedPlaylistItem>();
|
||||
}
|
||||
}
|
||||
public class ParsedPlaylistItem : BaseModel {
|
||||
public int Id { get; set; }
|
||||
public string VideoId { get; set; }
|
||||
public string VideoType { get; set; }
|
||||
public bool IsProcessed { get; set; }
|
||||
public int PlaylistId { get; set; }
|
||||
public Playlist Playlist { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -7,5 +7,7 @@ namespace PodNoms.Api.Persistence {
|
||||
Task<Playlist> GetAsync(int id);
|
||||
Task<IEnumerable<Playlist>> GetAllAsync();
|
||||
Task<Playlist> AddOrUpdateAsync(Playlist playlist);
|
||||
Task<ParsedPlaylistItem> GetParsedItem(string itemId, int playlistId);
|
||||
Task<List<ParsedPlaylistItem>> GetUnprocessedItems();
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using PodNoms.Api.Models;
|
||||
@@ -18,7 +19,7 @@ namespace PodNoms.Api.Persistence {
|
||||
return entry;
|
||||
}
|
||||
public async Task<IEnumerable<Playlist>> GetAllAsync() {
|
||||
return await _context.Playlists.ToListAsync();
|
||||
return await _context.Playlists.Include(p => p.ParsedPlaylistItems).ToListAsync();
|
||||
}
|
||||
public async Task<Playlist> AddOrUpdateAsync(Playlist playlist) {
|
||||
if (playlist.Id != 0) {
|
||||
@@ -30,5 +31,20 @@ namespace PodNoms.Api.Persistence {
|
||||
}
|
||||
return playlist;
|
||||
}
|
||||
public async Task<ParsedPlaylistItem> GetParsedItem(string itemId, int playlistId) {
|
||||
return await _context.ParsedPlaylistItems
|
||||
.Include(i => i.Playlist)
|
||||
.Include(i => i.Playlist.Podcast)
|
||||
.Include(i => i.Playlist.Podcast.AppUser)
|
||||
.SingleOrDefaultAsync(i => i.VideoId == itemId && i.PlaylistId == playlistId);
|
||||
}
|
||||
public async Task<List<ParsedPlaylistItem>> GetUnprocessedItems() {
|
||||
return await _context.ParsedPlaylistItems
|
||||
.Where(p => p.IsProcessed == false)
|
||||
.Include(i => i.Playlist)
|
||||
.Include(i => i.Playlist.Podcast)
|
||||
.Include(i => i.Playlist.Podcast.AppUser)
|
||||
.ToListAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Design;
|
||||
@@ -15,24 +18,37 @@ namespace PodNoms.Api.Persistence {
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder) {
|
||||
base.OnModelCreating(modelBuilder);
|
||||
|
||||
|
||||
modelBuilder.Entity<Podcast>()
|
||||
.Property(b => b.CreateDate)
|
||||
.HasDefaultValueSql("getdate()");
|
||||
|
||||
modelBuilder.Entity<Podcast>()
|
||||
.Property(b => b.Slug)
|
||||
.IsUnicode(true);
|
||||
|
||||
modelBuilder.Entity<PodcastEntry>()
|
||||
.Property(b => b.CreateDate)
|
||||
.HasDefaultValueSql("getdate()");
|
||||
|
||||
}
|
||||
public override int SaveChanges() {
|
||||
_addTimestamps();
|
||||
return base.SaveChanges();
|
||||
}
|
||||
public override Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default(System.Threading.CancellationToken)) {
|
||||
_addTimestamps();
|
||||
return base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
|
||||
}
|
||||
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default) {
|
||||
_addTimestamps();
|
||||
return base.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
void _addTimestamps() {
|
||||
var modifiedEntries = ChangeTracker.Entries()
|
||||
.Where(x => (x.State == EntityState.Added || x.State == EntityState.Modified));
|
||||
|
||||
var now = DateTime.Now;
|
||||
foreach (var entry in modifiedEntries) {
|
||||
var entity = entry.Entity as BaseModel;
|
||||
if (entity != null) {
|
||||
if (entry.State == EntityState.Added) {
|
||||
entity.CreateDate = now;
|
||||
}
|
||||
entity.UpdateDate = now;
|
||||
}
|
||||
}
|
||||
}
|
||||
public DbSet<Podcast> Podcasts { get; set; }
|
||||
public DbSet<PodcastEntry> PodcastEntries { get; set; }
|
||||
public DbSet<Playlist> Playlists { get; set; }
|
||||
public DbSet<ParsedPlaylistItem> ParsedPlaylistItems { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<UserSecretsId>aspnet-PodNoms.Api-1E27B6DE-BA4B-4F75-BBF8-CA34FB4D260A</UserSecretsId>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<RootNamespace>PodNoms.Api</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="wwwroot\" />
|
||||
@@ -13,10 +14,8 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentValidation.AspNetCore" Version="7.5.2" />
|
||||
<PackageReference Include="Google.Apis" Version="1.32.2" />
|
||||
<PackageReference Include="Google.Apis.Auth" Version="1.32.2" />
|
||||
<PackageReference Include="Google.Apis.Core" Version="1.32.2" />
|
||||
<PackageReference Include="Google.Apis.Plus.v1" Version="1.32.2.1182" />
|
||||
<PackageReference Include="Google.Apis.Plus.v1" Version="1.33.0.1209" />
|
||||
<PackageReference Include="Google.Apis.YouTube.v3" Version="1.33.0.1217" />
|
||||
<PackageReference Include="Hangfire" Version="1.6.17" />
|
||||
<PackageReference Include="Hangfire.MemoryStorage" Version="1.5.2" />
|
||||
<PackageReference Include="Lib.Net.Http.WebPush" Version="1.3.0" />
|
||||
|
||||
@@ -54,24 +54,22 @@ namespace PodNoms.Api.Services.Downloader {
|
||||
return $"{{\"Error\": \"{ex.Message}\"}}";
|
||||
}
|
||||
}
|
||||
public async Task<AudioType> GetInfo() {
|
||||
public AudioType GetInfo() {
|
||||
var ret = AudioType.Invalid;
|
||||
await Task.Run(() => {
|
||||
var youtubeDl = new YoutubeDL();
|
||||
youtubeDl.VideoUrl = this._url;
|
||||
var info = youtubeDl.GetDownloadInfo();
|
||||
var yt = new YoutubeDL();
|
||||
yt.VideoUrl = this._url;
|
||||
var info = yt.GetDownloadInfo();
|
||||
|
||||
if (info != null &&
|
||||
(info.Errors.Count == 0 || info.VideoSize != null)) {
|
||||
this._properties = info;
|
||||
// have to dump playlist handling for now
|
||||
if (info is PlaylistDownloadInfo && ((PlaylistDownloadInfo)info).Videos.Count > 0) {
|
||||
ret = AudioType.Playlist;
|
||||
} else if (info is VideoDownloadInfo) {
|
||||
ret = AudioType.Valid;
|
||||
}
|
||||
if (info != null &&
|
||||
(info.Errors.Count == 0 || info.VideoSize != null)) {
|
||||
this._properties = info;
|
||||
// have to dump playlist handling for now
|
||||
if (info is PlaylistDownloadInfo && ((PlaylistDownloadInfo)info).Videos.Count > 0) {
|
||||
ret = AudioType.Playlist;
|
||||
} else if (info is VideoDownloadInfo) {
|
||||
ret = AudioType.Valid;
|
||||
}
|
||||
});
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -89,10 +87,12 @@ namespace PodNoms.Api.Services.Downloader {
|
||||
yt.StandardOutputEvent += (sender, output) => {
|
||||
if (output.Contains("%")) {
|
||||
var progress = _parseProgress(output);
|
||||
Console.WriteLine($"Processing {progress.CurrentSpeed} {progress.ETA} {progress.Percentage}");
|
||||
if (DownloadProgress != null) {
|
||||
DownloadProgress(this, progress);
|
||||
}
|
||||
} else {
|
||||
Console.WriteLine(output);
|
||||
if (PostProcessing != null) {
|
||||
PostProcessing(this, output);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ namespace PodNoms.Api.Services.Jobs {
|
||||
public static void BootstrapJobs() {
|
||||
RecurringJob.AddOrUpdate<ClearOrphanAudioJob>(x => x.Execute(), Cron.Daily(1));
|
||||
RecurringJob.AddOrUpdate<UpdateYouTubeDlJob>(x => x.Execute(), Cron.Daily(1, 30));
|
||||
|
||||
// BackgroundJob.Schedule<ProcessPlaylistsJob>(x => x.Execute(), TimeSpan.FromSeconds(1));
|
||||
}
|
||||
}
|
||||
|
||||
80
server/Services/Jobs/ProcessPlaylistItemJob.cs
Normal file
80
server/Services/Jobs/ProcessPlaylistItemJob.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
using System.Threading.Tasks;
|
||||
using Hangfire;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using PodNoms.Api.Models;
|
||||
using PodNoms.Api.Persistence;
|
||||
using PodNoms.Api.Services.Downloader;
|
||||
using PodNoms.Api.Services.Processor;
|
||||
using PodNoms.Api.Utils.RemoteParsers;
|
||||
|
||||
namespace PodNoms.Api.Services.Jobs {
|
||||
public class ProcessPlaylistItemJob : IJob {
|
||||
public readonly IPlaylistRepository _playlistRepository;
|
||||
public readonly IEntryRepository _entryRepository;
|
||||
private readonly IAudioUploadProcessService _uploadService;
|
||||
private readonly IConfiguration _options;
|
||||
private readonly IPodcastRepository _podcastRepository;
|
||||
private readonly ApplicationsSettings _applicationsSettings;
|
||||
private readonly ILogger<ProcessPlaylistItemJob> _logger;
|
||||
private readonly IUnitOfWork _unitOfWork;
|
||||
public ProcessPlaylistItemJob(IPlaylistRepository playlistRepository, IEntryRepository entryRepository,
|
||||
IAudioUploadProcessService uploadService, IConfiguration options,
|
||||
IPodcastRepository podcastRepository, IOptions<ApplicationsSettings> applicationsSettings,
|
||||
IUnitOfWork unitOfWork, ILogger<ProcessPlaylistItemJob> logger) {
|
||||
this._unitOfWork = unitOfWork;
|
||||
this._playlistRepository = playlistRepository;
|
||||
this._entryRepository = entryRepository;
|
||||
this._uploadService = uploadService;
|
||||
this._options = options;
|
||||
this._podcastRepository = podcastRepository;
|
||||
this._applicationsSettings = applicationsSettings.Value;
|
||||
this._logger = logger;
|
||||
}
|
||||
public async Task Execute() {
|
||||
var items = await _playlistRepository.GetUnprocessedItems();
|
||||
foreach (var item in items) {
|
||||
await ExecuteForItem(item.VideoId, item.Playlist.Id);
|
||||
}
|
||||
}
|
||||
public async Task ExecuteForItem(string itemId, int playlistId) {
|
||||
var item = await _playlistRepository.GetParsedItem(itemId, playlistId);
|
||||
if (item != null && !string.IsNullOrEmpty(item.VideoType) && item.VideoType.Equals("youtube")) {
|
||||
var url = $"https://www.youtube.com/watch?v={item.VideoId}";
|
||||
var downloader = new AudioDownloader(url, _applicationsSettings.Downloader);
|
||||
var info = downloader.GetInfo();
|
||||
if (info == AudioType.Valid) {
|
||||
var podcast = await _podcastRepository.GetAsync(item.Playlist.PodcastId);
|
||||
var uid = System.Guid.NewGuid().ToString();
|
||||
var file = downloader.DownloadAudio(uid);
|
||||
if (System.IO.File.Exists(file)) {
|
||||
//we have the file so lets create the entry and ship to CDN
|
||||
var entry = new PodcastEntry {
|
||||
Title = downloader.Properties?.Title,
|
||||
Uid = uid,
|
||||
Description = downloader.Properties?.Description,
|
||||
ProcessingStatus = ProcessingStatus.Uploading,
|
||||
ImageUrl = downloader.Properties?.Thumbnail
|
||||
};
|
||||
podcast.PodcastEntries.Add(entry);
|
||||
await _unitOfWork.CompleteAsync();
|
||||
var uploaded = await _uploadService.UploadAudio(entry.Id, file);
|
||||
if (uploaded) {
|
||||
item.IsProcessed = true;
|
||||
await _unitOfWork.CompleteAsync();
|
||||
BackgroundJob.Enqueue<INotifyJobCompleteService>(
|
||||
service => service.NotifyUser(entry.Podcast.AppUser.Id, "PodNoms", $"{entry.Title} has finished processing",
|
||||
entry.Podcast.GetThumbnailUrl(
|
||||
this._options.GetSection("Storage")["CdnUrl"],
|
||||
this._options.GetSection("ImageFileStorageSettings")["ContainerName"])
|
||||
));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_logger.LogError($"Processing playlist item {itemId} failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,16 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Hangfire;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using NYoutubeDL.Models;
|
||||
using PodNoms.Api.Models;
|
||||
using PodNoms.Api.Persistence;
|
||||
using PodNoms.Api.Services.Downloader;
|
||||
using PodNoms.Api.Utils.RemoteParsers;
|
||||
using static NYoutubeDL.Helpers.Enums;
|
||||
|
||||
namespace PodNoms.Api.Services.Jobs {
|
||||
@@ -16,44 +19,51 @@ namespace PodNoms.Api.Services.Jobs {
|
||||
public readonly IEntryRepository _entryRepository;
|
||||
private readonly ApplicationsSettings _applicationsSettings;
|
||||
private readonly ILogger<ProcessPlaylistsJob> _logger;
|
||||
private readonly YouTubeParser _youTubeParser;
|
||||
private readonly MixcloudParser _mixcloudParser;
|
||||
private readonly IUnitOfWork _unitOfWork;
|
||||
|
||||
public ProcessPlaylistsJob(IPlaylistRepository playlistRepository,
|
||||
IEntryRepository entryRepository, IOptions<ApplicationsSettings> applicationsSettings, ILoggerFactory logger) {
|
||||
_playlistRepository = playlistRepository;
|
||||
_entryRepository = entryRepository;
|
||||
_applicationsSettings = applicationsSettings.Value;
|
||||
_logger = logger.CreateLogger<ProcessPlaylistsJob>();
|
||||
public ProcessPlaylistsJob(IPlaylistRepository playlistRepository, IEntryRepository entryRepository,
|
||||
IUnitOfWork unitOfWork, IOptions<ApplicationsSettings> applicationsSettings,
|
||||
ILoggerFactory logger, YouTubeParser youTubeParser, MixcloudParser mixcloudParser) {
|
||||
this._unitOfWork = unitOfWork;
|
||||
this._youTubeParser = youTubeParser;
|
||||
this._mixcloudParser = mixcloudParser;
|
||||
this._playlistRepository = playlistRepository;
|
||||
this._entryRepository = entryRepository;
|
||||
this._applicationsSettings = applicationsSettings.Value;
|
||||
this._logger = logger.CreateLogger<ProcessPlaylistsJob>();
|
||||
}
|
||||
|
||||
public async Task Execute() {
|
||||
var playists = await _playlistRepository.GetAllAsync();
|
||||
var playlists = await _playlistRepository.GetAllAsync();
|
||||
var resultList = new List<ParsedItemResult>();
|
||||
|
||||
foreach (var playlist in playists) {
|
||||
foreach (var playlist in playlists) {
|
||||
var downloader = new AudioDownloader(playlist.SourceUrl, _applicationsSettings.Downloader);
|
||||
var info = await downloader.GetInfo();
|
||||
var info = downloader.GetInfo();
|
||||
var id = ((PlaylistDownloadInfo)downloader.RawProperties).Id;
|
||||
if (info == AudioType.Playlist && downloader.RawProperties is PlaylistDownloadInfo) {
|
||||
var list = ((PlaylistDownloadInfo)downloader.RawProperties).Videos
|
||||
.OrderByDescending(x => x.Id)
|
||||
.Take(10);
|
||||
StringBuilder br = new StringBuilder();
|
||||
foreach (var item in list) {
|
||||
_logger.LogDebug($"Processing: {item.Id} - {item.Url}");
|
||||
br.Append($"Processing: {item.Id} - {item.Title}\n");
|
||||
|
||||
var outputDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
|
||||
Directory.CreateDirectory(outputDir);
|
||||
|
||||
var yt = new NYoutubeDL.YoutubeDL(playlist.SourceUrl);
|
||||
yt.Options.PostProcessingOptions.ExtractAudio = true;
|
||||
yt.Options.PostProcessingOptions.AudioFormat = AudioFormat.mp3;
|
||||
yt.Options.VideoSelectionOptions.PlaylistItems = "1,2,3";
|
||||
yt.Options.FilesystemOptions.Output = Path.Combine(outputDir, "%(playlist)s/%(playlist_index)s - %(title)s.%(ext)s");
|
||||
|
||||
var p = yt.Download();
|
||||
p.WaitForExit();
|
||||
if (_youTubeParser.ValidateUrl(playlist.SourceUrl)) {
|
||||
var searchTerm = (playlist.SourceUrl.Contains("/user/")) ? "forUsername" : "id";
|
||||
resultList = await _youTubeParser.GetPlaylistEntriesForId(id);
|
||||
//make sure the items are sorted in ascending date order
|
||||
//so they will be processed in the order they were created
|
||||
} else if (_mixcloudParser.ValidateUrl(playlist.SourceUrl)) {
|
||||
resultList = await _mixcloudParser.GetEntries(id);
|
||||
}
|
||||
_logger.LogDebug(br.ToString());
|
||||
|
||||
}
|
||||
foreach (var item in resultList?.OrderBy(r => r.UploadDate)) {
|
||||
if (!playlist.ParsedPlaylistItems.Any(p => p.VideoId == item.Id)) {
|
||||
playlist.ParsedPlaylistItems.Add(new ParsedPlaylistItem {
|
||||
VideoId = item.Id,
|
||||
VideoType = item.VideoType
|
||||
});
|
||||
BackgroundJob.Enqueue<ProcessPlaylistItemJob>(service => service.ExecuteForItem(item.Id, playlist.Id));
|
||||
}
|
||||
}
|
||||
await _unitOfWork.CompleteAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
// Copyright 2017 Brian Allred
|
||||
//
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
@@ -28,7 +28,7 @@ namespace NYoutubeDL.Helpers
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Abstract class that extends the functionality of a traditional NotifyPropertyChanged implementation
|
||||
/// </summary>
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
// Copyright 2017 Brian Allred
|
||||
//
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
@@ -18,8 +18,7 @@
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
namespace NYoutubeDL.Models
|
||||
{
|
||||
namespace NYoutubeDL.Models {
|
||||
#region Using
|
||||
|
||||
using System;
|
||||
@@ -32,8 +31,7 @@ namespace NYoutubeDL.Models
|
||||
/// <summary>
|
||||
/// Class holding data about the current download, which is parsed from youtube-dl's standard output
|
||||
/// </summary>
|
||||
public class DownloadInfo : NotifyPropertyChangedEx
|
||||
{
|
||||
public class DownloadInfo : NotifyPropertyChangedEx {
|
||||
protected const string ALREADY = "already";
|
||||
|
||||
protected const string DOWNLOADRATESTRING = "iB/s";
|
||||
@@ -51,7 +49,7 @@ namespace NYoutubeDL.Models
|
||||
private string eta;
|
||||
|
||||
private string status = Enums.DownloadStatus.WAITING.ToString();
|
||||
|
||||
private string id;
|
||||
private string title;
|
||||
|
||||
private int videoProgress;
|
||||
@@ -61,8 +59,7 @@ namespace NYoutubeDL.Models
|
||||
/// <summary>
|
||||
/// The current download rate
|
||||
/// </summary>
|
||||
public string DownloadRate
|
||||
{
|
||||
public string DownloadRate {
|
||||
get => this.downloadRate;
|
||||
set => this.SetField(ref this.downloadRate, value);
|
||||
}
|
||||
@@ -75,8 +72,7 @@ namespace NYoutubeDL.Models
|
||||
/// <summary>
|
||||
/// The current download's estimated time remaining
|
||||
/// </summary>
|
||||
public string Eta
|
||||
{
|
||||
public string Eta {
|
||||
get => this.eta;
|
||||
set => this.SetField(ref this.eta, value);
|
||||
}
|
||||
@@ -84,29 +80,30 @@ namespace NYoutubeDL.Models
|
||||
/// <summary>
|
||||
/// The status of the video currently downloading
|
||||
/// </summary>
|
||||
public string Status
|
||||
{
|
||||
public string Status {
|
||||
get => this.status;
|
||||
set
|
||||
{
|
||||
set {
|
||||
if (!this.status.Equals(Enums.DownloadStatus.ERROR.ToString()) &&
|
||||
!this.status.Equals(Enums.DownloadStatus.WARNING.ToString()))
|
||||
{
|
||||
!this.status.Equals(Enums.DownloadStatus.WARNING.ToString())) {
|
||||
this.SetField(ref this.status, value);
|
||||
}
|
||||
else if (value.Equals(Enums.DownloadStatus.ERROR.ToString()) &&
|
||||
this.status.Equals(Enums.DownloadStatus.WARNING.ToString()))
|
||||
{
|
||||
} else if (value.Equals(Enums.DownloadStatus.ERROR.ToString()) &&
|
||||
this.status.Equals(Enums.DownloadStatus.WARNING.ToString())) {
|
||||
this.SetField(ref this.status, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The id of the playlist
|
||||
/// </summary>
|
||||
public string Id {
|
||||
get => this.id;
|
||||
set => this.SetField(ref this.id, value);
|
||||
}
|
||||
/// <summary>
|
||||
/// The title of the video currently downloading
|
||||
/// </summary>
|
||||
public string Title
|
||||
{
|
||||
public string Title {
|
||||
get => this.title;
|
||||
set => this.SetField(ref this.title, value);
|
||||
}
|
||||
@@ -114,23 +111,16 @@ namespace NYoutubeDL.Models
|
||||
/// <summary>
|
||||
/// The current download progresss
|
||||
/// </summary>
|
||||
public int VideoProgress
|
||||
{
|
||||
public int VideoProgress {
|
||||
get => this.videoProgress;
|
||||
set
|
||||
{
|
||||
set {
|
||||
this.SetField(ref this.videoProgress, value);
|
||||
|
||||
if (value == 0)
|
||||
{
|
||||
if (value == 0) {
|
||||
this.Status = Enums.DownloadStatus.WAITING.ToString();
|
||||
}
|
||||
else if (value == 100)
|
||||
{
|
||||
} else if (value == 100) {
|
||||
this.Status = Enums.DownloadStatus.DONE.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
this.Status = Enums.DownloadStatus.DOWNLOADING.ToString();
|
||||
}
|
||||
}
|
||||
@@ -139,8 +129,7 @@ namespace NYoutubeDL.Models
|
||||
/// <summary>
|
||||
/// The current download's total size
|
||||
/// </summary>
|
||||
public string VideoSize
|
||||
{
|
||||
public string VideoSize {
|
||||
get => this.videoSize;
|
||||
set => this.SetField(ref this.videoSize, value);
|
||||
}
|
||||
@@ -150,31 +139,25 @@ namespace NYoutubeDL.Models
|
||||
/// </summary>
|
||||
public List<string> Warnings { get; } = new List<string>();
|
||||
|
||||
internal static DownloadInfo CreateDownloadInfo(string output)
|
||||
{
|
||||
try
|
||||
{
|
||||
internal static DownloadInfo CreateDownloadInfo(string output) {
|
||||
if (string.IsNullOrEmpty(output) || output.Equals("null"))
|
||||
return null;
|
||||
|
||||
try {
|
||||
PlaylistInfo info = JsonConvert.DeserializeObject<PlaylistInfo>(output);
|
||||
if (!string.IsNullOrEmpty(info._type) && info._type.Equals("playlist"))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(info._type) && info._type.Equals("playlist")) {
|
||||
return new PlaylistDownloadInfo(info);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
} catch (Exception ex) {
|
||||
Console.WriteLine(ex);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
try {
|
||||
VideoInfo info = JsonConvert.DeserializeObject<VideoInfo>(output);
|
||||
if (!string.IsNullOrEmpty(info.title))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(info.title)) {
|
||||
return new VideoDownloadInfo(info);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
} catch (Exception ex) {
|
||||
Console.WriteLine(ex);
|
||||
}
|
||||
|
||||
@@ -186,57 +169,45 @@ namespace NYoutubeDL.Models
|
||||
/// </summary>
|
||||
public event EventHandler<string> ErrorEvent;
|
||||
|
||||
internal virtual void ParseError(object sender, string error)
|
||||
{
|
||||
internal virtual void ParseError(object sender, string error) {
|
||||
this.ErrorEvent?.Invoke(this, error);
|
||||
if (error.Contains("WARNING"))
|
||||
{
|
||||
if (error.Contains("WARNING")) {
|
||||
this.Warnings.Add(error);
|
||||
this.Status = Enums.DownloadStatus.WARNING.ToString();
|
||||
}
|
||||
else if (error.Contains("ERROR"))
|
||||
{
|
||||
} else if (error.Contains("ERROR")) {
|
||||
this.Errors.Add(error);
|
||||
this.Status = Enums.DownloadStatus.ERROR.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
internal virtual void ParseOutput(object sender, string output)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (output.Contains("%"))
|
||||
{
|
||||
internal virtual void ParseOutput(object sender, string output) {
|
||||
try {
|
||||
if (output.Contains("%")) {
|
||||
int progressIndex = output.LastIndexOf(' ', output.IndexOf('%')) + 1;
|
||||
string progressString = output.Substring(progressIndex, output.IndexOf('%') - progressIndex);
|
||||
this.VideoProgress = (int) Math.Round(double.Parse(progressString));
|
||||
this.VideoProgress = (int)Math.Round(double.Parse(progressString));
|
||||
|
||||
int sizeIndex = output.LastIndexOf(' ', output.IndexOf(DOWNLOADSIZESTRING)) + 1;
|
||||
string sizeString = output.Substring(sizeIndex, output.IndexOf(DOWNLOADSIZESTRING) - sizeIndex + 2);
|
||||
this.VideoSize = sizeString;
|
||||
}
|
||||
|
||||
if (output.Contains(DOWNLOADRATESTRING))
|
||||
{
|
||||
if (output.Contains(DOWNLOADRATESTRING)) {
|
||||
int rateIndex = output.LastIndexOf(' ', output.LastIndexOf(DOWNLOADRATESTRING)) + 1;
|
||||
string rateString =
|
||||
output.Substring(rateIndex, output.LastIndexOf(DOWNLOADRATESTRING) - rateIndex + 4);
|
||||
this.DownloadRate = rateString;
|
||||
}
|
||||
|
||||
if (output.Contains(ETASTRING))
|
||||
{
|
||||
if (output.Contains(ETASTRING)) {
|
||||
this.Eta = output.Substring(output.LastIndexOf(' ') + 1);
|
||||
}
|
||||
|
||||
if (output.Contains(ALREADY))
|
||||
{
|
||||
if (output.Contains(ALREADY)) {
|
||||
this.Status = Enums.DownloadStatus.DONE.ToString();
|
||||
this.VideoProgress = 100;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
} catch (Exception) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
// Copyright 2017 Brian Allred
|
||||
//
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
@@ -39,6 +39,7 @@ namespace NYoutubeDL.Models
|
||||
|
||||
public PlaylistDownloadInfo(PlaylistInfo info)
|
||||
{
|
||||
this.Id = info.id;
|
||||
this.Title = info.title;
|
||||
foreach (VideoInfo videoInfo in info.entries)
|
||||
{
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
// Copyright 2017 Brian Allred
|
||||
//
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
@@ -180,11 +180,6 @@ namespace NYoutubeDL.Models
|
||||
|
||||
public int? Width { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The ID string of the video
|
||||
/// </summary>
|
||||
public string Id { get; }
|
||||
|
||||
public List<ThumbnailDownloadInfo> Thumbnails { get; } = new List<ThumbnailDownloadInfo>();
|
||||
|
||||
public List<string> Tags { get; }
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace PodNoms.Api.Services.Processor {
|
||||
public async Task<AudioType> GetInformation(PodcastEntry entry) {
|
||||
|
||||
var downloader = new AudioDownloader(entry.SourceUrl, _applicationsSettings.Downloader);
|
||||
var ret = await downloader.GetInfo();
|
||||
var ret = downloader.GetInfo();
|
||||
if (ret == AudioType.Valid) {
|
||||
entry.Title = downloader.Properties?.Title;
|
||||
entry.Description = downloader.Properties?.Description;
|
||||
|
||||
@@ -46,6 +46,7 @@ using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.AspNetCore.Identity.UI.Services;
|
||||
using PodNoms.Api.Utils.RemoteParsers;
|
||||
|
||||
namespace PodNoms.Api {
|
||||
public class Startup {
|
||||
@@ -102,7 +103,7 @@ namespace PodNoms.Api {
|
||||
services.Configure<ImageFileStorageSettings>(Configuration.GetSection("ImageFileStorageSettings"));
|
||||
services.Configure<AudioFileStorageSettings>(Configuration.GetSection("AudioFileStorageSettings"));
|
||||
services.Configure<FormOptions>(options => {
|
||||
options.ValueCountLimit = 10;
|
||||
// options.ValueCountLimit = 10;
|
||||
options.ValueLengthLimit = int.MaxValue;
|
||||
options.MemoryBufferThreshold = Int32.MaxValue;
|
||||
options.MultipartBodyLengthLimit = long.MaxValue;
|
||||
@@ -112,6 +113,10 @@ namespace PodNoms.Api {
|
||||
e.AddProfile(new MappingProvider(Configuration));
|
||||
});
|
||||
|
||||
services.AddHttpClient("mixcloud", c => {
|
||||
c.BaseAddress = new Uri("https://api.mixcloud.com/");
|
||||
c.DefaultRequestHeaders.Add("Accept", "application/json");
|
||||
});
|
||||
services.AddHttpClient();
|
||||
var jwtAppSettingOptions = Configuration.GetSection(nameof(JwtIssuerOptions));
|
||||
|
||||
@@ -220,6 +225,8 @@ namespace PodNoms.Api {
|
||||
services.AddScoped<INotifyJobCompleteService, NotifyJobCompleteService>();
|
||||
services.AddScoped<IAudioUploadProcessService, AudioUploadProcessService>();
|
||||
services.AddScoped<IMailSender, MailgunSender>();
|
||||
services.AddScoped<YouTubeParser>();
|
||||
services.AddScoped<MixcloudParser>();
|
||||
services.AddHttpClient<Services.Gravatar.GravatarHttpClient>();
|
||||
|
||||
//register the codepages (required for slugify)
|
||||
|
||||
36
server/Utils/RemoteParsers/MixcloudParser.cs
Normal file
36
server/Utils/RemoteParsers/MixcloudParser.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace PodNoms.Api.Utils.RemoteParsers {
|
||||
public class MixcloudParser {
|
||||
const string URL_REGEX = @"^(http(s)?:\/\/)?((w){3}.)?mixcloud?(\.com)?\/.+";
|
||||
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
|
||||
public MixcloudParser(IHttpClientFactory httpClientFactory) {
|
||||
this._httpClientFactory = httpClientFactory;
|
||||
}
|
||||
public bool ValidateUrl(string url) {
|
||||
var regex = new Regex(URL_REGEX);
|
||||
var result = regex.Match(url);
|
||||
return result.Success;
|
||||
}
|
||||
public async Task<List<ParsedItemResult>> GetEntries(string identifier) {
|
||||
var client = _httpClientFactory.CreateClient("mixcloud");
|
||||
var result = await client.GetAsync(identifier);
|
||||
if (result.IsSuccessStatusCode) {
|
||||
var typed = JsonConvert.DeserializeObject<MixcloudResult>(await result.Content.ReadAsStringAsync());
|
||||
return typed.data[0].cloudcasts.Select(c => new ParsedItemResult {
|
||||
Id = c.key,
|
||||
VideoType = "mixcloud",
|
||||
UploadDate = c.updated_time
|
||||
}).ToList();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
75
server/Utils/RemoteParsers/MixcloudViewModels.cs
Normal file
75
server/Utils/RemoteParsers/MixcloudViewModels.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PodNoms.Api.Utils.RemoteParsers {
|
||||
|
||||
|
||||
public class Paging {
|
||||
public string previous { get; set; }
|
||||
public string next { get; set; }
|
||||
}
|
||||
|
||||
public class Pictures {
|
||||
public string medium { get; set; }
|
||||
public string extra_large { get; set; }
|
||||
public string large { get; set; }
|
||||
public string medium_mobile { get; set; }
|
||||
public string small { get; set; }
|
||||
public string thumbnail { get; set; }
|
||||
}
|
||||
|
||||
public class From {
|
||||
public string url { get; set; }
|
||||
public string username { get; set; }
|
||||
public string name { get; set; }
|
||||
public string key { get; set; }
|
||||
public Pictures pictures { get; set; }
|
||||
}
|
||||
|
||||
public class Tag {
|
||||
public string url { get; set; }
|
||||
public string name { get; set; }
|
||||
public string key { get; set; }
|
||||
}
|
||||
|
||||
public class User {
|
||||
public string url { get; set; }
|
||||
public string username { get; set; }
|
||||
public string name { get; set; }
|
||||
public string key { get; set; }
|
||||
}
|
||||
|
||||
public class Cloudcast {
|
||||
public IList<Tag> tags { get; set; }
|
||||
public int play_count { get; set; }
|
||||
public User user { get; set; }
|
||||
public string key { get; set; }
|
||||
public DateTime created_time { get; set; }
|
||||
public int audio_length { get; set; }
|
||||
public string slug { get; set; }
|
||||
public int favorite_count { get; set; }
|
||||
public int listener_count { get; set; }
|
||||
public string name { get; set; }
|
||||
public string url { get; set; }
|
||||
public int repost_count { get; set; }
|
||||
public DateTime updated_time { get; set; }
|
||||
public int comment_count { get; set; }
|
||||
}
|
||||
|
||||
public class Datum {
|
||||
public From from { get; set; }
|
||||
public string title { get; set; }
|
||||
public string url { get; set; }
|
||||
public string key { get; set; }
|
||||
public DateTime created_time { get; set; }
|
||||
public IList<Cloudcast> cloudcasts { get; set; }
|
||||
public string type { get; set; }
|
||||
}
|
||||
|
||||
public class MixcloudResult {
|
||||
public Paging paging { get; set; }
|
||||
public IList<Datum> data { get; set; }
|
||||
public string name { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
9
server/Utils/RemoteParsers/ParsedItemResult.cs
Normal file
9
server/Utils/RemoteParsers/ParsedItemResult.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace PodNoms.Api.Utils.RemoteParsers {
|
||||
public class ParsedItemResult {
|
||||
public string Id { get; set; }
|
||||
public string VideoType { get; set; }
|
||||
public DateTime? UploadDate { get; set; }
|
||||
}
|
||||
}
|
||||
61
server/Utils/RemoteParsers/YouTubeParser.cs
Normal file
61
server/Utils/RemoteParsers/YouTubeParser.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Google.Apis.Services;
|
||||
using Google.Apis.YouTube.v3;
|
||||
using Microsoft.Extensions.Options;
|
||||
using PodNoms.Api.Models;
|
||||
|
||||
namespace PodNoms.Api.Utils.RemoteParsers {
|
||||
public partial class YouTubeParser {
|
||||
const string URL_REGEX = @"^(http(s)?:\/\/)?((w){3}.)?youtu(be|.be)?(\.com)?\/.+";
|
||||
private readonly AppSettings _settings;
|
||||
private YouTubeService youtube;
|
||||
public YouTubeParser(IOptions<AppSettings> options) {
|
||||
this._settings = options.Value;
|
||||
this.youtube = _getYouTubeService();
|
||||
}
|
||||
private YouTubeService _getYouTubeService() {
|
||||
return new YouTubeService(new BaseClientService.Initializer() {
|
||||
ApiKey = _settings.GoogleApiKey,
|
||||
ApplicationName = this.GetType().ToString()
|
||||
});
|
||||
}
|
||||
|
||||
public bool ValidateUrl(string url) {
|
||||
var regex = new Regex(URL_REGEX);
|
||||
var result = regex.Match(url);
|
||||
return result.Success;
|
||||
}
|
||||
public async Task<List<ParsedItemResult>> GetPlaylistEntriesForId(string id, int nCount = 10) {
|
||||
var playlistRequest = youtube.PlaylistItems.List("contentDetails");
|
||||
playlistRequest.PlaylistId = id;
|
||||
playlistRequest.MaxResults = nCount;
|
||||
var plists = await playlistRequest.ExecuteAsync();
|
||||
return plists.Items
|
||||
.Select(p => new ParsedItemResult {
|
||||
Id = p.ContentDetails.VideoId,
|
||||
VideoType = "youtube",
|
||||
UploadDate = p.ContentDetails.VideoPublishedAt
|
||||
}).ToList();
|
||||
}
|
||||
public async Task<List<ParsedItemResult>> GetPlaylistEntriesForChannelName(string channelName, string searchType, int nCount = 10) {
|
||||
|
||||
var request = youtube.Channels.List("contentDetails");
|
||||
if (searchType.Equals("id"))
|
||||
request.Id = channelName;
|
||||
else
|
||||
request.ForUsername = channelName;
|
||||
request.MaxResults = 1;
|
||||
var resp = await request.ExecuteAsync();
|
||||
if (resp.Items.Count == 1) {
|
||||
var uploadListId = resp.Items[0].ContentDetails.RelatedPlaylists.Uploads;
|
||||
if (!string.IsNullOrEmpty(uploadListId)) {
|
||||
return await GetPlaylistEntriesForId(uploadListId, nCount);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,9 +8,7 @@
|
||||
}
|
||||
},
|
||||
"App": {
|
||||
"Version": "0.23.0",
|
||||
"SiteUrl": "http://localhost:4200",
|
||||
"RssUrl": "http://localhost:5000/rss/"
|
||||
"Version": "0.23.0"
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"DefaultConnection": "server=localhost;database=PodNoms;user id=sa;password=cTXu1nJLCpC/c",
|
||||
|
||||
Reference in New Issue
Block a user