v4 rework

This commit is contained in:
Laura Hausmann 2020-01-04 14:23:52 +01:00
parent 79bcc27257
commit 9fe898f282
7 changed files with 125 additions and 131 deletions

View file

@ -3,30 +3,16 @@
@using System.Net
@using static ConferenceModel
@{
int tagFormat;
switch (Request.Query["c"]) {
case "36c3":
tagFormat = 2;
break;
case "35c3":
case "34c3":
tagFormat = 1;
break;
case "33c3":
tagFormat = 0;
break;
default:
Response.Redirect("/");
return;
if (c3stream.Conferences.All(c => c.Acronym != Request.Query["c"])) {
Response.Redirect("/");
return;
}
c3stream.UpdateCookie(Request, Response, $"/Conference?c={Request.Query["c"]}&");
ReadUserData();
ViewData["Title"] = Request.Query["c"];
var wc = new WebClient();
var jsonpath = System.IO.Path.Combine(c3stream.DataPath, Request.Query["c"] + ".json");
var json = System.IO.File.Exists(jsonpath) ? System.IO.File.ReadAllText(jsonpath) : wc.DownloadString($"https://api.media.ccc.de/public/conferences/{Request.Query["c"]}");
var conference = Conference.FromJson(json);
var conference = c3stream.Conferences.First(c => c.Acronym == Request.Query["c"]);
wc.Dispose();
}
@ -44,20 +30,14 @@
</tr>
</thead>
<tbody>
@foreach (var talk in Request.Query["orderby"] == "published" ? conference.Events.OrderByDescending(p => p.ReleaseDate) : conference.Events.OrderBy(p => p.Date)) {
TalkMetadata metadata;
if (EventMetadata.Any(p => p.Guid == talk.Guid?.ToString())) {
metadata = EventMetadata.First(p => p.Guid == talk.Guid?.ToString());
}
else {
metadata = GetEvent(talk.Guid?.ToString());
EventMetadata.Add(metadata);
}
var isWatched = EventMetadata.Any(p => p.Guid == talk.Guid?.ToString() && p.State.FirstOrDefault(q => q.Guid == Request.Cookies["bookmark"])?.State == "watched");
var isMarked = EventMetadata.Any(p => p.Guid == talk.Guid?.ToString() && p.State.FirstOrDefault(q => q.Guid == Request.Cookies["bookmark"])?.State == "marked");
var file = metadata.Talk.Recordings.FirstOrDefault(p => System.IO.File.Exists(System.IO.Path.Combine(c3stream.CachePath, conference.Acronym, p.Filename)));
var eventName = tagFormat == 0 ? conference.Acronym : talk.Tags[0].Replace("-", "-<br/>");
var category = tagFormat switch {
@foreach (var talk in Request.Query["orderby"] == "published" ? conference.Talks.OrderByDescending(p => p.ReleaseDate) : conference.Talks.OrderBy(p => p.Date)) {
var state = UserData.FirstOrDefault(p => p.TalkId == talk.Guid && p.UserId == Request.Cookies["bookmark"])?.State;
var isWatched = state == "watched";
var isMarked = state == "marked";
var file = $"{talk.Slug}.mp4";
var tagV = c3stream.Conferences.First(c => c.Acronym == Request.Query["c"]).TagVersion;
var eventName = tagV == 0 ? conference.Acronym : talk.Tags[0].Replace("-", "-<br/>");
var category = tagV switch {
0 => talk.Tags[0],
1 => talk.Tags[2],
2 => talk.Tags[3],
@ -83,8 +63,8 @@
<a href="@talk.FrontendLink.AbsoluteUri" target="_blank" type="button" class="btn btn-primary w-100" data-toggle="tooltip" data-placement="top" title="Play">
<i class="fas fa-play-circle"></i>
</a>
@if (file != null) {
<a href="@(c3stream.CacheUrl + $"{conference.Acronym}/{file.Filename}")" target="_blank" type="button" class="btn btn-primary w-100" data-toggle="tooltip" data-placement="top" title="Mirror">
@if (System.IO.File.Exists(System.IO.Path.Combine(c3stream.CachePath, conference.Acronym, file))) {
<a href="@(c3stream.CacheUrl + $"{conference.Acronym}/{file}")" target="_blank" type="button" class="btn btn-primary w-100" data-toggle="tooltip" data-placement="top" title="Mirror">
<i class="fas fa-cloud-download"></i>
</a>
}

View file

@ -1,80 +1,58 @@
using System.Collections.Generic;
using System.Linq;
using System.Net;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace c3stream.Pages {
public class ConferenceModel : PageModel {
public static List<TalkMetadata> EventMetadata = new List<TalkMetadata>();
public static List<UserStatus> UserData = new List<UserStatus>();
private readonly ILogger<ConferenceModel> _logger;
public ConferenceModel(ILogger<ConferenceModel> logger) => _logger = logger;
public void OnGet() {
var guid = Request.Query["guid"];
var state = Request.Query["state"];
var guid = Request.Query["guid"];
var state = Request.Query["state"];
var userid = Request.Cookies["bookmark"];
if (string.IsNullOrWhiteSpace(guid) || string.IsNullOrWhiteSpace(state) || !Request.Cookies.ContainsKey("bookmark"))
return;
lock (c3stream.Lock) {
ReadEventMetadata();
var existing = EventMetadata.FirstOrDefault(p => p.Guid == guid)?.State.FirstOrDefault(p => p.Guid == Request.Cookies["bookmark"]);
ReadUserData();
var existing = UserData.FirstOrDefault(p => p.TalkId == guid && p.UserId == userid);
if (existing != null)
existing.State = state;
if (state == "unwatched")
UserData.Remove(existing);
else
existing.State = state;
else
EventMetadata.FirstOrDefault(p => p.Guid == guid)?.State.Add(new UserState(Request.Cookies["bookmark"], state));
WriteEventMetadata();
UserData.Add(new UserStatus(userid, guid, state));
WriteUserData();
Response.Redirect("/");
}
}
public static TalkMetadata GetEvent(string guid) {
TalkMetadata metadata;
lock (c3stream.Lock) {
ReadEventMetadata();
using (var wc = new WebClient()) {
var json = wc.DownloadString($"https://api.media.ccc.de/public/events/{guid}");
var talk = Talk.FromJson(json);
metadata = new TalkMetadata(guid, talk);
EventMetadata.Add(metadata);
}
WriteEventMetadata();
}
return metadata;
}
public static void ReadEventMetadata() {
public static void ReadUserData() {
lock (c3stream.Lock)
EventMetadata = JsonConvert.DeserializeObject<List<TalkMetadata>>(System.IO.File.ReadAllText(c3stream.DbPath));
UserData = JsonConvert.DeserializeObject<List<UserStatus>>(System.IO.File.ReadAllText(c3stream.DbPath));
}
public static void WriteEventMetadata() {
System.IO.File.WriteAllText(c3stream.DbPath, JsonConvert.SerializeObject(EventMetadata));
}
public class TalkMetadata {
public readonly string Guid;
public List<UserState> State;
public Talk Talk;
public TalkMetadata(string guid, Talk talk) {
Guid = guid;
State = new List<UserState>();
Talk = talk;
public static void WriteUserData() {
lock (c3stream.Lock) {
System.IO.File.WriteAllText(c3stream.DbPath, JsonConvert.SerializeObject(UserData));
}
}
public class UserState {
public string Guid;
public string State;
public class UserStatus {
public readonly string TalkId;
public readonly string UserId;
public string State;
public UserState(string guid, string state = "unwatched") {
Guid = guid;
State = state;
public UserStatus(string userId, string talkId, string state = "unwatched") {
UserId = userId;
State = state;
TalkId = talkId;
}
}
}

View file

@ -2,7 +2,7 @@
@model IndexModel
@{
ViewData["Title"] = "Home";
c3stream.UpdateCookie(Request, Response, $"/?");
c3stream.UpdateCookie(Request, Response, "/?");
}
<div style="text-align: center">
@ -10,9 +10,8 @@
Your bookmark link:<br/>
<code onclick="copyToClipboard(this)">https://@Request.Host.Value?bookmark=@Request.Cookies["bookmark"]</code><br/><br/>
<div class="btn-group">
<a type="button" class="btn btn-primary" href="/Conference?c=36c3&bookmark=@Request.Cookies["bookmark"]">36c3</a>
<a type="button" class="btn btn-primary" href="/Conference?c=35c3&bookmark=@Request.Cookies["bookmark"]">35c3</a>
<a type="button" class="btn btn-primary" href="/Conference?c=34c3&bookmark=@Request.Cookies["bookmark"]">34c3</a>
<a type="button" class="btn btn-primary" href="/Conference?c=33c3&bookmark=@Request.Cookies["bookmark"]">33c3</a>
@foreach (var conf in c3stream.Conferences) {
<a type="button" class="btn btn-primary" href="/Conference?c=@conf.Acronym&bookmark=@Request.Cookies["bookmark"]">@conf.Acronym</a>
}
</div>
</div>

View file

@ -4,53 +4,41 @@
ViewData["Title"] = "Info";
}
@{
if (string.IsNullOrWhiteSpace(Request.Query["guid"])) {
if (string.IsNullOrWhiteSpace(Request.Query["guid"]) || c3stream.GetEventByGuid(Request.Query["guid"]) == null) {
Response.Redirect("/");
return;
}
c3stream.UpdateCookie(Request, Response, $"/Info?guid={Request.Query["guid"]}&");
ConferenceModel.ReadEventMetadata();
var talk = ConferenceModel.EventMetadata.FirstOrDefault(p => p.Guid == Request.Query["guid"]);
ConferenceModel.ReadUserData();
var talk = c3stream.GetEventByGuid(Request.Query["guid"]);
var state = ConferenceModel.UserData.FirstOrDefault(p => p.TalkId == Request.Query["guid"] && p.UserId == Request.Cookies["bookmark"])?.State;
if (talk == null) {
Response.Redirect("/");
return;
}
if (state == null) {
state = "unwatched";
}
var title = talk.Talk.Title;
var speakers = talk.Talk.Persons.Aggregate((s, s1) => $"{s}, {s1}");
var description = talk.Talk.Description;
var title = talk.Title;
var speakers = talk.Persons.Aggregate((s, s1) => $"{s}, {s1}");
var description = talk.Description;
if (string.IsNullOrEmpty(description)) {
description = "&lt;missing description&gt;";
}
var isWatched = talk.State.FirstOrDefault(q => q.Guid == Request.Cookies["bookmark"])?.State == "watched";
var isMarked = talk.State.FirstOrDefault(q => q.Guid == Request.Cookies["bookmark"])?.State == "marked";
var file = talk.Talk.Recordings.FirstOrDefault(p => System.IO.File.Exists(System.IO.Path.Combine(c3stream.CachePath, talk.Talk.ConferenceUrl.AbsoluteUri.Split("/").Last(), p.Filename)));
var eventName = talk.Talk.Tags[0].Replace("-", "-<br/>");
var isWatched = state == "watched";
var isMarked = state == "marked";
var file = $"{talk.Slug}.mp4";
var conference = c3stream.GetConferenceByEventGuid(talk.Guid);
var eventName = talk.Tags[0].Replace("-", "-<br/>");
int tagFormat;
switch (talk.Talk.ConferenceUrl.AbsoluteUri.Split("/").Last()) {
case "36c3":
tagFormat = 2;
break;
case "35c3":
case "34c3":
tagFormat = 1;
break;
case "33c3":
tagFormat = 0;
break;
default:
Response.Redirect("/");
return;
}
var category = tagFormat switch {
0 => talk.Talk.Tags[0],
1 => talk.Talk.Tags[2],
2 => talk.Talk.Tags[3],
var category = c3stream.GetConferenceByEventGuid(Request.Query["guid"]).TagVersion switch {
0 => talk.Tags[0],
1 => talk.Tags[2],
2 => talk.Tags[3],
_ => ""
};
}
@ -66,11 +54,11 @@ else {
}
<div class="btn-group" role="group" style="margin-bottom: 10px">
<a href="@talk.Talk.FrontendLink.AbsoluteUri" target="_blank" type="button" class="btn btn-primary w-100" data-toggle="tooltip" data-placement="right" title="Play">
<a href="@talk.FrontendLink.AbsoluteUri" target="_blank" type="button" class="btn btn-primary w-100" data-toggle="tooltip" data-placement="right" title="Play">
<i class="fas fa-play-circle"></i>
</a>
@if (file != null) {
<a href="@(c3stream.CacheUrl + $"{talk.Talk.ConferenceUrl.AbsoluteUri.Split("/").Last()}/{file.Filename}")" target="_blank" type="button" class="btn btn-primary w-100" data-toggle="tooltip" data-placement="right" title="Mirror">
@if (System.IO.File.Exists(System.IO.Path.Combine(c3stream.CachePath, conference.Acronym, file))) {
<a href="@(c3stream.CacheUrl + $"{conference.Acronym}/{file}")" target="_blank" type="button" class="btn btn-primary w-100" data-toggle="tooltip" data-placement="right" title="Mirror">
<i class="fas fa-cloud-download"></i>
</a>
}

View file

@ -12,7 +12,7 @@
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container-fluid" style="width: 90%">
<a class="navbar-brand" asp-area="" asp-page="/Index">c3stream</a>
<a class="navbar-brand" asp-area="" asp-page="/Index">c3stream <small style="font-size: x-small">v4</small></a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>

View file

@ -56,7 +56,7 @@ namespace c3stream {
public class Event {
[JsonProperty("guid", NullValueHandling = NullValueHandling.Ignore)]
public Guid? Guid { get; set; }
public string Guid { get; set; }
[JsonProperty("title", NullValueHandling = NullValueHandling.Ignore)]
public string Title { get; set; }
@ -144,7 +144,7 @@ namespace c3stream {
public partial class Talk {
[JsonProperty("guid", NullValueHandling = NullValueHandling.Ignore)]
public Guid? Guid { get; set; }
public string Guid { get; set; }
[JsonProperty("title", NullValueHandling = NullValueHandling.Ignore)]
public string Title { get; set; }

View file

@ -1,5 +1,8 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using c3stream.Pages;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
@ -7,18 +10,43 @@ using Microsoft.Extensions.Hosting;
namespace c3stream {
public static class c3stream {
public const string DataPath = "data";
public const string DbFile = "_c3stream.json";
public const string CachePath = "/mnt/storage/archive/Video/congress/";
public const string CacheUrl = "https://mirror.c3stream.de/";
public static object Lock = new object();
public static string DbPath = Path.Combine(DataPath, DbFile);
public const string DataPath = "data";
public const string DbFile = "c3stream.user.json";
public const string CachePath = "/mnt/storage/archive/Video/congress/";
public const string CacheUrl = "https://mirror.c3stream.de/";
public static object Lock = new object();
public static string DbPath = Path.Combine(DataPath, DbFile);
public static List<ConferenceObject> Conferences = new List<ConferenceObject> {
new ConferenceObject("36c3", 2, true),
new ConferenceObject("35c3", 1),
new ConferenceObject("34c3", 1),
new ConferenceObject("33c3"),
new ConferenceObject("32c3"),
};
public static void Main(string[] args) {
if (!Directory.Exists(DataPath))
Directory.CreateDirectory(DataPath);
if (!File.Exists(DbPath))
ConferenceModel.WriteEventMetadata();
ConferenceModel.WriteUserData();
using var wc = new WebClient();
foreach (var conference in Conferences) {
var jsonpath = Path.Combine(DataPath, conference.Acronym + "_index.json");
var json = "";
if (conference.Ongoing || !File.Exists(jsonpath)) {
json = wc.DownloadString($"https://api.media.ccc.de/public/conferences/{conference.Acronym}");
File.WriteAllText(jsonpath, json);
}
else {
json = File.ReadAllText(jsonpath);
}
var parsed = Conference.FromJson(json);
conference.Talks.AddRange(parsed.Events);
}
CreateHostBuilder(args).Build().Run();
}
@ -40,7 +68,28 @@ namespace c3stream {
}
}
public static Event GetEventByGuid(string guid) {
return Conferences.SelectMany(c => c.Talks.Where(talk => talk.Guid.ToString() == guid)).FirstOrDefault();
}
public static ConferenceObject GetConferenceByEventGuid(string guid) {
return Conferences.FirstOrDefault(c => c.Talks.Any(t => t.Guid.ToString() == guid));
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
public class ConferenceObject {
public string Acronym;
public bool Ongoing;
public int TagVersion;
public List<Event> Talks = new List<Event>();
public ConferenceObject(string acronym, int tagVersion = 0, bool ongoing = false) {
Acronym = acronym;
TagVersion = tagVersion;
Ongoing = ongoing;
}
}
}
}