From db4a42171def9c68796db4dc9e5d758af70634b4 Mon Sep 17 00:00:00 2001 From: Laura Hausmann Date: Wed, 9 Feb 2022 20:45:14 +0100 Subject: [PATCH] Add watchlist, enable migrations --- Pages/Index.cshtml | 25 +++-- Pages/Watchlist.cshtml | 110 ++++++++++++++++++++ Pages/Watchlist.cshtml.cs | 39 +++++++ c3stream.cs | 210 +++++++++++++++++++------------------- 4 files changed, 270 insertions(+), 114 deletions(-) create mode 100644 Pages/Watchlist.cshtml create mode 100644 Pages/Watchlist.cshtml.cs diff --git a/Pages/Index.cshtml b/Pages/Index.cshtml index ed6f0fb..9347543 100644 --- a/Pages/Index.cshtml +++ b/Pages/Index.cshtml @@ -1,17 +1,22 @@ @page +@using global::c3stream.DataModels @model IndexModel @{ - ViewData["Title"] = "Home"; - var cookie = c3stream.UpdateCookie(Request, Response, "/"); + ViewData["Title"] = "Home"; + var cookie = c3stream.UpdateCookie(Request, Response, "/"); + var marked = new Database.DbConn().States.Any(p => p.UserId == cookie && p.State == "marked"); }
-

Welcome to c3stream!

- Your bookmark link:
- https://@Request.Host.Value?bookmark=@cookie

-
- @foreach (var conf in c3stream.Conferences) { - @conf.Acronym - } -
+

Welcome to c3stream!

+ Your bookmark link:
+ https://@Request.Host.Value?bookmark=@cookie

+
+ @if (marked) { + watchlist + } + @foreach (var conf in c3stream.Conferences) { + @conf.Acronym + } +
\ No newline at end of file diff --git a/Pages/Watchlist.cshtml b/Pages/Watchlist.cshtml new file mode 100644 index 0000000..504ac9a --- /dev/null +++ b/Pages/Watchlist.cshtml @@ -0,0 +1,110 @@ +@page +@model WatchlistModel +@using System.Net +@using global::c3stream.DataModels +@using static WatchlistModel +@{ + var cookie = c3stream.UpdateCookie(Request, Response, $"/Watchlist"); + ViewData["Title"] = "Watchlist"; + await using var db = new Database.DbConn(); + var states = db.States.ToList(); + var marked = db.States.Where(p => p.UserId == cookie && p.State == "marked").Select(p => p.TalkId).ToList(); + var watchlist = c3stream.GetEventsByGuid(marked); +} + + + + + + + + + + + + + + + + @foreach (var talk in Request.Query["orderby"] == "published" ? watchlist.OrderByDescending(p => p.ReleaseDate) : watchlist.OrderBy(p => p.Date)) { + var state = states.FirstOrDefault(p => p.TalkId == talk.Guid && p.UserId == cookie)?.State; + var isWatched = state == "watched"; + var isMarked = state == "marked"; + var file = $"{talk.Slug}.mp4"; + var conference = c3stream.GetConferenceByEventGuid(talk.Guid); + var eventName = talk.Tags.Count <= 1 ? conference.Acronym : talk.Tags[0].Replace("-", "-
"); + var category = talk.Tags.Count switch { + 0 => "", + 1 => talk.Tags[0], + 2 => "", + 3 => talk.Tags[2], + 4 => talk.Tags[3], + 5 => talk.Tags[3], + 6 => talk.Tags[3], // rc3: is this correct? + _ => "" + }; + + + + + @if (isWatched) { + + } + else if (isMarked) { + + } + else { + + } + + + + + } + +
ConferenceEvent + @Html.Raw(Request.Query["orderby"] == "published" ? $"Published" : $"Date") + CategoryTitleSpeaker(s)LangActions
@Html.Raw(eventName)@(Request.Query["orderby"] == "published" ? talk.ReleaseDate?.Date.ToShortDateString() : talk.Date?.Date.ToShortDateString())@category@talk.Title@talk.Title@talk.Title@(talk.Persons.Any() ? talk.Persons.Aggregate((s, s1) => $"{s}, {s1}") : "")@talk.OriginalLanguage +
+ + + + @if (System.IO.File.Exists(System.IO.Path.Combine(c3stream.CachePath, conference.Acronym, file))) { + + + + } + else { + + + + } + + + + @if (isWatched) { + + + } + else if (isMarked) { + + + } + else { + + + } +
+
\ No newline at end of file diff --git a/Pages/Watchlist.cshtml.cs b/Pages/Watchlist.cshtml.cs new file mode 100644 index 0000000..8a9b367 --- /dev/null +++ b/Pages/Watchlist.cshtml.cs @@ -0,0 +1,39 @@ +using System.Collections.Generic; +using System.Linq; +using c3stream.DataModels; +using c3stream.DataModels.Tables; +using LinqToDB; +using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; + +namespace c3stream.Pages { + public class WatchlistModel : PageModel { + private readonly ILogger _logger; + + public WatchlistModel(ILogger logger) => _logger = logger; + + public void OnGet() { + var guid = Request.Query["guid"].ToString(); + var state = Request.Query["state"].ToString(); + var userid = Request.Cookies["bookmark"]; + if (string.IsNullOrWhiteSpace(guid) || string.IsNullOrWhiteSpace(state) || !Request.Cookies.ContainsKey("bookmark")) + return; + + using var db = new Database.DbConn(); + var existing = db.States.FirstOrDefault(p => p.TalkId == guid && p.UserId == userid); + if (existing != null) + if (state == "unwatched") + db.States.Delete(p => p == existing); + else { + existing.State = state; + db.Update(existing); + } + else + db.Insert(new States { + State = state, TalkId = guid, UserId = userid + }); + Response.Redirect("/"); + } + } +} \ No newline at end of file diff --git a/c3stream.cs b/c3stream.cs index a1c005b..598c146 100644 --- a/c3stream.cs +++ b/c3stream.cs @@ -9,127 +9,129 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Hosting; -namespace c3stream { - public static class c3stream { - public const string DataPath = "data"; - public const string DbFile = "c3stream.sqlite"; - public const string CachePath = "/mnt/storage/archive/Video/congress/"; - public const string CacheUrl = "https://mirror.c3stream.de/"; - public static object Lock = new(); - public static string DbPath = Path.Combine(DataPath, DbFile); +namespace c3stream; - public static readonly List Conferences = new() { - new ConferenceObject("rc3-2021", true), - new ConferenceObject("rc3"), - new ConferenceObject("36c3"), - new ConferenceObject("camp2019"), - new ConferenceObject("gpn19"), - new ConferenceObject("35c3"), - new ConferenceObject("34c3"), - new ConferenceObject("33c3"), - new ConferenceObject("32c3"), - new ConferenceObject("31c3"), - new ConferenceObject("30c3") - }; +public static class c3stream { + public const string DataPath = "data"; + public const string DbFile = "c3stream.sqlite"; + public const string CachePath = "/mnt/storage/archive/Video/congress/"; + public const string CacheUrl = "https://mirror.c3stream.de/"; + public static object Lock = new(); + public static string DbPath = Path.Combine(DataPath, DbFile); - public static void Main(string[] args) { - if (!Directory.Exists(DataPath)) - Directory.CreateDirectory(DataPath); - if (!File.Exists(DbPath)) - File.Copy(Path.Combine(DataPath, "database.init.sqlite"), DbPath); + public static readonly List Conferences = new() { + new ConferenceObject("rc3-2021", true), + new ConferenceObject("rc3"), + new ConferenceObject("36c3"), + new ConferenceObject("camp2019"), + new ConferenceObject("gpn19"), + new ConferenceObject("35c3"), + new ConferenceObject("34c3"), + new ConferenceObject("33c3"), + new ConferenceObject("32c3"), + new ConferenceObject("31c3"), + new ConferenceObject("30c3") + }; - DataConnection.DefaultSettings = new Database.Settings(); + public static void Main(string[] args) { + if (!Directory.Exists(DataPath)) + Directory.CreateDirectory(DataPath); + if (!File.Exists(DbPath)) + File.Copy(Path.Combine(DataPath, "database.init.sqlite"), DbPath); - foreach (var conference in Conferences) - UpdateConference(conference); + DataConnection.DefaultSettings = new Database.Settings(); + Migrations.RunMigrations(); - if (args.Length != 0) { - if (args[0] == "logo") - foreach (var conference in Conferences) { - Console.WriteLine($"wget {conference.LogoUri} -O {Path.Combine(CachePath, conference.Acronym, "logo.png")}"); - } - else if (Conferences.All(p => p.Acronym != args[0])) - Console.WriteLine("No matching conference found."); - else - foreach (var talk in Conferences.First(p => p.Acronym == args[0]).Talks) - Console.WriteLine($"youtube-dl -f \"best[ext = mp4]\" {talk.FrontendLink} -o \"{Path.Combine(CachePath, args[0], talk.Slug)}.mp4\""); - } - else { - CreateHostBuilder(args).Build().Run(); - } + foreach (var conference in Conferences) + UpdateConference(conference); + + if (args.Length != 0) { + if (args[0] == "logo") + foreach (var conference in Conferences) + Console.WriteLine($"wget {conference.LogoUri} -O {Path.Combine(CachePath, conference.Acronym, "logo.png")}"); + else if (Conferences.All(p => p.Acronym != args[0])) + Console.WriteLine("No matching conference found."); + else + foreach (var talk in Conferences.First(p => p.Acronym == args[0]).Talks) + Console.WriteLine($"youtube-dl -f \"best[ext = mp4]\" {talk.FrontendLink} -o \"{Path.Combine(CachePath, args[0], talk.Slug)}.mp4\""); + } + else { + CreateHostBuilder(args).Build().Run(); + } + } + + //TODO: move this to the database as well + public static void UpdateConference(ConferenceObject conference) { + using var httpc = new HttpClient(); + + var jsonpath = Path.Combine(DataPath, conference.Acronym + "_index.json"); + var json = ""; + if (!File.Exists(jsonpath)) { + json = httpc.GetStringAsync($"https://api.media.ccc.de/public/conferences/{conference.Acronym}").Result; + File.WriteAllText(jsonpath, json); + } + else if (conference.Ongoing) { + json = httpc.GetStringAsync($"https://api.media.ccc.de/public/conferences/{conference.Acronym}").Result; + } + else { + json = File.ReadAllText(jsonpath); } - //TODO: move this to the database as well - public static void UpdateConference(ConferenceObject conference) { - using var httpc = new HttpClient(); + var parsed = Conference.FromJson(json); + lock (Lock) { + conference.Talks.Clear(); + conference.LogoUri = parsed.LogoUrl.AbsoluteUri; + conference.Talks.AddRange(parsed.Events); + conference.Talks.ForEach(p => p.Guid = p.Guid.Trim()); + } + } - var jsonpath = Path.Combine(DataPath, conference.Acronym + "_index.json"); - var json = ""; - if (!File.Exists(jsonpath)) { - json = httpc.GetStringAsync($"https://api.media.ccc.de/public/conferences/{conference.Acronym}").Result; - File.WriteAllText(jsonpath, json); - } - else if (conference.Ongoing) { - json = httpc.GetStringAsync($"https://api.media.ccc.de/public/conferences/{conference.Acronym}").Result; - } - else { - json = File.ReadAllText(jsonpath); - } - - var parsed = Conference.FromJson(json); - lock (Lock) { - conference.Talks.Clear(); - conference.LogoUri = parsed.LogoUrl.AbsoluteUri; - conference.Talks.AddRange(parsed.Events); - conference.Talks.ForEach(p => p.Guid = p.Guid.Trim()); - } + public static string UpdateCookie(HttpRequest request, HttpResponse response, string redirectUri) { + var cookie = ""; + //if new bookmark is in uri + if (request.Query.ContainsKey("bookmark") && Guid.TryParseExact(request.Query["bookmark"], "D", out _)) { + response.Cookies.Append("bookmark", request.Query["bookmark"], new CookieOptions { Expires = DateTimeOffset.MaxValue }); + cookie = request.Query["bookmark"]; + } + //if no cookie exists or cookie is invalid + else if (!request.Cookies.ContainsKey("bookmark") || !Guid.TryParseExact(request.Cookies["bookmark"], "D", out _)) { + var guid = Guid.NewGuid().ToString(); + response.Cookies.Append("bookmark", guid, new CookieOptions { Expires = DateTimeOffset.MaxValue }); + cookie = guid; + } + else { + cookie = request.Cookies["bookmark"]; } - public static string UpdateCookie(HttpRequest request, HttpResponse response, string redirectUri) { - var cookie = ""; - //if new bookmark is in uri - if (request.Query.ContainsKey("bookmark") && Guid.TryParseExact(request.Query["bookmark"], "D", out _)) { - response.Cookies.Append("bookmark", request.Query["bookmark"], new CookieOptions { Expires = DateTimeOffset.MaxValue }); - cookie = request.Query["bookmark"]; - } - //if no cookie exists or cookie is invalid - else if (!request.Cookies.ContainsKey("bookmark") || !Guid.TryParseExact(request.Cookies["bookmark"], "D", out _)) { - var guid = Guid.NewGuid().ToString(); - response.Cookies.Append("bookmark", guid, new CookieOptions { Expires = DateTimeOffset.MaxValue }); - cookie = guid; - } - else { - cookie = request.Cookies["bookmark"]; - } + if (request.Query.ContainsKey("bookmark")) + response.Redirect(redirectUri); - if (request.Query.ContainsKey("bookmark")) { - response.Redirect(redirectUri); - } + return cookie; + } - return cookie; - } + public static Event GetEventByGuid(string guid) { + return Conferences.SelectMany(c => c.Talks.Where(e => e.Guid == guid)).FirstOrDefault(); + } - public static Event GetEventByGuid(string guid) { - return Conferences.SelectMany(c => c.Talks.Where(talk => talk.Guid.ToString() == guid)).FirstOrDefault(); - } + public static IEnumerable GetEventsByGuid(IEnumerable guids) { + return Conferences.SelectMany(c => c.Talks.Where(e => guids.Contains(e.Guid))); + } - public static ConferenceObject GetConferenceByEventGuid(string guid) { - return Conferences.FirstOrDefault(c => c.Talks.Any(t => t.Guid.ToString() == guid)); - } + public static ConferenceObject GetConferenceByEventGuid(string guid) { + return Conferences.FirstOrDefault(c => c.Talks.Any(t => t.Guid == guid)); + } - public static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); + public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); - public class ConferenceObject { - public string Acronym; - public bool Ongoing; - public string LogoUri; - public List Talks = new(); + public class ConferenceObject { + public string Acronym; + public string LogoUri; + public bool Ongoing; + public List Talks = new(); - public ConferenceObject(string acronym, bool ongoing = false) { - Acronym = acronym; - Ongoing = ongoing; - } + public ConferenceObject(string acronym, bool ongoing = false) { + Acronym = acronym; + Ongoing = ongoing; } } } \ No newline at end of file