migrate to database storage, fix css goofs

This commit is contained in:
Laura Hausmann 2020-12-28 17:05:29 +01:00
parent c90ebab27c
commit 5971c8ff5d
Signed by: zotan
GPG Key ID: 5EC1D38FFC321311
10 changed files with 211 additions and 103 deletions

View File

@ -5,6 +5,12 @@
<e p="$USER_HOME$/.cache/JetBrains/Rider2020.3/resharper-host/local/Transient/Rider/v203/SolutionCaches/_c3stream.-187536235.00" t="ExcludeRecursive" />
<e p="$PROJECT_DIR$" t="IncludeRecursive">
<e p=".gitignore" t="Include" />
<e p="DataModels" t="Include">
<e p="Database.cs" t="Include" />
<e p="Tables" t="Include">
<e p="States.cs" t="Include" />
</e>
</e>
<e p="LICENSE" t="Include" />
<e p="Pages" t="Include">
<e p="Conference.cshtml" t="Include" />
@ -37,13 +43,15 @@
<e p="c3stream.csproj" t="IncludeRecursive" />
<e p="c3stream.sln" t="IncludeFlat" />
<e p="obj" t="ExcludeRecursive">
<e p="x64" t="Include">
<e p="Debug" t="Include">
<e p="netcoreapp3.1" t="Include">
<e p="net50" t="Include">
<e p="c3stream.AssemblyInfo.cs" t="Include" />
<e p="c3stream.RazorAssemblyInfo.cs" t="Include" />
</e>
</e>
</e>
</e>
<e p="packages" t="ExcludeRecursive" />
<e p="wwwroot" t="Include">
<e p="css" t="Include">
@ -108,31 +116,86 @@
</e>
</e>
<e p="webfonts" t="Include">
<e p="fa-brands-400.eot" t="Include" />
<e p="fa-brands-400.svg" t="Include" />
<e p="fa-brands-400.ttf" t="Include" />
<e p="fa-brands-400.woff" t="Include" />
<e p="fa-brands-400.woff2" t="Include" />
<e p="fa-duotone-900.eot" t="Include" />
<e p="fa-duotone-900.svg" t="Include" />
<e p="fa-duotone-900.ttf" t="Include" />
<e p="fa-duotone-900.woff" t="Include" />
<e p="fa-duotone-900.woff2" t="Include" />
<e p="fa-light-300.eot" t="Include" />
<e p="fa-light-300.svg" t="Include" />
<e p="fa-light-300.ttf" t="Include" />
<e p="fa-light-300.woff" t="Include" />
<e p="fa-light-300.woff2" t="Include" />
<e p="fa-regular-400.eot" t="Include" />
<e p="fa-regular-400.svg" t="Include" />
<e p="fa-regular-400.ttf" t="Include" />
<e p="fa-regular-400.woff" t="Include" />
<e p="fa-regular-400.woff2" t="Include" />
<e p="fa-solid-900.eot" t="Include" />
<e p="fa-solid-900.svg" t="Include" />
<e p="fa-solid-900.ttf" t="Include" />
<e p="fa-solid-900.woff" t="Include" />
<e p="fa-solid-900.woff2" t="Include" />
<e p="pro-fa-brands-400-5.0.0.woff2" t="Include" />
<e p="pro-fa-brands-400-5.12.0.woff2" t="Include" />
<e p="pro-fa-brands-400-5.3.0.woff2" t="Include" />
<e p="pro-fa-brands-400-5.8.0.woff2" t="Include" />
<e p="pro-fa-duotone-900-5.0.0.woff2" t="Include" />
<e p="pro-fa-duotone-900-5.0.10.woff2" t="Include" />
<e p="pro-fa-duotone-900-5.0.11.woff2" t="Include" />
<e p="pro-fa-duotone-900-5.0.13.woff2" t="Include" />
<e p="pro-fa-duotone-900-5.0.3.woff2" t="Include" />
<e p="pro-fa-duotone-900-5.0.5.woff2" t="Include" />
<e p="pro-fa-duotone-900-5.0.7.woff2" t="Include" />
<e p="pro-fa-duotone-900-5.0.9.woff2" t="Include" />
<e p="pro-fa-duotone-900-5.1.0.woff2" t="Include" />
<e p="pro-fa-duotone-900-5.10.1.woff2" t="Include" />
<e p="pro-fa-duotone-900-5.10.2.woff2" t="Include" />
<e p="pro-fa-duotone-900-5.11.0.woff2" t="Include" />
<e p="pro-fa-duotone-900-5.11.1.woff2" t="Include" />
<e p="pro-fa-duotone-900-5.12.0.woff2" t="Include" />
<e p="pro-fa-duotone-900-5.2.0.woff2" t="Include" />
<e p="pro-fa-duotone-900-5.3.0.woff2" t="Include" />
<e p="pro-fa-duotone-900-5.4.0.woff2" t="Include" />
<e p="pro-fa-duotone-900-5.8.0.woff2" t="Include" />
<e p="pro-fa-duotone-900-5.9.0.woff2" t="Include" />
<e p="pro-fa-light-300-5.0.0.woff2" t="Include" />
<e p="pro-fa-light-300-5.0.10.woff2" t="Include" />
<e p="pro-fa-light-300-5.0.11.woff2" t="Include" />
<e p="pro-fa-light-300-5.0.13.woff2" t="Include" />
<e p="pro-fa-light-300-5.0.3.woff2" t="Include" />
<e p="pro-fa-light-300-5.0.5.woff2" t="Include" />
<e p="pro-fa-light-300-5.0.7.woff2" t="Include" />
<e p="pro-fa-light-300-5.0.9.woff2" t="Include" />
<e p="pro-fa-light-300-5.1.0.woff2" t="Include" />
<e p="pro-fa-light-300-5.10.1.woff2" t="Include" />
<e p="pro-fa-light-300-5.10.2.woff2" t="Include" />
<e p="pro-fa-light-300-5.11.0.woff2" t="Include" />
<e p="pro-fa-light-300-5.11.1.woff2" t="Include" />
<e p="pro-fa-light-300-5.12.0.woff2" t="Include" />
<e p="pro-fa-light-300-5.2.0.woff2" t="Include" />
<e p="pro-fa-light-300-5.3.0.woff2" t="Include" />
<e p="pro-fa-light-300-5.4.0.woff2" t="Include" />
<e p="pro-fa-light-300-5.8.0.woff2" t="Include" />
<e p="pro-fa-light-300-5.9.0.woff2" t="Include" />
<e p="pro-fa-regular-400-5.0.0.woff2" t="Include" />
<e p="pro-fa-regular-400-5.0.10.woff2" t="Include" />
<e p="pro-fa-regular-400-5.0.11.woff2" t="Include" />
<e p="pro-fa-regular-400-5.0.13.woff2" t="Include" />
<e p="pro-fa-regular-400-5.0.3.woff2" t="Include" />
<e p="pro-fa-regular-400-5.0.5.woff2" t="Include" />
<e p="pro-fa-regular-400-5.0.7.woff2" t="Include" />
<e p="pro-fa-regular-400-5.0.9.woff2" t="Include" />
<e p="pro-fa-regular-400-5.1.0.woff2" t="Include" />
<e p="pro-fa-regular-400-5.10.1.woff2" t="Include" />
<e p="pro-fa-regular-400-5.10.2.woff2" t="Include" />
<e p="pro-fa-regular-400-5.11.0.woff2" t="Include" />
<e p="pro-fa-regular-400-5.11.1.woff2" t="Include" />
<e p="pro-fa-regular-400-5.12.0.woff2" t="Include" />
<e p="pro-fa-regular-400-5.2.0.woff2" t="Include" />
<e p="pro-fa-regular-400-5.3.0.woff2" t="Include" />
<e p="pro-fa-regular-400-5.4.0.woff2" t="Include" />
<e p="pro-fa-regular-400-5.8.0.woff2" t="Include" />
<e p="pro-fa-regular-400-5.9.0.woff2" t="Include" />
<e p="pro-fa-solid-900-5.0.0.woff2" t="Include" />
<e p="pro-fa-solid-900-5.0.11.woff2" t="Include" />
<e p="pro-fa-solid-900-5.0.13.woff2" t="Include" />
<e p="pro-fa-solid-900-5.0.3.woff2" t="Include" />
<e p="pro-fa-solid-900-5.0.5.woff2" t="Include" />
<e p="pro-fa-solid-900-5.0.7.woff2" t="Include" />
<e p="pro-fa-solid-900-5.0.9.woff2" t="Include" />
<e p="pro-fa-solid-900-5.1.0.woff2" t="Include" />
<e p="pro-fa-solid-900-5.10.1.woff2" t="Include" />
<e p="pro-fa-solid-900-5.10.2.woff2" t="Include" />
<e p="pro-fa-solid-900-5.11.0.woff2" t="Include" />
<e p="pro-fa-solid-900-5.11.1.woff2" t="Include" />
<e p="pro-fa-solid-900-5.12.0.woff2" t="Include" />
<e p="pro-fa-solid-900-5.12.1.woff2" t="Include" />
<e p="pro-fa-solid-900-5.2.0.woff2" t="Include" />
<e p="pro-fa-solid-900-5.3.0.woff2" t="Include" />
<e p="pro-fa-solid-900-5.4.0.woff2" t="Include" />
<e p="pro-fa-solid-900-5.8.0.woff2" t="Include" />
<e p="pro-fa-solid-900-5.9.0.woff2" t="Include" />
</e>
</e>
</e>

34
DataModels/Database.cs Normal file
View File

@ -0,0 +1,34 @@
using System.Collections.Generic;
using System.Linq;
using c3stream.DataModels.Tables;
using LinqToDB;
using LinqToDB.Configuration;
using LinqToDB.Data;
namespace c3stream.DataModels {
public class Database {
public class ConnectionStringSettings : IConnectionStringSettings {
public string ConnectionString { get; set; }
public string Name { get; set; }
public string ProviderName { get; set; }
public bool IsGlobal => false;
}
public class Settings : ILinqToDBSettings {
public IEnumerable<IDataProviderSettings> DataProviders => Enumerable.Empty<IDataProviderSettings>();
public string DefaultConfiguration => "SQLite";
public string DefaultDataProvider => "SQLite";
public IEnumerable<IConnectionStringSettings> ConnectionStrings {
get { yield return new ConnectionStringSettings {Name = "db", ProviderName = "SQLite", ConnectionString = @"Data Source=data/c3stream.sqlite;"}; }
}
}
public class DbConn : DataConnection {
public DbConn() : base("db") { }
public ITable<States> States => GetTable<States>();
}
}
}

View File

@ -0,0 +1,10 @@
using LinqToDB.Mapping;
namespace c3stream.DataModels.Tables {
[Table(Name = "States")]
public class States {
[Column(Name = "TalkId"), PrimaryKey, NotNull] public string TalkId { get; set; }
[Column(Name = "UserId"), PrimaryKey, NotNull] public string UserId { get; set; }
[Column(Name = "State"), NotNull] public string State { get; set; }
}
}

View File

@ -1,6 +1,7 @@
@page
@model ConferenceModel
@using System.Net
@using global::c3stream.DataModels
@using static ConferenceModel
@{
if (c3stream.Conferences.All(c => c.Acronym != Request.Query["c"])) {
@ -9,7 +10,6 @@
}
c3stream.UpdateCookie(Request, Response, $"/Conference?c={Request.Query["c"]}");
ReadUserData();
ViewData["Title"] = Request.Query["c"];
var wc = new WebClient();
var conference = c3stream.Conferences.First(c => c.Acronym == Request.Query["c"]);
@ -17,6 +17,8 @@
c3stream.UpdateConference(conference);
}
wc.Dispose();
await using var db = new Database.DbConn();
var states = db.States.ToList();
}
<table class="table">
@ -34,7 +36,7 @@
</thead>
<tbody>
@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 state = states.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";
@ -66,43 +68,43 @@
<td>@talk.OriginalLanguage</td>
<td>
<div class="btn-group" role="group">
<a href="@talk.FrontendLink.AbsoluteUri" role="button" class="btn btn-primary w-100" data-toggle="tooltip" data-placement="top" title="Play">
<a href="@talk.FrontendLink.AbsoluteUri" role="button" class="btn btn-primary btn-c3saction w-100" data-toggle="tooltip" data-placement="top" title="Play">
<i class="fas fa-play-circle"></i>
</a>
@if (System.IO.File.Exists(System.IO.Path.Combine(c3stream.CachePath, conference.Acronym, file))) {
<a href="@(c3stream.CacheUrl + $"{conference.Acronym}/{file}")" role="button" class="btn btn-primary w-100" data-toggle="tooltip" data-placement="top" title="Mirror">
<a href="@(c3stream.CacheUrl + $"{conference.Acronym}/{file}")" role="button" class="btn btn-primary btn-c3saction w-100" data-toggle="tooltip" data-placement="top" title="Mirror">
<i class="fas fa-cloud-download"></i>
</a>
}
else {
<a href="/" role="button" class="btn btn-primary disabled">
<a href="/" role="button" class="btn btn-primary btn-c3saction disabled">
<i class="fas fa-cloud-download"></i>
</a>
}
<a href="/Info?guid=@talk.Guid" role="button" class="btn btn-primary w-100" data-toggle="tooltip" data-placement="top" title="Info">
<a href="/Info?guid=@talk.Guid" role="button" class="btn btn-primary btn-c3saction w-100" data-toggle="tooltip" data-placement="top" title="Info">
<i class="fas fa-info-circle"></i>
</a>
@if (isWatched) {
<button onclick="SetState('@talk.Guid', 'unwatched')" class="btn btn-primary w-100" data-toggle="tooltip" data-placement="top" title="Mark unwatched">
<button onclick="SetState('@talk.Guid', 'unwatched')" class="btn btn-primary btn-c3saction w-100" data-toggle="tooltip" data-placement="top" title="Mark unwatched">
<i class="fas fa-times"></i>
</button>
<button class="btn btn-primary disabled">
<button class="btn btn-primary btn-c3saction disabled">
<i class="fas fa-clock"></i>
</button>
}
else if (isMarked) {
<button onclick="SetState('@talk.Guid', 'watched')" class="btn btn-primary w-100" data-toggle="tooltip" data-placement="top" title="Mark watched">
<button onclick="SetState('@talk.Guid', 'watched')" class="btn btn-primary btn-c3saction w-100" data-toggle="tooltip" data-placement="top" title="Mark watched">
<i class="fas fa-check"></i>
</button>
<button onclick="SetState('@talk.Guid', 'unwatched')" class="btn btn-primary w-100" data-toggle="tooltip" data-placement="top" title="Remove from watch later">
<button onclick="SetState('@talk.Guid', 'unwatched')" class="btn btn-primary btn-c3saction w-100" data-toggle="tooltip" data-placement="top" title="Remove from watch later">
<i class="fas fa-undo-alt"></i>
</button>
}
else {
<button onclick="SetState('@talk.Guid', 'watched')" class="btn btn-primary w-100" data-toggle="tooltip" data-placement="top" title="Mark watched">
<button onclick="SetState('@talk.Guid', 'watched')" class="btn btn-primary btn-c3saction w-100" data-toggle="tooltip" data-placement="top" title="Mark watched">
<i class="fas fa-check"></i>
</button>
<button onclick="SetState('@talk.Guid', 'marked')" class="btn btn-primary w-100" data-toggle="tooltip" data-placement="top" title="Add to watch later">
<button onclick="SetState('@talk.Guid', 'marked')" class="btn btn-primary btn-c3saction w-100" data-toggle="tooltip" data-placement="top" title="Add to watch later">
<i class="fas fa-clock"></i>
</button>
}

View File

@ -1,58 +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 ConferenceModel : PageModel {
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"].ToString();
var state = Request.Query["state"].ToString();
var userid = Request.Cookies["bookmark"];
if (string.IsNullOrWhiteSpace(guid) || string.IsNullOrWhiteSpace(state) || !Request.Cookies.ContainsKey("bookmark"))
return;
lock (c3stream.Lock) {
ReadUserData();
var existing = UserData.FirstOrDefault(p => p.TalkId == guid && p.UserId == userid);
using var db = new Database.DbConn();
var existing = db.States.FirstOrDefault(p => p.TalkId == guid && p.UserId == userid);
if (existing != null)
if (state == "unwatched")
UserData.Remove(existing);
else
db.States.Delete(p => p == existing);
else {
existing.State = state;
db.Update(existing);
}
else
UserData.Add(new UserStatus(userid, guid, state));
WriteUserData();
db.Insert(new States {
State = state, TalkId = guid, UserId = userid
});
Response.Redirect("/");
}
}
public static void ReadUserData() {
lock (c3stream.Lock)
UserData = JsonConvert.DeserializeObject<List<UserStatus>>(System.IO.File.ReadAllText(c3stream.DbPath));
}
public static void WriteUserData() {
lock (c3stream.Lock)
System.IO.File.WriteAllText(c3stream.DbPath, JsonConvert.SerializeObject(UserData));
}
public class UserStatus {
public readonly string TalkId;
public readonly string UserId;
public string State;
public UserStatus(string userId, string talkId, string state = "unwatched") {
UserId = userId;
State = state;
TalkId = talkId;
}
}
}
}

View File

@ -1,4 +1,5 @@
@page
@using global::c3stream.DataModels
@model InfoModel
@{
ViewData["Title"] = "Info";
@ -11,9 +12,10 @@
c3stream.UpdateCookie(Request, Response, $"/Info?guid={Request.Query["guid"]}");
ConferenceModel.ReadUserData();
await using var db = new Database.DbConn();
var talk = c3stream.GetEventByGuid(Request.Query["guid"]);
var state = ConferenceModel.UserData.FirstOrDefault(p => p.TalkId == Request.Query["guid"] && p.UserId == Request.Cookies["bookmark"])?.State;
var state = db.States.FirstOrDefault(p => p.TalkId == Request.Query["guid"].ToString() && p.UserId == Request.Cookies["bookmark"])?.State;
if (talk == null) {
Response.Redirect("/");
return;
@ -44,6 +46,7 @@
3 => talk.Tags[2],
4 => talk.Tags[3],
5 => talk.Tags[3],
6 => talk.Tags[3], // rc3: is this correct?
_ => "<unknown tag format>"
};
}
@ -67,40 +70,40 @@ else {
<h5>@eventName - @category - @talk.Date?.Date.ToShortDateString()</h5>
<div class="btn-group" role="group" style="margin-bottom: 10px">
<a href="@talk.FrontendLink.AbsoluteUri" role="button" class="btn btn-primary w-100" data-toggle="tooltip" data-placement="right" title="Play">
<a href="@talk.FrontendLink.AbsoluteUri" role="button" class="btn btn-primary btn-c3saction w-100" data-toggle="tooltip" data-placement="right" title="Play">
<i class="fas fa-play-circle"></i>
</a>
@if (System.IO.File.Exists(System.IO.Path.Combine(c3stream.CachePath, conference.Acronym, file))) {
<a href="@(c3stream.CacheUrl + $"{conference.Acronym}/{file}")" role="button" class="btn btn-primary w-100" data-toggle="tooltip" data-placement="right" title="Mirror">
<a href="@(c3stream.CacheUrl + $"{conference.Acronym}/{file}")" role="button" class="btn btn-primary btn-c3saction w-100" data-toggle="tooltip" data-placement="right" title="Mirror">
<i class="fas fa-cloud-download"></i>
</a>
}
else {
<a href="/" role="button" class="btn btn-primary disabled">
<a href="/" role="button" class="btn btn-primary btn-c3saction disabled">
<i class="fas fa-cloud-download"></i>
</a>
}
@if (isWatched) {
<button onclick="SetState('@talk.Guid', 'unwatched')" class="btn btn-primary w-100" data-toggle="tooltip" data-placement="left" title="Mark unwatched">
<button onclick="SetState('@talk.Guid', 'unwatched')" class="btn btn-primary btn-c3saction w-100" data-toggle="tooltip" data-placement="left" title="Mark unwatched">
<i class="fas fa-times"></i>
</button>
<button class="btn btn-primary disabled">
<button class="btn btn-primary btn-c3saction disabled">
<i class="fas fa-clock"></i>
</button>
}
else if (isMarked) {
<button onclick="SetState('@talk.Guid', 'watched')" class="btn btn-primary w-100" data-toggle="tooltip" data-placement="left" title="Mark watched">
<button onclick="SetState('@talk.Guid', 'watched')" class="btn btn-primary btn-c3saction w-100" data-toggle="tooltip" data-placement="left" title="Mark watched">
<i class="fas fa-check"></i>
</button>
<button onclick="SetState('@talk.Guid', 'unwatched')" class="btn btn-primary w-100" data-toggle="tooltip" data-placement="left" title="Remove from watch later">
<button onclick="SetState('@talk.Guid', 'unwatched')" class="btn btn-primary btn-c3saction w-100" data-toggle="tooltip" data-placement="left" title="Remove from watch later">
<i class="fas fa-undo-alt"></i>
</button>
}
else {
<button onclick="SetState('@talk.Guid', 'watched')" class="btn btn-primary w-100" data-toggle="tooltip" data-placement="left" title="Mark watched">
<button onclick="SetState('@talk.Guid', 'watched')" class="btn btn-primary btn-c3saction w-100" data-toggle="tooltip" data-placement="left" title="Mark watched">
<i class="fas fa-check"></i>
</button>
<button onclick="SetState('@talk.Guid', 'marked')" class="btn btn-primary w-100" data-toggle="tooltip" data-placement="left" title="Add to watch later">
<button onclick="SetState('@talk.Guid', 'marked')" class="btn btn-primary btn-c3saction w-100" data-toggle="tooltip" data-placement="left" title="Add to watch later">
<i class="fas fa-clock"></i>
</button>
}

View File

@ -3,7 +3,10 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using c3stream.DataModels;
using c3stream.Pages;
using LinqToDB.Common;
using LinqToDB.Data;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Hosting;
@ -11,13 +14,13 @@ using Microsoft.Extensions.Hosting;
namespace c3stream {
public static class c3stream {
public const string DataPath = "data";
public const string DbFile = "c3stream.user.json";
public const string DbFile = "c3stream.sqlite";
public const string CachePath = "/mnt/storage/archive/Video/congress/";
public const string CacheUrl = "https://c3stream-mirror.zotan.services/";
public static object Lock = new object();
public static object Lock = new();
public static string DbPath = Path.Combine(DataPath, DbFile);
public static List<ConferenceObject> Conferences = new List<ConferenceObject> {
public static readonly List<ConferenceObject> Conferences = new() {
new ConferenceObject("rc3", true),
new ConferenceObject("36c3"),
new ConferenceObject("camp2019"),
@ -34,7 +37,9 @@ namespace c3stream {
if (!Directory.Exists(DataPath))
Directory.CreateDirectory(DataPath);
if (!File.Exists(DbPath))
ConferenceModel.WriteUserData();
File.Copy(Path.Combine(DataPath, "database.init.sqlite"), DbPath);
DataConnection.DefaultSettings = new Database.Settings();
foreach (var conference in Conferences)
UpdateConference(conference);
@ -55,6 +60,7 @@ namespace c3stream {
}
}
//TODO: move this to the database as well
public static void UpdateConference(ConferenceObject conference) {
using var wc = new WebClient();
@ -111,7 +117,7 @@ namespace c3stream {
public string Acronym;
public bool Ongoing;
public string LogoUri;
public List<Event> Talks = new List<Event>();
public List<Event> Talks = new();
public ConferenceObject(string acronym, bool ongoing = false) {
Acronym = acronym;

View File

@ -1,10 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework>net50</TargetFramework>
<Configurations>Release;Debug</Configurations>
<Platforms>x64</Platforms>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="linq2db" Version="3.2.2" />
<PackageReference Include="Microsoft.Data.Sqlite" Version="5.0.1" PrivateAssets="none" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
</ItemGroup>
@ -32,5 +36,7 @@
<Content Remove="data\**" />
</ItemGroup>
<ItemGroup>
<Folder Include="DataModels" />
</ItemGroup>
</Project>

View File

@ -4,13 +4,13 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "c3stream", "c3stream.csproj
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{BC6A24FE-B35F-4F0A-8E8E-221E61E41EEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BC6A24FE-B35F-4F0A-8E8E-221E61E41EEF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BC6A24FE-B35F-4F0A-8E8E-221E61E41EEF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BC6A24FE-B35F-4F0A-8E8E-221E61E41EEF}.Release|Any CPU.Build.0 = Release|Any CPU
{BC6A24FE-B35F-4F0A-8E8E-221E61E41EEF}.Debug|x64.ActiveCfg = Debug|x64
{BC6A24FE-B35F-4F0A-8E8E-221E61E41EEF}.Debug|x64.Build.0 = Debug|x64
{BC6A24FE-B35F-4F0A-8E8E-221E61E41EEF}.Release|x64.ActiveCfg = Release|x64
{BC6A24FE-B35F-4F0A-8E8E-221E61E41EEF}.Release|x64.Build.0 = Release|x64
EndGlobalSection
EndGlobal

View File

@ -88,6 +88,9 @@ body {
color: #ffffff;
border-color: #3c6385;
background-color: #375a7a;
}
.btn-c3saction {
width: 42px !important;
}