v4 rework
This commit is contained in:
parent
79bcc27257
commit
9fe898f282
|
@ -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>
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
|
@ -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 = "<missing description>";
|
||||
}
|
||||
|
||||
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>
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
4
Types.cs
4
Types.cs
|
@ -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; }
|
||||
|
|
63
c3stream.cs
63
c3stream.cs
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue