Tesses.CMS Done enough
This commit is contained in:
parent
1b8a789600
commit
ba91f939fc
|
@ -93,6 +93,26 @@ public partial class App : Application
|
|||
return title;
|
||||
}
|
||||
|
||||
internal static (string loginButtonText,LoggedInUserAccount? login) LoginData()
|
||||
{
|
||||
LoggedInUserAccount? login=null;
|
||||
string loginText="Offline";
|
||||
Task.Run(async()=>{
|
||||
try {
|
||||
Client.Users.LoginToken = Platform.Configuration.LoginToken;
|
||||
login = await Client.Users.GetLoggedInUserAccountAsync();
|
||||
loginText = login.LoggedIn ? login.ProperName : "Login";
|
||||
} catch(Exception ex)
|
||||
{
|
||||
_=ex;
|
||||
}
|
||||
}).Wait();
|
||||
|
||||
return (loginText,login);
|
||||
}
|
||||
|
||||
|
||||
|
||||
internal static async Task<IImage> GetMovieThumbnailAsync(string username, string name)
|
||||
{
|
||||
//we need to cache the resource
|
||||
|
@ -249,6 +269,15 @@ public partial class App : Application
|
|||
}
|
||||
}
|
||||
|
||||
internal static bool HasDownloaded(UserAccount account,Movie movie)
|
||||
{
|
||||
UnixPath dir = Special.Root / "Downloads" / account.Username / "Movies" / movie.Name;
|
||||
UnixPath filename = dir / movie.ProperName + ".mp4";
|
||||
var fs = Platform.DownloadFilesystem;
|
||||
if(fs is null) return false;
|
||||
return fs.FileExists(filename);
|
||||
}
|
||||
|
||||
internal static void StartDownload(UserAccount account, Movie movie)
|
||||
{
|
||||
string username = account.Username;
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.5.002.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tesses.CMS.Avalonia", "Tesses.CMS.Avalonia.csproj", "{36061BA4-CB71-4B6C-8C0A-6482635EB893}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{36061BA4-CB71-4B6C-8C0A-6482635EB893}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{36061BA4-CB71-4B6C-8C0A-6482635EB893}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{36061BA4-CB71-4B6C-8C0A-6482635EB893}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{36061BA4-CB71-4B6C-8C0A-6482635EB893}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {B5F29959-050C-43EB-A56F-C7760E27834E}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,40 @@
|
|||
namespace Tesses.CMS.Avalonia.ViewModels;
|
||||
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Tesses.CMS.Avalonia.Models;
|
||||
using System.Threading.Tasks;
|
||||
using ReactiveUI;
|
||||
using Tesses.CMS.Avalonia.Views.HomePages;
|
||||
using Tesses.CMS.Avalonia.ViewModels.HomePages;
|
||||
|
||||
public partial class AccountViewModel : ViewModelBase
|
||||
{
|
||||
|
||||
|
||||
MainViewModel m;
|
||||
|
||||
public AccountViewModel(MainViewModel m)
|
||||
{
|
||||
this.m = m;
|
||||
this.LogoutCommand = ReactiveCommand.CreateFromTask(LogoutAsync);
|
||||
}
|
||||
|
||||
|
||||
public IReactiveCommand LogoutCommand {get;init;}
|
||||
|
||||
public async Task LogoutAsync()
|
||||
{
|
||||
App.Client.Users.LoginToken = App.Platform.Configuration.LoginToken;
|
||||
|
||||
|
||||
await App.Client.Users.LogoutAsync();
|
||||
|
||||
(m.LoginText,_) = App.LoginData();
|
||||
m.CurrentPage = new HomePageViewModel();
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@ public partial class HomePageViewModel : ViewModelBase
|
|||
public HomePageViewModel()
|
||||
{
|
||||
_curPage = new HomeUserListPageViewModel(this);
|
||||
|
||||
}
|
||||
private ViewModelBase _curPage;
|
||||
public ViewModelBase CurrentPage
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
namespace Tesses.CMS.Avalonia.ViewModels.HomePages;
|
||||
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using global::Avalonia.Controls;
|
||||
using Tesses.CMS.Avalonia.Models;
|
||||
using Tesses.CMS.Avalonia.Views.HomePages;
|
||||
using Tesses.CMS.Client;
|
||||
|
||||
public partial class HomeAboutMePageViewModel : ViewModelBase, IBackable
|
||||
{
|
||||
HomePageViewModel homePage;
|
||||
HomeUserPageViewModel userPage;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _aboutMe;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _properName;
|
||||
|
||||
public HomeAboutMePageViewModel(HomePageViewModel homePage,HomeUserPageViewModel userPage)
|
||||
{
|
||||
App.Log("In HomeAboutMePageViewModel::ctor block begin");
|
||||
this.homePage = homePage;
|
||||
this.userPage = userPage;
|
||||
this.AboutMe = userPage.Account.AboutMe;
|
||||
this.ProperName = $"About {userPage.Account.ProperName}";
|
||||
|
||||
App.Log("In HomeAboutMePageViewModel::ctor block end");
|
||||
|
||||
}
|
||||
|
||||
public ViewModelBase Back()
|
||||
{
|
||||
return userPage;
|
||||
}
|
||||
}
|
|
@ -44,12 +44,17 @@ public partial class HomeMoviePageViewModel : ViewModelBase, IBackable
|
|||
[ObservableProperty]
|
||||
private bool _canWatch=false;
|
||||
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _canDownload=false;
|
||||
|
||||
[ObservableProperty]
|
||||
|
||||
private string _addOrRemoveFromFavorites="";
|
||||
|
||||
[ObservableProperty]
|
||||
private string _downloadButtonText="Download";
|
||||
|
||||
private bool _favoriteExists=false;
|
||||
public bool FavoriteExists {
|
||||
get=>_favoriteExists;
|
||||
|
@ -66,6 +71,7 @@ public partial class HomeMoviePageViewModel : ViewModelBase, IBackable
|
|||
|
||||
public HomeMoviePageViewModel(HomePageViewModel home,HomeMovieListPageViewModel movieList,UserAccount account,MovieItem movie)
|
||||
{
|
||||
this.DownloadCommand = ReactiveCommand.CreateFromTask(DownloadAsync);
|
||||
this.account = account;
|
||||
username = account.Username;
|
||||
this.home = home;
|
||||
|
@ -89,6 +95,11 @@ public partial class HomeMoviePageViewModel : ViewModelBase, IBackable
|
|||
Media = JObject.FromObject(movie.Movie)
|
||||
};
|
||||
FavoriteExists = App.FavoritesExists(fav);
|
||||
if(App.HasDownloaded(account,movie.Movie))
|
||||
{
|
||||
CanDownload = true;
|
||||
DownloadButtonText = "Watch Downloaded";
|
||||
}
|
||||
|
||||
Task.Run(async()=>{
|
||||
var res=await App.Client.Movies.GetMovieContentMetadataAsync(username,movie.Movie.Name);
|
||||
|
@ -96,13 +107,19 @@ public partial class HomeMoviePageViewModel : ViewModelBase, IBackable
|
|||
watchUrl = res.BrowserStream;
|
||||
CanWatch = res.HasBrowserStream;
|
||||
|
||||
if(!App.HasDownloaded(account,movie.Movie))
|
||||
{
|
||||
CanDownload = res.HasDownloadStream;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}).Wait(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public ViewModelBase Back()
|
||||
{
|
||||
return movieList;
|
||||
|
@ -116,12 +133,19 @@ public partial class HomeMoviePageViewModel : ViewModelBase, IBackable
|
|||
home.CurrentPage = new HomeMovieVideoPlayerViewModel(home,this,watchUrl);
|
||||
}
|
||||
}
|
||||
[RelayCommand]
|
||||
public void Download()
|
||||
public IReactiveCommand DownloadCommand {get;init;}
|
||||
public async Task DownloadAsync()
|
||||
{
|
||||
if(App.HasDownloaded(account,movie))
|
||||
{
|
||||
await this.home.PlayDownloadedAsync(fav);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(CanDownload)
|
||||
App.StartDownload(account,movie);
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
public void AddToFavorites()
|
||||
|
|
|
@ -41,6 +41,7 @@ public partial class HomeUserPageViewModel : ViewModelBase, IBackable
|
|||
this.account = account;
|
||||
UserItems.Add(new UserPageItem("Movies",new HomeMovieListPageViewModel(homePage,this)));
|
||||
UserItems.Add(new UserPageItem("Shows",new HomeShowListPageViewModel(homePage,this)));
|
||||
UserItems.Add(new UserPageItem("About",new HomeAboutMePageViewModel(homePage,this)));
|
||||
}
|
||||
[ObservableProperty]
|
||||
private UserPageItem? _selectedListItem;
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
namespace Tesses.CMS.Avalonia.ViewModels;
|
||||
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Tesses.CMS.Avalonia.Models;
|
||||
using System.Threading.Tasks;
|
||||
using ReactiveUI;
|
||||
using Tesses.CMS.Avalonia.Views.HomePages;
|
||||
using Tesses.CMS.Avalonia.ViewModels.HomePages;
|
||||
|
||||
public partial class LoginViewModel : ViewModelBase
|
||||
{
|
||||
[ObservableProperty]
|
||||
private string _email="";
|
||||
|
||||
[ObservableProperty]
|
||||
private string _password="";
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _failed=false;
|
||||
|
||||
MainViewModel m;
|
||||
|
||||
public LoginViewModel(MainViewModel m)
|
||||
{
|
||||
this.m = m;
|
||||
this.LoginCommand = ReactiveCommand.CreateFromTask(LoginAsync);
|
||||
}
|
||||
|
||||
|
||||
public IReactiveCommand LoginCommand {get;init;}
|
||||
|
||||
public async Task LoginAsync()
|
||||
{
|
||||
Failed=false;
|
||||
var tkn= await App.Client.Users.CreateTokenAsync(Email,Password);
|
||||
if(tkn.Success)
|
||||
{
|
||||
App.Platform.Configuration.LoginToken = tkn.Cookie;
|
||||
await App.Platform.WriteConfigurationAsync();
|
||||
(m.LoginText,_) = App.LoginData();
|
||||
m.CurrentPage = new HomePageViewModel();
|
||||
}
|
||||
else
|
||||
{
|
||||
Failed=true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,6 +7,8 @@ using CommunityToolkit.Mvvm.ComponentModel;
|
|||
using CommunityToolkit.Mvvm.Input;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Tesses.CMS.Avalonia.Models;
|
||||
using Tesses.CMS.Avalonia.Views;
|
||||
using Tesses.CMS.Client;
|
||||
|
||||
public partial class MainViewModel : ViewModelBase
|
||||
{
|
||||
|
@ -21,6 +23,8 @@ public partial class MainViewModel : ViewModelBase
|
|||
SelectedListItem = Pages.First();
|
||||
this.Title = title;
|
||||
|
||||
(LoginText,_)= App.LoginData();
|
||||
|
||||
if(Environment.GetCommandLineArgs().Length > 1)
|
||||
{
|
||||
string path = Environment.GetCommandLineArgs()[1];
|
||||
|
@ -55,7 +59,7 @@ public partial class MainViewModel : ViewModelBase
|
|||
[ObservableProperty]
|
||||
private Page? _selectedListItem;
|
||||
[ObservableProperty]
|
||||
private string _loginText="Login";
|
||||
private string _loginText="";
|
||||
|
||||
[ObservableProperty]
|
||||
private string _title;
|
||||
|
@ -81,6 +85,20 @@ public partial class MainViewModel : ViewModelBase
|
|||
private void LoginAccount()
|
||||
{
|
||||
App.Log("Login button");
|
||||
LoggedInUserAccount? data=null;
|
||||
(LoginText,data)= App.LoginData();
|
||||
|
||||
if(data is not null)
|
||||
{
|
||||
if(data.LoggedIn)
|
||||
{
|
||||
CurrentPage = new AccountViewModel(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentPage = new LoginViewModel(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void SetHome()
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:vm="clr-namespace:Tesses.CMS.Avalonia.ViewModels"
|
||||
xmlns:v="clr-namespace:Tesses.CMS.Avalonia.Views"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Tesses.CMS.Avalonia.Views.AccountView"
|
||||
x:DataType="vm:AccountViewModel">
|
||||
<Design.DataContext>
|
||||
<!-- This only sets the DataContext for the previewer in an IDE,
|
||||
to set the actual DataContext for runtime, set the DataContext property in code (look at App.axaml.cs) -->
|
||||
<vm:AccountViewModel />
|
||||
</Design.DataContext>
|
||||
<StackPanel Margin="20">
|
||||
<Button Command="{Binding LogoutCommand}">Logout</Button>
|
||||
</StackPanel>
|
||||
</UserControl>
|
|
@ -0,0 +1,16 @@
|
|||
using System.Threading.Tasks;
|
||||
using Avalonia.Controls;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
namespace Tesses.CMS.Avalonia.Views;
|
||||
|
||||
public partial class AccountView : UserControl
|
||||
{
|
||||
public AccountView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:vm="clr-namespace:Tesses.CMS.Avalonia.ViewModels.HomePages"
|
||||
xmlns:v="clr-namespace:Tesses.CMS.Avalonia.Views"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Tesses.CMS.Avalonia.Views.HomePages.HomeAboutMePageView"
|
||||
x:DataType="vm:HomeAboutMePageViewModel">
|
||||
<Design.DataContext>
|
||||
<!-- This only sets the DataContext for the previewer in an IDE,
|
||||
to set the actual DataContext for runtime, set the DataContext property in code (look at App.axaml.cs) -->
|
||||
<vm:HomeAboutMePageViewModel />
|
||||
</Design.DataContext>
|
||||
<ScrollViewer>
|
||||
<Grid RowDefinitions="Auto,*" Margin="20">
|
||||
<TextBlock Text="{Binding ProperName}" Grid.Row="0" />
|
||||
|
||||
<v:InlineText Margin="0 20 0 0" Grid.Row="1" Text="{Binding AboutMe}" />
|
||||
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
|
@ -0,0 +1,11 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
namespace Tesses.CMS.Avalonia.Views.HomePages;
|
||||
|
||||
public partial class HomeAboutMePageView : UserControl
|
||||
{
|
||||
public HomeAboutMePageView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
|
@ -25,7 +25,7 @@
|
|||
</Grid>
|
||||
<Grid Grid.Row="1" ColumnDefinitions="Auto,Auto,Auto">
|
||||
<Button Grid.Column="0" Command="{Binding WatchCommand}" Content="Watch" IsVisible="{Binding CanWatch}"/>
|
||||
<Button Grid.Column="1" Command="{Binding DownloadCommand}" Content="Download" IsVisible="{Binding CanDownload}"/>
|
||||
<Button Grid.Column="1" Command="{Binding DownloadCommand}" Content="{Binding DownloadButtonText}" IsVisible="{Binding CanDownload}"/>
|
||||
<Button Grid.Column="2" Command="{Binding AddToFavoritesCommand}" Content="{Binding AddOrRemoveFromFavorites}"/>
|
||||
|
||||
</Grid>
|
||||
|
|
|
@ -49,7 +49,9 @@ public class InlineText : WrapPanel
|
|||
{
|
||||
if(b.Length > 0)
|
||||
{
|
||||
this.Children.Add(new TextBlock(){Text = b.ToString()});
|
||||
var res = new TextBlock(){Text = $"\u200B{b.ToString()}\u200B",TextWrapping = TextWrapping.Wrap};
|
||||
|
||||
this.Children.Add(res);
|
||||
b.Clear();
|
||||
}
|
||||
StringBuilder b2 = new StringBuilder();
|
||||
|
@ -62,7 +64,7 @@ public class InlineText : WrapPanel
|
|||
}
|
||||
b2.Append(text[i]);
|
||||
}
|
||||
var tb = new TextBlock(){Text = b2.ToString()};
|
||||
var tb = new TextBlock(){Text = $"\u200B{b2.ToString()}\u200B",TextWrapping = TextWrapping.Wrap};
|
||||
tb.Foreground = new SolidColorBrush(Color.FromRgb(0,0,255));
|
||||
tb.TextDecorations = TextDecorations.Underline;
|
||||
|
||||
|
@ -80,7 +82,7 @@ public class InlineText : WrapPanel
|
|||
}
|
||||
if(b.Length > 0)
|
||||
{
|
||||
this.Children.Add(new TextBlock(){Text = b.ToString()});
|
||||
this.Children.Add(new TextBlock(){Text = $"\u200B{b.ToString()}\u200B", TextWrapping = TextWrapping.Wrap});
|
||||
b.Clear();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:vm="clr-namespace:Tesses.CMS.Avalonia.ViewModels"
|
||||
xmlns:v="clr-namespace:Tesses.CMS.Avalonia.Views"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Tesses.CMS.Avalonia.Views.LoginView"
|
||||
x:DataType="vm:LoginViewModel">
|
||||
<Design.DataContext>
|
||||
<!-- This only sets the DataContext for the previewer in an IDE,
|
||||
to set the actual DataContext for runtime, set the DataContext property in code (look at App.axaml.cs) -->
|
||||
<vm:LoginViewModel />
|
||||
</Design.DataContext>
|
||||
<StackPanel Margin="20">
|
||||
<TextBlock Background="Red" IsVisible="{Binding Failed}">The Email or Password was incorrect, please try again.</TextBlock>
|
||||
<TextBlock Margin="0 5" >Email:</TextBlock>
|
||||
<TextBox Text="{Binding Email}" Watermark="Enter your email"/>
|
||||
<TextBlock Margin="0 5" >Password:</TextBlock>
|
||||
<TextBox Text="{Binding Password}" PasswordChar="*" Watermark="Enter your password"/>
|
||||
<Button Command="{Binding LoginCommand}">Login</Button>
|
||||
</StackPanel>
|
||||
</UserControl>
|
|
@ -0,0 +1,16 @@
|
|||
using System.Threading.Tasks;
|
||||
using Avalonia.Controls;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
namespace Tesses.CMS.Avalonia.Views;
|
||||
|
||||
public partial class LoginView : UserControl
|
||||
{
|
||||
public LoginView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -256,7 +256,12 @@ namespace Tesses.CMS.Client
|
|||
|
||||
public async Task LogoutAsync()
|
||||
{
|
||||
(await client.client.GetAsync("/logout")).Dispose();
|
||||
(await client.client.GetAsync($"{client.rooturl}/logout")).Dispose();
|
||||
}
|
||||
|
||||
public async Task<LoggedInUserAccount> GetLoggedInUserAccountAsync()
|
||||
{
|
||||
return JsonConvert.DeserializeObject<LoggedInUserAccount>(await client.client.GetStringAsync($"{client.rooturl}/api/v1/LoggedInUserAccount"));
|
||||
}
|
||||
|
||||
|
||||
|
@ -280,11 +285,10 @@ namespace Tesses.CMS.Client
|
|||
return "";
|
||||
}
|
||||
set{
|
||||
if(string.IsNullOrWhiteSpace(value))
|
||||
if(client.client.DefaultRequestHeaders.Contains("Authorization"))
|
||||
client.client.DefaultRequestHeaders.Remove("Authorization");
|
||||
else
|
||||
client.client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer",value);
|
||||
if(!string.IsNullOrWhiteSpace(value))
|
||||
client.client.DefaultRequestHeaders.Add("Authorization",$"Bearer {value}");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -297,6 +301,26 @@ namespace Tesses.CMS.Client
|
|||
}
|
||||
}
|
||||
|
||||
public class LoggedInUserAccount
|
||||
{
|
||||
[JsonProperty("logged_in")]
|
||||
public bool LoggedIn {get;set;}=false;
|
||||
|
||||
[JsonProperty("username")]
|
||||
public string UserName {get;set;}="";
|
||||
|
||||
[JsonProperty("proper_name")]
|
||||
public string ProperName {get;set;}="";
|
||||
[JsonProperty("is_admin")]
|
||||
public bool IsAdmin {get;set;}=false;
|
||||
|
||||
[JsonProperty("is_invited")]
|
||||
public bool IsInvited {get;set;}=false;
|
||||
|
||||
[JsonProperty("is_verified")]
|
||||
public bool IsVerified {get;set;}=false;
|
||||
}
|
||||
|
||||
public class LoginToken
|
||||
{
|
||||
[JsonProperty("success")]
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.5.002.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tesses.CMS.Client", "Tesses.CMS.Client.csproj", "{887B0982-1D90-413D-BFEE-72065D115DE0}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{887B0982-1D90-413D-BFEE-72065D115DE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{887B0982-1D90-413D-BFEE-72065D115DE0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{887B0982-1D90-413D-BFEE-72065D115DE0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{887B0982-1D90-413D-BFEE-72065D115DE0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {17F92768-0843-4A4F-B369-22B8120B4996}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.5.002.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tesses.CMS.Providers.LiteDb", "Tesses.CMS.Providers.LiteDb.csproj", "{D0D6C7FF-2B46-4909-9741-77DBDFD52D4D}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{D0D6C7FF-2B46-4909-9741-77DBDFD52D4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D0D6C7FF-2B46-4909-9741-77DBDFD52D4D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D0D6C7FF-2B46-4909-9741-77DBDFD52D4D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D0D6C7FF-2B46-4909-9741-77DBDFD52D4D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {45074933-DBC8-4448-B846-2287DFF81409}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -1,5 +1,5 @@
|
|||
<h1>Change movie metadata</h1>
|
||||
<form action="./edit" method="post" enctype="application/x-www-form-urlencoded">
|
||||
<h1>Change episode metadata</h1>
|
||||
<form action="./edit?csrf={{csrf}}" method="post" enctype="application/x-www-form-urlencoded">
|
||||
<div class="mb-3">
|
||||
<label for="proper-name" class="form-label">Proper Name</label>
|
||||
<input type="text" class="form-control" id="proper-name" name="proper_name" value="{{propername}}">
|
||||
|
@ -12,7 +12,7 @@
|
|||
|
||||
</form>
|
||||
<h1>Upload episode files</h1>
|
||||
<form action="./upload" method="post" enctype="multipart/form-data">
|
||||
<form action="./upload?csrf={{csrf2}}" method="post" enctype="multipart/form-data">
|
||||
<h1>You should do these in order (not required but recomended because you can only upload one at a time, that is in one tab at least)</h1>
|
||||
<select class="form-select" name="type" aria-label="Select resource">
|
||||
<option value="thumbnail" selected>Thumbnail (should be 120x214, the coverart for the episode)</option>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<h1>Change season metadata</h1>
|
||||
<form action="./edit" method="post" enctype="application/x-www-form-urlencoded">
|
||||
<form action="./edit?csrf={{csrf}}" method="post" enctype="application/x-www-form-urlencoded">
|
||||
<div class="mb-3">
|
||||
<label for="proper-name" class="form-label">Proper Name</label>
|
||||
<input type="text" class="form-control" id="proper-name" name="proper_name" value="{{propername}}">
|
||||
|
@ -13,7 +13,7 @@
|
|||
</form>
|
||||
<br>
|
||||
<h1>Add episode</h1>
|
||||
<form action="./addepisode" method="post" enctype="application/x-www-form-urlencoded">
|
||||
<form action="./addepisode?csrf={{csrf2}}" method="post" enctype="application/x-www-form-urlencoded">
|
||||
<div class="mb-3">
|
||||
<label for="name" class="form-label">Episode Name</label>
|
||||
<input type="text" class="form-control" id="name" name="name" aria-describedby="message">
|
||||
|
@ -38,7 +38,7 @@
|
|||
</form>
|
||||
<br>
|
||||
<h1>Upload asset files</h1>
|
||||
<form action="./upload" method="post" enctype="multipart/form-data">
|
||||
<form action="./upload?csrf={{csrf3}}" method="post" enctype="multipart/form-data">
|
||||
<h1>You should do these in order (not required but recomended because you can only upload one at a time, that is in one tab at least)</h1>
|
||||
<select class="form-select" name="type" aria-label="Select resource">
|
||||
<option value="thumbnail" selected>Thumbnail (should be 120x214, the coverart for the season (also used for when episode does not have one))</option>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<h1>Change show metadata</h1>
|
||||
<form action="./edit" method="post" enctype="application/x-www-form-urlencoded">
|
||||
<form action="./edit?csrf={{csrf}}" method="post" enctype="application/x-www-form-urlencoded">
|
||||
<div class="mb-3">
|
||||
<label for="proper-name" class="form-label">Proper Name</label>
|
||||
<input type="text" class="form-control" id="proper-name" name="proper_name" value="{{propername}}">
|
||||
|
@ -13,7 +13,7 @@
|
|||
</form>
|
||||
<br>
|
||||
<h1>Add season</h1>
|
||||
<form action="./addseason" method="post" enctype="application/x-www-form-urlencoded">
|
||||
<form action="./addseason?csrf={{csrf2}}" method="post" enctype="application/x-www-form-urlencoded">
|
||||
<div class="mb-3">
|
||||
<label for="number" class="form-label">Season Number</label>
|
||||
<input type="number" min="1" class="form-control" id="number" name="number" value="{{newseasonnumber}}">
|
||||
|
@ -32,7 +32,7 @@
|
|||
</form>
|
||||
<br>
|
||||
<h1>Upload asset files</h1>
|
||||
<form action="./upload" method="post" enctype="multipart/form-data">
|
||||
<form action="./upload?csrf={{csrf3}}" method="post" enctype="multipart/form-data">
|
||||
<h1>You should do these in order (not required but recomended because you can only upload one at a time, that is in one tab at least)</h1>
|
||||
<select class="form-select" name="type" aria-label="Select resource">
|
||||
<option value="thumbnail" selected>Thumbnail (should be 120x214, the coverart for the show (also used for when season or episode does not have one))</option>
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
const end = document.getElementById('end');
|
||||
const text = document.getElementById('text');
|
||||
const _captions = document.getElementById('captions');
|
||||
var csrf = "{{csrf}}";
|
||||
function set_max()
|
||||
{
|
||||
begin.max = video_player.duration;
|
||||
|
@ -50,7 +51,7 @@
|
|||
_delete.classList.add('btn');
|
||||
_delete.classList.add('btn-danger');
|
||||
_delete.onclick = ()=>{
|
||||
var index=captions.indexof(item);
|
||||
var index=captions.indexOf(item);
|
||||
if(index > -1)
|
||||
{
|
||||
captions.splice(index,1);
|
||||
|
@ -116,20 +117,25 @@
|
|||
addEventListener("DOMContentLoaded", (event) => {loaded();});
|
||||
function save()
|
||||
{
|
||||
fetch("./subtitles?lang={{lang}}",{method: 'POST',
|
||||
fetch(`./subtitles?lang={{lang}}&csrf=${csrf}`,{method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
},body: JSON.stringify(captions)/*https://stackoverflow.com/a/29823632*/}).then(e=>{
|
||||
if(e.ok)
|
||||
{
|
||||
alert("Saved");
|
||||
return e.json();
|
||||
}
|
||||
else
|
||||
{
|
||||
alert("Failed");
|
||||
return Promise.reject();
|
||||
}
|
||||
e.close();
|
||||
|
||||
}).catch(e=>{
|
||||
alert("Failed to save.");
|
||||
}).then(e=>{
|
||||
csrf=e.csrf;
|
||||
alert("Success.");
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -932,7 +932,10 @@ namespace Tesses.CMS
|
|||
{
|
||||
foreach (var c in cookies)
|
||||
{
|
||||
var co = c.Split(new char[] { '=' }, 2);
|
||||
foreach(var cE in c.Split(new string[]{"; "},StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
|
||||
var co = cE.Split(new char[] { '=' }, 2);
|
||||
if (co.Length == 2 && co[0] == "Session")
|
||||
{
|
||||
if (provider.ContainsSession(co[1]))
|
||||
|
@ -943,6 +946,19 @@ namespace Tesses.CMS
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ctx.RequestHeaders.TryGetFirst("Authorization", out var auth))
|
||||
{
|
||||
var co = auth.Split(new char[] { ' ' }, 2);
|
||||
if (co.Length == 2 && co[0] == "Bearer")
|
||||
{
|
||||
if (provider.ContainsSession(co[1]))
|
||||
{
|
||||
provider.DeleteSession(co[1]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
HttpClient client = new HttpClient();
|
||||
|
@ -1141,16 +1157,19 @@ namespace Tesses.CMS
|
|||
cookie = "";
|
||||
if (ctx.RequestHeaders.TryGetValue("Cookie", out var cookies))
|
||||
{
|
||||
|
||||
foreach (var c in cookies)
|
||||
{
|
||||
|
||||
var co = c.Split(new char[] { '=' }, 2);
|
||||
foreach(var cE in c.Split(new string[]{"; "},StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
var co = cE.Split(new char[] { '=' }, 2);
|
||||
if (co.Length == 2 && co[0] == "Session")
|
||||
{
|
||||
cookie = co[1];
|
||||
long? account = provider.GetSession(cookie);
|
||||
|
||||
|
||||
|
||||
if (account.HasValue)
|
||||
{
|
||||
if (requiresCSRF)
|
||||
|
@ -1164,12 +1183,14 @@ namespace Tesses.CMS
|
|||
}
|
||||
throw new InvalidCSRFException();
|
||||
}
|
||||
|
||||
return provider.GetUserById(account.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ctx.RequestHeaders.TryGetFirst("Authentication", out var auth))
|
||||
}
|
||||
else if (ctx.RequestHeaders.TryGetFirst("Authorization", out var auth))
|
||||
{
|
||||
var co = auth.Split(new char[] { ' ' }, 2);
|
||||
if (co.Length == 2 && co[0] == "Bearer")
|
||||
|
@ -2094,7 +2115,7 @@ namespace Tesses.CMS
|
|||
|
||||
string user = usersPathValueServer.GetValue(ctx);
|
||||
string show = showPathValueServer.GetValue(ctx);
|
||||
var me = GetAccount(ctx);
|
||||
var me = GetAccount(ctx,out var cookie);
|
||||
string seasonS = seasonPathValueServer.GetValue(ctx);
|
||||
string episodeS = episodePathValueServer.GetValue(ctx);
|
||||
if (!int.TryParse(seasonS, out var season))
|
||||
|
@ -2110,7 +2131,17 @@ namespace Tesses.CMS
|
|||
if (me != null)
|
||||
{
|
||||
if (_episode != null)
|
||||
await ctx.SendTextAsync(await RenderHtmlAsync(ctx, await pageEditEpisodeDetails.RenderAsync(new { Propername = System.Web.HttpUtility.HtmlAttributeEncode(_episode.ProperName), Description = System.Web.HttpUtility.HtmlEncode(_episode.Description) })));
|
||||
{
|
||||
string csrf="";
|
||||
string csrf2="";
|
||||
|
||||
if(me != null)
|
||||
{
|
||||
csrf = HttpUtility.UrlEncode(CreateCSRF(me.Id,cookie));
|
||||
csrf2 = HttpUtility.UrlEncode(CreateCSRF(me.Id,cookie));
|
||||
}
|
||||
await ctx.SendTextAsync(await RenderHtmlAsync(ctx, await pageEditEpisodeDetails.RenderAsync(new { Propername = System.Web.HttpUtility.HtmlAttributeEncode(_episode.ProperName), Description = System.Web.HttpUtility.HtmlEncode(_episode.Description), csrf, csrf2 })));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2166,7 +2197,7 @@ namespace Tesses.CMS
|
|||
int season = 1;
|
||||
if (!int.TryParse(seasonS, out season))
|
||||
season = 1;
|
||||
var me = GetAccount(ctx);
|
||||
var me = GetAccount(ctx,out var cookie);
|
||||
|
||||
var _season = provider.GetSeason(user, show, season);
|
||||
|
||||
|
@ -2178,7 +2209,18 @@ namespace Tesses.CMS
|
|||
if (me != null)
|
||||
{
|
||||
if (_season != null)
|
||||
await ctx.SendTextAsync(await RenderHtmlAsync(ctx, await pageEditSeasonDetails.RenderAsync(new { Propername = System.Web.HttpUtility.HtmlAttributeEncode(_season.ProperName), newseasonnumber = provider.EpisodeCount(user, show, season) + 1, Description = System.Web.HttpUtility.HtmlEncode(_season.Description) })));
|
||||
{
|
||||
string csrf="";
|
||||
string csrf2="";
|
||||
string csrf3="";
|
||||
if(me != null)
|
||||
{
|
||||
csrf = HttpUtility.UrlEncode(CreateCSRF(me.Id,cookie));
|
||||
csrf2 = HttpUtility.UrlEncode(CreateCSRF(me.Id,cookie));
|
||||
csrf3 = HttpUtility.UrlEncode(CreateCSRF(me.Id,cookie));
|
||||
}
|
||||
await ctx.SendTextAsync(await RenderHtmlAsync(ctx, await pageEditSeasonDetails.RenderAsync(new { Propername = System.Web.HttpUtility.HtmlAttributeEncode(_season.ProperName), newseasonnumber = provider.EpisodeCount(user, show, season) + 1, Description = System.Web.HttpUtility.HtmlEncode(_season.Description), csrf,csrf2,csrf3 })));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2315,7 +2357,7 @@ namespace Tesses.CMS
|
|||
{
|
||||
string user = usersPathValueServer.GetValue(ctx);
|
||||
string show = showPathValueServer.GetValue(ctx);
|
||||
var me = GetAccount(ctx);
|
||||
var me = GetAccount(ctx,out var cookie);
|
||||
var _show = provider.GetShow(user, show);
|
||||
|
||||
if (me != null && me.Username != user && !me.IsAdmin)
|
||||
|
@ -2326,7 +2368,18 @@ namespace Tesses.CMS
|
|||
if (me != null)
|
||||
{
|
||||
if (_show != null)
|
||||
await ctx.SendTextAsync(await RenderHtmlAsync(ctx, await pageEditShowDetails.RenderAsync(new { Propername = System.Web.HttpUtility.HtmlAttributeEncode(_show.ProperName), newseasonnumber = provider.SeasonCount(user, show) + 1, Description = System.Web.HttpUtility.HtmlEncode(_show.Description) })));
|
||||
{
|
||||
string csrf="";
|
||||
string csrf2="";
|
||||
string csrf3="";
|
||||
if(me != null)
|
||||
{
|
||||
csrf = HttpUtility.UrlEncode(CreateCSRF(me.Id,cookie));
|
||||
csrf2 = HttpUtility.UrlEncode(CreateCSRF(me.Id,cookie));
|
||||
csrf3 = HttpUtility.UrlEncode(CreateCSRF(me.Id,cookie));
|
||||
}
|
||||
await ctx.SendTextAsync(await RenderHtmlAsync(ctx, await pageEditShowDetails.RenderAsync(new { Propername = System.Web.HttpUtility.HtmlAttributeEncode(_show.ProperName), newseasonnumber = provider.SeasonCount(user, show) + 1, Description = System.Web.HttpUtility.HtmlEncode(_show.Description) ,csrf,csrf2,csrf3 })));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2616,7 +2669,7 @@ namespace Tesses.CMS
|
|||
{
|
||||
string user = usersPathValueServer.GetValue(ctx);
|
||||
string movie = moviePathValueServer.GetValue(ctx);
|
||||
var me = GetAccount(ctx,true);
|
||||
var me = GetAccount(ctx,out var cookie,true);
|
||||
var _movie = provider.GetMovie(user, movie);
|
||||
if (me != null && me.Username != user && !me.IsAdmin)
|
||||
{
|
||||
|
@ -2642,12 +2695,13 @@ namespace Tesses.CMS
|
|||
{
|
||||
Subtitle.ToSrt(srtFile, json);
|
||||
}
|
||||
await ctx.SendTextAsync("Success");
|
||||
var csrf=HttpUtility.UrlEncode(this.CreateCSRF(me.Id, cookie));
|
||||
await ctx.SendJsonAsync(new{success=true,csrf});
|
||||
return;
|
||||
}
|
||||
}
|
||||
ctx.StatusCode = 400;
|
||||
await ctx.SendTextAsync("Fail");
|
||||
await ctx.SendJsonAsync(new{success=false});
|
||||
}
|
||||
private async Task SubtitlesEpisodeAsync(ServerContext ctx)
|
||||
{
|
||||
|
@ -2661,7 +2715,7 @@ namespace Tesses.CMS
|
|||
if (!int.TryParse(episodeS, out var episode))
|
||||
episode = 1;
|
||||
|
||||
var me = GetAccount(ctx);
|
||||
var me = GetAccount(ctx,out var cookie);
|
||||
var _show = provider.GetMovie(user, show);
|
||||
var _episode = provider.GetEpisode(user, show, season, episode);
|
||||
if (me != null && me.Username != user && !me.IsAdmin)
|
||||
|
@ -2675,6 +2729,10 @@ namespace Tesses.CMS
|
|||
string langDir = Path.Combine(path, user, "show", show, $"Season {season.ToString("D2")}", $"{_episode.EpisodeName} S{season.ToString("D2")}E{episode.ToString("D2")}-subtitles", lang);
|
||||
string langFile = Path.Combine(langDir, $"{_episode.ProperName} S{season.ToString("D2")}E{episode.ToString("D2")}.json");
|
||||
string browserfile = $"{Configuration.Root.TrimEnd('/')}/content/{user}/show/{show}/Season%20{season.ToString("D2")}/S{season.ToString("D2")}E{episode.ToString("D2")}.mp4";
|
||||
string csrf="";
|
||||
|
||||
csrf = HttpUtility.UrlEncode(CreateCSRF(me.Id,cookie));
|
||||
|
||||
string json = "";
|
||||
bool hasjson = false;
|
||||
if (File.Exists(langFile))
|
||||
|
@ -2682,7 +2740,7 @@ namespace Tesses.CMS
|
|||
hasjson = true;
|
||||
json = File.ReadAllText(langFile);
|
||||
}
|
||||
await ctx.SendTextAsync(await RenderHtmlAsync(ctx, await pageSubtitleEditor.RenderAsync(new { hasjson, json, lang, browserfile })));
|
||||
await ctx.SendTextAsync(await RenderHtmlAsync(ctx, await pageSubtitleEditor.RenderAsync(new { hasjson, json, lang, browserfile, csrf })));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2749,7 +2807,7 @@ namespace Tesses.CMS
|
|||
{
|
||||
string user = usersPathValueServer.GetValue(ctx);
|
||||
string movie = moviePathValueServer.GetValue(ctx);
|
||||
var me = GetAccount(ctx);
|
||||
var me = GetAccount(ctx,out var cookie);
|
||||
var _movie = provider.GetMovie(user, movie);
|
||||
if (me != null && me.Username != user && !me.IsAdmin)
|
||||
{
|
||||
|
@ -2769,7 +2827,8 @@ namespace Tesses.CMS
|
|||
hasjson = true;
|
||||
json = File.ReadAllText(langFile);
|
||||
}
|
||||
await ctx.SendTextAsync(await RenderHtmlAsync(ctx, await pageSubtitleEditor.RenderAsync(new { hasjson, json, lang, browserfile })));
|
||||
var csrf=HttpUtility.UrlEncode(this.CreateCSRF(me.Id, cookie));
|
||||
await ctx.SendTextAsync(await RenderHtmlAsync(ctx, await pageSubtitleEditor.RenderAsync(new { hasjson, json, lang, browserfile,csrf })));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -3993,7 +4052,7 @@ namespace Tesses.CMS
|
|||
{
|
||||
var user = provider.GetUserById(show.UserId);
|
||||
int count2 = provider.EpisodeCount(user.Username, show.Name, season);
|
||||
for (int j = 1; j < count2; j++)
|
||||
for (int j = 1; j <= count2; j++)
|
||||
{
|
||||
yield return provider.GetEpisode(user.Username, show.Name, season, j);
|
||||
}
|
||||
|
@ -4172,6 +4231,7 @@ namespace Tesses.CMS
|
|||
});
|
||||
},new SwagmeDocumentation("Branding for server"));
|
||||
swagmeServer.Add("/Login", ApiLogin, new SwagmeDocumentation("Login to account", "<b>email</b>: the email of account</br><b>password</b>: the password of account</br><b>type</b>: json or cookie"), "POST", "Users");
|
||||
swagmeServer.Add("/LoggedInUserAccount",LoggedInAccountAsync,new SwagmeDocumentation("Get logged in account via authorization"),"GET","Users");
|
||||
swagmeServer.Add("/GetPublicUsers", ApiGetPublicUsers, new SwagmeDocumentation("Get all public users"), "GET", "Users");
|
||||
swagmeServer.Add("/Updates", (ctx) =>
|
||||
{
|
||||
|
@ -4205,6 +4265,19 @@ namespace Tesses.CMS
|
|||
return swagmeServer;
|
||||
}
|
||||
|
||||
private async Task LoggedInAccountAsync(ServerContext ctx)
|
||||
{
|
||||
var account = this.GetAccount(ctx);
|
||||
if(account is null)
|
||||
{
|
||||
await ctx.SendJsonAsync(new LoggedInUserAccount{LoggedIn=false});
|
||||
}
|
||||
else
|
||||
{
|
||||
await ctx.SendJsonAsync(new LoggedInUserAccount{LoggedIn=true,UserName = account.Username, ProperName = account.ProperName, IsAdmin = account.IsAdmin, IsInvited = account.IsInvited, IsVerified=account.IsVerified});
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ApiLogin(ServerContext ctx)
|
||||
{
|
||||
ctx.ParseBody();
|
||||
|
@ -4381,7 +4454,7 @@ namespace Tesses.CMS
|
|||
if (type == "json")
|
||||
{
|
||||
List<Season> seasons = new List<Season>();
|
||||
for (int i = 1; i < provider.SeasonCount(s.UserId, s.Id); i++)
|
||||
for (int i = 1; i <= provider.SeasonCount(s.UserId, s.Id); i++)
|
||||
{
|
||||
var season = provider.GetSeason(s.UserId, s.Id, i);
|
||||
if (season != null)
|
||||
|
@ -4471,7 +4544,7 @@ namespace Tesses.CMS
|
|||
if (type == "json")
|
||||
{
|
||||
List<Episode> episodes = new List<Episode>();
|
||||
for (int i = 1; i < provider.EpisodeCount(s.UserId, s.Id, season); i++)
|
||||
for (int i = 1; i <= provider.EpisodeCount(s.UserId, s.Id, season); i++)
|
||||
{
|
||||
var episode = provider.GetEpisode(s.UserId, s.Id, season, i);
|
||||
if (episode != null)
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace Tesses.CMS
|
|||
Season = SeasonNumber,
|
||||
Episode = EpisodeNumber,
|
||||
Description = System.Web.HttpUtility.HtmlEncode(Description),
|
||||
Thumbnail = File.Exists(Path.Combine(dir,user,"show",show,$"Season {SeasonNumber.ToString("D2")}",$"{EpisodeName} S{SeasonNumber.ToString("D2")}E{SeasonNumber.ToString("D2")}-thumbnail.jpg")) ? $"{configuration.Root.TrimEnd('/')}/content/{user}/show/{show}/Season%20{SeasonNumber.ToString("D2")}/{EpisodeName}%20S{SeasonNumber.ToString("D2")}E{SeasonNumber.ToString("D2")}-thumbnail.jpg" : File.Exists(Path.Combine(dir,user,"show",show,$"Season {SeasonNumber.ToString("D2")}","thumbnail.jpg")) ? $"{configuration.Root.TrimEnd('/')}/content/{user}/show/{show}/Season%20{SeasonNumber.ToString("D2")}/thumbnail.jpg" : $"{configuration.Root.TrimEnd('/')}/content/{user}/show/{show}/thumbnail.jpg"
|
||||
Thumbnail = File.Exists(Path.Combine(dir,user,"show",show,$"Season {SeasonNumber.ToString("D2")}",$"{EpisodeName} S{SeasonNumber.ToString("D2")}E{EpisodeNumber.ToString("D2")}-thumbnail.jpg")) ? $"{configuration.Root.TrimEnd('/')}/content/{user}/show/{show}/Season%20{SeasonNumber.ToString("D2")}/{EpisodeName}%20S{SeasonNumber.ToString("D2")}E{EpisodeNumber.ToString("D2")}-thumbnail.jpg" : File.Exists(Path.Combine(dir,user,"show",show,$"Season {SeasonNumber.ToString("D2")}","thumbnail.jpg")) ? $"{configuration.Root.TrimEnd('/')}/content/{user}/show/{show}/Season%20{SeasonNumber.ToString("D2")}/thumbnail.jpg" : $"{configuration.Root.TrimEnd('/')}/content/{user}/show/{show}/thumbnail.jpg"
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Tesses.CMS
|
||||
{
|
||||
public class LoggedInUserAccount
|
||||
{
|
||||
[JsonProperty("logged_in")]
|
||||
public bool LoggedIn {get;set;}=false;
|
||||
|
||||
[JsonProperty("username")]
|
||||
public string UserName {get;set;}="";
|
||||
|
||||
[JsonProperty("proper_name")]
|
||||
public string ProperName {get;set;}="";
|
||||
|
||||
[JsonProperty("is_admin")]
|
||||
public bool IsAdmin {get;set;}=false;
|
||||
|
||||
[JsonProperty("is_invited")]
|
||||
public bool IsInvited {get;set;}=false;
|
||||
|
||||
[JsonProperty("is_verified")]
|
||||
public bool IsVerified {get;set;}=false;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.5.002.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tesses.CMS", "Tesses.CMS.csproj", "{2AB7647E-947B-43FD-8348-4F43B13DD9AA}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{2AB7647E-947B-43FD-8348-4F43B13DD9AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2AB7647E-947B-43FD-8348-4F43B13DD9AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2AB7647E-947B-43FD-8348-4F43B13DD9AA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2AB7647E-947B-43FD-8348-4F43B13DD9AA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C4517F8F-92D8-4A81-8081-C8683339096F}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"Title": "TessesStudios",
|
||||
"Urls": [{"Url":"https://tesses.net", "Text":"Tesses"}, {"Url": "https://jellyfin.site.tesses.net/", "Text": "Jellyfin (use guest)"}],
|
||||
"Root": "CHANGE_TO_DOMAIN_NAME",
|
||||
"Email":{
|
||||
"Host": "CHANGE_TO_EMAIL_SMTP_SERVER",
|
||||
"User": "CHANGE_TO_EMAIL_USERNAME",
|
||||
"Pass": "CHNAGE_TO_EMAIL_PASS",
|
||||
"Port": 587,
|
||||
"Encryption": "StartTls",
|
||||
"Email": "CHANGE_TO_EMAIL"
|
||||
},
|
||||
"Publish": "RequireInvite"
|
||||
}
|
Loading…
Reference in New Issue