Add migrations, add private streams
parent
cade2df6a5
commit
59b3dc6f68
|
@ -4,3 +4,4 @@ obj/
|
|||
/packages/
|
||||
/data/
|
||||
app.db
|
||||
app.db.bak
|
||||
|
|
|
@ -2,26 +2,26 @@
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using RTMPDash.DataModels;
|
||||
|
||||
namespace RTMPDash.Controllers {
|
||||
[ApiController, Route("/api/authenticate")]
|
||||
public class RtmpAuthController : ControllerBase {
|
||||
[HttpGet]
|
||||
public string Get() {
|
||||
var db = new AppDb.DbConn();
|
||||
if (!db.Users.Any(p => p.StreamKey == Request.Query["name"])) {
|
||||
Response.StatusCode = 403;
|
||||
return "unauthorized";
|
||||
}
|
||||
namespace RTMPDash.Controllers;
|
||||
|
||||
var user = db.Users.FirstOrDefault(p => p.StreamKey == Request.Query["name"]);
|
||||
|
||||
Response.Headers.Add("x-rtmp-user", user!.Username);
|
||||
|
||||
if (user.AllowRestream && !string.IsNullOrWhiteSpace(user.RestreamTargets))
|
||||
Response.Headers.Add("x-rtmp-target", user.RestreamTargets);
|
||||
|
||||
Response.StatusCode = 302;
|
||||
return "authorized as " + user!.Username;
|
||||
[ApiController, Route("/api/authenticate")]
|
||||
public class RtmpAuthController : ControllerBase {
|
||||
[HttpGet]
|
||||
public string Get() {
|
||||
var db = new AppDb.DbConn();
|
||||
if (!db.Users.Any(p => p.StreamKey == Request.Query["name"])) {
|
||||
Response.StatusCode = 403;
|
||||
return "unauthorized";
|
||||
}
|
||||
|
||||
var user = db.Users.FirstOrDefault(p => p.StreamKey == Request.Query["name"]);
|
||||
|
||||
Response.Headers.Add("x-rtmp-user", user!.IsPrivate ? user!.PrivateAccessKey : user!.Username);
|
||||
|
||||
if (user.AllowRestream && !string.IsNullOrWhiteSpace(user.RestreamTargets))
|
||||
Response.Headers.Add("x-rtmp-target", user.RestreamTargets);
|
||||
|
||||
Response.StatusCode = 302;
|
||||
return "authorized as " + user!.Username;
|
||||
}
|
||||
}
|
|
@ -5,35 +5,32 @@ using LinqToDB.Configuration;
|
|||
using LinqToDB.Data;
|
||||
using RTMPDash.DataModels.Tables;
|
||||
|
||||
namespace RTMPDash.DataModels {
|
||||
public class AppDb {
|
||||
public class ConnectionStringSettings : IConnectionStringSettings {
|
||||
public string ConnectionString { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string ProviderName { get; set; }
|
||||
public bool IsGlobal => false;
|
||||
}
|
||||
namespace RTMPDash.DataModels;
|
||||
|
||||
public class Settings : ILinqToDBSettings {
|
||||
public IEnumerable<IDataProviderSettings> DataProviders => Enumerable.Empty<IDataProviderSettings>();
|
||||
public class AppDb {
|
||||
public class ConnectionStringSettings : IConnectionStringSettings {
|
||||
public string ConnectionString { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string ProviderName { get; set; }
|
||||
public bool IsGlobal => false;
|
||||
}
|
||||
|
||||
public string DefaultConfiguration => "SQLite";
|
||||
public string DefaultDataProvider => "SQLite";
|
||||
public class Settings : ILinqToDBSettings {
|
||||
public IEnumerable<IDataProviderSettings> DataProviders => Enumerable.Empty<IDataProviderSettings>();
|
||||
|
||||
public IEnumerable<IConnectionStringSettings> ConnectionStrings {
|
||||
get {
|
||||
yield return new ConnectionStringSettings {
|
||||
Name = "db", ProviderName = "SQLite", ConnectionString = @"Data Source=app.db;"
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
public string DefaultConfiguration => "SQLite";
|
||||
public string DefaultDataProvider => "SQLite";
|
||||
|
||||
public class DbConn : DataConnection {
|
||||
public DbConn() : base("db") { }
|
||||
|
||||
public ITable<User> Users => GetTable<User>();
|
||||
public ITable<Invite> Invites => GetTable<Invite>();
|
||||
public IEnumerable<IConnectionStringSettings> ConnectionStrings {
|
||||
get { yield return new ConnectionStringSettings { Name = "db", ProviderName = "SQLite", ConnectionString = @"Data Source=app.db;" }; }
|
||||
}
|
||||
}
|
||||
|
||||
public class DbConn : DataConnection {
|
||||
public DbConn() : base("db") { }
|
||||
|
||||
public ITable<User> Users => GetTable<User>();
|
||||
public ITable<Invite> Invites => GetTable<Invite>();
|
||||
public ITable<DbInfo> DbInfo => GetTable<DbInfo>();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
using LinqToDB.Mapping;
|
||||
|
||||
namespace RTMPDash.DataModels.Tables;
|
||||
|
||||
[Table(Name = "DbInfo")]
|
||||
public class DbInfo {
|
||||
[Column(Name = "ID"), PrimaryKey, Identity, NotNull] public int Id { get; set; }
|
||||
[Column(Name = "DbVer"), NotNull] public int DbVer { get; set; }
|
||||
}
|
|
@ -1,18 +1,20 @@
|
|||
using LinqToDB.Mapping;
|
||||
|
||||
namespace RTMPDash.DataModels.Tables {
|
||||
[Table(Name = "Users")]
|
||||
public class User {
|
||||
[Column(Name = "Username"), PrimaryKey] public string Username { get; set; }
|
||||
[Column(Name = "Password")] public string Password { get; set; }
|
||||
[Column(Name = "IsAdmin")] public bool IsAdmin { get; set; }
|
||||
[Column(Name = "AllowRestream")] public bool AllowRestream { get; set; }
|
||||
[Column(Name = "StreamKey")] public string StreamKey { get; set; }
|
||||
[Column(Name = "PronounSubject")] public string PronounSubject { get; set; }
|
||||
[Column(Name = "PronounPossessive")] public string PronounPossessive { get; set; }
|
||||
[Column(Name = "ChatUrl")] public string ChatUrl { get; set; }
|
||||
[Column(Name = "AnnouncementUrl")] public string AnnouncementUrl { get; set; }
|
||||
[Column(Name = "RestreamTargets")] public string RestreamTargets { get; set; }
|
||||
[Column(Name = "RestreamUrls")] public string RestreamUrls { get; set; }
|
||||
}
|
||||
namespace RTMPDash.DataModels.Tables;
|
||||
|
||||
[Table(Name = "Users")]
|
||||
public class User {
|
||||
[Column(Name = "Username"), PrimaryKey] public string Username { get; set; }
|
||||
[Column(Name = "Password")] public string Password { get; set; }
|
||||
[Column(Name = "IsAdmin")] public bool IsAdmin { get; set; }
|
||||
[Column(Name = "AllowRestream")] public bool AllowRestream { get; set; }
|
||||
[Column(Name = "StreamKey")] public string StreamKey { get; set; }
|
||||
[Column(Name = "PronounSubject")] public string PronounSubject { get; set; }
|
||||
[Column(Name = "PronounPossessive")] public string PronounPossessive { get; set; }
|
||||
[Column(Name = "ChatUrl")] public string ChatUrl { get; set; }
|
||||
[Column(Name = "AnnouncementUrl")] public string AnnouncementUrl { get; set; }
|
||||
[Column(Name = "RestreamTargets")] public string RestreamTargets { get; set; }
|
||||
[Column(Name = "RestreamUrls")] public string RestreamUrls { get; set; }
|
||||
[Column(Name = "IsPrivate")] public bool IsPrivate { get; set; }
|
||||
[Column(Name = "PrivateAccessKey")] public string PrivateAccessKey { get; set; }
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LinqToDB;
|
||||
using LinqToDB.Data;
|
||||
using RTMPDash.DataModels;
|
||||
using RTMPDash.DataModels.Tables;
|
||||
|
||||
namespace RTMPDash;
|
||||
|
||||
/**
|
||||
* TODO: Initial migrations should create all tables & an admin user and print a randomly generated password for the admin user
|
||||
* *
|
||||
*/
|
||||
public static class Migrations {
|
||||
public const int DbVer = 1;
|
||||
|
||||
private static readonly List<Migration> _migrations = new() {
|
||||
new Migration(1, "ALTER TABLE Users ADD IsPrivate INTEGER DEFAULT 0 NOT NULL"), new Migration(1, "ALTER TABLE Users ADD PrivateAccessKey TEXT")
|
||||
};
|
||||
|
||||
public static void RunMigrations() {
|
||||
using var db = new AppDb.DbConn();
|
||||
|
||||
if (db.DataProvider.GetSchemaProvider().GetSchema(db).Tables.All(t => t.TableName != "DbInfo")) {
|
||||
db.CreateTable<DbInfo>();
|
||||
db.InsertWithIdentity(new DbInfo { DbVer = 0 });
|
||||
}
|
||||
|
||||
var dbinfo = db.DbInfo.First();
|
||||
var ccolor = Console.ForegroundColor;
|
||||
|
||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
Console.WriteLine($"Database version: {db.DbInfo.ToList().First().DbVer}");
|
||||
|
||||
var migrationsToRun = _migrations.FindAll(p => p.IntroducedWithDbVer > db.DbInfo.First().DbVer);
|
||||
if (migrationsToRun.Count == 0) {
|
||||
Console.ForegroundColor = ConsoleColor.Green;
|
||||
Console.WriteLine("No migrations to run.");
|
||||
}
|
||||
else {
|
||||
migrationsToRun.ForEach(RunMigration);
|
||||
dbinfo.DbVer = DbVer;
|
||||
db.Update(dbinfo);
|
||||
Console.ForegroundColor = ConsoleColor.DarkGreen;
|
||||
Console.WriteLine($"Database version is now: {DbVer}");
|
||||
Console.ForegroundColor = ConsoleColor.Green;
|
||||
Console.WriteLine("Finished running migrations.");
|
||||
}
|
||||
|
||||
Console.ForegroundColor = ccolor;
|
||||
}
|
||||
|
||||
private static void RunMigration(Migration mig) => mig.Run();
|
||||
|
||||
private class Migration {
|
||||
private readonly string _sql;
|
||||
public readonly int IntroducedWithDbVer;
|
||||
|
||||
public Migration(int introducedWithDbVer, string sql) {
|
||||
IntroducedWithDbVer = introducedWithDbVer;
|
||||
_sql = sql;
|
||||
}
|
||||
|
||||
public void Run() {
|
||||
using var db = new AppDb.DbConn();
|
||||
|
||||
Console.ForegroundColor = ConsoleColor.DarkCyan;
|
||||
Console.Write("Running migration: ");
|
||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
Console.WriteLine(_sql);
|
||||
db.Execute(_sql);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,11 +24,29 @@ else {
|
|||
<p>Thanks for using @Program.SiteName. If you have any issues, please contact me on @Html.Raw(Program.ContactInfo)</p>
|
||||
<hr/>
|
||||
<p>Please subscribe to the <a href="@Program.ServiceAnnouncementUrl" target="_blank">Service Announcements Channel</a> to get informed about maintenance and other important things.</p>
|
||||
<hr>
|
||||
<p class="mb-0">When using OBS, the stream key and leading slash before it is to be left out in the RTMP url.</p>
|
||||
<hr/>
|
||||
<p class="mb-0">For low-latancy streams, please set your keyframe interval to 1-2 seconds. Otherwise, automatic or something in the range of 4-8 seconds is fine.</p>
|
||||
</div>
|
||||
if (StreamUtils.ListLiveUsers().Contains(user.Username) && user.IsPrivate) {
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<h4 class="alert-heading">Warning!</h4>
|
||||
<p class="mb-0">
|
||||
You set your stream to private, but have not restarted your stream since.
|
||||
<br/>
|
||||
While this setting is applied immediately, the old player URL will remain accessible until you stop and restart your stream.
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
else if (StreamUtils.ListLiveUsers().Contains(user.PrivateAccessKey) && !user.IsPrivate) {
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<h4 class="alert-heading">Warning!</h4>
|
||||
<p class="mb-0">
|
||||
You set your stream to public, but have not restarted your stream since.
|
||||
<br/>
|
||||
While this setting is applied immediately, the public player will not work until you restart your stream.
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text" style="width:23ch">Profile URL</span>
|
||||
|
@ -42,10 +60,21 @@ else {
|
|||
<div class="input-group-prepend">
|
||||
<span class="input-group-text" style="width:23ch">Player URL</span>
|
||||
</div>
|
||||
<input type="text" class="form-control" id="input-playerurl" value="@Program.PlayerDomain/@user.Username" disabled>
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-outline-secondary" role="button" id="button-copy-playerurl" onclick="copyToClipboard(document.getElementById('input-playerurl').value);">Copy</button>
|
||||
</div>
|
||||
@if (user.IsPrivate) {
|
||||
<input type="text" class="form-control" id="input-playerurl" value="@Program.PlayerDomain/@user.PrivateAccessKey" disabled>
|
||||
<div class="input-group-append">
|
||||
<button onclick="ajax_and_reload('private_toggle')" class="btn btn-outline-info" role="button" id="button-toggle-private">Private</button>
|
||||
<button class="btn btn-outline-secondary" role="button" id="button-copy-playerurl" onclick="copyToClipboard(document.getElementById('input-playerurl').value);">Copy</button>
|
||||
</div>
|
||||
}
|
||||
else {
|
||||
<input type="text" class="form-control" id="input-playerurl" value="@Program.PlayerDomain/@user.Username" disabled>
|
||||
<div class="input-group-append">
|
||||
<button onclick="ajax_and_reload('private_toggle')" class="btn btn-outline-success" role="button" id="button-toggle-private">Public</button>
|
||||
<button class="btn btn-outline-secondary" role="button" id="button-copy-playerurl" onclick="copyToClipboard(document.getElementById('input-playerurl').value);">Copy</button>
|
||||
</div>
|
||||
}
|
||||
|
||||
</div>
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
|
@ -61,9 +90,10 @@ else {
|
|||
<div class="input-group-prepend">
|
||||
<span class="input-group-text" style="width:23ch">Stream URL</span>
|
||||
</div>
|
||||
<input type="text" class="form-control" id="input-streamurl" value="@Program.IngressDomain/ingress/@user.StreamKey" disabled>
|
||||
<input type="text" class="form-control" id="input-streamurl" value="@Program.IngressDomain/ingress" disabled>
|
||||
<div class="input-group-append">
|
||||
@if (StreamUtils.IsLive(user.Username, stats)) {
|
||||
@* ReSharper disable once ConvertIfStatementToSwitchStatement *@
|
||||
@if (!user.IsPrivate && StreamUtils.IsLive(user.Username, stats)) {
|
||||
var uptime = TimeSpan.FromMilliseconds(StreamUtils.GetClientTime(user.Username, stats)).StripMilliseconds();
|
||||
if (user.AllowRestream && !string.IsNullOrWhiteSpace(user.RestreamTargets)) {
|
||||
if (StreamUtils.GetClientTime(user.Username, stats) > 5000) {
|
||||
|
@ -84,6 +114,27 @@ else {
|
|||
}
|
||||
<button class="btn btn-dark" role="button" disabled>@uptime.ToString("c")</button>
|
||||
}
|
||||
else if (user.IsPrivate && StreamUtils.IsLive(user.PrivateAccessKey, stats)) {
|
||||
var uptime = TimeSpan.FromMilliseconds(StreamUtils.GetClientTime(user.PrivateAccessKey, stats)).StripMilliseconds();
|
||||
if (user.AllowRestream && !string.IsNullOrWhiteSpace(user.RestreamTargets)) {
|
||||
if (StreamUtils.GetClientTime(user.Username, stats) > 5000) {
|
||||
var restreams = StreamUtils.CountLiveRestreams(user.PrivateAccessKey, stats);
|
||||
if (restreams > 0) {
|
||||
<button class="btn btn-success" role="button" style="width:20ch" disabled>Live & restreaming</button>
|
||||
}
|
||||
else {
|
||||
<button class="btn btn-warning" role="button" style="width:22ch" disabled>Live & restream down</button>
|
||||
}
|
||||
}
|
||||
else {
|
||||
<button class="btn btn-dark" role="button" style="width:13ch" disabled>Starting...</button>
|
||||
}
|
||||
}
|
||||
else {
|
||||
<button class="btn btn-success" role="button" style="width:13ch" disabled>Live</button>
|
||||
}
|
||||
<button class="btn btn-dark" role="button" disabled>@uptime.ToString("c")</button>
|
||||
}
|
||||
else {
|
||||
<button class="btn btn-danger" role="button" style="width:13ch" disabled>No data</button>
|
||||
}
|
||||
|
|
|
@ -5,80 +5,84 @@ using Microsoft.AspNetCore.Http;
|
|||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using RTMPDash.DataModels;
|
||||
|
||||
namespace RTMPDash.Pages {
|
||||
public class DashboardModel : PageModel {
|
||||
public void OnGet() { }
|
||||
namespace RTMPDash.Pages;
|
||||
|
||||
public void OnPost() {
|
||||
if (!Request.HasFormContentType
|
||||
|| string.IsNullOrWhiteSpace(Request.Form["action"])
|
||||
|| string.IsNullOrWhiteSpace(HttpContext.Session.GetString("authenticatedUser")))
|
||||
return;
|
||||
public class DashboardModel : PageModel {
|
||||
public void OnGet() { }
|
||||
|
||||
using var db = new AppDb.DbConn();
|
||||
var user = db.Users.FirstOrDefault(p => p.Username == HttpContext.Session.GetString("authenticatedUser"));
|
||||
public void OnPost() {
|
||||
if (!Request.HasFormContentType || string.IsNullOrWhiteSpace(Request.Form["action"]) || string.IsNullOrWhiteSpace(HttpContext.Session.GetString("authenticatedUser")))
|
||||
return;
|
||||
|
||||
if (Request.Form["action"] == "password_change") {
|
||||
var newPass = Request.Form["pass"];
|
||||
user!.Password = newPass.ToString().Sha256();
|
||||
db.Update(user);
|
||||
Response.Redirect("/Logout");
|
||||
}
|
||||
using var db = new AppDb.DbConn();
|
||||
var user = db.Users.FirstOrDefault(p => p.Username == HttpContext.Session.GetString("authenticatedUser"));
|
||||
|
||||
if (Request.Form["action"] == "chaturl_set") {
|
||||
user!.ChatUrl = Request.Form["value"];
|
||||
if (Request.Form["action"] == "password_change") {
|
||||
var newPass = Request.Form["pass"];
|
||||
user!.Password = newPass.ToString().Sha256();
|
||||
db.Update(user);
|
||||
Response.Redirect("/Logout");
|
||||
}
|
||||
|
||||
if (Request.Form["action"] == "chaturl_set") {
|
||||
user!.ChatUrl = Request.Form["value"];
|
||||
db.Update(user);
|
||||
Response.Redirect("/Dashboard");
|
||||
}
|
||||
|
||||
if (Request.Form["action"] == "announceurl_set") {
|
||||
user!.AnnouncementUrl = Request.Form["value"];
|
||||
db.Update(user);
|
||||
Response.Redirect("/Dashboard");
|
||||
}
|
||||
|
||||
if (user!.AllowRestream) {
|
||||
if (Request.Form["action"] == "restream_urls_set") {
|
||||
user!.RestreamUrls = Request.Form["value"];
|
||||
db.Update(user);
|
||||
Response.Redirect("/Dashboard");
|
||||
}
|
||||
|
||||
if (Request.Form["action"] == "announceurl_set") {
|
||||
user!.AnnouncementUrl = Request.Form["value"];
|
||||
if (Request.Form["action"] == "restream_targets_set") {
|
||||
var newtgts = Request.Form["value"].ToString();
|
||||
if (newtgts.Contains("localhost") || newtgts.Contains("127.0.0.1") || newtgts.Contains(user.StreamKey))
|
||||
return;
|
||||
|
||||
user!.RestreamTargets = newtgts;
|
||||
db.Update(user);
|
||||
Response.Redirect("/Dashboard");
|
||||
}
|
||||
}
|
||||
|
||||
if (user!.AllowRestream) {
|
||||
if (Request.Form["action"] == "restream_urls_set") {
|
||||
user!.RestreamUrls = Request.Form["value"];
|
||||
db.Update(user);
|
||||
Response.Redirect("/Dashboard");
|
||||
}
|
||||
if (Request.Form["action"] == "pronoun_subj_set") {
|
||||
var target = string.IsNullOrWhiteSpace(Request.Form["value"]) ? "they" : Request.Form["value"].ToString();
|
||||
user!.PronounSubject = target.ToLowerInvariant();
|
||||
db.Update(user);
|
||||
Response.Redirect("/Dashboard");
|
||||
}
|
||||
|
||||
if (Request.Form["action"] == "restream_targets_set") {
|
||||
var newtgts = Request.Form["value"].ToString();
|
||||
if (newtgts.Contains("localhost")
|
||||
|| newtgts.Contains("127.0.0.1")
|
||||
|| newtgts.Contains(user.StreamKey))
|
||||
return;
|
||||
if (Request.Form["action"] == "pronoun_poss_set") {
|
||||
var target = string.IsNullOrWhiteSpace(Request.Form["value"]) ? "their" : Request.Form["value"].ToString();
|
||||
user!.PronounPossessive = target.ToLowerInvariant();
|
||||
db.Update(user);
|
||||
Response.Redirect("/Dashboard");
|
||||
}
|
||||
|
||||
user!.RestreamTargets = newtgts;
|
||||
db.Update(user);
|
||||
Response.Redirect("/Dashboard");
|
||||
}
|
||||
if (Request.Form["action"] == "streamkey_reset") {
|
||||
user!.StreamKey = Guid.NewGuid().ToString();
|
||||
db.Update(user);
|
||||
}
|
||||
|
||||
if (Request.Form["action"] == "private_toggle") {
|
||||
if (user.IsPrivate) {
|
||||
user!.IsPrivate = false;
|
||||
}
|
||||
else {
|
||||
user!.PrivateAccessKey = Guid.NewGuid().ToString();
|
||||
user!.IsPrivate = true;
|
||||
}
|
||||
|
||||
if (Request.Form["action"] == "pronoun_subj_set") {
|
||||
var target = string.IsNullOrWhiteSpace(Request.Form["value"])
|
||||
? "they"
|
||||
: Request.Form["value"].ToString();
|
||||
user!.PronounSubject = target.ToLowerInvariant();
|
||||
db.Update(user);
|
||||
Response.Redirect("/Dashboard");
|
||||
}
|
||||
|
||||
if (Request.Form["action"] == "pronoun_poss_set") {
|
||||
var target = string.IsNullOrWhiteSpace(Request.Form["value"])
|
||||
? "their"
|
||||
: Request.Form["value"].ToString();
|
||||
user!.PronounPossessive = target.ToLowerInvariant();
|
||||
db.Update(user);
|
||||
Response.Redirect("/Dashboard");
|
||||
}
|
||||
|
||||
if (Request.Form["action"] == "streamkey_reset") {
|
||||
user!.StreamKey = Guid.NewGuid().ToString();
|
||||
db.Update(user);
|
||||
}
|
||||
db.Update(user);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,13 +1,17 @@
|
|||
@page
|
||||
@using RTMPDash.DataModels
|
||||
@model IndexModel
|
||||
@{
|
||||
ViewData["Title"] = "Home";
|
||||
var liveUsers = StreamUtils.ListLiveUsers();
|
||||
var db = new AppDb.DbConn();
|
||||
var allStreams = StreamUtils.ListLiveUsers();
|
||||
var allUsers = db.Users.Where(p => !p.IsPrivate).Select(p => p.Username);
|
||||
var liveUsers = allStreams.Intersect(allUsers);
|
||||
}
|
||||
|
||||
<div class="text-center">
|
||||
<h1 class="display-4">Welcome</h1>
|
||||
@if (liveUsers.Count > 0) {
|
||||
@if (liveUsers.Any()) {
|
||||
<p>The following users are currently live:</p>
|
||||
<div class="btn-group btn-group" role="group">
|
||||
@foreach (var user in liveUsers) {
|
||||
|
|
|
@ -6,40 +6,46 @@ using Microsoft.AspNetCore.Mvc.RazorPages;
|
|||
using RTMPDash.DataModels;
|
||||
using RTMPDash.DataModels.Tables;
|
||||
|
||||
namespace RTMPDash.Pages {
|
||||
public class RegisterModel : PageModel {
|
||||
public void OnPost() {
|
||||
if (!Request.HasFormContentType
|
||||
|| string.IsNullOrWhiteSpace(Request.Form["user"])
|
||||
|| string.IsNullOrWhiteSpace(Request.Form["pass"])
|
||||
|| string.IsNullOrWhiteSpace(Request.Form["code"]))
|
||||
return;
|
||||
namespace RTMPDash.Pages;
|
||||
|
||||
using var db = new AppDb.DbConn();
|
||||
if (!db.Invites.Any(p => p.Code == Request.Form["code"]))
|
||||
return;
|
||||
public class RegisterModel : PageModel {
|
||||
public void OnPost() {
|
||||
if (!Request.HasFormContentType
|
||||
|| string.IsNullOrWhiteSpace(Request.Form["user"])
|
||||
|| string.IsNullOrWhiteSpace(Request.Form["pass"])
|
||||
|| string.IsNullOrWhiteSpace(Request.Form["code"]))
|
||||
return;
|
||||
|
||||
var user = db.Users.FirstOrDefault(p => p.Username == Request.Form["user"].ToString());
|
||||
if (user != null) {
|
||||
//user already exists
|
||||
Response.Redirect("/Register?e=user_exists");
|
||||
return;
|
||||
}
|
||||
using var db = new AppDb.DbConn();
|
||||
if (!db.Invites.Any(p => p.Code == Request.Form["code"]))
|
||||
return;
|
||||
|
||||
user = new User {
|
||||
Username = Request.Form["user"].ToString(),
|
||||
Password = Request.Form["pass"].ToString().Sha256(),
|
||||
StreamKey = Guid.NewGuid().ToString(),
|
||||
PronounSubject = "they",
|
||||
PronounPossessive = "their",
|
||||
AllowRestream = true
|
||||
};
|
||||
|
||||
db.Insert(user);
|
||||
|
||||
db.Delete(db.Invites.First(p => p.Code == Request.Form["code"]));
|
||||
|
||||
HttpContext.Session.SetString("authenticatedUser", user.Username);
|
||||
var user = db.Users.FirstOrDefault(p => p.Username == Request.Form["user"].ToString());
|
||||
if (user != null) {
|
||||
//user already exists
|
||||
Response.Redirect("/Register?e=user_exists");
|
||||
return;
|
||||
}
|
||||
|
||||
if (db.Users.Any(p => p.StreamKey == Request.Form["user"] || p.PrivateAccessKey == Request.Form["user"])) {
|
||||
//user invalid
|
||||
Response.Redirect("/Register?e=user_invalid");
|
||||
return;
|
||||
}
|
||||
|
||||
user = new User {
|
||||
Username = Request.Form["user"].ToString(),
|
||||
Password = Request.Form["pass"].ToString().Sha256(),
|
||||
StreamKey = Guid.NewGuid().ToString(),
|
||||
PronounSubject = "they",
|
||||
PronounPossessive = "their",
|
||||
AllowRestream = true
|
||||
};
|
||||
|
||||
db.Insert(user);
|
||||
|
||||
db.Delete(db.Invites.First(p => p.Code == Request.Form["code"]));
|
||||
|
||||
HttpContext.Session.SetString("authenticatedUser", user.Username);
|
||||
}
|
||||
}
|
|
@ -10,7 +10,7 @@
|
|||
}
|
||||
var user = db.Users.First(p => p.Username == Model.User);
|
||||
var stats = StreamUtils.GetStatsObject();
|
||||
var live = StreamUtils.IsLive(user.Username, stats);
|
||||
var live = StreamUtils.IsLive(user.Username, stats) && !user.IsPrivate;
|
||||
Stream stream = null;
|
||||
if (live) {
|
||||
stream = stats.Server.Applications.First(p => p.Name == "ingress").MethodLive.Streams.FirstOrDefault(p => p.Name == user.Username);
|
||||
|
|
50
Program.cs
50
Program.cs
|
@ -5,34 +5,34 @@ using Microsoft.AspNetCore.Hosting;
|
|||
using Microsoft.Extensions.Hosting;
|
||||
using RTMPDash.DataModels;
|
||||
|
||||
namespace RTMPDash {
|
||||
public class Program {
|
||||
public const string SiteName = "chaos.stream";
|
||||
public const string IngressDomain = "rtmp://chaos.stream";
|
||||
public const string RootDomain = "https://chaos.stream";
|
||||
public const string PlayerDomain = "https://live.on.chaos.stream";
|
||||
public const string FragmentDomain = "https://cdn.chaos.stream";
|
||||
public const string StatsDomain = "https://stats.chaos.stream";
|
||||
public const string PrivacyEmail = "chaosstream-privacy@zotan.email";
|
||||
public const string CopyrightEmail = "chaosstream-copyright@zotan.email";
|
||||
public const string AbuseEmail = "chaosstream-abuse@zotan.email";
|
||||
public const string ServiceAnnouncementUrl = "https://t.me/chaosstream";
|
||||
public const string ServiceStatusUrl = "https://status.chaos.stream";
|
||||
namespace RTMPDash;
|
||||
|
||||
public const string ContactInfo =
|
||||
"<a href=\"https://t.me/zotan\" target=\"_blank\">Telegram</a>, <a href=\"https://threema.id/S59S9U8J\" target=\"_blank\">Threema</a>, or via <a href=\"mailto:chaosstream-contact@zotan.email\" target=\"_blank\">email</a>.";
|
||||
public class Program {
|
||||
public const string SiteName = "chaos.stream";
|
||||
public const string IngressDomain = "rtmp://chaos.stream";
|
||||
public const string RootDomain = "https://chaos.stream";
|
||||
public const string PlayerDomain = "https://live.on.chaos.stream";
|
||||
public const string FragmentDomain = "https://cdn.chaos.stream";
|
||||
public const string StatsDomain = "https://stats.chaos.stream";
|
||||
public const string PrivacyEmail = "chaosstream-privacy@zotan.email";
|
||||
public const string CopyrightEmail = "chaosstream-copyright@zotan.email";
|
||||
public const string AbuseEmail = "chaosstream-abuse@zotan.email";
|
||||
public const string ServiceAnnouncementUrl = "https://t.me/chaosstream";
|
||||
public const string ServiceStatusUrl = "https://status.chaos.stream";
|
||||
|
||||
public static void Main(string[] args) {
|
||||
DataConnection.DefaultSettings = new AppDb.Settings();
|
||||
ThreadPool.SetMinThreads(100, 100);
|
||||
CreateHostBuilder(args).Build().Run();
|
||||
}
|
||||
public const string ContactInfo =
|
||||
"<a href=\"https://t.me/zotan\" target=\"_blank\">Telegram</a>, <a href=\"https://threema.id/S59S9U8J\" target=\"_blank\">Threema</a>, or via <a href=\"mailto:chaosstream-contact@zotan.email\" target=\"_blank\">email</a>.";
|
||||
|
||||
public static IHostBuilder CreateHostBuilder(string[] args) =>
|
||||
Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
|
||||
public static void Main(string[] args) {
|
||||
DataConnection.DefaultSettings = new AppDb.Settings();
|
||||
ThreadPool.SetMinThreads(100, 100);
|
||||
Migrations.RunMigrations();
|
||||
CreateHostBuilder(args).Build().Run();
|
||||
}
|
||||
|
||||
public static class TimeExtensions {
|
||||
public static TimeSpan StripMilliseconds(this TimeSpan time) => new(time.Days, time.Hours, time.Minutes, time.Seconds);
|
||||
}
|
||||
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
|
||||
}
|
||||
|
||||
public static class TimeExtensions {
|
||||
public static TimeSpan StripMilliseconds(this TimeSpan time) => new(time.Days, time.Hours, time.Minutes, time.Seconds);
|
||||
}
|
Loading…
Reference in New Issue