2023-12-16 01:40:05 +00:00
using System ;
using System.IO ;
using System.Threading.Tasks ;
using Newtonsoft.Json ;
using Tesses.WebServer ;
using Scriban ;
using System.Collections.Generic ;
using Tesses.WebServer.Swagme ;
using System.Net ;
using System.Web ;
using System.Text ;
using System.Xml ;
using Microsoft.SyndicationFeed.Rss ;
using Microsoft.SyndicationFeed.Atom ;
using Microsoft.SyndicationFeed ;
using PlaylistsNET.Models ;
using PlaylistsNET.Content ;
using System.Security.Cryptography ;
using System.Collections.Concurrent ;
using System.Diagnostics ;
using System.Linq ;
2024-01-04 02:53:13 +00:00
using MailKit.Net.Smtp ;
using MimeKit ;
2024-07-28 22:59:28 +00:00
using System.Net.Http ;
using System.Runtime.Serialization ;
2023-12-16 01:40:05 +00:00
namespace Tesses.CMS
{
2024-07-28 22:59:28 +00:00
public class Subtitle
2024-01-04 02:53:13 +00:00
{
[JsonProperty("end")]
2024-07-28 22:59:28 +00:00
public double End { get ; set ; }
2024-01-04 02:53:13 +00:00
[JsonProperty("begin")]
2024-07-28 22:59:28 +00:00
public double Begin { get ; set ; }
2024-01-04 02:53:13 +00:00
[JsonProperty("text")]
2024-07-28 22:59:28 +00:00
public string Text { get ; set ; }
2024-01-04 02:53:13 +00:00
public void ToWebVTT ( TextWriter writer )
{
2024-07-28 22:59:28 +00:00
var begin = TimeSpan . FromSeconds ( Begin ) ;
2024-01-04 02:53:13 +00:00
var end = TimeSpan . FromSeconds ( End ) ;
2024-07-28 22:59:28 +00:00
2024-01-04 02:53:13 +00:00
writer . WriteLine ( $"{begin.ToString(" hh \ \ : mm \ \ : ss \ \ . fff ")} --> {end.ToString(" hh \ \ : mm \ \ : ss \ \ . fff ")}" ) ;
2024-07-28 22:59:28 +00:00
2024-01-04 02:53:13 +00:00
writer . WriteLine ( HttpUtility . HtmlEncode ( Text ) ) ;
}
public void ToSrt ( TextWriter writer )
{
2024-07-28 22:59:28 +00:00
var begin = TimeSpan . FromSeconds ( Begin ) ;
2024-01-04 02:53:13 +00:00
var end = TimeSpan . FromSeconds ( End ) ;
writer . WriteLine ( $"{begin.ToString(" hh \ \ : mm \ \ : ss \ \ , fff ")} --> {end.ToString(" hh \ \ : mm \ \ : ss \ \ , fff ")}" ) ;
writer . WriteLine ( Text ) ;
}
2024-07-28 22:59:28 +00:00
public static void ToWebVTT ( TextWriter writer , List < Subtitle > subtitles )
2024-01-04 02:53:13 +00:00
{
writer . WriteLine ( "WEBVTT" ) ;
2024-07-28 22:59:28 +00:00
for ( int i = 0 ; i < subtitles . Count ; i + + )
2024-01-04 02:53:13 +00:00
{
writer . WriteLine ( ) ;
2024-07-28 22:59:28 +00:00
writer . WriteLine ( i + 1 ) ;
2024-01-04 02:53:13 +00:00
subtitles [ i ] . ToWebVTT ( writer ) ;
}
}
2024-07-28 22:59:28 +00:00
public static void ToSrt ( TextWriter writer , List < Subtitle > subtitles )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
for ( int i = 0 ; i < subtitles . Count ; i + + )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
if ( i > 0 ) writer . WriteLine ( ) ;
writer . WriteLine ( i + 1 ) ;
2024-01-04 02:53:13 +00:00
subtitles [ i ] . ToSrt ( writer ) ;
}
}
}
2023-12-16 01:40:05 +00:00
public class CMSServer
{
2024-07-28 22:59:28 +00:00
public static readonly Language [ ] Languages = new Language [ ]
{
2024-01-04 02:53:13 +00:00
new Language ( )
{
LangCode = "en-US" ,
LangCodeVideo = "en" ,
LangTitle = "English (US)"
} ,
new Language ( )
{
LangCode = "en-UK" ,
LangCodeVideo = "en" ,
LangTitle = "English (UK)"
} ,
new Language ( )
{
LangCode = "ar-AE" ,
LangCodeVideo = "ar" ,
LangTitle = "Arabic (AE)"
} ,
new Language ( )
{
LangCode = "zh-CN" ,
LangCodeVideo = "zh" ,
LangTitle = "Chinese (CN)"
} ,
new Language ( )
{
LangCode = "zh-TW" ,
LangCodeVideo = "zh" ,
LangTitle = "Chinese (TW)"
} ,
new Language ( )
{
LangCode = "cs-CZ" ,
LangCodeVideo = "cs" ,
LangTitle = "Czech (CZ)"
} ,
new Language ( )
{
LangCode = "da-DK" ,
LangCodeVideo = "da" ,
LangTitle = "Danish (DK)"
} ,
new Language ( )
{
LangCode = "in-ID" ,
LangCodeVideo = "in" ,
LangTitle = "Indonesian (ID)"
} ,
new Language ( )
{
LangCode = "ms-MY" ,
LangCodeVideo = "ms" ,
LangTitle = "Malaysian (MY)"
} ,
new Language ( )
{
LangCode = "nl-NL" ,
LangCodeVideo = "nl" ,
LangTitle = "Dutch (NL)"
} ,
new Language ( )
{
LangCode = "fr-FR" ,
LangCodeVideo = "fr" ,
LangTitle = "French (FR)"
} ,
new Language ( )
{
LangCode = "fi-FI" ,
LangCodeVideo = "fi" ,
LangTitle = "Finnish (FI)"
} ,
new Language ( )
{
LangCode = "de-DE" ,
LangCodeVideo = "de" ,
LangTitle = "German (DE)"
} ,
new Language ( )
{
LangCode = "it-IT" ,
LangCodeVideo = "it" ,
LangTitle = "Italian (IT)"
} ,
new Language ( )
{
LangCode = "ja-JP" ,
LangCodeVideo = "ja" ,
LangTitle = "Japanese (JP)"
} ,
new Language ( )
{
LangCode = "ko-KR" ,
LangCodeVideo = "ko" ,
LangTitle = "Korean (KR)"
} ,
new Language ( )
{
LangCode = "no-NO" ,
LangCodeVideo = "no" ,
LangTitle = "Norwegian (NO)"
} ,
new Language ( )
{
LangCode = "pl-PL" ,
LangCodeVideo = "pl" ,
LangTitle = "Polish (PL)"
} ,
new Language ( )
{
LangCode = "pt-BR" ,
LangCodeVideo = "pt" ,
LangTitle = "Portuguese (BR)"
} ,
new Language ( )
{
LangCode = "ro-RO" ,
LangCodeVideo = "ro" ,
LangTitle = "Romanian (RO)"
} ,
new Language ( )
{
LangCode = "ru-RU" ,
LangCodeVideo = "ru" ,
LangTitle = "Russian (RU)"
} ,
new Language ( )
{
LangCode = "es-ES" ,
LangCodeVideo = "es" ,
LangTitle = "Spanish (ES)"
} ,
new Language ( )
{
LangCode = "sv-SE" ,
LangCodeVideo = "sv" ,
LangTitle = "Swedish (SE)"
} ,
new Language ( )
{
LangCode = "th-TH" ,
LangCodeVideo = "th" ,
LangTitle = "Thai (TH)"
} ,
new Language ( )
{
LangCode = "tl-PH" ,
LangCodeVideo = "tl" ,
LangTitle = "Filipino (PH)"
} ,
new Language ( )
{
LangCode = "tr-TR" ,
LangCodeVideo = "tr" ,
LangTitle = "Turkish (TR)"
}
} ;
2024-07-28 22:59:28 +00:00
public class Language
{
public string LangCode { get ; set ; }
public string LangCodeVideo { get ; set ; }
public string LangTitle { get ; set ; }
}
public ShowContentMetaData GetShowContentMetaData ( string user , string show )
{
string showDir = Path . Combine ( this . path , user , "show" , show ) ;
var _show = new ShowContentMetaData ( )
{
Info = provider . GetShow ( user , show ) ,
HasPoster = File . Exists ( Path . Combine ( path , user , "show" , show , "poster.jpg" ) ) ,
HasThumbnail = File . Exists ( Path . Combine ( path , user , "show" , show , "thumbnail.jpg" ) ) ,
HasShowTorrent = File . Exists ( Path . Combine ( path , user , "show" , show , $"{show}.torrent" ) ) ,
HasShowWithExtrasTorrent = File . Exists ( Path . Combine ( path , user , "show" , show , $"{show}_withextras.torrent" ) ) ,
PosterUrl = $"{Configuration.Root.TrimEnd('/')}/content/{user}/show/{show}/poster.jpg" ,
ThumbnailUrl = $"{Configuration.Root.TrimEnd('/')}/content/{user}/show/{show}/thumbnail.jpg" ,
ShowTorrentUrl = $"{Configuration.Root.TrimEnd('/')}/content/{user}/show/{show}/{show}.torrent" ,
ShowWithExtrasTorrentUrl = $"{Configuration.Root.TrimEnd('/')}/content/{user}/show/{show}/{show}_withextras.torrent"
} ;
string extrasPath = Path . Combine ( path , user , "show" , show , "extras" ) ;
if ( Directory . Exists ( extrasPath ) )
FindExtras ( $"{Configuration.Root.TrimEnd('/')}/content/{user}/show/{show}/extras/" , extrasPath , _show . ExtraStreams ) ;
return _show ;
}
public SeasonContentMetaData GetSeasonContentMetaData ( string user , string show , int season )
{
string showDir = Path . Combine ( this . path , user , "show" , show ) ;
string episodeDir = Path . Combine ( showDir , $"Season {season.ToString(" D2 ")}" ) ;
var _season0 = new SeasonContentMetaData ( )
{
Info = provider . GetSeason ( user , show , season ) ,
HasPoster = File . Exists ( Path . Combine ( episodeDir , "poster.jpg" ) ) ? true : File . Exists ( Path . Combine ( this . path , user , "show" , show , "poster.jpg" ) ) ,
HasThumbnail = File . Exists ( Path . Combine ( episodeDir , "thumbnail.jpg" ) ) ? true : File . Exists ( Path . Combine ( this . path , user , "show" , show , "thumbnail.jpg" ) ) ,
PosterUrl = File . Exists ( Path . Combine ( episodeDir , "poster.jpg" ) ) ? $"{Configuration.Root.TrimEnd('/')}/content/{user}/show/{show}/Season%20{season.ToString(" D2 ")}/poster.jpg" : $"{Configuration.Root.TrimEnd('/')}/content/{user}/show/{show}/poster.jpg" ,
ThumbnailUrl = File . Exists ( Path . Combine ( episodeDir , "thumbnail.jpg" ) ) ? $"{Configuration.Root.TrimEnd('/')}/content/{user}/show/{show}/Season%20{season.ToString(" D2 ")}/thumbnail.jpg" : $"{Configuration.Root.TrimEnd('/')}/content/{user}/show/{show}/thumbnail.jpg" ,
} ;
return _season0 ;
}
public EpisodeContentMetaData GetEpisodeContentMetaData ( string user , string show , int season , int episode )
{
string episodeDir = Path . Combine ( this . path , user , "show" , show , $"Season {season.ToString(" D2 ")}" ) ;
var _episode = provider . GetEpisode ( user , show , season , episode ) ;
string name = $"{_episode.EpisodeName} S{season.ToString(" D2 ")}E{episode.ToString(" D2 ")}" ;
var _episode0 = new EpisodeContentMetaData ( )
{
HasPoster = File . Exists ( Path . Combine ( episodeDir , $"{name}-poster.jpg" ) ) ? true : ( File . Exists ( Path . Combine ( episodeDir , "poster.jpg" ) ) ? true : File . Exists ( Path . Combine ( this . path , user , "show" , show , "poster.jpg" ) ) ) ,
HasThumbnail = File . Exists ( Path . Combine ( episodeDir , $"{name}-thumbnail.jpg" ) ) ? true : ( File . Exists ( Path . Combine ( episodeDir , "thumbnail.jpg" ) ) ? true : File . Exists ( Path . Combine ( this . path , user , "show" , show , "thumbnail.jpg" ) ) ) ,
HasBrowserStream = File . Exists ( Path . Combine ( episodeDir , $"S{season.ToString(" D2 ")}E{episode.ToString(" D2 ")}.mp4" ) ) ,
HasDownloadStream = File . Exists ( Path . Combine ( episodeDir , $"{_episode.EpisodeName} S{season.ToString(" D2 ")}E{episode.ToString(" D2 ")}.mp4" ) ) ,
PosterUrl = File . Exists ( Path . Combine ( episodeDir , $"{name}-poster.jpg" ) ) ? $"{Configuration.Root.TrimEnd('/')}/content/{user}/show/{show}/Season%20{season.ToString(" D2 ")}/{_episode.EpisodeName}%20S{season.ToString(" D2 ")}E{episode.ToString(" D2 ")}-poster.jpg" : File . Exists ( Path . Combine ( episodeDir , "poster.jpg" ) ) ? $"{Configuration.Root.TrimEnd('/')}/content/{user}/show/{show}/Season%20{season.ToString(" D2 ")}/poster.jpg" : $"{Configuration.Root.TrimEnd('/')}/content/{user}/show/{show}/poster.jpg" ,
ThumbnailUrl = File . Exists ( Path . Combine ( episodeDir , $"{name}-thumbnail.jpg" ) ) ? $"{Configuration.Root.TrimEnd('/')}/content/{user}/show/{show}/Season%20{season.ToString(" D2 ")}/{_episode.EpisodeName}%20S{season.ToString(" D2 ")}E{episode.ToString(" D2 ")}-thumbnail.jpg" : File . Exists ( Path . Combine ( episodeDir , "thumbnail.jpg" ) ) ? $"{Configuration.Root.TrimEnd('/')}/content/{user}/show/{show}/Season%20{season.ToString(" D2 ")}/thumbnail.jpg" : $"{Configuration.Root.TrimEnd('/')}/content/{user}/show/{show}/thumbnail.jpg" ,
BrowserStream = $"{Configuration.Root.TrimEnd('/')}/content/{user}/show/{show}/Season%20{season.ToString(" D2 ")}/S{season.ToString(" D2 ")}E{episode.ToString(" D2 ")}.mp4" ,
DownloadStream = $"{Configuration.Root.TrimEnd('/')}/content/{user}/show/{show}/Season%20{season.ToString(" D2 ")}/{_episode.EpisodeName}%20S{season.ToString(" D2 ")}E{episode.ToString(" D2 ")}.mp4" ,
Info = provider . GetEpisode ( user , show , season , episode )
} ;
GetEpisodeSubtitleStreams ( _episode0 . SubtitlesStreams , user , show , season , episode , _episode . EpisodeName ) ;
return _episode0 ;
}
public void GetEpisodeSubtitleStreams ( List < SubtitleStream > subtitleStreams , string user , string show , int season , int episode , string episode_name )
{
2024-01-04 02:53:13 +00:00
2024-07-28 22:59:28 +00:00
string subDir = Path . Combine ( path , user , "show" , show , $"Season {season.ToString(" D2 ")}" , $"{episode_name} S{season.ToString(" D2 ")}E{episode.ToString(" D2 ")}-subtitles" ) ;
GetSubtitleStreams ( subtitleStreams , subDir , $"{Configuration.Root.TrimEnd('/')}/content/{user}/show/{show}/Season%20{season.ToString(" D2 ")}/{episode_name}%20S{season.ToString(" D2 ")}E{episode.ToString(" D2 ")}-subtitles" , $"{episode_name}%20S{season.ToString(" D2 ")}E{episode.ToString(" D2 ")}" ) ;
}
public void GetMovieSubtitleStreams ( List < SubtitleStream > subtitleStreams , string user , string movie )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
string subDir = Path . Combine ( path , user , "movie" , movie , "subtitles" ) ;
GetSubtitleStreams ( subtitleStreams , subDir , $"{Configuration.Root.TrimEnd('/')}/content/{user}/movie/{movie}/subtitles" , movie ) ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
public void GetSubtitleStreams ( List < SubtitleStream > subtitleStreams , string subDir , string subUrl , string file )
{
2024-01-04 02:53:13 +00:00
2024-07-28 22:59:28 +00:00
if ( Directory . Exists ( subDir ) )
foreach ( var language in Directory . GetDirectories ( subDir ) )
{
string languageCode = Path . GetFileName ( language ) ; //en-US for english
subtitleStreams . Add ( new SubtitleStream ( ) { LanguageCode = languageCode , VttUrl = $"{subUrl}/{languageCode}/{file}.vtt" , SrtUrl = $"{subUrl}/{languageCode}/{file}.srt" } ) ;
}
}
public AlbumContentMetaData GetAlbumContentMetadata ( string user , string album )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
var _albumMeta = provider . GetAlbum ( user , album ) ;
List < Track > browserStreams = new List < Track > ( ) ;
List < Track > downloadStreams = new List < Track > ( ) ;
if ( _albumMeta ! = null )
{
int trackNumber = 1 ;
foreach ( var track in _albumMeta . Tracks )
{
string baseurl = $"{Configuration.Root.TrimEnd('/')}/content/{user}/album/{album}" ;
string browserurl = $"{baseurl}/{HttpUtility.UrlPathEncode(track)}.mp3" ;
string downloadurl = $"{baseurl}/{trackNumber.ToString(" D2 ")}%20{HttpUtility.UrlPathEncode(_albumMeta.AlbumArtist)}%20-%20{HttpUtility.UrlPathEncode(track)}.flac" ;
if ( File . Exists ( Path . Combine ( path , user , "album" , album , $"{track}.mp3" ) ) )
browserStreams . Add ( new Track { Url = browserurl , Name = track , TrackNumber = trackNumber } ) ;
if ( File . Exists ( Path . Combine ( path , user , "album" , album , $"{trackNumber.ToString(" D2 ")} {_albumMeta.AlbumArtist} - {track}.flac" ) ) )
downloadStreams . Add ( new Track { Url = downloadurl , Name = track , TrackNumber = trackNumber } ) ;
2024-01-04 02:53:13 +00:00
2024-07-28 22:59:28 +00:00
trackNumber + + ;
}
}
var _album = new AlbumContentMetaData ( )
{
HasPoster = File . Exists ( Path . Combine ( path , user , "album" , album , "poster.jpg" ) ) ,
HasThumbnail = File . Exists ( Path . Combine ( path , user , "album" , album , "thumbnail.jpg" ) ) ,
HasAlbumTorrent = File . Exists ( Path . Combine ( path , user , "album" , album , $"{album}.torrent" ) ) ,
HasAlbumWithExtrasTorrent = File . Exists ( Path . Combine ( path , user , "album" , album , $"{album}_withextras.torrent" ) ) ,
PosterUrl = $"{Configuration.Root.TrimEnd('/')}/content/{user}/album/{album}/poster.jpg" ,
ThumbnailUrl = $"{Configuration.Root.TrimEnd('/')}/content/{user}/album/{album}/thumbnail.jpg" ,
AlbumTorrentUrl = $"{Configuration.Root.TrimEnd('/')}/content/{user}/album/{album}/{album}.torrent" ,
AlbumWithExtrasTorrentUrl = $"{Configuration.Root.TrimEnd('/')}/content/{user}/album/{album}/{album}_withextras.torrent" ,
DownloadStreams = downloadStreams ,
BrowserStreams = browserStreams ,
Info = _albumMeta
} ;
string extrasPath = Path . Combine ( path , user , "album" , album , "extras" ) ;
if ( Directory . Exists ( extrasPath ) )
FindExtras ( $"{Configuration.Root.TrimEnd('/')}/content/{user}/album/{album}/extras/" , extrasPath , _album . ExtraStreams ) ;
return _album ;
}
2024-01-04 02:53:13 +00:00
2024-07-28 22:59:28 +00:00
public MovieContentMetaData GetMovieContentMetaData ( string user , string movie )
{
var _movie = new MovieContentMetaData ( )
{
HasPoster = File . Exists ( Path . Combine ( path , user , "movie" , movie , "poster.jpg" ) ) ,
HasThumbnail = File . Exists ( Path . Combine ( path , user , "movie" , movie , "thumbnail.jpg" ) ) ,
HasBrowserStream = File . Exists ( Path . Combine ( path , user , "movie" , movie , "browser.mp4" ) ) ,
HasDownloadStream = File . Exists ( Path . Combine ( path , user , "movie" , movie , $"{movie}.mp4" ) ) ,
HasMovieTorrent = File . Exists ( Path . Combine ( path , user , "movie" , movie , $"{movie}.torrent" ) ) ,
HasMovieWithExtrasTorrent = File . Exists ( Path . Combine ( path , user , "movie" , movie , $"{movie}_withextras.torrent" ) ) ,
PosterUrl = $"{Configuration.Root.TrimEnd('/')}/content/{user}/movie/{movie}/poster.jpg" ,
ThumbnailUrl = $"{Configuration.Root.TrimEnd('/')}/content/{user}/movie/{movie}/thumbnail.jpg" ,
BrowserStream = $"{Configuration.Root.TrimEnd('/')}/content/{user}/movie/{movie}/browser.mp4" ,
DownloadStream = $"{Configuration.Root.TrimEnd('/')}/content/{user}/movie/{movie}/{movie}.mp4" ,
MovieTorrentUrl = $"{Configuration.Root.TrimEnd('/')}/content/{user}/movie/{movie}/{movie}.torrent" ,
MovieWithExtrasTorrentUrl = $"{Configuration.Root.TrimEnd('/')}/content/{user}/movie/{movie}/{movie}_withextras.torrent"
} ;
GetMovieSubtitleStreams ( _movie . SubtitlesStreams , user , movie ) ;
string extrasPath = Path . Combine ( path , user , "movie" , movie , "extras" ) ;
if ( Directory . Exists ( extrasPath ) )
FindExtras ( $"{Configuration.Root.TrimEnd('/')}/content/{user}/movie/{movie}/extras/" , extrasPath , _movie . ExtraStreams ) ;
return _movie ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
private void FindExtras ( string extras , string v , List < ExtraDataStream > extraStreams )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
foreach ( var d in Directory . GetDirectories ( v ) )
{
var dirname = Path . GetFileName ( d ) ;
string url = $"{extras}{dirname}/" ;
ExtraDataStream dataStream = new ExtraDataStream ( ) ;
dataStream . IsDir = true ;
dataStream . Name = dirname ;
dataStream . Url = url ;
2024-01-04 02:53:13 +00:00
2024-07-28 22:59:28 +00:00
FindExtras ( url , d , dataStream . Items ) ;
extraStreams . Add ( dataStream ) ;
}
foreach ( var f in Directory . GetFiles ( v ) )
{
var filename = Path . GetFileName ( f ) ;
var url = $"{extras}{filename}" ;
ExtraDataStream dataStream = new ExtraDataStream ( ) ;
dataStream . IsDir = false ;
dataStream . Name = filename ;
dataStream . Url = url ;
extraStreams . Add ( dataStream ) ;
}
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
EmailCreator Creator { get ; set ; }
2024-01-04 02:53:13 +00:00
2023-12-16 01:40:05 +00:00
Template pageShell ;
Template pageIndex ;
Template pageDevcenter ;
2024-01-04 02:53:13 +00:00
Template pageShow ;
Template pageSeason ;
2024-07-28 22:59:28 +00:00
Template pageEpisode ;
2024-01-04 02:53:13 +00:00
Template pageShows ;
2023-12-16 01:40:05 +00:00
Template pageMovie ;
2024-07-28 22:59:28 +00:00
Template pageAlbum ;
Template pageMusicPlayer ;
private Template pageAlbums ;
2023-12-16 01:40:05 +00:00
Template pageMovies ;
Template pageWatchMovie ;
2024-07-28 22:59:28 +00:00
Template pageWatchEpisode ;
2023-12-16 01:40:05 +00:00
Template pageUpload ;
Template pageUsers ;
Template pageEditMovieDetails ;
2024-01-04 02:53:13 +00:00
Template pageEditShowDetails ;
Template pageEditSeasonDetails ;
2024-07-28 22:59:28 +00:00
Template pageEditEpisodeDetails ;
Template pageEditAlbumDetails ;
2023-12-16 01:40:05 +00:00
2024-01-04 02:53:13 +00:00
Template pageExtrasViewer ;
Template pageEditUser ;
2024-07-28 22:59:28 +00:00
private Template pageTracklist ;
2024-01-04 02:53:13 +00:00
Template aboutUser ;
Template pageSubtitleLangList ;
Template pageSubtitleEditor ;
2024-07-28 22:59:28 +00:00
Template pageMailingList ;
Template pageVerifyEmail ;
Template pageManage ;
Template pageEmailMovie ;
Template pageWebhook ;
private Template siteWebMan ;
2023-12-16 01:40:05 +00:00
RouteServer routeServer ;
2024-07-28 22:59:28 +00:00
2023-12-16 01:40:05 +00:00
PathValueServer usersPathValueServer ;
PathValueServer moviePathValueServer ;
2024-01-04 02:53:13 +00:00
2024-07-28 22:59:28 +00:00
PathValueServer albumPathValueServer ;
2024-01-04 02:53:13 +00:00
PathValueServer showPathValueServer ;
PathValueServer seasonPathValueServer ;
2024-07-28 22:59:28 +00:00
PathValueServer episodePathValueServer ;
2024-01-04 02:53:13 +00:00
MountableServer showMountableServer ;
2023-12-16 01:40:05 +00:00
MountableServer usersMountableServer ;
2024-01-04 02:53:13 +00:00
MountableServer seasonMountableServer ;
2023-12-16 01:40:05 +00:00
2024-07-28 22:59:28 +00:00
2023-12-16 01:40:05 +00:00
RouteServer movieRouteServer ;
2024-01-04 02:53:13 +00:00
RouteServer showRouteServer ;
RouteServer seasonRouteServer ;
2024-07-28 22:59:28 +00:00
RouteServer episodeRouteServer ;
private RouteServer albumRouteServer ;
2023-12-16 01:40:05 +00:00
IContentProvider provider ;
string path ;
2024-07-28 22:59:28 +00:00
private event Action < object > SendEvents ;
public CMSServer ( string configpath , IContentProvider provider )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
this . provider = provider ;
usersMountableServer = new MountableServer ( ) ;
2023-12-16 01:40:05 +00:00
usersPathValueServer = new PathValueServer ( usersMountableServer ) ;
2024-07-28 22:59:28 +00:00
movieRouteServer = new RouteServer ( ) ;
2024-01-04 02:53:13 +00:00
showRouteServer = new RouteServer ( ) ;
2024-07-28 22:59:28 +00:00
seasonRouteServer = new RouteServer ( ) ;
episodeRouteServer = new RouteServer ( ) ;
albumRouteServer = new RouteServer ( ) ;
2023-12-16 01:40:05 +00:00
moviePathValueServer = new PathValueServer ( movieRouteServer ) ;
2024-07-28 22:59:28 +00:00
showMountableServer = new MountableServer ( showRouteServer ) ;
showPathValueServer = new PathValueServer ( showMountableServer ) ;
albumPathValueServer = new PathValueServer ( albumRouteServer ) ;
2024-01-04 02:53:13 +00:00
seasonMountableServer = new MountableServer ( seasonRouteServer ) ;
2024-07-28 22:59:28 +00:00
seasonPathValueServer = new PathValueServer ( seasonMountableServer ) ;
episodePathValueServer = new PathValueServer ( episodeRouteServer ) ;
string configJson = Path . Combine ( configpath , "config.json" ) ;
if ( File . Exists ( configJson ) )
2023-12-16 01:40:05 +00:00
{
Configuration = JsonConvert . DeserializeObject < CMSConfiguration > ( File . ReadAllText ( configJson ) ) ;
}
2024-07-28 22:59:28 +00:00
if ( Configuration . BittorrentTrackers . Count = = 0 )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
Configuration . BittorrentTrackers . AddRange ( new string [ ] {
2023-12-16 01:40:05 +00:00
"https://t1.hloli.org:443/announce" ,
"http://1337.abcvg.info:80/announce" ,
"http://tracker.renfei.net:8080/announce" ,
"http://tracker.gbitt.info:80/announce" ,
"http://p2p.0g.cx:6969/announce" ,
"https://tracker.foreverpirates.co:443/announce"
} ) ;
}
2024-07-28 22:59:28 +00:00
Creator = new EmailCreator ( Configuration ) ;
pageShell = Template . Parse ( AssetProvider . ReadAllText ( "/PageShell.html" ) ) ;
2023-12-16 01:40:05 +00:00
pageIndex = Template . Parse ( AssetProvider . ReadAllText ( "/Index.html" ) ) ;
pageDevcenter = Template . Parse ( AssetProvider . ReadAllText ( "/Devcenter.html" ) ) ;
pageMovie = Template . Parse ( AssetProvider . ReadAllText ( "/MoviePage.html" ) ) ;
2024-07-28 22:59:28 +00:00
pageAlbum = Template . Parse ( AssetProvider . ReadAllText ( "/AlbumPage.html" ) ) ;
pageMusicPlayer = Template . Parse ( AssetProvider . ReadAllText ( "/MusicPlayerPage.html" ) ) ;
pageAlbums = Template . Parse ( AssetProvider . ReadAllText ( "/AlbumsPage.html" ) ) ;
2023-12-16 01:40:05 +00:00
pageMovies = Template . Parse ( AssetProvider . ReadAllText ( "/MoviesPage.html" ) ) ;
pageUsers = Template . Parse ( AssetProvider . ReadAllText ( "/UsersPage.html" ) ) ;
pageWatchMovie = Template . Parse ( AssetProvider . ReadAllText ( "/WatchMovie.html" ) ) ;
2024-07-28 22:59:28 +00:00
pageWatchEpisode = Template . Parse ( AssetProvider . ReadAllText ( "/WatchEpisode.html" ) ) ;
2023-12-16 01:40:05 +00:00
pageUpload = Template . Parse ( AssetProvider . ReadAllText ( "/Upload.html" ) ) ;
pageEditMovieDetails = Template . Parse ( AssetProvider . ReadAllText ( "/EditMovieDetails.html" ) ) ;
2024-01-04 02:53:13 +00:00
pageEditShowDetails = Template . Parse ( AssetProvider . ReadAllText ( "/EditShowDetails.html" ) ) ;
pageEditSeasonDetails = Template . Parse ( AssetProvider . ReadAllText ( "/EditSeasonDetails.html" ) ) ;
2024-07-28 22:59:28 +00:00
pageEditEpisodeDetails = Template . Parse ( AssetProvider . ReadAllText ( "/EditEpisodeDetails.html" ) ) ;
pageEditAlbumDetails = Template . Parse ( AssetProvider . ReadAllText ( "/EditAlbumDetails.html" ) ) ;
2024-01-04 02:53:13 +00:00
pageExtrasViewer = Template . Parse ( AssetProvider . ReadAllText ( "/ExtrasViewer.html" ) ) ;
pageEditUser = Template . Parse ( AssetProvider . ReadAllText ( "/AccountEditor.html" ) ) ;
2024-07-28 22:59:28 +00:00
pageTracklist = Template . Parse ( AssetProvider . ReadAllText ( "/Tracklist.html" ) ) ;
2024-01-04 02:53:13 +00:00
aboutUser = Template . Parse ( AssetProvider . ReadAllText ( "/AboutUser.html" ) ) ;
pageVerifyEmail = Template . Parse ( AssetProvider . ReadAllText ( "/VerifyEmailWeb.html" ) ) ;
pageManage = Template . Parse ( AssetProvider . ReadAllText ( "/ManageHtml.html" ) ) ;
pageSubtitleLangList = Template . Parse ( AssetProvider . ReadAllText ( "/SubtitleLangList.html" ) ) ;
pageSubtitleEditor = Template . Parse ( AssetProvider . ReadAllText ( "/SubtitleEditor.html" ) ) ;
pageShow = Template . Parse ( AssetProvider . ReadAllText ( "/ShowPage.html" ) ) ;
pageSeason = Template . Parse ( AssetProvider . ReadAllText ( "/SeasonPage.html" ) ) ;
2024-07-28 22:59:28 +00:00
pageEpisode = Template . Parse ( AssetProvider . ReadAllText ( "/EpisodePage.html" ) ) ;
2024-01-04 02:53:13 +00:00
pageShows = Template . Parse ( AssetProvider . ReadAllText ( "/ShowsPage.html" ) ) ;
2024-07-28 22:59:28 +00:00
pageMailingList = Template . Parse ( AssetProvider . ReadAllText ( "/MailingList.html" ) ) ;
pageEmailMovie = Template . Parse ( AssetProvider . ReadAllText ( "/EmailMovie.html" ) ) ;
pageWebhook = Template . Parse ( AssetProvider . ReadAllText ( "/Webhook.html" ) ) ;
siteWebMan = Template . Parse ( "/site.webmanifest" ) ;
2023-12-16 01:40:05 +00:00
MountableServer mountableServer = new MountableServer ( new AssetProvider ( ) ) ;
2024-07-28 22:59:28 +00:00
path = Path . Combine ( configpath , "content" ) ;
mountableServer . Mount ( "/content/" , new StaticServer ( path ) { AllowListingDirectories = true } ) ;
mountableServer . Mount ( "/api/v1/" , CreateSwagme ( ) ) ;
mountableServer . Mount ( "/user/" , usersPathValueServer ) ;
2023-12-16 01:40:05 +00:00
routeServer = new RouteServer ( mountableServer ) ;
2024-07-28 22:59:28 +00:00
routeServer . Add ( "/" , Index , "GET" ) ;
routeServer . Add ( "/site.webmanifest" , SiteWebManifestAsync , "GET" ) ;
routeServer . Add ( "/devcenter" , Devcenter , "GET" ) ;
routeServer . Add ( "/upload" , UploadPage1 , "GET" ) ;
routeServer . Add ( "/upload" , Upload , "POST" ) ;
routeServer . Add ( "/users" , UsersAsync , "GET" ) ;
routeServer . Add ( "/login" , LoginAsync ) ;
routeServer . Add ( "/logout" , LogoutAsync ) ;
routeServer . Add ( "/login" , LoginPostAsync , "POST" ) ;
routeServer . Add ( "/signup" , SignupAsync ) ;
routeServer . Add ( "/signup" , SignupPostAsync , "POST" ) ;
routeServer . Add ( "/account" , AccountAsync ) ;
routeServer . Add ( "/account" , AccountPostAsync , "POST" ) ;
routeServer . Add ( "/verify" , VerifyAsync ) ;
routeServer . Add ( "/resend" , ResendVerification , "GET" ) ;
routeServer . Add ( "/manage" , ManageAsync ) ;
routeServer . Add ( "/manage" , ManagePostAsync , "POST" ) ;
2024-01-04 02:53:13 +00:00
routeServer . Add ( "/impersonate" , ImpersonateAsync ) ;
2024-07-28 22:59:28 +00:00
2023-12-16 01:40:05 +00:00
RegisterUsersPath ( ) ;
2024-07-28 22:59:28 +00:00
Task . Factory . StartNew ( async ( ) = >
{
Stopwatch watch = new Stopwatch ( ) ;
watch . Start ( ) ;
while ( Running )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
if ( tasks . TryDequeue ( out var item ) )
2023-12-16 01:40:05 +00:00
{
await item ( ) ;
}
await Task . Delay ( TimeSpan . FromSeconds ( 0.125 ) ) ;
2024-07-28 22:59:28 +00:00
if ( watch . Elapsed . TotalMinutes > 10 )
{
ClearExpiredCSRF ( ) ;
watch . Restart ( ) ;
}
2023-12-16 01:40:05 +00:00
}
} ) . Wait ( 0 ) ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
private void ClearExpiredCSRF ( )
{
lock ( CsrfTokens )
{
List < CSRF > csrfs = new List < CSRF > ( ) ;
var dtNow = DateTime . Now ;
foreach ( var item in CsrfTokens )
{
if ( item . Expires < dtNow ) csrfs . Add ( item ) ;
}
foreach ( var item in csrfs )
{
CsrfTokens . Remove ( item ) ;
}
}
}
private async Task SiteWebManifestAsync ( ServerContext ctx )
{
await ctx . SendTextAsync ( await siteWebMan . RenderAsync ( new
{
rooturl = $"{Configuration.Root.TrimEnd('/')}/" ,
title = Configuration . Title
} ) , "application/manifest+json" ) ;
}
2024-01-04 02:53:13 +00:00
public async Task ManagePostAsync ( ServerContext ctx )
{
ctx . ParseBody ( ) ;
2024-07-28 22:59:28 +00:00
var account = GetAccount ( ctx , true ) ;
if ( account ! = null & & account . IsAdmin )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
if ( ctx . QueryParams . TryGetFirst ( "name" , out var name ) )
2024-01-04 02:53:13 +00:00
{
bool isinvited = ctx . QueryParams . ContainsKey ( "invited" ) ;
bool isverified = ctx . QueryParams . ContainsKey ( "verified" ) ;
bool isadmin = ctx . QueryParams . ContainsKey ( "admin" ) ;
var a = provider . GetUserAccount ( name ) ;
a . IsInvited = isinvited ;
a . IsVerified = isverified ;
a . IsAdmin = isadmin ;
provider . UpdateUser ( a ) ;
}
}
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/manage" ) ;
}
public async Task ImpersonateAsync ( ServerContext ctx )
{
2024-07-28 22:59:28 +00:00
var account = GetAccount ( ctx , out var cookie , true ) ;
if ( account ! = null & & account . IsAdmin )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
if ( ctx . QueryParams . TryGetFirst ( "user" , out var user ) )
2024-01-04 02:53:13 +00:00
{
var _user = provider . GetUserAccount ( user ) ;
2024-07-28 22:59:28 +00:00
if ( _user ! = null )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
provider . ChangeSession ( cookie , _user . Id ) ;
2024-01-04 02:53:13 +00:00
}
}
}
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/" ) ;
//impersonate
}
private async Task ManageAsync ( ServerContext ctx )
{
2024-07-28 22:59:28 +00:00
var account = GetAccount ( ctx , out var cookie , false ) ; List < object > users = new List < object > ( ) ;
if ( account ! = null & & account . IsAdmin )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
int i = 0 ;
foreach ( var user in provider . GetUsers ( ) )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
if ( account . Id ! = user . Id )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
string csrf = "" ;
string csrf2 = "" ;
if ( account ! = null )
{
csrf = HttpUtility . UrlEncode ( CreateCSRF ( account . Id , cookie ) ) ;
csrf2 = HttpUtility . HtmlAttributeEncode ( CreateCSRF ( account . Id , cookie ) ) ;
}
string impersonate = $"{Configuration.Root.TrimEnd('/')}/impersonate?user={user.Username}&csrf={csrf}" ;
users . Add ( new { csrf = csrf2 , nameattr = HttpUtility . HtmlAttributeEncode ( user . Username ) , propername = HttpUtility . HtmlEncode ( user . ProperName ) , name = HttpUtility . HtmlEncode ( user . Username ) , isverified = user . IsVerified , isadmin = user . IsAdmin , isinvited = user . IsInvited , impersonate = impersonate , i = i } ) ;
i + + ;
2024-01-04 02:53:13 +00:00
}
}
2024-07-28 22:59:28 +00:00
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , await pageManage . RenderAsync ( new { users = users } ) ) ) ;
2024-01-04 02:53:13 +00:00
}
private async Task ResendVerification ( ServerContext ctx )
{
2024-07-28 22:59:28 +00:00
var account = GetAccount ( ctx ) ;
if ( account ! = null )
{
if ( account . IsVerified )
2024-01-04 02:53:13 +00:00
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/" ) ;
2024-07-28 22:59:28 +00:00
else
{
var code = GetOrGenerateVerification ( account ) ;
await Creator . SendVerificationEmailAsync ( account , code ) ;
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , await pageVerifyEmail . RenderAsync ( new { Email = account . Email } ) ) ) ;
}
}
2024-01-04 02:53:13 +00:00
}
private async Task VerifyAsync ( ServerContext ctx )
{
2024-07-28 22:59:28 +00:00
bool failed = true ;
2024-01-04 02:53:13 +00:00
2024-07-28 22:59:28 +00:00
if ( ctx . QueryParams . TryGetFirst ( "token" , out var token ) )
2024-01-04 02:53:13 +00:00
{
var item = provider . GetVerificationAccount ( token ) ;
2024-07-28 22:59:28 +00:00
if ( item . HasValue )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
var a = provider . GetUserById ( item . Value ) ;
2024-01-04 02:53:13 +00:00
a . IsVerified = true ;
provider . UpdateUser ( a ) ;
2024-07-28 22:59:28 +00:00
failed = false ;
2024-01-04 02:53:13 +00:00
provider . DeleteVerificationCode ( token ) ;
}
2024-07-28 22:59:28 +00:00
if ( ! failed )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , "<h1>Your account has been verified, click login to login.</h1><a href=\"./login\" class=\"btn btn-primary\">Login</a>" ) ) ;
2024-01-04 02:53:13 +00:00
}
}
2024-07-28 22:59:28 +00:00
if ( failed )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , "<h1>Failed to verify account</h1>" ) ) ;
2024-01-04 02:53:13 +00:00
}
}
private async Task AccountPostAsync ( ServerContext ctx )
{
ctx . ParseBody ( ) ;
2024-07-28 22:59:28 +00:00
var account = GetAccount ( ctx , true ) ;
if ( account ! = null )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
if ( ctx . QueryParams . TryGetFirst ( "about_me" , out var about_me ) & & ctx . QueryParams . TryGetFirst ( "proper_name" , out var proper_name ) )
2024-01-04 02:53:13 +00:00
{
account . AboutMe = about_me ;
account . ProperName = proper_name ;
provider . UpdateUser ( account ) ;
2024-07-28 22:59:28 +00:00
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/" ) ;
2024-01-04 02:53:13 +00:00
}
}
else
{
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/login" ) ;
}
}
private async Task AccountAsync ( ServerContext ctx )
{
var account = GetAccount ( ctx ) ;
2024-07-28 22:59:28 +00:00
if ( account ! = null )
2024-01-04 02:53:13 +00:00
{
//account page
2024-07-28 22:59:28 +00:00
var res = new { admin = account . IsAdmin , Notverified = ! account . IsVerified , Propername = HttpUtility . HtmlAttributeEncode ( account . ProperName ) , Aboutme = HttpUtility . HtmlEncode ( account . AboutMe ) } ;
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , await pageEditUser . RenderAsync ( res ) ) ) ;
2024-01-04 02:53:13 +00:00
}
else
{
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/login" ) ;
}
}
private async Task LogoutAsync ( ServerContext ctx )
{
Logout ( ctx ) ;
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/" ) ;
}
2024-07-28 22:59:28 +00:00
public bool Running = true ;
2023-12-16 01:40:05 +00:00
public async Task LoginAsync ( ServerContext ctx )
{
2024-07-28 22:59:28 +00:00
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , await AssetProvider . ReadAllTextAsync ( "/LoginPage.html" ) , false , false , true ) ) ;
2023-12-16 01:40:05 +00:00
}
public async Task SignupAsync ( ServerContext ctx )
{
2024-07-28 22:59:28 +00:00
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , await AssetProvider . ReadAllTextAsync ( "/SignupPage.html" ) , false , false , true ) ) ;
2023-12-16 01:40:05 +00:00
}
public async Task SignupPostAsync ( ServerContext ctx )
{
ctx . ParseBody ( ) ;
2024-07-28 22:59:28 +00:00
if ( ctx . QueryParams . TryGetFirst ( "email" , out var email ) & & ctx . QueryParams . TryGetFirst ( "name" , out var name ) & & ctx . QueryParams . TryGetFirst ( "proper_name" , out var proper_name ) & & ctx . QueryParams . TryGetFirst ( "password" , out var password ) & & ctx . QueryParams . TryGetFirst ( "confirm_password" , out var confirm_password ) )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
bool error = false , emailTaken = false , nameTaken = false , properNameTaken = false , passwordDontMatch = false , passwordNotGoodEnough = false ;
foreach ( var user in provider . GetUsers ( ) )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
if ( user . Username = = name )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
nameTaken = true ;
error = true ;
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
if ( user . Email = = email )
{
emailTaken = true ;
error = true ;
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
if ( user . ProperName = = proper_name )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
properNameTaken = true ;
error = true ;
2023-12-16 01:40:05 +00:00
}
}
2024-07-28 22:59:28 +00:00
if ( password ! = confirm_password )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
error = true ;
passwordDontMatch = true ;
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
if ( password . Length < 10 )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
error = true ;
passwordNotGoodEnough = true ;
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
if ( error )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
StringBuilder b = new StringBuilder ( ) ;
if ( emailTaken )
2023-12-16 01:40:05 +00:00
{
b . AppendLine ( "<h1>Email is taken</h1>" ) ;
}
2024-07-28 22:59:28 +00:00
if ( nameTaken )
2023-12-16 01:40:05 +00:00
{
b . AppendLine ( "<h1>Name is taken</h1>" ) ;
}
2024-07-28 22:59:28 +00:00
if ( properNameTaken )
2023-12-16 01:40:05 +00:00
{
b . AppendLine ( "<h1>Proper Name is taken" ) ;
}
2024-07-28 22:59:28 +00:00
if ( passwordNotGoodEnough )
2023-12-16 01:40:05 +00:00
{
b . AppendLine ( "<h1>Password not good enough</h1>" ) ;
}
2024-07-28 22:59:28 +00:00
if ( passwordDontMatch )
2023-12-16 01:40:05 +00:00
{
b . AppendLine ( "<h1>Passwords don't match</h1>" ) ;
}
await ctx . SendTextAsync ( b . ToString ( ) ) ;
}
else
{
2024-07-28 22:59:28 +00:00
provider . CreateUser ( Configuration , name , proper_name , email , password ) ;
var account = provider . GetUserAccount ( name ) ;
if ( account . IsVerified )
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/" ) ;
2024-01-04 02:53:13 +00:00
else
{
2024-07-28 22:59:28 +00:00
var code = GetOrGenerateVerification ( account ) ;
await Creator . SendVerificationEmailAsync ( account , code ) ;
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , await pageVerifyEmail . RenderAsync ( new { Email = email } ) ) ) ;
2024-01-04 02:53:13 +00:00
}
2023-12-16 01:40:05 +00:00
}
}
}
2024-01-04 02:53:13 +00:00
private string GetOrGenerateVerification ( UserAccount account )
{
2024-07-28 22:59:28 +00:00
var now = DateTime . Now ;
2024-01-04 02:53:13 +00:00
2024-07-28 22:59:28 +00:00
byte [ ] bytes = new byte [ 32 ] ;
string token ;
using ( var rng = RandomNumberGenerator . Create ( ) )
do
{
rng . GetBytes ( bytes ) ;
token = Convert . ToBase64String ( bytes ) ;
} while ( provider . ContainsVerificationCode ( token ) ) ;
provider . CreateVerificationCode ( token , account . Id ) ;
return token ;
2024-01-04 02:53:13 +00:00
}
2023-12-16 01:40:05 +00:00
public async Task LoginPostAsync ( ServerContext ctx )
{
ctx . ParseBody ( ) ;
2024-07-28 22:59:28 +00:00
if ( ctx . QueryParams . TryGetFirst ( "email" , out var email ) & & ctx . QueryParams . TryGetFirst ( "password" , out var password ) )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
foreach ( var a in provider . GetUsers ( ) )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
if ( a . Email ! = email ) continue ;
if ( a . Email = = email & & a . PasswordCorrect ( password ) )
2023-12-16 01:40:05 +00:00
{
//we got it
2024-07-28 22:59:28 +00:00
byte [ ] bytes = new byte [ 32 ] ;
2023-12-16 01:40:05 +00:00
string cookie ;
2024-07-28 22:59:28 +00:00
using ( var rng = RandomNumberGenerator . Create ( ) )
do
{
rng . GetBytes ( bytes ) ;
cookie = Convert . ToBase64String ( bytes ) ;
} while ( provider . ContainsSession ( cookie ) ) ;
2023-12-16 01:40:05 +00:00
2024-07-28 22:59:28 +00:00
provider . CreateSession ( cookie , a . Id ) ;
ctx . ResponseHeaders . Add ( "Set-Cookie" , $"Session={cookie}; Path=/" ) ;
2023-12-16 01:40:05 +00:00
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/" ) ;
return ;
2024-07-28 22:59:28 +00:00
}
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
ctx . StatusCode = 401 ;
2023-12-16 01:40:05 +00:00
await ctx . SendTextAsync ( "<h1>Incorrect</h1><a href=\"./\">Home</a> | <a href=\"./login\">Login</a>" ) ;
2024-07-28 22:59:28 +00:00
2023-12-16 01:40:05 +00:00
}
}
2024-01-04 02:53:13 +00:00
private void Logout ( ServerContext ctx )
{
2024-07-28 22:59:28 +00:00
if ( ctx . RequestHeaders . TryGetValue ( "Cookie" , out var cookies ) )
{
foreach ( var c in cookies )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
var co = c . Split ( new char [ ] { '=' } , 2 ) ;
if ( co . Length = = 2 & & co [ 0 ] = = "Session" )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
if ( provider . ContainsSession ( co [ 1 ] ) )
2024-01-04 02:53:13 +00:00
{
provider . DeleteSession ( co [ 1 ] ) ;
return ;
}
}
}
}
2024-07-28 22:59:28 +00:00
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
HttpClient client = new HttpClient ( ) ;
private async Task SendEvent ( EventType type , string userpropername , string username , string name , string propername , string description , string body )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
CMSEvent evt = new CMSEvent ( ) { Type = type , Username = username , Name = name , ProperName = propername , UserProperName = userpropername , Description = description , Body = body } ;
try
{
SendEvents ? . Invoke ( evt ) ;
}
catch ( Exception ex ) { _ = ex ; }
foreach ( var user in provider . GetUsers ( ) )
{
foreach ( var wh in user . Webhooks )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
if ( wh . Username ! = username ) continue ;
if ( ( type = = EventType . MovieCreate | | type = = EventType . MovieUpdate ) & & wh . EnabledMovies )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
switch ( wh . Type )
{
case WebHookType . Ntfy :
//ntfy is the easiest
{
string con = $"Movie {propername} by {userpropername} was {(type == EventType.MovieCreate ? " created " : " updated ")}" ;
try
{
await SendNtfyAsync ( $"{Configuration.Root.TrimEnd('/')}/user/{username}/movie/{name}/" , wh . Url , wh . Key , wh . Priority , con , body ) ;
//(await client.PostAsync(wh.Url,new StringContent(con))).Dispose();
}
catch ( Exception ex )
{
_ = ex ;
}
}
break ;
case WebHookType . Gotify :
{
string con = $"Movie {propername} by {userpropername} was {(type == EventType.MovieCreate ? " created " : " updated ")}" ;
await SendGotifyAsync ( wh . Url , wh . Key , wh . Priority , con , body ) ;
}
break ;
case WebHookType . Other :
( await client . PostAsync ( wh . Url , new StringContent ( JsonConvert . SerializeObject ( new { key = wh . Key , data = evt } ) , Encoding . UTF8 , "application/json" ) ) ) . Dispose ( ) ;
break ;
}
}
if ( ( type = = EventType . ShowCreate | | type = = EventType . ShowUpdate ) & & wh . EnabledShows )
{
switch ( wh . Type )
{
case WebHookType . Ntfy :
//ntfy is the easiest
{
string con = $"Show {propername} by {userpropername} was {(type == EventType.ShowCreate ? " created " : " updated ")}" ;
try
{
await SendNtfyAsync ( $"{Configuration.Root.TrimEnd('/')}/user/{username}/show/{name}/" , wh . Url , wh . Key , wh . Priority , con , body ) ;
}
catch ( Exception ex )
{
_ = ex ;
}
}
break ;
case WebHookType . Gotify :
{
string con = $"Show {propername} by {userpropername} was {(type == EventType.ShowCreate ? " created " : " updated ")}" ;
await SendGotifyAsync ( wh . Url , wh . Key , wh . Priority , con , body ) ;
}
break ;
case WebHookType . Other :
( await client . PostAsync ( wh . Url , new StringContent ( JsonConvert . SerializeObject ( new { key = wh . Key , data = evt } ) , Encoding . UTF8 , "application/json" ) ) ) . Dispose ( ) ;
break ;
}
}
if ( ( type = = EventType . AlbumCreate | | type = = EventType . AlbumUpdate ) & & wh . EnabledShows )
{
switch ( wh . Type )
{
case WebHookType . Ntfy :
//ntfy is the easiest
{
string con = $"Album {propername} by {userpropername} was {(type == EventType.AlbumCreate ? " created " : " updated ")}" ;
try
{
await SendNtfyAsync ( $"{Configuration.Root.TrimEnd('/')}/user/{username}/album/{name}/" , wh . Url , wh . Key , wh . Priority , con , body ) ;
}
catch ( Exception ex )
{
_ = ex ;
}
}
break ;
case WebHookType . Gotify :
{
string con = $"Album {propername} by {userpropername} was {(type == EventType.AlbumCreate ? " created " : " updated ")}" ;
await SendGotifyAsync ( wh . Url , wh . Key , wh . Priority , con , body ) ;
}
break ;
case WebHookType . Other :
( await client . PostAsync ( wh . Url , new StringContent ( JsonConvert . SerializeObject ( new { key = wh . Key , data = evt } ) , Encoding . UTF8 , "application/json" ) ) ) . Dispose ( ) ;
break ;
}
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
2023-12-16 01:40:05 +00:00
}
}
}
2024-07-28 22:59:28 +00:00
private async Task SendNtfyAsync ( string cmsurl , string url , string key , int priority , string con , string body )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
try
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
using ( HttpRequestMessage request = new HttpRequestMessage ( HttpMethod . Post , url ) )
{
request . Headers . Add ( "Title" , con ) ;
request . Headers . Add ( "Click" , cmsurl ) ;
request . Headers . Add ( "Priority" , priority . ToString ( ) ) ;
if ( ! string . IsNullOrWhiteSpace ( key ) )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
request . Headers . Add ( "Authorization" , $"Bearer {key}" ) ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
request . Content = new StringContent ( body ) ;
( await client . SendAsync ( request ) ) . Dispose ( ) ;
}
}
catch ( Exception ex )
{
_ = ex ;
}
}
private async Task SendGotifyAsync ( string url , string key , int prio , string con , string body )
{
try
{
HttpRequestMessage request = new HttpRequestMessage ( HttpMethod . Post , $"{url.TrimEnd('/')}/message" ) ;
request . Headers . Add ( "X-Gotify-Key" , key ) ;
request . Content = new StringContent ( JsonConvert . SerializeObject ( new { message = body , title = con , priority = prio } ) , Encoding . UTF8 , "application/json" ) ;
( await client . SendAsync ( request ) ) . Dispose ( ) ;
}
catch ( Exception ex )
{
_ = ex ;
}
}
private string CreateCSRF ( long account , string cookie )
{
lock ( CsrfTokens )
{
CSRF csrf = new CSRF ( account , cookie ) ;
CsrfTokens . Add ( csrf ) ;
return csrf . CSRFToken ;
}
}
List < CSRF > CsrfTokens { get ; set ; } = new List < CSRF > ( ) ;
private UserAccount GetAccount ( ServerContext ctx , bool requiresCSRF = false )
{
return GetAccount ( ctx , out var s , requiresCSRF ) ;
}
bool IsValidCSRFAndDestroy ( long account , string cookie , string csrf )
{
lock ( CsrfTokens )
{
var now = DateTime . Now ;
foreach ( var token in CsrfTokens )
{
if ( token . Expires > now & & cookie = = token . Cookie & & csrf = = token . CSRFToken & & account = = token . UserId )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
CsrfTokens . Remove ( token ) ;
return true ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
}
return false ;
}
}
private UserAccount GetAccount ( ServerContext ctx , out string cookie , bool requiresCSRF = false )
{
cookie = "" ;
if ( ctx . RequestHeaders . TryGetValue ( "Cookie" , out var cookies ) )
{
foreach ( var c in cookies )
{
var co = c . Split ( new char [ ] { '=' } , 2 ) ;
if ( co . Length = = 2 & & co [ 0 ] = = "Session" )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
cookie = co [ 1 ] ;
long? account = provider . GetSession ( cookie ) ;
if ( account . HasValue )
{
if ( requiresCSRF )
{
if ( ctx . QueryParams . TryGetFirst ( "csrf" , out var csrf ) )
{
if ( IsValidCSRFAndDestroy ( account . Value , cookie , csrf ) )
{
return provider . GetUserById ( account . Value ) ;
}
}
throw new InvalidCSRFException ( ) ;
}
return provider . GetUserById ( account . Value ) ;
}
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
}
}
else if ( ctx . RequestHeaders . TryGetFirst ( "Authentication" , out var auth ) )
{
var co = auth . Split ( new char [ ] { ' ' } , 2 ) ;
if ( co . Length = = 2 & & co [ 0 ] = = "Bearer" )
{
long? account = provider . GetSession ( co [ 1 ] ) ;
if ( account . HasValue )
return provider . GetUserById ( account . Value ) ;
}
}
return null ;
}
private async Task UsersAsync ( ServerContext ctx )
{
List < object > users = new List < object > ( ) ;
foreach ( var user in provider . GetUsers ( ) )
{
if ( ! user . IsAdmin & & Configuration . Publish = = CMSPublish . Admin )
{
//await ctx.SendTextAsync(await RenderHtmlAsync(ctx,"<h1>You can't upload content</h1>"));
continue ;
}
if ( ! ( user . IsAdmin | | user . IsInvited ) & & Configuration . Publish = = CMSPublish . RequireInvite )
{
//await ctx.SendTextAsync(await RenderHtmlAsync(ctx,"<h1>You can't upload content</h1>"));
continue ;
}
if ( ! ( user . IsAdmin | | user . IsInvited | | user . IsVerified ) )
{
//await ctx.SendTextAsync(await RenderHtmlAsync(ctx,"<h1>You can't upload content</h1>"));
continue ;
}
2024-01-04 02:53:13 +00:00
2023-12-16 01:40:05 +00:00
users . Add ( user . Scriban ( ) ) ;
}
2024-07-28 22:59:28 +00:00
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , await pageUsers . RenderAsync ( new
{
Users = users ,
rooturl = $"{Configuration.Root.TrimEnd('/')}/"
2023-12-16 01:40:05 +00:00
} ) ) ) ;
}
2024-07-28 22:59:28 +00:00
const string badC = "/\\\"&,?|:;*@!# " ;
const string badCKeepSpace = "/\\\"&,?|:;*@!#" ;
private string FixStringKeepSpace ( string str )
{
StringBuilder b = new StringBuilder ( ) ;
foreach ( var item in str )
{
if ( char . IsControl ( item ) )
{
continue ;
}
if ( item > = 127 ) continue ;
if ( badCKeepSpace . Contains ( item . ToString ( ) ) ) continue ;
b . Append ( item . ToString ( ) ) ;
}
return b . ToString ( ) ;
}
2023-12-16 01:40:05 +00:00
private string FixString ( string str )
{
2024-07-28 22:59:28 +00:00
StringBuilder b = new StringBuilder ( ) ;
foreach ( var item in str )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
if ( char . IsControl ( item ) )
2023-12-16 01:40:05 +00:00
{
continue ;
}
2024-07-28 22:59:28 +00:00
if ( item > = 127 ) continue ;
if ( badC . Contains ( item . ToString ( ) ) ) continue ;
2023-12-16 01:40:05 +00:00
b . Append ( item . ToString ( ) ) ;
}
return b . ToString ( ) ;
}
private async Task Upload ( ServerContext ctx )
{
ctx . ParseBody ( ) ;
2024-07-28 22:59:28 +00:00
if ( ctx . QueryParams . TryGetFirst ( "name" , out var name ) & & ctx . QueryParams . TryGetFirst ( "proper_name" , out var proper_name ) & & ctx . QueryParams . TryGetFirst ( "type" , out var type ) & & ctx . QueryParams . TryGetFirst ( "description" , out var description ) )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
var account = GetAccount ( ctx , true ) ;
if ( account ! = null )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
if ( ! account . IsAdmin & & Configuration . Publish = = CMSPublish . Admin )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , "<h1>You can't upload content</h1>" ) ) ;
2023-12-16 01:40:05 +00:00
return ;
}
2024-07-28 22:59:28 +00:00
if ( ! ( account . IsAdmin | | account . IsInvited ) & & Configuration . Publish = = CMSPublish . RequireInvite )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , "<h1>You can't upload content</h1>" ) ) ;
2023-12-16 01:40:05 +00:00
return ;
}
2024-07-28 22:59:28 +00:00
if ( ! ( account . IsAdmin | | account . IsInvited | | account . IsVerified ) )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , "<h1>You can't upload content</h1>" ) ) ;
2023-12-16 01:40:05 +00:00
return ;
}
name = FixString ( name ) ;
2024-07-28 22:59:28 +00:00
switch ( type )
2023-12-16 01:40:05 +00:00
{
case "movie" :
2024-07-28 22:59:28 +00:00
var movie = provider . CreateMovie ( account . Username , name , proper_name , description . Replace ( "\r" , "" ) ) ;
ScheduleTask ( async ( ) = >
{
await this . Creator . EmailMovieAsync ( provider , account , movie , false ) ;
await SendEvent ( EventType . MovieCreate , account . ProperName , account . Username , movie . Name , movie . ProperName , movie . Description , "" ) ;
} ) ;
2023-12-16 01:40:05 +00:00
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/user/{account.Username}/movie/{name}/edit" ) ;
break ;
2024-01-04 02:53:13 +00:00
case "show" :
2024-07-28 22:59:28 +00:00
var show = provider . CreateShow ( account . Username , name , proper_name , description ) ;
ScheduleTask ( async ( ) = >
{
await this . Creator . EmailShowAsync ( provider , account , show , false ) ;
await SendEvent ( EventType . ShowCreate , account . ProperName , account . Username , show . Name , show . ProperName , show . Description , "" ) ;
} ) ;
2024-01-04 02:53:13 +00:00
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/user/{account.Username}/show/{name}/edit" ) ;
break ;
2024-07-28 22:59:28 +00:00
case "album" :
var album = provider . CreateAlbum ( account . Username , name , proper_name , description ) ;
ScheduleTask ( async ( ) = >
{
await this . Creator . EmailAlbumAsync ( provider , account , album , false ) ;
await SendEvent ( EventType . AlbumCreate , account . ProperName , account . Username , album . Name , album . ProperName , album . Description , "" ) ;
} ) ;
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/user/{account.Username}/album/{name}/edit" ) ;
break ;
2024-01-04 02:53:13 +00:00
}
}
else
{
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/login" ) ;
}
}
else
{
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/" ) ;
}
}
public async Task UploadPage1 ( ServerContext ctx )
{
2024-07-28 22:59:28 +00:00
var account = GetAccount ( ctx , out var cookie ) ;
if ( account ! = null )
{
var csrf = HttpUtility . HtmlAttributeEncode ( CreateCSRF ( account . Id , cookie ) ) ;
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , await RenderUpload1Async ( csrf ) , false , false , false , true ) ) ;
}
2024-01-04 02:53:13 +00:00
}
public IServer Movies ( )
{
2024-07-28 22:59:28 +00:00
RouteServer routeServer = new RouteServer ( ) ;
routeServer . Add ( "/" , MoviesAsync ) ;
2024-01-04 02:53:13 +00:00
return routeServer ;
}
public async Task MoviesAsync ( ServerContext ctx )
{
2024-07-28 22:59:28 +00:00
string user = usersPathValueServer . GetValue ( ctx ) ;
List < object > movies = new List < object > ( ) ;
foreach ( var item in provider . GetMovies ( user ) )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
var data = GetMovieContentMetaData ( user , item . Name ) ;
2024-01-04 02:53:13 +00:00
movies . Add ( item . Scriban ( data . ThumbnailUrl ) ) ;
}
2024-07-28 22:59:28 +00:00
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , await pageMovies . RenderAsync ( new { Movies = movies } ) ) ) ;
2024-01-04 02:53:13 +00:00
}
private void RegisterUsersPath ( )
{
2024-07-28 22:59:28 +00:00
RouteServer routeServer = new RouteServer ( ) ;
routeServer . Add ( "/" , UserPageAsync ) ;
routeServer . Add ( "/about" , AboutAsync ) ;
routeServer . Add ( "/mailinglist" , MailingListAsync ) ;
routeServer . Add ( "/mailinglist" , MailingListPostAsync , "POST" ) ;
routeServer . Add ( "/webhooks" , Webhooks ) ;
routeServer . Add ( "/update_webhook" , UpdateWebhook , "POST" ) ;
routeServer . Add ( "/create_webhook" , CreateWebhook , "POST" ) ;
usersMountableServer . Mount ( "/" , routeServer ) ;
usersMountableServer . Mount ( "/movies/" , Movies ( ) ) ;
usersMountableServer . Mount ( "/movie/" , moviePathValueServer ) ;
usersMountableServer . Mount ( "/shows/" , Shows ( ) ) ;
usersMountableServer . Mount ( "/show/" , showPathValueServer ) ;
usersMountableServer . Mount ( "/albums/" , Albums ( ) ) ;
usersMountableServer . Mount ( "/album/" , albumPathValueServer ) ;
2024-01-04 02:53:13 +00:00
RegisterMoviePath ( ) ;
RegisterShowPath ( ) ;
2024-07-28 22:59:28 +00:00
RegisterAlbumPath ( ) ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
private async Task CreateWebhook ( ServerContext ctx )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
ctx . ParseBody ( ) ;
string username = usersPathValueServer . GetValue ( ctx ) ;
var theAccount = provider . GetUserAccount ( username ) ;
var account = GetAccount ( ctx , true ) ;
if ( account ! = null )
{
if ( ! ctx . QueryParams . TryGetFirst ( "key" , out var key ) ) key = "" ;
if ( ! ctx . QueryParams . TryGetFirstInt32 ( "priority" , out var priority ) ) priority = 2 ;
bool enablemovies = ctx . QueryParams . GetFirstBoolean ( "enablemovies" ) ;
bool enableshows = ctx . QueryParams . GetFirstBoolean ( "enableshows" ) ;
bool enablealbums = ctx . QueryParams . GetFirstBoolean ( "enablealbums" ) ;
bool enablesoftware = ctx . QueryParams . GetFirstBoolean ( "enablesoftware" ) ;
bool enableother = ctx . QueryParams . GetFirstBoolean ( "enableother" ) ;
if ( ctx . QueryParams . TryGetFirst ( "name" , out var name ) & & ctx . QueryParams . TryGetFirst ( "url" , out var url ) & & ctx . QueryParams . TryGetFirst ( "type" , out var type ) )
{
WebHook hook = new WebHook
{
Username = username ,
Priority = priority ,
Url = url ,
WebhookName = name ,
Type = type = = "ntfy" ? WebHookType . Ntfy : ( type = = "gotify" ? WebHookType . Gotify : WebHookType . Other ) ,
Key = key ,
EnabledMovies = enablemovies ,
EnabledShows = enableshows ,
EnabledAlbums = enablealbums ,
EnabledSoftware = enablesoftware ,
EnabledOther = enableother
} ;
account . Webhooks . Add ( hook ) ;
provider . UpdateUser ( account ) ;
}
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/user/{username}/webhooks" ) ;
}
else
{
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/login" ) ;
}
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
private async Task UpdateWebhook ( ServerContext ctx )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
ctx . ParseBody ( ) ;
string username = usersPathValueServer . GetValue ( ctx ) ;
var theAccount = provider . GetUserAccount ( username ) ;
var account = GetAccount ( ctx , true ) ;
if ( account ! = null )
{
if ( ! ctx . QueryParams . TryGetFirst ( "key" , out var key ) ) key = "" ;
if ( ! ctx . QueryParams . TryGetFirstInt32 ( "priority" , out var priority ) ) priority = 2 ;
bool enablemovies = ctx . QueryParams . GetFirstBoolean ( "enablemovies" ) ;
bool enableshows = ctx . QueryParams . GetFirstBoolean ( "enableshows" ) ;
bool enablealbums = ctx . QueryParams . GetFirstBoolean ( "enablealbums" ) ;
bool enablesoftware = ctx . QueryParams . GetFirstBoolean ( "enablesoftware" ) ;
bool enableother = ctx . QueryParams . GetFirstBoolean ( "enableother" ) ;
if ( ctx . QueryParams . TryGetFirst ( "name" , out var name ) & & ctx . QueryParams . TryGetFirst ( "url" , out var url ) )
{
foreach ( var item in account . Webhooks )
{
if ( item . WebhookName = = name & & item . Username = = username )
{
if ( ctx . QueryParams . TryGetFirst ( "action" , out var val ) & & val = = "Delete" )
{
account . Webhooks . Remove ( item ) ;
provider . UpdateUser ( account ) ;
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/user/{username}/webhooks" ) ;
return ;
}
item . EnabledMovies = enablemovies ;
item . EnabledShows = enableshows ;
item . EnabledAlbums = enablealbums ;
item . EnabledSoftware = enablesoftware ;
item . EnabledOther = enableother ;
item . Key = key ;
item . Priority = priority ;
item . Url = url ;
provider . UpdateUser ( account ) ;
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/user/{username}/webhooks" ) ;
return ;
}
}
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/user/{username}/webhooks" ) ;
}
else
{
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/login" ) ;
}
}
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
private async Task Webhooks ( ServerContext ctx )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
string username = usersPathValueServer . GetValue ( ctx ) ;
var theAccount = provider . GetUserAccount ( username ) ;
var account = GetAccount ( ctx ) ;
if ( account ! = null )
{
List < object > webhooks = new List < object > ( ) ;
foreach ( var item in account . Webhooks )
{
if ( item . Username ! = username ) continue ;
2024-01-04 02:53:13 +00:00
2024-07-28 22:59:28 +00:00
webhooks . Add ( new { name = item . WebhookName , ntfy = item . Type = = WebHookType . Ntfy , gotify = item . Type = = WebHookType . Gotify , priority = item . Priority , url = item . Url , key = item . Key , enablemovies = item . EnabledMovies , enableshows = item . EnabledShows , enablealbums = item . EnabledAlbums , enablesoftware = item . EnabledSoftware , enableother = item . EnabledOther } ) ;
}
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , await pageWebhook . RenderAsync ( new
{
webhooks
} ) ) ) ;
}
else
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/login" ) ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
}
2024-01-04 02:53:13 +00:00
2024-07-28 22:59:28 +00:00
private async Task MailingListPostAsync ( ServerContext ctx )
{
string user = usersPathValueServer . GetValue ( ctx ) ;
var theAccount = provider . GetUserAccount ( user ) ;
var account = GetAccount ( ctx , true ) ;
if ( account ! = null )
{
ctx . ParseBody ( ) ;
MailEntry entry = null ;
foreach ( var item in theAccount . AccountsToMail )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
if ( item . UserId = = account . Id )
{
entry = item ;
break ;
}
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
if ( entry = = null )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
entry = new MailEntry ( ) { UserId = account . Id } ;
theAccount . AccountsToMail . Add ( entry ) ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
entry . EnableMovies = ctx . QueryParams . ContainsKey ( "enablemovies" ) ;
entry . EnableShows = ctx . QueryParams . ContainsKey ( "enableshows" ) ;
entry . EnableSingles = ctx . QueryParams . ContainsKey ( "enablesingles" ) ;
entry . EnableAlbums = ctx . QueryParams . ContainsKey ( "enablealbums" ) ;
entry . EnableSoftware = ctx . QueryParams . ContainsKey ( "enablesoftware" ) ;
entry . EnableOther = ctx . QueryParams . ContainsKey ( "enableother" ) ;
entry . EnableUpdates = ctx . QueryParams . ContainsKey ( "enableupdates" ) ;
provider . UpdateUser ( theAccount ) ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/user/{user}/" ) ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
private async Task MailingListAsync ( ServerContext ctx )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
string user = usersPathValueServer . GetValue ( ctx ) ;
var theAccount = provider . GetUserAccount ( user ) ;
var account = GetAccount ( ctx ) ;
if ( account ! = null )
{
MailEntry entry = new MailEntry ( ) { UserId = account . Id } ;
foreach ( var item in theAccount . AccountsToMail )
{
if ( item . UserId = = account . Id )
{
entry = item ;
break ;
}
}
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , await pageMailingList . RenderAsync ( new
{
enablemovies = entry . EnableMovies ,
enableshows = entry . EnableShows ,
enablesingles = entry . EnableSingles ,
enablealbums = entry . EnableAlbums ,
enablesoftware = entry . EnableSoftware ,
enableother = entry . EnableOther ,
enableupdates = entry . EnableUpdates
} ) ) ) ;
return ;
}
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/login" ) ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
private async Task EditAlbumPagePostAsync ( ServerContext ctx )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
ctx . ParseBody ( ) ;
string user = usersPathValueServer . GetValue ( ctx ) ;
string album = albumPathValueServer . GetValue ( ctx ) ;
var me = GetAccount ( ctx , true ) ;
var _album = provider . GetAlbum ( user , album ) ;
2024-01-04 02:53:13 +00:00
2024-07-28 22:59:28 +00:00
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
me = null ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
if ( me ! = null )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
if ( _album ! = null )
{
if ( ctx . QueryParams . TryGetFirst ( "proper_name" , out var proper_name ) & & ctx . QueryParams . TryGetFirst ( "description" , out var description ) & & ctx . QueryParams . TryGetFirst ( "album_artist" , out var album_artst ) & & ctx . QueryParams . TryGetFirst ( "year" , out var yearS ) & & int . TryParse ( yearS , out var year ) )
{
_album . ProperName = proper_name ;
_album . Description = description . Replace ( "\r" , "" ) ;
_album . AlbumArtist = FixStringKeepSpace ( album_artst ) ;
_album . Year = year ;
provider . UpdateAlbum ( _album ) ;
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , "<h1>Success</h1><a href=\"./edit\"><- Back</a>" ) ) ;
return ;
}
}
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , "<h1>Failed</h1><a href=\"./edit\"><- Back</a>" ) ) ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
private void RegisterAlbumPath ( )
{
albumRouteServer . Add ( "/" , AlbumPageAsync ) ;
albumRouteServer . Add ( "/play" , PlayAlbumAsync ) ;
albumRouteServer . Add ( "/edit" , EditAlbumPageAsync ) ;
albumRouteServer . Add ( "/edit" , EditAlbumPagePostAsync , "POST" ) ;
albumRouteServer . Add ( "/upload" , UploadAlbumStreamAsync , "POST" ) ;
albumRouteServer . Add ( "/sendupdate" , SendAlbumUpdateAsync , "POST" ) ;
albumRouteServer . Add ( "/edit_tracklist" , EditTracklistAsync ) ;
albumRouteServer . Add ( "/edit_tracklist" , EditTracklistPostAsync , "POST" ) ;
albumRouteServer . Add ( "/upload_extra" , UploadAlbumExtraAsync , "POST" ) ;
albumRouteServer . Add ( "/extras" , ExtrasAlbumPageAsync ) ;
albumRouteServer . Add ( "/mkdir" , ExtrasAlbumMkdirAsync , "POST" ) ;
2024-01-04 02:53:13 +00:00
2024-07-28 22:59:28 +00:00
}
private async Task EditTracklistPostAsync ( ServerContext ctx )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
string user = usersPathValueServer . GetValue ( ctx ) ;
string album = albumPathValueServer . GetValue ( ctx ) ;
2024-01-04 02:53:13 +00:00
2024-07-28 22:59:28 +00:00
var _album = provider . GetAlbum ( user , album ) ;
var _user = provider . GetUserAccount ( user ) ;
var me = GetAccount ( ctx , true ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
me = null ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
if ( _album ! = null & & me ! = null & & _user ! = null )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
Directory . CreateDirectory ( Path . Combine ( path , user , "album" , album ) ) ;
var tmpFile = Path . Combine ( path , user , "album" , album , $"tmp{DateTime.Now.ToFileTime().ToString()}.bin" ) ;
foreach ( var item in ctx . ParseBody ( ( n , fn , ct ) = > File . Create ( tmpFile ) ) )
item . Value . Dispose ( ) ;
if ( ! ctx . QueryParams . TryGetFirst ( "operation" , out var operation ) )
operation = "" ;
if ( ! ctx . QueryParams . TryGetFirstInt32 ( "track_id" , out var track_id ) )
track_id = 0 ;
switch ( operation )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
case "Yes" :
{
string oldtrack = _album . Tracks [ track_id ] ;
string flac = Path . Combine ( path , user , "album" , album , $"{(track_id + 1).ToString(" D2 ")} {_album.AlbumArtist} - {oldtrack}.flac" ) ;
if ( File . Exists ( flac ) ) File . Delete ( flac ) ;
string oldmp3 = Path . Combine ( path , user , "album" , album , $"{oldtrack}.mp3" ) ;
if ( File . Exists ( oldmp3 ) ) File . Delete ( oldmp3 ) ;
_album . Tracks . RemoveAt ( track_id ) ;
for ( int i = track_id ; i < _album . Tracks . Count ; i + + )
{
string oldflac = Path . Combine ( path , user , "album" , album , $"{(track_id + 2).ToString(" D2 ")} {_album.AlbumArtist} - {oldtrack}.flac" ) ;
string newflac = Path . Combine ( path , user , "album" , album , $"{(track_id + 1).ToString(" D2 ")} {_album.AlbumArtist} - {oldtrack}.flac" ) ;
if ( File . Exists ( oldflac ) ) File . Move ( oldflac , newflac ) ;
}
provider . UpdateAlbum ( _album ) ;
}
break ;
case "Delete" :
{
string oldtrack = _album . Tracks [ track_id ] ;
string text = $"<h1>Delete Track: {oldtrack}?</h1><span>Note the media files will be removed</span><form method=\" POST \ " action=\"./edit_tracklist\"><input type=\"hidden\" name=\"track_id\" value=\"{track_id}\"><input type=\"submit\" name=\"operation\" value=\"Yes\" class=\"btn btn-danger\" value=\"Yes\"><a href=\"./edit_tracklist\" class=\"btn btn-primary\">No</a></form>" ;
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , text ) ) ;
return ;
}
case "Upload" :
{
string oldtrack = _album . Tracks [ track_id ] ;
string flac = Path . Combine ( path , user , "album" , album , $"{(track_id + 1).ToString(" D2 ")} {_album.AlbumArtist} - {oldtrack}.flac" ) ;
File . Move ( tmpFile , flac ) ;
ScheduleTask ( async ( ) = >
{
await GenerateBittorentFileAlbumAsync ( user , album ) ;
} ) ;
string oldmp3 = Path . Combine ( path , user , "album" , album , $"{oldtrack}.mp3" ) ;
ScheduleFFmpeg ( $"-y -i \" { flac } \ " {Configuration.BrowserTranscodeMp3} \"{oldmp3}\"" ) ;
}
break ;
case "Rename" :
{
if ( track_id < _album . Tracks . Count )
{
if ( ! ctx . QueryParams . TryGetFirst ( "track_name" , out var track_name ) )
track_name = $"Track {track_id.ToString(" D2 ")}" ;
track_name = FixStringKeepSpace ( track_name ) ;
string oldtrack = _album . Tracks [ track_id ] ;
string oldflac = Path . Combine ( path , user , "album" , album , $"{(track_id + 1).ToString(" D2 ")} {_album.AlbumArtist} - {oldtrack}.flac" ) ;
string oldmp3 = Path . Combine ( path , user , "album" , album , $"{oldtrack}.mp3" ) ;
string newflac = Path . Combine ( path , user , "album" , album , $"{(track_id + 1).ToString(" D2 ")} {_album.AlbumArtist} - {track_name}.flac" ) ;
string newmp3 = Path . Combine ( path , user , "album" , album , $"{track_name}.mp3" ) ;
if ( oldflac ! = newflac & & File . Exists ( oldflac ) )
File . Move ( oldflac , newflac ) ;
if ( oldmp3 ! = newmp3 & & File . Exists ( oldmp3 ) )
File . Move ( oldmp3 , newmp3 ) ;
_album . Tracks [ track_id ] = track_name ;
provider . UpdateAlbum ( _album ) ;
}
}
break ;
case "Add" :
{
if ( ! ctx . QueryParams . TryGetFirst ( "track_name" , out var track_name ) )
track_name = $"Track {track_id.ToString(" D2 ")}" ;
2024-01-04 02:53:13 +00:00
2024-07-28 22:59:28 +00:00
_album . Tracks . Add ( FixStringKeepSpace ( track_name ) ) ;
provider . UpdateAlbum ( _album ) ;
}
break ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
if ( File . Exists ( tmpFile ) )
File . Delete ( tmpFile ) ;
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/user/{user}/album/{album}/edit_tracklist" ) ;
}
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
private async Task EditTracklistAsync ( ServerContext ctx )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
string user = usersPathValueServer . GetValue ( ctx ) ;
string album = albumPathValueServer . GetValue ( ctx ) ;
2024-01-04 02:53:13 +00:00
2024-07-28 22:59:28 +00:00
var _album = provider . GetAlbum ( user , album ) ;
var _user = provider . GetUserAccount ( user ) ;
var me = GetAccount ( ctx , out var cookie ) ;
2024-01-04 02:53:13 +00:00
2024-07-28 22:59:28 +00:00
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
me = null ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
if ( _album ! = null & & me ! = null & & _user ! = null )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
List < object > tracks = new List < object > ( ) ;
string csrf = "" ;
if ( me ! = null )
csrf = HttpUtility . UrlEncode ( CreateCSRF ( me . Id , cookie ) ) ;
for ( int i = 0 ; i < _album . Tracks . Count ; i + + )
{
tracks . Add ( new { index = i , name = HttpUtility . HtmlAttributeEncode ( _album . Tracks [ i ] ) } ) ;
}
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , await pageTracklist . RenderAsync ( new { tracks , csrf } ) ) ) ;
2024-01-04 02:53:13 +00:00
}
}
2024-07-28 22:59:28 +00:00
private async Task PlayAlbumAsync ( ServerContext ctx )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
string user = usersPathValueServer . GetValue ( ctx ) ;
string album = albumPathValueServer . GetValue ( ctx ) ;
2024-01-04 02:53:13 +00:00
2024-07-28 22:59:28 +00:00
var _album = provider . GetAlbum ( user , album ) ;
var _user = provider . GetUserAccount ( user ) ;
2024-01-04 02:53:13 +00:00
2024-07-28 22:59:28 +00:00
var me = GetAccount ( ctx ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
me = null ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
if ( _album ! = null & & _user ! = null )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
List < object > list = new List < object > ( ) ;
int i = 1 ;
foreach ( var item in _album . Tracks )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
list . Add ( new
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
artist = _album . AlbumArtist ,
album = _album . ProperName ,
name = item ,
art = $"{Configuration.Root.TrimEnd('/')}/content/{user}/album/{album}/thumbnail.jpg" ,
url = $"{Configuration.Root.TrimEnd('/')}/content/{user}/album/{album}/{HttpUtility.UrlPathEncode(item)}.mp3" ,
download = $"{Configuration.Root.TrimEnd('/')}/content/{user}/album/{album}/{i.ToString(" D2 ")}%20{HttpUtility.UrlPathEncode(_album.AlbumArtist)}%20-%20{HttpUtility.UrlPathEncode(item)}.flac"
} ) ;
i + + ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
object v = new
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
rooturl = $"{Configuration.Root.TrimEnd('/')}/" ,
list = JsonConvert . SerializeObject ( list )
} ;
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , await pageMusicPlayer . RenderAsync ( v ) ) ) ;
2024-01-04 02:53:13 +00:00
}
}
2024-07-28 22:59:28 +00:00
private async Task AlbumPageAsync ( ServerContext ctx )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
string user = usersPathValueServer . GetValue ( ctx ) ;
string album = albumPathValueServer . GetValue ( ctx ) ;
var _album = provider . GetAlbum ( user , album ) ;
var _user = provider . GetUserAccount ( user ) ;
var me = GetAccount ( ctx , out var cookie ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
me = null ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
object value ;
if ( _album ! = null & & _user ! = null )
{
string albumDir = Path . Combine ( this . path , user , "album" , album ) ;
bool torrent = File . Exists ( Path . Combine ( albumDir , $"{album}.torrent" ) ) ;
bool torrent_wextra = File . Exists ( Path . Combine ( albumDir , $"{album}_withextras.torrent" ) ) ;
bool extrasexists = Directory . Exists ( Path . Combine ( albumDir , "extras" ) ) | | me ! = null ;
2024-01-04 02:53:13 +00:00
2024-07-28 22:59:28 +00:00
string thumb = $"{Configuration.Root.TrimEnd('/')}/content/{user}/album/{album}/thumbnail.jpg" ;
string csrf = "" ;
if ( me ! = null )
csrf = HttpUtility . UrlEncode ( CreateCSRF ( me . Id , cookie ) ) ;
value = new
{
csrf ,
extrasexists ,
torrentexists = torrent ,
torrentwextraexists = torrent_wextra ,
torrent = $"{Configuration.Root.TrimEnd('/')}/content/{user}/album/{album}/{album}.torrent" ,
torrentwextra = $"{Configuration.Root.TrimEnd('/')}/content/{user}/album/{album}/{album}_withextras.torrent" ,
editable = me ! = null ,
userproper = HttpUtility . HtmlEncode ( _user . ProperName ) ,
username = HttpUtility . HtmlEncode ( user ) ,
rooturl = $"{Configuration.Root.TrimEnd('/')}/" ,
title = Configuration . Title ,
hasalbum = true ,
albumthumbnail = thumb ,
albumproper = HttpUtility . HtmlEncode ( _album . ProperName ) ,
albumname = HttpUtility . HtmlEncode ( _album . Name ) ,
albumdescription = DescriptLinkUtils ( _album . Description ? ? "" ) . Replace ( "\n" , "<br>" )
} ;
}
else
{
value = new
{
username = user ,
rooturl = $"{Configuration.Root.TrimEnd('/')}/" ,
title = Configuration . Title ,
hasalbum = false
} ;
}
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , await pageAlbum . RenderAsync ( value ) ) ) ;
}
private void RegisterShowPath ( )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
showRouteServer . Add ( "/" , ShowPageAsync ) ;
showRouteServer . Add ( "/edit" , EditShowPageAsync ) ;
showRouteServer . Add ( "/edit" , EditShowPagePostAsync , "POST" ) ;
showRouteServer . Add ( "/upload" , UploadShowStreamAsync , "POST" ) ;
showRouteServer . Add ( "/addseason" , AddSeasonAsync , "POST" ) ;
showRouteServer . Add ( "/upload_extra" , UploadShowExtraAsync , "POST" ) ;
showRouteServer . Add ( "/extras" , ExtrasShowPageAsync ) ;
showRouteServer . Add ( "/mkdir" , ExtrasShowMkdirAsync , "POST" ) ;
showRouteServer . Add ( "/sendupdate" , SendShowUpdateAsync , "POST" ) ;
showMountableServer . Mount ( "/season/" , seasonPathValueServer ) ;
RegisterSeasonPath ( ) ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
private void RegisterSeasonPath ( )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
seasonRouteServer . Add ( "/" , SeasonPageAsync ) ;
seasonRouteServer . Add ( "/edit" , EditSeasonPageAsync ) ;
seasonRouteServer . Add ( "/edit" , EditSeasonPagePostAsync , "POST" ) ;
seasonRouteServer . Add ( "/addepisode" , AddEpisodeAsync , "POST" ) ;
seasonRouteServer . Add ( "/upload" , UploadSeasonStreamAsync , "POST" ) ;
seasonMountableServer . Mount ( "/episode/" , episodePathValueServer ) ;
RegisterEpisodePath ( ) ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
private void RegisterEpisodePath ( )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
episodeRouteServer . Add ( "/" , EpisodePageAsync ) ;
episodeRouteServer . Add ( "/edit" , EditEpisodePageAsync ) ;
episodeRouteServer . Add ( "/edit" , EditEpisodePagePostAsync , "POST" ) ;
episodeRouteServer . Add ( "/upload" , UploadEpisodeStreamAsync , "POST" ) ;
episodeRouteServer . Add ( "/subtitles" , SubtitlesEpisodeAsync ) ;
episodeRouteServer . Add ( "/subtitles" , SubtitlesEpisodePostAsync , "POST" ) ;
episodeRouteServer . Add ( "/play" , PlayEpisodePageAsync ) ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
private async Task EpisodePageAsync ( ServerContext ctx )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
string user = usersPathValueServer . GetValue ( ctx ) ;
string show = showPathValueServer . GetValue ( ctx ) ;
var _show = provider . GetShow ( user , show ) ;
var _user = provider . GetUserAccount ( user ) ;
2024-01-04 02:53:13 +00:00
var me = GetAccount ( ctx ) ;
2024-07-28 22:59:28 +00:00
string seasonS = seasonPathValueServer . GetValue ( ctx ) ;
string episodeS = episodePathValueServer . GetValue ( ctx ) ;
if ( ! int . TryParse ( seasonS , out var season ) ) season = 1 ;
if ( ! int . TryParse ( episodeS , out var episode ) ) episode = 1 ;
var _season = provider . GetSeason ( user , show , season ) ;
var _episode = provider . GetEpisode ( user , show , season , episode ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
me = null ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
object value ;
if ( _show ! = null & & _user ! = null )
{
string episodeDir = Path . Combine ( this . path , user , "show" , show , $"Season {season.ToString(" D2 ")}" ) ;
bool episodebrowserexists = File . Exists ( Path . Combine ( episodeDir , $"S{season.ToString(" D2 ")}E{episode.ToString(" D2 ")}.mp4" ) ) ;
string name = $"{_episode.EpisodeName} S{season.ToString(" D2 ")}E{episode.ToString(" D2 ")}" ;
bool episodeexists = File . Exists ( Path . Combine ( episodeDir , $"{name}.mp4" ) ) ;
string thumb = File . Exists ( Path . Combine ( episodeDir , $"{name}-thumbnail.jpg" ) ) ? $"{Configuration.Root.TrimEnd('/')}/content/{user}/show/{show}/Season%20{season.ToString(" D2 ")}/{_episode.EpisodeName}%20S{season.ToString(" D2 ")}E{episode.ToString(" D2 ")}-thumbnail.jpg" : File . Exists ( Path . Combine ( episodeDir , "thumbnail.jpg" ) ) ? $"{Configuration.Root.TrimEnd('/')}/content/{user}/show/{show}/Season%20{season.ToString(" D2 ")}/thumbnail.jpg" : $"{Configuration.Root.TrimEnd('/')}/content/{user}/show/{show}/thumbnail.jpg" ;
value = new
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
episodebrowserexists ,
episodeexists ,
downloadurl = $"{Configuration.Root.TrimEnd('/')}/content/{user}/show/{show}/Season%20{season.ToString(" D2 ")}/{_episode.EpisodeName}%20S{season.ToString(" D2 ")}E{episode.ToString(" D2 ")}.mp4" ,
editable = me ! = null ,
userproper = HttpUtility . HtmlEncode ( _user . ProperName ) ,
username = HttpUtility . HtmlEncode ( user ) ,
rooturl = $"{Configuration.Root.TrimEnd('/')}/" ,
title = Configuration . Title ,
hasmovie = true ,
episodethumbnail = thumb ,
seasonproper = HttpUtility . HtmlEncode ( _season . ProperName ) ,
showpropername = HttpUtility . HtmlEncode ( _show . ProperName ) ,
episodeproperattr = HttpUtility . HtmlAttributeEncode ( _episode . ProperName ) ,
episodeproper = HttpUtility . HtmlEncode ( _episode . ProperName ) ,
episodename = HttpUtility . HtmlEncode ( _episode . EpisodeName ) ,
episodedescription = DescriptLinkUtils ( _episode . Description ? ? "" ) . Replace ( "\n" , "<br>" )
} ;
2024-01-04 02:53:13 +00:00
}
else
{
2024-07-28 22:59:28 +00:00
value = new
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
username = user ,
rooturl = $"{Configuration.Root.TrimEnd('/')}/" ,
title = Configuration . Title ,
hasmovie = false
} ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , await pageEpisode . RenderAsync ( value ) ) ) ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
private async Task UploadEpisodeStreamAsync ( ServerContext ctx )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
string user = usersPathValueServer . GetValue ( ctx ) ;
string show = showPathValueServer . GetValue ( ctx ) ;
var me = GetAccount ( ctx , true ) ;
string seasonS = seasonPathValueServer . GetValue ( ctx ) ;
string episodeS = episodePathValueServer . GetValue ( ctx ) ;
if ( ! int . TryParse ( seasonS , out var season ) )
season = 1 ;
if ( ! int . TryParse ( episodeS , out var episode ) )
episode = 1 ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
me = null ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
if ( me ! = null )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
Directory . CreateDirectory ( Path . Combine ( path , user , "show" , show ) ) ;
var tmpFile = Path . Combine ( path , user , "show" , show , $"tmp{DateTime.Now.ToFileTime().ToString()}.bin" ) ;
foreach ( var item in ctx . ParseBody ( ( n , fn , ct ) = > File . Create ( tmpFile ) ) )
2024-01-04 02:53:13 +00:00
item . Value . Dispose ( ) ;
2024-07-28 22:59:28 +00:00
var _episode = provider . GetEpisode ( user , show , season , episode ) ;
if ( _episode ! = null )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
if ( ctx . QueryParams . TryGetFirst ( "type" , out var type ) )
{
switch ( type )
{
case "thumbnail" :
string thumb = Path . Combine ( path , user , "show" , show , $"Season {season.ToString(" D2 ")}" , $"{_episode.EpisodeName} S{season.ToString(" D2 ")}E{episode.ToString(" D2 ")}-thumbnail.jpg" ) ;
if ( File . Exists ( thumb ) ) File . Delete ( thumb ) ;
File . Move ( tmpFile , thumb ) ;
break ;
case "poster" :
string poster = Path . Combine ( path , user , "show" , show , $"Season {season.ToString(" D2 ")}" , $"{_episode.EpisodeName} S{season.ToString(" D2 ")}E{episode.ToString(" D2 ")}-poster.jpg" ) ;
if ( File . Exists ( poster ) ) File . Delete ( poster ) ;
File . Move ( tmpFile , poster ) ;
break ;
case "movie" :
string movie = Path . Combine ( path , user , "show" , show , $"Season {season.ToString(" D2 ")}" , $"{_episode.EpisodeName} S{season.ToString(" D2 ")}E{episode.ToString(" D2 ")}.mp4" ) ;
if ( File . Exists ( movie ) ) File . Delete ( movie ) ;
File . Move ( tmpFile , movie ) ;
ScheduleFFmpeg ( $"-y -i \" { movie } \ " {Configuration.BrowserTranscode} \"{Path.Combine(path, user, " show ", show, $" Season { season . ToString ( "D2" ) } ", $" S { season . ToString ( "D2" ) } E { episode . ToString ( "D2" ) } . mp4 ")}\"" ) ;
break ;
}
ScheduleTask ( async ( ) = >
{
await GenerateBittorentFileShowAsync ( user , show ) ;
} ) ;
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , "<h1>Success</h1><a href=\"./edit\"><- Back</a>" ) ) ;
return ;
}
2024-01-04 02:53:13 +00:00
}
}
2024-07-28 22:59:28 +00:00
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , "<h1>Failed</h1><a href=\"./edit\"><- Back</a>" ) ) ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
private async Task AddEpisodeAsync ( ServerContext ctx )
2024-01-04 02:53:13 +00:00
{
ctx . ParseBody ( ) ;
2024-07-28 22:59:28 +00:00
string user = usersPathValueServer . GetValue ( ctx ) ;
string show = showPathValueServer . GetValue ( ctx ) ;
string season = seasonPathValueServer . GetValue ( ctx ) ;
2024-01-04 02:53:13 +00:00
var me = GetAccount ( ctx ) ;
2024-07-28 22:59:28 +00:00
var _show = provider . GetShow ( user , show ) ;
2023-12-16 01:40:05 +00:00
2024-07-28 22:59:28 +00:00
int seasonNo = 1 ;
if ( ! int . TryParse ( season , out seasonNo ) )
seasonNo = 1 ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
me = null ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
if ( me ! = null )
{
int episode = 1 ;
if ( ctx . QueryParams . TryGetFirst ( "number" , out var number ) & & ! int . TryParse ( number , out episode ) )
episode = 1 ;
if ( ctx . QueryParams . TryGetFirst ( "proper_name" , out var proper_name ) & & ctx . QueryParams . TryGetFirst ( "description" , out var description ) & & ctx . QueryParams . TryGetFirst ( "name" , out var name ) )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
provider . CreateEpisode ( user , show , seasonNo , episode , name , proper_name , description ) ;
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/user/{user}/show/{show}/season/{seasonNo}/episode/{episode}/edit" ) ;
2023-12-16 01:40:05 +00:00
}
else
{
2024-07-28 22:59:28 +00:00
2023-12-16 01:40:05 +00:00
}
}
}
2024-07-28 22:59:28 +00:00
private async Task EditSeasonPagePostAsync ( ServerContext ctx )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
ctx . ParseBody ( ) ;
string user = usersPathValueServer . GetValue ( ctx ) ;
string show = showPathValueServer . GetValue ( ctx ) ;
string seasonS = seasonPathValueServer . GetValue ( ctx ) ;
if ( ! int . TryParse ( seasonS , out var season ) )
season = 1 ;
2024-01-04 02:53:13 +00:00
2024-07-28 22:59:28 +00:00
var me = GetAccount ( ctx , true ) ;
var _season = provider . GetSeason ( user , show , season ) ;
2023-12-16 01:40:05 +00:00
2024-07-28 22:59:28 +00:00
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
me = null ;
2024-01-04 02:53:13 +00:00
}
2023-12-16 01:40:05 +00:00
2024-07-28 22:59:28 +00:00
if ( me ! = null )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
if ( _season ! = null )
{
if ( ctx . QueryParams . TryGetFirst ( "proper_name" , out var proper_name ) & & ctx . QueryParams . TryGetFirst ( "description" , out var description ) )
{
_season . ProperName = proper_name ;
_season . Description = description . Replace ( "\r" , "" ) ;
provider . UpdateSeason ( _season ) ;
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , "<h1>Success</h1><a href=\"./edit\"><- Back</a>" ) ) ;
return ;
}
}
}
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , "<h1>Failed</h1><a href=\"./edit\"><- Back</a>" ) ) ;
}
public async Task EditEpisodePageAsync ( ServerContext ctx )
{
string user = usersPathValueServer . GetValue ( ctx ) ;
string show = showPathValueServer . GetValue ( ctx ) ;
var me = GetAccount ( ctx ) ;
string seasonS = seasonPathValueServer . GetValue ( ctx ) ;
string episodeS = episodePathValueServer . GetValue ( ctx ) ;
if ( ! int . TryParse ( seasonS , out var season ) )
season = 1 ;
if ( ! int . TryParse ( episodeS , out var episode ) )
episode = 1 ;
var _episode = provider . GetEpisode ( user , show , season , episode ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
{
me = null ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
if ( me ! = null )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
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 ) } ) ) ) ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
else
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , "<h1>You are unauthorized to edit this</h1>" ) ) ;
2024-01-04 02:53:13 +00:00
}
2023-12-16 01:40:05 +00:00
2024-01-04 02:53:13 +00:00
}
2023-12-16 01:40:05 +00:00
2024-07-28 22:59:28 +00:00
private async Task EditEpisodePagePostAsync ( ServerContext ctx )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
ctx . ParseBody ( ) ;
string user = usersPathValueServer . GetValue ( ctx ) ;
string show = showPathValueServer . GetValue ( ctx ) ;
string seasonS = seasonPathValueServer . GetValue ( ctx ) ;
string episodeS = episodePathValueServer . GetValue ( ctx ) ;
if ( ! int . TryParse ( seasonS , out var season ) )
season = 1 ;
if ( ! int . TryParse ( episodeS , out var episode ) )
episode = 1 ;
2023-12-16 01:40:05 +00:00
2024-07-28 22:59:28 +00:00
var me = GetAccount ( ctx , true ) ;
var _episode = provider . GetEpisode ( user , show , season , episode ) ;
2023-12-16 01:40:05 +00:00
2024-07-28 22:59:28 +00:00
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
{
me = null ;
}
2023-12-16 01:40:05 +00:00
2024-07-28 22:59:28 +00:00
if ( me ! = null )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
if ( _episode ! = null )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
if ( ctx . QueryParams . TryGetFirst ( "proper_name" , out var proper_name ) & & ctx . QueryParams . TryGetFirst ( "description" , out var description ) )
{
_episode . ProperName = proper_name ;
_episode . Description = description . Replace ( "\r" , "" ) ;
provider . UpdateEpisode ( _episode ) ;
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , "<h1>Success</h1><a href=\"./edit\"><- Back</a>" ) ) ;
return ;
}
2023-12-16 01:40:05 +00:00
}
}
2024-07-28 22:59:28 +00:00
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , "<h1>Failed</h1><a href=\"./edit\"><- Back</a>" ) ) ;
2023-12-16 01:40:05 +00:00
2024-07-28 22:59:28 +00:00
}
2023-12-16 01:40:05 +00:00
2024-07-28 22:59:28 +00:00
private async Task EditSeasonPageAsync ( ServerContext ctx )
{
2023-12-16 01:40:05 +00:00
2024-07-28 22:59:28 +00:00
string user = usersPathValueServer . GetValue ( ctx ) ;
string show = showPathValueServer . GetValue ( ctx ) ;
string seasonS = seasonPathValueServer . GetValue ( ctx ) ;
int season = 1 ;
if ( ! int . TryParse ( seasonS , out season ) )
season = 1 ;
var me = GetAccount ( ctx ) ;
2023-12-16 01:40:05 +00:00
2024-07-28 22:59:28 +00:00
var _season = provider . GetSeason ( user , show , season ) ;
2023-12-16 01:40:05 +00:00
2024-07-28 22:59:28 +00:00
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
me = null ;
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
if ( me ! = null )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
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 ) } ) ) ) ;
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
else
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , "<h1>You are unauthorized to edit this</h1>" ) ) ;
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
}
2023-12-16 01:40:05 +00:00
2024-07-28 22:59:28 +00:00
private async Task SeasonPageAsync ( ServerContext ctx )
{
string user = usersPathValueServer . GetValue ( ctx ) ;
string show = showPathValueServer . GetValue ( ctx ) ;
string season = seasonPathValueServer . GetValue ( ctx ) ;
var _show = provider . GetShow ( user , show ) ;
var _user = provider . GetUserAccount ( user ) ;
if ( ! int . TryParse ( season , out var seasonNo ) )
seasonNo = 1 ;
var _season = provider . GetSeason ( user , show , seasonNo ) ;
var me = GetAccount ( ctx ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
me = null ;
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
object value ;
if ( _show ! = null & & _user ! = null & & _season ! = null )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
string showDir = Path . Combine ( this . path , user , "show" , show ) ;
string thumb = File . Exists ( Path . Combine ( showDir , $"Season {_season.SeasonNumber.ToString(" D2 ")}" , "thumbnail.jpg" ) ) ? $"{Configuration.Root.TrimEnd('/')}/content/{user}/show/{show}/Season%20{_season.SeasonNumber.ToString(" D2 ")}/thumbnail.jpg" : $"{Configuration.Root.TrimEnd('/')}/content/{user}/show/{show}/thumbnail.jpg" ;
List < object > episodes = new List < object > ( ) ;
for ( int i = 1 ; i < = provider . EpisodeCount ( user , show , seasonNo ) ; i + + )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
var item = provider . GetEpisode ( user , show , seasonNo , i ) ;
if ( item ! = null )
//var data = GetMovieContentMetaData(Configuration,user,item.Name);
episodes . Add ( item . Scriban ( Configuration , path , user , show ) ) ;
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
value = new
{
episodes ,
editable = me ! = null ,
userproper = HttpUtility . HtmlEncode ( _user . ProperName ) ,
username = HttpUtility . HtmlEncode ( user ) ,
rooturl = $"{Configuration.Root.TrimEnd('/')}/" ,
title = Configuration . Title ,
hasshow = true ,
seasonthumbnail = thumb ,
seasonproper = HttpUtility . HtmlEncode ( _season . ProperName ) ,
showproper = HttpUtility . HtmlEncode ( _show . ProperName ) ,
showname = HttpUtility . HtmlEncode ( _show . Name ) ,
seasondescription = DescriptLinkUtils ( _season . Description ? ? "" ) . Replace ( "\n" , "<br>" )
} ;
}
else
{
value = new
{
username = user ,
rooturl = $"{Configuration.Root.TrimEnd('/')}/" ,
title = Configuration . Title ,
hasshow = false
} ;
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , await pageSeason . RenderAsync ( value ) ) ) ;
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
private async Task AddSeasonAsync ( ServerContext ctx )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
ctx . ParseBody ( ) ;
string user = usersPathValueServer . GetValue ( ctx ) ;
string show = showPathValueServer . GetValue ( ctx ) ;
var me = GetAccount ( ctx ) ;
var _show = provider . GetShow ( user , show ) ;
2023-12-16 01:40:05 +00:00
2024-07-28 22:59:28 +00:00
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
me = null ;
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
if ( me ! = null )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
int season = 1 ;
if ( ctx . QueryParams . TryGetFirst ( "number" , out var number ) & & ! int . TryParse ( number , out season ) )
season = 1 ;
if ( ctx . QueryParams . TryGetFirst ( "proper_name" , out var proper_name ) & & ctx . QueryParams . TryGetFirst ( "description" , out var description ) )
{
provider . CreateSeason ( user , show , season , proper_name , description ) ;
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/user/{user}/show/{show}/season/{season}/edit" ) ;
}
else
{
}
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
}
private async Task EditShowPagePostAsync ( ServerContext ctx )
{
ctx . ParseBody ( ) ;
string user = usersPathValueServer . GetValue ( ctx ) ;
string show = showPathValueServer . GetValue ( ctx ) ;
var me = GetAccount ( ctx , true ) ;
var _show = provider . GetShow ( user , show ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
me = null ;
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
if ( me ! = null )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
if ( _show ! = null )
{
if ( ctx . QueryParams . TryGetFirst ( "proper_name" , out var proper_name ) & & ctx . QueryParams . TryGetFirst ( "description" , out var description ) )
{
_show . ProperName = proper_name ;
_show . Description = description . Replace ( "\r" , "" ) ;
provider . UpdateShow ( _show ) ;
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , "<h1>Success</h1><a href=\"./edit\"><- Back</a>" ) ) ;
return ;
}
}
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , "<h1>Failed</h1><a href=\"./edit\"><- Back</a>" ) ) ;
}
private async Task EditShowPageAsync ( ServerContext ctx )
{
string user = usersPathValueServer . GetValue ( ctx ) ;
string show = showPathValueServer . GetValue ( ctx ) ;
var me = GetAccount ( ctx ) ;
var _show = provider . GetShow ( user , show ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
me = null ;
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
if ( me ! = null )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
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 ) } ) ) ) ;
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
else
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , "<h1>You are unauthorized to edit this</h1>" ) ) ;
2023-12-16 01:40:05 +00:00
}
}
2024-07-28 22:59:28 +00:00
private async Task ShowPageAsync ( ServerContext ctx )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
string user = usersPathValueServer . GetValue ( ctx ) ;
string show = showPathValueServer . GetValue ( ctx ) ;
var _show = provider . GetShow ( user , show ) ;
var _user = provider . GetUserAccount ( user ) ;
var me = GetAccount ( ctx , out var cookie ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
me = null ;
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
object value ;
if ( _show ! = null & & _user ! = null )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
string csrf = "" ;
if ( me ! = null )
csrf = HttpUtility . UrlEncode ( CreateCSRF ( me . Id , cookie ) ) ;
string showDir = Path . Combine ( this . path , user , "show" , show ) ;
bool torrent = File . Exists ( Path . Combine ( showDir , $"{show}.torrent" ) ) ;
bool torrent_wextra = File . Exists ( Path . Combine ( showDir , $"{show}_withextras.torrent" ) ) ;
bool extrasexists = Directory . Exists ( Path . Combine ( showDir , "extras" ) ) | | me ! = null ;
string thumb = $"{Configuration.Root.TrimEnd('/')}/content/{user}/show/{show}/thumbnail.jpg" ;
List < object > seasons = new List < object > ( ) ;
for ( int i = 1 ; i < = provider . SeasonCount ( user , show ) ; i + + )
{
var item = provider . GetSeason ( user , show , i ) ;
if ( item ! = null )
//var data = GetMovieContentMetaData(Configuration,user,item.Name);
seasons . Add ( item . Scriban ( Configuration , path , user , show ) ) ;
}
value = new
{
csrf ,
seasons ,
extrasexists ,
torrentexists = torrent ,
torrentwextraexists = torrent_wextra ,
torrent = $"{Configuration.Root.TrimEnd('/')}/content/{user}/show/{show}/{show}.torrent" ,
torrentwextra = $"{Configuration.Root.TrimEnd('/')}/content/{user}/show/{show}/{show}_withextras.torrent" ,
editable = me ! = null ,
userproper = HttpUtility . HtmlEncode ( _user . ProperName ) ,
username = HttpUtility . HtmlEncode ( user ) ,
rooturl = $"{Configuration.Root.TrimEnd('/')}/" ,
title = Configuration . Title ,
hasshow = true ,
showthumbnail = thumb ,
showproper = HttpUtility . HtmlEncode ( _show . ProperName ) ,
showname = HttpUtility . HtmlEncode ( _show . Name ) ,
showdescription = DescriptLinkUtils ( _show . Description ? ? "" ) . Replace ( "\n" , "<br>" )
} ;
}
else
{
value = new
{
username = user ,
rooturl = $"{Configuration.Root.TrimEnd('/')}/" ,
title = Configuration . Title ,
hasshow = false
} ;
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , await pageShow . RenderAsync ( value ) ) ) ;
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
private IServer Shows ( )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
RouteServer routeServer = new RouteServer ( ) ;
routeServer . Add ( "/" , ShowsAsync ) ;
return routeServer ;
}
2024-01-04 02:53:13 +00:00
2024-07-28 22:59:28 +00:00
private IServer Albums ( )
{
RouteServer routeServer = new RouteServer ( ) ;
routeServer . Add ( "/" , AlbumsAsync ) ;
return routeServer ;
}
2024-01-04 02:53:13 +00:00
2024-07-28 22:59:28 +00:00
private async Task ShowsAsync ( ServerContext ctx )
{
string user = usersPathValueServer . GetValue ( ctx ) ;
List < object > shows = new List < object > ( ) ;
foreach ( var item in provider . GetShows ( user ) )
{
//var data = GetMovieContentMetaData(Configuration,user,item.Name);
shows . Add ( item . Scriban ( Configuration , user ) ) ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , await pageShows . RenderAsync ( new { Shows = shows } ) ) ) ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
private async Task AlbumsAsync ( ServerContext ctx )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
string user = usersPathValueServer . GetValue ( ctx ) ;
List < object > albums = new List < object > ( ) ;
foreach ( var item in provider . GetAlbums ( user ) )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
//var data = GetMovieContentMetaData(Configuration,user,item.Name);
string thumb = $"{Configuration.Root.TrimEnd('/')}/content/{user}/album/{item.Name}/thumbnail.jpg" ;
albums . Add ( item . Scriban ( thumb ) ) ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , await pageAlbums . RenderAsync ( new { Albums = albums } ) ) ) ;
}
2024-01-04 02:53:13 +00:00
2024-07-28 22:59:28 +00:00
private static bool StartsWithAt ( string str , int indexof , string startsWith )
{
if ( str . Length - indexof < startsWith . Length ) return false ;
for ( int i = 0 ; i < startsWith . Length ; i + + )
{
if ( str [ i + indexof ] ! = startsWith [ i ] ) return false ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
return true ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
internal static string DescriptLinkUtils ( string url )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
StringBuilder b = new StringBuilder ( ) ;
for ( int i = 0 ; i < url . Length ; i + + )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
if ( StartsWithAt ( url , i , "http:" ) | | StartsWithAt ( url , i , "https:" ) | | StartsWithAt ( url , i , "ftp:" ) | | StartsWithAt ( url , i , "ftps:" ) | | StartsWithAt ( url , i , "sftp:" ) | | StartsWithAt ( url , i , "magnet:" ) )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
StringBuilder b2 = new StringBuilder ( ) ;
for ( ; i < url . Length ; i + + )
{
if ( url [ i ] = = '\n' | | url [ i ] = = ' ' )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
break ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
b2 . Append ( url [ i ] ) ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
b . Append ( $"<a href=\" { HttpUtility . HtmlAttributeEncode ( b2 . ToString ( ) ) } \ ">{HttpUtility.HtmlEncode(b2.ToString())}</a>" ) ;
}
else
{
b . Append ( HttpUtility . HtmlEncode ( url [ i ] ) ) ;
2024-01-04 02:53:13 +00:00
}
}
2024-07-28 22:59:28 +00:00
return b . ToString ( ) ;
}
private async Task AboutAsync ( ServerContext ctx )
{
var username = usersPathValueServer . GetValue ( ctx ) ;
var accountData = provider . GetUserAccount ( username ) ;
if ( accountData ! = null )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , await aboutUser . RenderAsync ( new { Propername = HttpUtility . HtmlEncode ( accountData . ProperName ) , Aboutme = DescriptLinkUtils ( accountData . AboutMe ? ? "" ) . Replace ( "\n" , "<br>" ) } ) ) ) ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
}
private async Task UserPageAsync ( ServerContext ctx )
{
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , await AssetProvider . ReadAllTextAsync ( "/UserPage.html" ) ) ) ;
}
ConcurrentQueue < Func < Task > > tasks = new ConcurrentQueue < Func < Task > > ( ) ;
private void RegisterMoviePath ( )
{
movieRouteServer . Add ( "/" , MoviePageAsync ) ;
movieRouteServer . Add ( "/play" , PlayMoviePageAsync ) ;
movieRouteServer . Add ( "/edit" , EditMoviePageAsync ) ;
movieRouteServer . Add ( "/sendupdate" , SendMovieUpdateAsync , "POST" ) ;
movieRouteServer . Add ( "/edit" , EditMoviePagePostAsync , "POST" ) ;
movieRouteServer . Add ( "/upload" , UploadMovieStreamAsync , "POST" ) ;
movieRouteServer . Add ( "/upload_extra" , UploadMovieExtraAsync , "POST" ) ;
movieRouteServer . Add ( "/extras" , ExtrasMoviePageAsync ) ;
movieRouteServer . Add ( "/mkdir" , ExtrasMovieMkdirAsync , "POST" ) ;
movieRouteServer . Add ( "/subtitles" , SubtitlesMovieAsync ) ;
movieRouteServer . Add ( "/subtitles" , SubtitlesMoviePostAsync , "POST" ) ;
//http://192.168.0.158:62444/user/tesses/movie/MyGreatMovie/mkdir
}
private async Task SendShowUpdateAsync ( ServerContext ctx )
{
string user = usersPathValueServer . GetValue ( ctx ) ;
string show = showPathValueServer . GetValue ( ctx ) ;
var me = GetAccount ( ctx , true ) ;
var _user = provider . GetUserAccount ( user ) ;
var _show = provider . GetShow ( user , show ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
{
me = null ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
if ( me ! = null )
{
ctx . ParseBody ( ) ;
if ( ! ctx . QueryParams . TryGetFirst ( "body" , out var body ) )
{
body = "" ;
}
ScheduleTask ( async ( ) = >
{
await Creator . EmailShowAsync ( provider , _user , _show , true , body ) ;
await SendEvent ( EventType . ShowUpdate , _user . ProperName , _user . Username , _show . Name , _show . ProperName , _show . Description , body ) ;
} ) ;
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/user/{user}/show/{show}/" ) ;
}
else
{
await ctx . SendTextAsync ( "Failed to send update" ) ;
}
}
private async Task SendMovieUpdateAsync ( ServerContext ctx )
{
string user = usersPathValueServer . GetValue ( ctx ) ;
string movie = moviePathValueServer . GetValue ( ctx ) ;
var me = GetAccount ( ctx , true ) ;
var _user = provider . GetUserAccount ( user ) ;
var _movie = provider . GetMovie ( user , movie ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
{
me = null ;
}
if ( me ! = null )
{
ctx . ParseBody ( ) ;
if ( ! ctx . QueryParams . TryGetFirst ( "body" , out var body ) )
{
body = "" ;
}
ScheduleTask ( async ( ) = >
{
await Creator . EmailMovieAsync ( provider , _user , _movie , true , body ) ;
await SendEvent ( EventType . MovieUpdate , _user . ProperName , _user . Username , _movie . Name , _movie . ProperName , _movie . Description , body ) ;
} ) ;
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/user/{user}/movie/{movie}/" ) ;
}
else
{
await ctx . SendTextAsync ( "Failed to send update" ) ;
}
}
private async Task SendAlbumUpdateAsync ( ServerContext ctx )
{
string user = usersPathValueServer . GetValue ( ctx ) ;
string album = albumPathValueServer . GetValue ( ctx ) ;
var me = GetAccount ( ctx , true ) ;
var _user = provider . GetUserAccount ( user ) ;
var _album = provider . GetAlbum ( user , album ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
{
me = null ;
}
if ( me ! = null )
{
ctx . ParseBody ( ) ;
if ( ! ctx . QueryParams . TryGetFirst ( "body" , out var body ) )
{
body = "" ;
}
ScheduleTask ( async ( ) = >
{
await Creator . EmailAlbumAsync ( provider , _user , _album , true , body ) ;
await SendEvent ( EventType . AlbumUpdate , _user . ProperName , _user . Username , _album . Name , _album . ProperName , _album . Description , body ) ;
} ) ;
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/user/{user}/album/{album}/" ) ;
}
else
{
await ctx . SendTextAsync ( "Failed to send update" ) ;
}
}
private async Task SubtitlesMoviePostAsync ( ServerContext ctx )
{
string user = usersPathValueServer . GetValue ( ctx ) ;
string movie = moviePathValueServer . GetValue ( ctx ) ;
var me = GetAccount ( ctx , true ) ;
var _movie = provider . GetMovie ( user , movie ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
{
me = null ;
}
if ( me ! = null )
{
if ( ctx . QueryParams . TryGetFirst ( "lang" , out var lang ) & & ! string . IsNullOrWhiteSpace ( lang ) )
{
var json = await ctx . ReadJsonAsync < List < Subtitle > > ( ) ;
string langDir = Path . Combine ( path , user , "movie" , movie , "subtitles" , lang ) ;
Directory . CreateDirectory ( langDir ) ;
string langFile = Path . Combine ( langDir , $"{movie}.json" ) ;
string vtt = Path . Combine ( langDir , $"{movie}.vtt" ) ;
string srt = Path . Combine ( langDir , $"{movie}.srt" ) ;
File . WriteAllText ( langFile , JsonConvert . SerializeObject ( json ) ) ;
using ( var vttFile = File . CreateText ( vtt ) )
{
Subtitle . ToWebVTT ( vttFile , json ) ;
}
using ( var srtFile = File . CreateText ( srt ) )
{
Subtitle . ToSrt ( srtFile , json ) ;
}
await ctx . SendTextAsync ( "Success" ) ;
return ;
}
}
ctx . StatusCode = 400 ;
await ctx . SendTextAsync ( "Fail" ) ;
}
private async Task SubtitlesEpisodeAsync ( ServerContext ctx )
{
string user = usersPathValueServer . GetValue ( ctx ) ;
string show = showPathValueServer . GetValue ( ctx ) ;
string seasonS = seasonPathValueServer . GetValue ( ctx ) ;
string episodeS = episodePathValueServer . GetValue ( ctx ) ;
if ( ! int . TryParse ( seasonS , out var season ) )
season = 1 ;
if ( ! int . TryParse ( episodeS , out var episode ) )
episode = 1 ;
var me = GetAccount ( ctx ) ;
var _show = provider . GetMovie ( user , show ) ;
var _episode = provider . GetEpisode ( user , show , season , episode ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
{
me = null ;
}
if ( me ! = null )
{
if ( ctx . QueryParams . TryGetFirst ( "lang" , out var lang ) & & ! string . IsNullOrWhiteSpace ( lang ) )
{
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 json = "" ;
bool hasjson = false ;
if ( File . Exists ( langFile ) )
{
hasjson = true ;
json = File . ReadAllText ( langFile ) ;
}
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , await pageSubtitleEditor . RenderAsync ( new { hasjson , json , lang , browserfile } ) ) ) ;
}
else
{
List < object > languages = new List < object > ( ) ;
foreach ( var item in Languages )
{
languages . Add ( new { code = item . LangCode , name = item . LangTitle } ) ;
}
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , await pageSubtitleLangList . RenderAsync ( new { languages } ) ) ) ;
}
}
}
private async Task SubtitlesEpisodePostAsync ( ServerContext ctx )
{
string user = usersPathValueServer . GetValue ( ctx ) ;
string show = showPathValueServer . GetValue ( ctx ) ;
string seasonS = seasonPathValueServer . GetValue ( ctx ) ;
string episodeS = episodePathValueServer . GetValue ( ctx ) ;
if ( ! int . TryParse ( seasonS , out var season ) )
season = 1 ;
if ( ! int . TryParse ( episodeS , out var episode ) )
episode = 1 ;
var me = GetAccount ( ctx , true ) ;
var _show = provider . GetMovie ( user , show ) ;
var _episode = provider . GetEpisode ( user , show , season , episode ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
{
me = null ;
}
if ( me ! = null )
{
if ( ctx . QueryParams . TryGetFirst ( "lang" , out var lang ) & & ! string . IsNullOrWhiteSpace ( lang ) )
{
var json = await ctx . ReadJsonAsync < List < Subtitle > > ( ) ;
string langDir = Path . Combine ( path , user , "show" , show , $"Season {season.ToString(" D2 ")}" , $"{_episode.EpisodeName} S{season.ToString(" D2 ")}E{episode.ToString(" D2 ")}-subtitles" , lang ) ;
Directory . CreateDirectory ( langDir ) ;
string langFile = Path . Combine ( langDir , $"{_episode.ProperName} S{season.ToString(" D2 ")}E{episode.ToString(" D2 ")}.json" ) ;
string vtt = Path . Combine ( langDir , $"{_episode.ProperName} S{season.ToString(" D2 ")}E{episode.ToString(" D2 ")}.vtt" ) ;
string srt = Path . Combine ( langDir , $"{_episode.ProperName} S{season.ToString(" D2 ")}E{episode.ToString(" D2 ")}.srt" ) ;
File . WriteAllText ( langFile , JsonConvert . SerializeObject ( json ) ) ;
using ( var vttFile = File . CreateText ( vtt ) )
{
Subtitle . ToWebVTT ( vttFile , json ) ;
}
using ( var srtFile = File . CreateText ( srt ) )
{
Subtitle . ToSrt ( srtFile , json ) ;
}
await ctx . SendTextAsync ( "Success" ) ;
return ;
}
}
ctx . StatusCode = 400 ;
await ctx . SendTextAsync ( "Fail" ) ;
}
private async Task SubtitlesMovieAsync ( ServerContext ctx )
{
string user = usersPathValueServer . GetValue ( ctx ) ;
string movie = moviePathValueServer . GetValue ( ctx ) ;
var me = GetAccount ( ctx ) ;
var _movie = provider . GetMovie ( user , movie ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
{
me = null ;
}
if ( me ! = null )
{
if ( ctx . QueryParams . TryGetFirst ( "lang" , out var lang ) & & ! string . IsNullOrWhiteSpace ( lang ) )
{
string langDir = Path . Combine ( path , user , "movie" , movie , "subtitles" , lang ) ;
string langFile = Path . Combine ( langDir , $"{movie}.json" ) ;
string browserfile = $"{Configuration.Root.TrimEnd('/')}/content/{user}/movie/{movie}/browser.mp4" ;
string json = "" ;
bool hasjson = false ;
if ( File . Exists ( langFile ) )
{
hasjson = true ;
json = File . ReadAllText ( langFile ) ;
}
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , await pageSubtitleEditor . RenderAsync ( new { hasjson , json , lang , browserfile } ) ) ) ;
}
else
{
List < object > languages = new List < object > ( ) ;
foreach ( var item in Languages )
{
languages . Add ( new { code = item . LangCode , name = item . LangTitle } ) ;
}
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , await pageSubtitleLangList . RenderAsync ( new { languages } ) ) ) ;
}
}
}
private async Task UploadAlbumExtraAsync ( ServerContext ctx )
{
string user = usersPathValueServer . GetValue ( ctx ) ;
string album = albumPathValueServer . GetValue ( ctx ) ;
var me = GetAccount ( ctx , true ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
{
me = null ;
}
if ( me ! = null )
{
Directory . CreateDirectory ( Path . Combine ( path , user , "album" , album ) ) ;
var tmpFile = Path . Combine ( path , user , "album" , album , $"tmp{DateTime.Now.ToFileTime().ToString()}.bin" ) ;
string filename = "" ;
foreach ( var item in ctx . ParseBody ( ( n , fn , ct ) = > { filename = fn ; return File . Create ( tmpFile ) ; } ) )
item . Value . Dispose ( ) ;
if ( ctx . QueryParams . TryGetFirst ( "parent" , out var parent ) )
{
var _path = SanitizePath ( $"{parent.TrimStart('/').TrimEnd('/')}/{filename}" ) . TrimStart ( '/' ) ;
var _path2 = Path . Combine ( path , user , "album" , album , "extras" , _path ) ;
if ( File . Exists ( _path2 ) )
File . Delete ( _path2 ) ;
File . Move ( tmpFile , _path2 ) ;
ScheduleTask ( async ( ) = >
{
await GenerateBittorentFileAlbumAsync ( user , album ) ;
} ) ;
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/user/{user}/album/{album}/extras?path={System.Web.HttpUtility.UrlEncode(parent)}" ) ;
}
}
}
private async Task UploadMovieExtraAsync ( ServerContext ctx )
{
string user = usersPathValueServer . GetValue ( ctx ) ;
string movie = moviePathValueServer . GetValue ( ctx ) ;
var me = GetAccount ( ctx , true ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
{
me = null ;
}
if ( me ! = null )
{
Directory . CreateDirectory ( Path . Combine ( path , user , "movie" , movie ) ) ;
var tmpFile = Path . Combine ( path , user , "movie" , movie , $"tmp{DateTime.Now.ToFileTime().ToString()}.bin" ) ;
string filename = "" ;
foreach ( var item in ctx . ParseBody ( ( n , fn , ct ) = > { filename = fn ; return File . Create ( tmpFile ) ; } ) )
item . Value . Dispose ( ) ;
if ( ctx . QueryParams . TryGetFirst ( "parent" , out var parent ) )
{
var _path = SanitizePath ( $"{parent.TrimStart('/').TrimEnd('/')}/{filename}" ) . TrimStart ( '/' ) ;
var _path2 = Path . Combine ( path , user , "movie" , movie , "extras" , _path ) ;
if ( File . Exists ( _path2 ) )
File . Delete ( _path2 ) ;
File . Move ( tmpFile , _path2 ) ;
ScheduleTask ( async ( ) = >
{
await GenerateBittorentFileMovieAsync ( user , movie ) ;
} ) ;
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/user/{user}/movie/{movie}/extras?path={System.Web.HttpUtility.UrlEncode(parent)}" ) ;
}
}
}
private async Task UploadShowExtraAsync ( ServerContext ctx )
{
string user = usersPathValueServer . GetValue ( ctx ) ;
string show = showPathValueServer . GetValue ( ctx ) ;
var me = GetAccount ( ctx , true ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
{
me = null ;
}
if ( me ! = null )
{
Directory . CreateDirectory ( Path . Combine ( path , user , "show" , show ) ) ;
var tmpFile = Path . Combine ( path , user , "show" , show , $"tmp{DateTime.Now.ToFileTime().ToString()}.bin" ) ;
string filename = "" ;
foreach ( var item in ctx . ParseBody ( ( n , fn , ct ) = > { filename = fn ; return File . Create ( tmpFile ) ; } ) )
item . Value . Dispose ( ) ;
if ( ctx . QueryParams . TryGetFirst ( "parent" , out var parent ) )
{
var _path = SanitizePath ( $"{parent.TrimStart('/').TrimEnd('/')}/{filename}" ) . TrimStart ( '/' ) ;
var _path2 = Path . Combine ( path , user , "show" , show , "extras" , _path ) ;
if ( File . Exists ( _path2 ) )
File . Delete ( _path2 ) ;
File . Move ( tmpFile , _path2 ) ;
ScheduleTask ( async ( ) = >
{
await GenerateBittorentFileShowAsync ( user , show ) ;
} ) ;
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/user/{user}/show/{show}/extras?path={System.Web.HttpUtility.UrlEncode(parent)}" ) ;
}
}
}
private async Task ExtrasAlbumMkdirAsync ( ServerContext ctx )
{
ctx . ParseBody ( ) ;
string user = usersPathValueServer . GetValue ( ctx ) ;
string album = albumPathValueServer . GetValue ( ctx ) ;
var me = GetAccount ( ctx , true ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
{
me = null ;
}
if ( ctx . QueryParams . TryGetFirst ( "parent" , out var parent ) & & ctx . QueryParams . TryGetFirst ( "name" , out var name ) )
{
var _path = SanitizePath ( $"{parent.TrimStart('/').TrimEnd('/')}/{name}" ) . TrimStart ( '/' ) ;
var _path2 = Path . Combine ( path , user , "album" , album , "extras" , _path ) ;
if ( me ! = null )
{
Directory . CreateDirectory ( _path2 ) ;
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/user/{user}/album/{album}/extras?path={System.Web.HttpUtility.UrlEncode(_path)}" ) ;
}
else
{
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/user/{user}/album/{album}/extras?path={System.Web.HttpUtility.UrlEncode(parent)}" ) ;
}
}
}
private async Task ExtrasMovieMkdirAsync ( ServerContext ctx )
{
ctx . ParseBody ( ) ;
string user = usersPathValueServer . GetValue ( ctx ) ;
string movie = moviePathValueServer . GetValue ( ctx ) ;
var me = GetAccount ( ctx , true ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
{
me = null ;
}
if ( ctx . QueryParams . TryGetFirst ( "parent" , out var parent ) & & ctx . QueryParams . TryGetFirst ( "name" , out var name ) )
{
var _path = SanitizePath ( $"{parent.TrimStart('/').TrimEnd('/')}/{name}" ) . TrimStart ( '/' ) ;
var _path2 = Path . Combine ( path , user , "movie" , movie , "extras" , _path ) ;
if ( me ! = null )
{
Directory . CreateDirectory ( _path2 ) ;
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/user/{user}/movie/{movie}/extras?path={System.Web.HttpUtility.UrlEncode(_path)}" ) ;
}
else
{
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/user/{user}/movie/{movie}/extras?path={System.Web.HttpUtility.UrlEncode(parent)}" ) ;
}
}
}
private async Task ExtrasShowMkdirAsync ( ServerContext ctx )
{
ctx . ParseBody ( ) ;
string user = usersPathValueServer . GetValue ( ctx ) ;
string show = showPathValueServer . GetValue ( ctx ) ;
var me = GetAccount ( ctx , true ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
{
me = null ;
}
if ( ctx . QueryParams . TryGetFirst ( "parent" , out var parent ) & & ctx . QueryParams . TryGetFirst ( "name" , out var name ) )
{
var _path = SanitizePath ( $"{parent.TrimStart('/').TrimEnd('/')}/{name}" ) . TrimStart ( '/' ) ;
var _path2 = Path . Combine ( path , user , "show" , show , "extras" , _path ) ;
if ( me ! = null )
{
Directory . CreateDirectory ( _path2 ) ;
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/user/{user}/show/{show}/extras?path={System.Web.HttpUtility.UrlEncode(_path)}" ) ;
}
else
{
await ctx . SendRedirectAsync ( $"{Configuration.Root.TrimEnd('/')}/user/{user}/show/{show}/extras?path={System.Web.HttpUtility.UrlEncode(parent)}" ) ;
}
}
}
public async Task ExtrasShowPageAsync ( ServerContext ctx )
{
string user = usersPathValueServer . GetValue ( ctx ) ;
string show = showPathValueServer . GetValue ( ctx ) ;
var me = GetAccount ( ctx ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
{
me = null ;
}
if ( ! ctx . QueryParams . TryGetFirst ( "path" , out var __path ) )
{
__path = "/" ;
}
__path = __path . TrimStart ( '/' ) ;
__path = SanitizePath ( __path ) ;
string extrasPath = Path . Combine ( path , user , "show" , show , "extras" ) ;
if ( __path . Length > 0 )
{
extrasPath = Path . Combine ( extrasPath , __path ) ;
}
List < object > paths = new List < object > ( ) ;
if ( __path . Length > 0 )
{
string up = Path . GetDirectoryName ( $"/{__path}" ) . TrimStart ( '/' ) ;
string path = $"./extras?path={System.Web.HttpUtility.UrlEncode(up)}" ;
paths . Add ( new { Path = path , Type = "[PARENT]" , Name = "Up" } ) ;
}
else
{
paths . Add ( new { Path = "./" , Type = "[PARENT]" , Name = "Up" } ) ;
}
if ( Directory . Exists ( extrasPath ) )
foreach ( var dir in Directory . EnumerateDirectories ( extrasPath ) )
{
string dirname = Path . GetFileName ( dir ) ;
string dirname_html = System . Web . HttpUtility . HtmlEncode ( dirname ) ;
string path = $"./extras?path={System.Web.HttpUtility.UrlEncode(__path.TrimEnd('/') + '/' + dirname)}" ;
paths . Add ( new { Path = path , Type = "[DIR]" , Name = dirname_html } ) ;
}
if ( Directory . Exists ( extrasPath ) )
foreach ( var file in Directory . EnumerateFiles ( extrasPath ) )
{
string filename = Path . GetFileName ( file ) ;
string filename_html = System . Web . HttpUtility . HtmlEncode ( filename ) ;
string path = $"{Configuration.Root.TrimEnd('/')}/content/{user}/show/{show}/extras/{System.Web.HttpUtility.UrlPathEncode(__path.TrimEnd('/') + '/' + filename)}" ;
paths . Add ( new { Path = path , Type = "[FILE]" , Name = filename_html } ) ;
}
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , await pageExtrasViewer . RenderAsync ( new { Extras = paths , Path = $"/{__path}" , Parent = __path , Editable = me ! = null } ) ) ) ;
}
private async Task ExtrasAlbumPageAsync ( ServerContext ctx )
{
string user = usersPathValueServer . GetValue ( ctx ) ;
string album = albumPathValueServer . GetValue ( ctx ) ;
var me = GetAccount ( ctx , out var cookie ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
{
me = null ;
}
if ( ! ctx . QueryParams . TryGetFirst ( "path" , out var __path ) )
{
__path = "/" ;
}
__path = __path . TrimStart ( '/' ) ;
__path = SanitizePath ( __path ) ;
string extrasPath = Path . Combine ( path , user , "album" , album , "extras" ) ;
if ( __path . Length > 0 )
{
extrasPath = Path . Combine ( extrasPath , __path ) ;
}
List < object > paths = new List < object > ( ) ;
if ( __path . Length > 0 )
{
string up = Path . GetDirectoryName ( $"/{__path}" ) . TrimStart ( '/' ) ;
string path = $"./extras?path={System.Web.HttpUtility.UrlEncode(up)}" ;
paths . Add ( new { Path = path , Type = "[PARENT]" , Name = "Up" } ) ;
}
else
{
paths . Add ( new { Path = "./" , Type = "[PARENT]" , Name = "Up" } ) ;
}
if ( Directory . Exists ( extrasPath ) )
foreach ( var dir in Directory . EnumerateDirectories ( extrasPath ) )
{
string dirname = Path . GetFileName ( dir ) ;
string dirname_html = System . Web . HttpUtility . HtmlEncode ( dirname ) ;
string path = $"./extras?path={System.Web.HttpUtility.UrlEncode(__path.TrimEnd('/') + '/' + dirname)}" ;
paths . Add ( new { Path = path , Type = "[DIR]" , Name = dirname_html } ) ;
}
if ( Directory . Exists ( extrasPath ) )
foreach ( var file in Directory . EnumerateFiles ( extrasPath ) )
{
string filename = Path . GetFileName ( file ) ;
string filename_html = System . Web . HttpUtility . HtmlEncode ( filename ) ;
string path = $"{Configuration.Root.TrimEnd('/')}/content/{user}/album/{album}/extras/{System.Web.HttpUtility.UrlPathEncode(__path.TrimEnd('/') + '/' + filename)}" ;
paths . Add ( new { Path = path , Type = "[FILE]" , Name = filename_html } ) ;
}
string csrf = "" ;
if ( me ! = null )
csrf = HttpUtility . UrlEncode ( CreateCSRF ( me . Id , cookie ) ) ;
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , await pageExtrasViewer . RenderAsync ( new { csrf , Extras = paths , Path = $"/{__path}" , Parent = __path , Editable = me ! = null } ) ) ) ;
}
private async Task ExtrasMoviePageAsync ( ServerContext ctx )
{
string user = usersPathValueServer . GetValue ( ctx ) ;
string movie = moviePathValueServer . GetValue ( ctx ) ;
var me = GetAccount ( ctx , out var cookie ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
{
me = null ;
}
if ( ! ctx . QueryParams . TryGetFirst ( "path" , out var __path ) )
{
__path = "/" ;
}
__path = __path . TrimStart ( '/' ) ;
__path = SanitizePath ( __path ) ;
string extrasPath = Path . Combine ( path , user , "movie" , movie , "extras" ) ;
if ( __path . Length > 0 )
{
extrasPath = Path . Combine ( extrasPath , __path ) ;
}
List < object > paths = new List < object > ( ) ;
if ( __path . Length > 0 )
{
string up = Path . GetDirectoryName ( $"/{__path}" ) . TrimStart ( '/' ) ;
string path = $"./extras?path={System.Web.HttpUtility.UrlEncode(up)}" ;
paths . Add ( new { Path = path , Type = "[PARENT]" , Name = "Up" } ) ;
}
else
{
paths . Add ( new { Path = "./" , Type = "[PARENT]" , Name = "Up" } ) ;
}
if ( Directory . Exists ( extrasPath ) )
foreach ( var dir in Directory . EnumerateDirectories ( extrasPath ) )
{
string dirname = Path . GetFileName ( dir ) ;
string dirname_html = System . Web . HttpUtility . HtmlEncode ( dirname ) ;
string path = $"./extras?path={System.Web.HttpUtility.UrlEncode(__path.TrimEnd('/') + '/' + dirname)}" ;
paths . Add ( new { Path = path , Type = "[DIR]" , Name = dirname_html } ) ;
}
if ( Directory . Exists ( extrasPath ) )
foreach ( var file in Directory . EnumerateFiles ( extrasPath ) )
{
string filename = Path . GetFileName ( file ) ;
string filename_html = System . Web . HttpUtility . HtmlEncode ( filename ) ;
string path = $"{Configuration.Root.TrimEnd('/')}/content/{user}/movie/{movie}/extras/{System.Web.HttpUtility.UrlPathEncode(__path.TrimEnd('/') + '/' + filename)}" ;
paths . Add ( new { Path = path , Type = "[FILE]" , Name = filename_html } ) ;
}
string csrf = "" ;
if ( me ! = null )
csrf = HttpUtility . UrlEncode ( CreateCSRF ( me . Id , cookie ) ) ;
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , await pageExtrasViewer . RenderAsync ( new { csrf , Extras = paths , Path = $"/{__path}" , Parent = __path , Editable = me ! = null } ) ) ) ;
}
private string SanitizePath ( string path )
{
if ( path . Length = = 0 ) return "" ;
List < string > paths = new List < string > ( ) ;
foreach ( var item in path . Replace ( '\\' , '/' ) . Split ( '/' ) )
{
if ( item = = "." | | item = = ".." ) continue ;
paths . Add ( item ) ;
}
return string . Join ( "/" , paths ) ;
}
private class PieceStream : Stream
{
public const int PieceLength = 16 * 1024 ;
public int CurpieceOffset { get ; private set ; } = 0 ;
public List < byte [ ] > Pieces { get ; private set ; } = new List < byte [ ] > ( ) ;
public byte [ ] CalculateCurPiece ( )
{
using ( var sha1 = SHA1 . Create ( ) )
{
return sha1 . ComputeHash ( Curpiece , 0 , CurpieceOffset ) ;
}
}
public byte [ ] Curpiece = new byte [ PieceLength ] ;
public override bool CanRead = > false ;
public override bool CanSeek = > false ;
public override bool CanWrite = > true ;
long len ;
public override long Length = > len ;
public bool HasPiece = > CurpieceOffset > 0 ;
public override long Position { get = > throw new NotImplementedException ( ) ; set = > throw new NotImplementedException ( ) ; }
public override void Flush ( )
{
}
public override int Read ( byte [ ] buffer , int offset , int count )
{
throw new NotImplementedException ( ) ;
}
public override long Seek ( long offset , SeekOrigin origin )
{
throw new NotImplementedException ( ) ;
}
public override void SetLength ( long value )
{
}
public override void Write ( byte [ ] buffer , int offset , int count )
{
for ( int i = 0 ; i < count ; i + + )
{
byte curByte = buffer [ i + offset ] ;
if ( CurpieceOffset < PieceLength )
{
Curpiece [ CurpieceOffset + + ] = curByte ;
}
else
{
Pieces . Add ( this . CalculateCurPiece ( ) ) ;
CurpieceOffset = 0 ;
Curpiece [ CurpieceOffset + + ] = curByte ;
}
}
len + = count ;
}
}
private async Task GenerateBittorentFileAlbumAsync ( string user , string album )
{
var _album = provider . GetAlbum ( user , album ) ;
string albumDir = Path . Combine ( this . path , user , "album" , album ) ;
Directory . CreateDirectory ( albumDir ) ;
string extrasDir = Path . Combine ( albumDir , "extras" ) ;
PieceStream strm = new PieceStream ( ) ;
//calculate without extras
List < string [ ] > paths = new List < string [ ] > ( ) ;
int track = 1 ;
foreach ( var item in _album . Tracks )
{
string name = $"{track.ToString(" D2 ")} {_album.AlbumArtist} - {item}.flac" ;
if ( File . Exists ( Path . Combine ( albumDir , name ) ) ) paths . Add ( new string [ ] { name } ) ;
track + + ;
}
if ( File . Exists ( Path . Combine ( albumDir , "thumbnail.jpg" ) ) )
paths . Add ( new string [ ] { "thumbnail.jpg" } ) ;
List < long > lengths = new List < long > ( ) ;
foreach ( var _path in paths . Select < string [ ] , string > ( e = > Path . Combine ( e ) ) )
using ( var movieStrm = File . OpenRead ( Path . Combine ( albumDir , _path ) ) )
{
lengths . Add ( movieStrm . Length ) ;
await movieStrm . CopyToAsync ( strm ) ;
}
Torrent torrent = new Torrent ( ) ;
torrent . AnnounceList . AddRange ( Configuration . BittorrentTrackers ) ;
torrent . CreationDate = DateTime . Now ;
torrent . UrlList = $"{Configuration.Root.TrimEnd('/')}/content/{user}/album/" ;
torrent . Info . PieceLength = PieceStream . PieceLength ;
torrent . Info . Name = album ;
foreach ( var piece in strm . Pieces )
{
torrent . Info . Pieces . Add ( piece ) ;
}
if ( strm . HasPiece ) torrent . Info . Pieces . Add ( strm . CalculateCurPiece ( ) ) ;
for ( int i = 0 ; i < paths . Count ; i + + )
{
var _path = paths [ i ] ;
var len = lengths [ i ] ;
torrent . Info . Files . Add ( new TorrentInfoFile ( ) { Path = _path , Length = len } ) ;
}
string torrentFile = Path . Combine ( albumDir , $"{album}.torrent" ) ;
using ( var file = File . Create ( torrentFile ) )
{
await torrent . ToTorrentFile ( ) . WriteToStreamAsync ( file ) ;
}
if ( Directory . Exists ( extrasDir ) )
{
List < string [ ] > paths2 = new List < string [ ] > ( ) ;
GetExtras ( paths2 , new string [ ] { "extras" } , extrasDir ) ;
foreach ( var _path in paths2 . Select < string [ ] , string > ( e = > Path . Combine ( e ) ) )
using ( var movieStrm = File . OpenRead ( Path . Combine ( albumDir , _path ) ) )
{
lengths . Add ( movieStrm . Length ) ;
await movieStrm . CopyToAsync ( strm ) ;
}
paths . AddRange ( paths2 ) ;
torrent = new Torrent ( ) ;
torrent . AnnounceList . AddRange ( Configuration . BittorrentTrackers ) ;
torrent . CreationDate = DateTime . Now ;
torrent . UrlList = $"{Configuration.Root.TrimEnd('/')}/content/{user}/album/" ;
torrent . Info . PieceLength = PieceStream . PieceLength ;
torrent . Info . Name = album ;
foreach ( var piece in strm . Pieces )
{
torrent . Info . Pieces . Add ( piece ) ;
}
if ( strm . HasPiece ) torrent . Info . Pieces . Add ( strm . CalculateCurPiece ( ) ) ;
for ( int i = 0 ; i < paths . Count ; i + + )
{
var _path = paths [ i ] ;
var len = lengths [ i ] ;
torrent . Info . Files . Add ( new TorrentInfoFile ( ) { Path = _path , Length = len } ) ;
}
torrentFile = Path . Combine ( albumDir , $"{album}_withextras.torrent" ) ;
using ( var file = File . Create ( torrentFile ) )
{
await torrent . ToTorrentFile ( ) . WriteToStreamAsync ( file ) ;
}
}
}
private async Task GenerateBittorentFileMovieAsync ( string user , string movie )
{
string movieDir = Path . Combine ( this . path , user , "movie" , movie ) ;
Directory . CreateDirectory ( movieDir ) ;
string extrasDir = Path . Combine ( movieDir , "extras" ) ;
string subtitles = Path . Combine ( movieDir , "subtitles" ) ;
PieceStream strm = new PieceStream ( ) ;
//calculate without extras
List < string [ ] > paths = new List < string [ ] > ( ) ;
if ( File . Exists ( Path . Combine ( movieDir , $"{movie}.mp4" ) ) )
paths . Add ( new string [ ] { $"{movie}.mp4" } ) ;
if ( File . Exists ( Path . Combine ( movieDir , "thumbnail.jpg" ) ) )
paths . Add ( new string [ ] { "thumbnail.jpg" } ) ;
if ( File . Exists ( Path . Combine ( movieDir , "poster.jpg" ) ) )
paths . Add ( new string [ ] { "poster.jpg" } ) ;
if ( Directory . Exists ( subtitles ) )
GetExtras ( paths , new string [ ] { "subtitles" } , subtitles ) ;
List < long > lengths = new List < long > ( ) ;
foreach ( var _path in paths . Select < string [ ] , string > ( e = > Path . Combine ( e ) ) )
using ( var movieStrm = File . OpenRead ( Path . Combine ( movieDir , _path ) ) )
{
lengths . Add ( movieStrm . Length ) ;
await movieStrm . CopyToAsync ( strm ) ;
}
Torrent torrent = new Torrent ( ) ;
torrent . AnnounceList . AddRange ( Configuration . BittorrentTrackers ) ;
torrent . CreationDate = DateTime . Now ;
torrent . UrlList = $"{Configuration.Root.TrimEnd('/')}/content/{user}/movie/" ;
torrent . Info . PieceLength = PieceStream . PieceLength ;
torrent . Info . Name = movie ;
foreach ( var piece in strm . Pieces )
{
torrent . Info . Pieces . Add ( piece ) ;
}
if ( strm . HasPiece ) torrent . Info . Pieces . Add ( strm . CalculateCurPiece ( ) ) ;
for ( int i = 0 ; i < paths . Count ; i + + )
{
var _path = paths [ i ] ;
var len = lengths [ i ] ;
torrent . Info . Files . Add ( new TorrentInfoFile ( ) { Path = _path , Length = len } ) ;
}
string torrentFile = Path . Combine ( movieDir , $"{movie}.torrent" ) ;
using ( var file = File . Create ( torrentFile ) )
{
await torrent . ToTorrentFile ( ) . WriteToStreamAsync ( file ) ;
}
if ( Directory . Exists ( extrasDir ) )
{
List < string [ ] > paths2 = new List < string [ ] > ( ) ;
GetExtras ( paths2 , new string [ ] { "extras" } , extrasDir ) ;
foreach ( var _path in paths2 . Select < string [ ] , string > ( e = > Path . Combine ( e ) ) )
using ( var movieStrm = File . OpenRead ( Path . Combine ( movieDir , _path ) ) )
{
lengths . Add ( movieStrm . Length ) ;
await movieStrm . CopyToAsync ( strm ) ;
}
paths . AddRange ( paths2 ) ;
torrent = new Torrent ( ) ;
torrent . AnnounceList . AddRange ( Configuration . BittorrentTrackers ) ;
torrent . CreationDate = DateTime . Now ;
torrent . UrlList = $"{Configuration.Root.TrimEnd('/')}/content/{user}/movie/" ;
torrent . Info . PieceLength = PieceStream . PieceLength ;
torrent . Info . Name = movie ;
foreach ( var piece in strm . Pieces )
{
torrent . Info . Pieces . Add ( piece ) ;
}
if ( strm . HasPiece ) torrent . Info . Pieces . Add ( strm . CalculateCurPiece ( ) ) ;
for ( int i = 0 ; i < paths . Count ; i + + )
{
var _path = paths [ i ] ;
var len = lengths [ i ] ;
torrent . Info . Files . Add ( new TorrentInfoFile ( ) { Path = _path , Length = len } ) ;
}
torrentFile = Path . Combine ( movieDir , $"{movie}_withextras.torrent" ) ;
using ( var file = File . Create ( torrentFile ) )
{
await torrent . ToTorrentFile ( ) . WriteToStreamAsync ( file ) ;
}
}
}
private void GetExtras ( List < string [ ] > paths2 , string [ ] torrentPath , string extrasDir )
{
foreach ( var dir in Directory . GetDirectories ( extrasDir ) )
{
string dirname = Path . GetFileName ( dir ) ;
string [ ] path = new string [ torrentPath . Length + 1 ] ;
Array . Copy ( torrentPath , path , torrentPath . Length ) ;
path [ path . Length - 1 ] = dirname ;
GetExtras ( paths2 , path , dir ) ;
}
foreach ( var file in Directory . GetFiles ( extrasDir ) )
{
string filename = Path . GetFileName ( file ) ;
string [ ] path = new string [ torrentPath . Length + 1 ] ;
Array . Copy ( torrentPath , path , torrentPath . Length ) ;
path [ path . Length - 1 ] = filename ;
paths2 . Add ( path ) ;
}
}
private async Task UploadSeasonStreamAsync ( ServerContext ctx )
{
string user = usersPathValueServer . GetValue ( ctx ) ;
string show = showPathValueServer . GetValue ( ctx ) ;
string season = seasonPathValueServer . GetValue ( ctx ) ;
var _show = provider . GetShow ( user , show ) ;
var _user = provider . GetUserAccount ( user ) ;
if ( ! int . TryParse ( season , out var seasonNo ) )
seasonNo = 1 ;
var _season = provider . GetSeason ( user , show , seasonNo ) ;
var me = GetAccount ( ctx , true ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
{
me = null ;
}
if ( me ! = null )
{
Directory . CreateDirectory ( Path . Combine ( path , user , "show" , show , $"Season {seasonNo.ToString(" D2 ")}" ) ) ;
var tmpFile = Path . Combine ( path , user , "show" , show , $"Season {seasonNo.ToString(" D2 ")}" , $"tmp{DateTime.Now.ToFileTime().ToString()}.bin" ) ;
foreach ( var item in ctx . ParseBody ( ( n , fn , ct ) = > File . Create ( tmpFile ) ) )
item . Value . Dispose ( ) ;
if ( _show ! = null )
{
if ( ctx . QueryParams . TryGetFirst ( "type" , out var type ) )
{
switch ( type )
{
case "thumbnail" :
string thumb = Path . Combine ( path , user , "show" , show , $"Season {seasonNo.ToString(" D2 ")}" , "thumbnail.jpg" ) ;
if ( File . Exists ( thumb ) ) File . Delete ( thumb ) ;
File . Move ( tmpFile , thumb ) ;
break ;
case "poster" :
string poster = Path . Combine ( path , user , "show" , show , $"Season {seasonNo.ToString(" D2 ")}" , "poster.jpg" ) ;
if ( File . Exists ( poster ) ) File . Delete ( poster ) ;
File . Move ( tmpFile , poster ) ;
break ;
}
ScheduleTask ( async ( ) = >
{
await GenerateBittorentFileShowAsync ( user , show ) ;
} ) ;
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , "<h1>Success</h1><a href=\"./edit\"><- Back</a>" ) ) ;
return ;
}
}
}
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , "<h1>Failed</h1><a href=\"./edit\"><- Back</a>" ) ) ;
}
private async Task UploadShowStreamAsync ( ServerContext ctx )
{
string user = usersPathValueServer . GetValue ( ctx ) ;
string show = showPathValueServer . GetValue ( ctx ) ;
var me = GetAccount ( ctx , true ) ;
var _show = provider . GetShow ( user , show ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
{
me = null ;
}
if ( me ! = null )
{
Directory . CreateDirectory ( Path . Combine ( path , user , "show" , show ) ) ;
var tmpFile = Path . Combine ( path , user , "show" , show , $"tmp{DateTime.Now.ToFileTime().ToString()}.bin" ) ;
foreach ( var item in ctx . ParseBody ( ( n , fn , ct ) = > File . Create ( tmpFile ) ) )
item . Value . Dispose ( ) ;
if ( _show ! = null )
{
if ( ctx . QueryParams . TryGetFirst ( "type" , out var type ) )
{
switch ( type )
{
case "thumbnail" :
string thumb = Path . Combine ( path , user , "show" , show , "thumbnail.jpg" ) ;
if ( File . Exists ( thumb ) ) File . Delete ( thumb ) ;
File . Move ( tmpFile , thumb ) ;
break ;
case "poster" :
string poster = Path . Combine ( path , user , "show" , show , "poster.jpg" ) ;
if ( File . Exists ( poster ) ) File . Delete ( poster ) ;
File . Move ( tmpFile , poster ) ;
break ;
}
ScheduleTask ( async ( ) = >
{
await GenerateBittorentFileShowAsync ( user , show ) ;
} ) ;
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , "<h1>Success</h1><a href=\"./edit\"><- Back</a>" ) ) ;
return ;
}
}
}
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , "<h1>Failed</h1><a href=\"./edit\"><- Back</a>" ) ) ;
}
private async Task GenerateBittorentFileShowAsync ( string user , string show )
{
string showDir = Path . Combine ( this . path , user , "show" , show ) ;
Directory . CreateDirectory ( showDir ) ;
string extrasDir = Path . Combine ( showDir , "extras" ) ;
PieceStream strm = new PieceStream ( ) ;
//calculate without extras
List < string [ ] > paths = new List < string [ ] > ( ) ;
for ( int i = 1 ; i < = provider . SeasonCount ( user , show ) ; i + + )
{
var season = provider . GetSeason ( user , show , i ) ;
if ( season ! = null )
{
string season_name = $"Season {i.ToString(" D2 ")}" ;
if ( ! Directory . Exists ( Path . Combine ( showDir , season_name ) ) ) continue ;
if ( File . Exists ( Path . Combine ( showDir , season_name , "thumbnail.jpg" ) ) )
paths . Add ( new string [ ] { season_name , "thumbnail.jpg" } ) ;
if ( File . Exists ( Path . Combine ( showDir , season_name , "poster.jpg" ) ) )
paths . Add ( new string [ ] { season_name , "poster.jpg" } ) ;
for ( int j = 1 ; j < = provider . EpisodeCount ( user , show , i ) ; j + + )
{
var episode = provider . GetEpisode ( user , show , i , j ) ;
if ( episode ! = null )
{
string name = $"{episode.EpisodeName} S{episode.SeasonNumber.ToString(" D2 ")}E{episode.EpisodeNumber.ToString(" D2 ")}" ;
string video_name = $"{name}.mp4" ;
string subtitles_name = $"{name}-subtitles" ;
string thumbnail = $"{name}-thumbnail.jpg" ;
string poster = $"{name}-poster.jpg" ;
if ( File . Exists ( Path . Combine ( showDir , season_name , poster ) ) )
paths . Add ( new string [ ] { season_name , poster } ) ;
if ( File . Exists ( Path . Combine ( showDir , season_name , thumbnail ) ) )
paths . Add ( new string [ ] { season_name , thumbnail } ) ;
if ( File . Exists ( Path . Combine ( showDir , season_name , video_name ) ) )
paths . Add ( new string [ ] { season_name , video_name } ) ;
if ( Directory . Exists ( Path . Combine ( showDir , season_name , subtitles_name ) ) )
GetExtras ( paths , new string [ ] { season_name , subtitles_name } , Path . Combine ( showDir , season_name , subtitles_name ) ) ;
}
}
}
}
if ( File . Exists ( Path . Combine ( showDir , "thumbnail.jpg" ) ) )
paths . Add ( new string [ ] { "thumbnail.jpg" } ) ;
if ( File . Exists ( Path . Combine ( showDir , "poster.jpg" ) ) )
paths . Add ( new string [ ] { "poster.jpg" } ) ;
List < long > lengths = new List < long > ( ) ;
foreach ( var _path in paths . Select < string [ ] , string > ( e = > Path . Combine ( e ) ) )
using ( var movieStrm = File . OpenRead ( Path . Combine ( showDir , _path ) ) )
{
lengths . Add ( movieStrm . Length ) ;
await movieStrm . CopyToAsync ( strm ) ;
}
Torrent torrent = new Torrent ( ) ;
torrent . AnnounceList . AddRange ( Configuration . BittorrentTrackers ) ;
torrent . CreationDate = DateTime . Now ;
torrent . UrlList = $"{Configuration.Root.TrimEnd('/')}/content/{user}/show/" ;
torrent . Info . PieceLength = PieceStream . PieceLength ;
torrent . Info . Name = show ;
foreach ( var piece in strm . Pieces )
{
torrent . Info . Pieces . Add ( piece ) ;
}
if ( strm . HasPiece ) torrent . Info . Pieces . Add ( strm . CalculateCurPiece ( ) ) ;
for ( int i = 0 ; i < paths . Count ; i + + )
{
var _path = paths [ i ] ;
var len = lengths [ i ] ;
torrent . Info . Files . Add ( new TorrentInfoFile ( ) { Path = _path , Length = len } ) ;
}
string torrentFile = Path . Combine ( showDir , $"{show}.torrent" ) ;
using ( var file = File . Create ( torrentFile ) )
{
await torrent . ToTorrentFile ( ) . WriteToStreamAsync ( file ) ;
}
if ( Directory . Exists ( extrasDir ) )
{
List < string [ ] > paths2 = new List < string [ ] > ( ) ;
GetExtras ( paths2 , new string [ ] { "extras" } , extrasDir ) ;
foreach ( var _path in paths2 . Select < string [ ] , string > ( e = > Path . Combine ( e ) ) )
using ( var movieStrm = File . OpenRead ( Path . Combine ( showDir , _path ) ) )
{
lengths . Add ( movieStrm . Length ) ;
await movieStrm . CopyToAsync ( strm ) ;
}
paths . AddRange ( paths2 ) ;
torrent = new Torrent ( ) ;
torrent . AnnounceList . AddRange ( Configuration . BittorrentTrackers ) ;
torrent . CreationDate = DateTime . Now ;
torrent . UrlList = $"{Configuration.Root.TrimEnd('/')}/content/{user}/show/" ;
torrent . Info . PieceLength = PieceStream . PieceLength ;
torrent . Info . Name = show ;
foreach ( var piece in strm . Pieces )
{
torrent . Info . Pieces . Add ( piece ) ;
}
if ( strm . HasPiece ) torrent . Info . Pieces . Add ( strm . CalculateCurPiece ( ) ) ;
for ( int i = 0 ; i < paths . Count ; i + + )
{
var _path = paths [ i ] ;
var len = lengths [ i ] ;
torrent . Info . Files . Add ( new TorrentInfoFile ( ) { Path = _path , Length = len } ) ;
}
torrentFile = Path . Combine ( showDir , $"{show}_withextras.torrent" ) ;
using ( var file = File . Create ( torrentFile ) )
{
await torrent . ToTorrentFile ( ) . WriteToStreamAsync ( file ) ;
}
}
}
private async Task UploadAlbumStreamAsync ( ServerContext ctx )
{
string user = usersPathValueServer . GetValue ( ctx ) ;
string album = albumPathValueServer . GetValue ( ctx ) ;
var me = GetAccount ( ctx , true ) ;
var _movie = provider . GetAlbum ( user , album ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
{
me = null ;
}
if ( me ! = null )
{
Directory . CreateDirectory ( Path . Combine ( path , user , "album" , album ) ) ;
var tmpFile = Path . Combine ( path , user , "album" , album , $"tmp{DateTime.Now.ToFileTime().ToString()}.bin" ) ;
foreach ( var item in ctx . ParseBody ( ( n , fn , ct ) = > File . Create ( tmpFile ) ) )
item . Value . Dispose ( ) ;
if ( _movie ! = null )
{
string thumb = Path . Combine ( path , user , "album" , album , "thumbnail.jpg" ) ;
if ( File . Exists ( thumb ) ) File . Delete ( thumb ) ;
File . Move ( tmpFile , thumb ) ;
ScheduleTask ( async ( ) = >
{
await GenerateBittorentFileAlbumAsync ( user , album ) ;
} ) ;
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , "<h1>Success</h1><a href=\"./edit\"><- Back</a>" ) ) ;
return ;
}
}
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , "<h1>Failed</h1><a href=\"./edit\"><- Back</a>" ) ) ;
}
private async Task UploadMovieStreamAsync ( ServerContext ctx )
{
string user = usersPathValueServer . GetValue ( ctx ) ;
string movie = moviePathValueServer . GetValue ( ctx ) ;
var me = GetAccount ( ctx , true ) ;
var _movie = provider . GetMovie ( user , movie ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
{
me = null ;
}
if ( me ! = null )
{
Directory . CreateDirectory ( Path . Combine ( path , user , "movie" , movie ) ) ;
var tmpFile = Path . Combine ( path , user , "movie" , movie , $"tmp{DateTime.Now.ToFileTime().ToString()}.bin" ) ;
foreach ( var item in ctx . ParseBody ( ( n , fn , ct ) = > File . Create ( tmpFile ) ) )
item . Value . Dispose ( ) ;
if ( _movie ! = null )
{
if ( ctx . QueryParams . TryGetFirst ( "type" , out var type ) )
{
switch ( type )
{
case "thumbnail" :
string thumb = Path . Combine ( path , user , "movie" , movie , "thumbnail.jpg" ) ;
if ( File . Exists ( thumb ) ) File . Delete ( thumb ) ;
File . Move ( tmpFile , thumb ) ;
break ;
case "poster" :
string poster = Path . Combine ( path , user , "movie" , movie , "poster.jpg" ) ;
if ( File . Exists ( poster ) ) File . Delete ( poster ) ;
File . Move ( tmpFile , poster ) ;
break ;
case "movie" :
string mov = Path . Combine ( path , user , "movie" , movie , $"{movie}.mp4" ) ;
if ( File . Exists ( mov ) ) File . Delete ( mov ) ;
File . Move ( tmpFile , mov ) ;
ScheduleFFmpeg ( $"-y -i \" { mov } \ " {Configuration.BrowserTranscode} \"{Path.Combine(path, user, " movie ", movie, " browser . mp4 ")}\"" ) ;
break ;
}
ScheduleTask ( async ( ) = >
{
await GenerateBittorentFileMovieAsync ( user , movie ) ;
} ) ;
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , "<h1>Success</h1><a href=\"./edit\"><- Back</a>" ) ) ;
return ;
}
}
}
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , "<h1>Failed</h1><a href=\"./edit\"><- Back</a>" ) ) ;
}
private void ScheduleFFmpeg ( string command )
{
ScheduleTask ( async ( ) = >
{
using ( Process process = new Process ( ) )
{
process . StartInfo . Arguments = command ;
process . StartInfo . FileName = "ffmpeg" ;
if ( process . Start ( ) )
{
await Task . Run ( process . WaitForExit ) ;
}
}
} ) ;
}
public void ScheduleTask ( Func < Task > task )
{
tasks . Enqueue ( task ) ;
}
public async Task EditMoviePagePostAsync ( ServerContext ctx )
{
ctx . ParseBody ( ) ;
string user = usersPathValueServer . GetValue ( ctx ) ;
string movie = moviePathValueServer . GetValue ( ctx ) ;
var me = GetAccount ( ctx , true ) ;
var _movie = provider . GetMovie ( user , movie ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
{
me = null ;
}
if ( me ! = null )
{
if ( _movie ! = null )
{
if ( ctx . QueryParams . TryGetFirst ( "proper_name" , out var proper_name ) & & ctx . QueryParams . TryGetFirst ( "description" , out var description ) )
{
_movie . ProperName = proper_name ;
_movie . Description = description . Replace ( "\r" , "" ) ;
provider . UpdateMovie ( _movie ) ;
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , "<h1>Success</h1><a href=\"./edit\"><- Back</a>" ) ) ;
return ;
}
}
}
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , "<h1>Failed</h1><a href=\"./edit\"><- Back</a>" ) ) ;
}
public async Task EditMoviePageAsync ( ServerContext ctx )
{
string user = usersPathValueServer . GetValue ( ctx ) ;
string movie = moviePathValueServer . GetValue ( ctx ) ;
var me = GetAccount ( ctx , out var cookie ) ;
var _movie = provider . GetMovie ( user , movie ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
{
me = null ;
}
if ( me ! = null )
{
if ( _movie ! = null )
{
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 pageEditMovieDetails . RenderAsync ( new { csrf , csrf2 , Propername = System . Web . HttpUtility . HtmlAttributeEncode ( _movie . ProperName ) , Description = System . Web . HttpUtility . HtmlEncode ( _movie . Description ) } ) ) ) ;
}
}
else
{
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , "<h1>You are unauthorized to edit this</h1>" ) ) ;
}
}
public async Task EditAlbumPageAsync ( ServerContext ctx )
{
string user = usersPathValueServer . GetValue ( ctx ) ;
string album = albumPathValueServer . GetValue ( ctx ) ;
var me = GetAccount ( ctx , out var cookie ) ;
var _album = provider . GetAlbum ( user , album ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
{
me = null ;
}
if ( me ! = null )
{
if ( _album ! = null )
{
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 pageEditAlbumDetails . RenderAsync ( new { Year = _album . Year , Propername = System . Web . HttpUtility . HtmlAttributeEncode ( _album . ProperName ) , Albumartist = System . Web . HttpUtility . HtmlAttributeEncode ( _album . AlbumArtist ) , Description = System . Web . HttpUtility . HtmlEncode ( _album . Description ) , csrf , csrf2 } ) ) ) ;
}
}
else
{
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , "<h1>You are unauthorized to edit this</h1>" ) ) ;
}
}
private async Task PlayEpisodePageAsync ( ServerContext ctx )
{
string user = usersPathValueServer . GetValue ( ctx ) ;
string show = showPathValueServer . GetValue ( ctx ) ;
string seasonS = seasonPathValueServer . GetValue ( ctx ) ;
string episodeS = episodePathValueServer . GetValue ( ctx ) ;
if ( ! int . TryParse ( seasonS , out var season ) ) season = 1 ;
if ( ! int . TryParse ( episodeS , out var episode ) ) episode = 1 ;
var _show = provider . GetShow ( user , show ) ;
var _episode = provider . GetEpisode ( user , show , season , episode ) ;
object value ;
if ( _show ! = null )
{
var data = GetEpisodeContentMetaData ( user , show , season , episode ) ;
List < object > subtitles = new List < object > ( ) ;
foreach ( var subtitle in data . SubtitlesStreams )
{
string languageName = "Unknown" ;
string langCode = "" ;
foreach ( var lang in Languages )
{
if ( lang . LangCode = = subtitle . LanguageCode )
{
languageName = lang . LangTitle ;
langCode = lang . LangCodeVideo ;
}
}
subtitles . Add ( new { langcode = langCode , name = languageName , file = subtitle . VttUrl } ) ;
}
string thumb = data . ThumbnailUrl ;
value = new
{
curepisode = episode ,
curseason = season ,
nextepisodeapi = $"{Configuration.Root.TrimEnd('/')}/api/v1/NextEpisode?user={user}&show={show}" ,
username = user ,
rooturl = $"{Configuration.Root.TrimEnd('/')}/" ,
title = Configuration . Title ,
hasmovie = true ,
episodethumbnail = thumb ,
episodename = _show . Name ,
episodeposter = data . PosterUrl ,
episodebrowserurl = data . BrowserStream ,
subtitles
} ;
}
else
{
value = new
{
username = user ,
rooturl = $"{Configuration.Root.TrimEnd('/')}/" ,
title = Configuration . Title ,
hasmovie = false
} ;
}
await ctx . SendTextAsync ( await pageWatchEpisode . RenderAsync ( value ) ) ;
}
private async Task PlayMoviePageAsync ( ServerContext ctx )
{
string user = usersPathValueServer . GetValue ( ctx ) ;
string movie = moviePathValueServer . GetValue ( ctx ) ;
var _movie = provider . GetMovie ( user , movie ) ;
object value ;
if ( _movie ! = null )
{
var data = GetMovieContentMetaData ( user , movie ) ;
List < object > subtitles = new List < object > ( ) ;
foreach ( var subtitle in data . SubtitlesStreams )
{
string languageName = "Unknown" ;
string langCode = "" ;
foreach ( var lang in Languages )
{
if ( lang . LangCode = = subtitle . LanguageCode )
{
languageName = lang . LangTitle ;
langCode = lang . LangCodeVideo ;
}
}
subtitles . Add ( new { langcode = langCode , name = languageName , file = subtitle . VttUrl } ) ;
}
string thumb = data . ThumbnailUrl ;
value = new
{
username = user ,
rooturl = $"{Configuration.Root.TrimEnd('/')}/" ,
title = Configuration . Title ,
hasmovie = true ,
moviethumbnail = thumb ,
movieurl = movie ,
moviename = _movie . Name ,
moviedescription = _movie . Description ,
movieposter = data . PosterUrl ,
moviebrowserurl = data . BrowserStream ,
subtitles
} ;
}
else
{
value = new
{
username = user ,
rooturl = $"{Configuration.Root.TrimEnd('/')}/" ,
title = Configuration . Title ,
hasmovie = false
} ;
}
await ctx . SendTextAsync ( await pageWatchMovie . RenderAsync ( value ) ) ;
}
IEnumerable < Episode > GetEpisodesFromShows ( IEnumerable < Show > shows )
{
foreach ( var show in shows )
{
foreach ( var episode in GetEpisodesFromShow ( show ) )
yield return episode ;
}
}
IEnumerable < Episode > GetEpisodesFromShow ( Show show )
{
var user = provider . GetUserById ( show . UserId ) ;
int count = provider . SeasonCount ( user . Username , show . Name ) ;
for ( int i = 1 ; i < = count ; i + + )
{
int count2 = provider . EpisodeCount ( user . Username , show . Name , i ) ;
for ( int j = 1 ; j < count2 ; j + + )
{
yield return provider . GetEpisode ( user . Username , show . Name , i , j ) ;
}
}
}
IEnumerable < Episode > GetEpisodesFromSeason ( Show show , int season )
{
var user = provider . GetUserById ( show . UserId ) ;
int count2 = provider . EpisodeCount ( user . Username , show . Name , season ) ;
for ( int j = 1 ; j < count2 ; j + + )
{
yield return provider . GetEpisode ( user . Username , show . Name , season , j ) ;
}
}
private async Task MoviePageAsync ( ServerContext ctx )
{
string user = usersPathValueServer . GetValue ( ctx ) ;
string movie = moviePathValueServer . GetValue ( ctx ) ;
var _movie = provider . GetMovie ( user , movie ) ;
var _user = provider . GetUserAccount ( user ) ;
var me = GetAccount ( ctx , out var cookie ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
{
me = null ;
}
object value ;
if ( _movie ! = null & & _user ! = null )
{
string movieDir = Path . Combine ( this . path , user , "movie" , movie ) ;
bool torrent = File . Exists ( Path . Combine ( movieDir , $"{movie}.torrent" ) ) ;
bool torrent_wextra = File . Exists ( Path . Combine ( movieDir , $"{movie}_withextras.torrent" ) ) ;
bool extrasexists = Directory . Exists ( Path . Combine ( movieDir , "extras" ) ) | | me ! = null ;
bool moviebrowserexists = File . Exists ( Path . Combine ( movieDir , "browser.mp4" ) ) ;
bool movieexists = File . Exists ( Path . Combine ( movieDir , $"{movie}.mp4" ) ) ;
string thumb = $"{Configuration.Root.TrimEnd('/')}/content/{user}/movie/{movie}/thumbnail.jpg" ;
string csrf = "" ;
if ( me ! = null )
csrf = HttpUtility . UrlEncode ( CreateCSRF ( me . Id , cookie ) ) ;
value = new
{
csrf ,
extrasexists ,
moviebrowserexists ,
movieexists ,
downloadurl = $"{Configuration.Root.TrimEnd('/')}/content/{user}/movie/{movie}/{movie}.mp4" ,
torrentexists = torrent ,
torrentwextraexists = torrent_wextra ,
torrent = $"{Configuration.Root.TrimEnd('/')}/content/{user}/movie/{movie}/{movie}.torrent" ,
torrentwextra = $"{Configuration.Root.TrimEnd('/')}/content/{user}/movie/{movie}/{movie}_withextras.torrent" ,
editable = me ! = null ,
userproper = HttpUtility . HtmlEncode ( _user . ProperName ) ,
username = HttpUtility . HtmlEncode ( user ) ,
rooturl = $"{Configuration.Root.TrimEnd('/')}/" ,
title = Configuration . Title ,
hasmovie = true ,
moviethumbnail = thumb ,
movieurl = movie ,
movieproperattr = HttpUtility . HtmlAttributeEncode ( _movie . ProperName ) ,
movieproper = HttpUtility . HtmlEncode ( _movie . ProperName ) ,
moviename = HttpUtility . HtmlEncode ( _movie . Name ) ,
moviedescription = DescriptLinkUtils ( _movie . Description ? ? "" ) . Replace ( "\n" , "<br>" )
} ;
}
else
{
value = new
{
username = user ,
rooturl = $"{Configuration.Root.TrimEnd('/')}/" ,
title = Configuration . Title ,
hasmovie = false
} ;
}
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , await pageMovie . RenderAsync ( value ) ) ) ;
}
private async Task ApiPutMovieExtraAsync ( ServerContext ctx )
{
if ( ctx . QueryParams . TryGetFirst ( "user" , out var user ) & & ctx . QueryParams . TryGetFirst ( "movie" , out var movie ) )
{
var me = GetAccount ( ctx , true ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
{
me = null ;
}
if ( me ! = null )
{
Directory . CreateDirectory ( Path . Combine ( path , user , "movie" , movie ) ) ;
var tmpFile = Path . Combine ( path , user , "movie" , movie , $"tmp{DateTime.Now.ToFileTime().ToString()}.bin" ) ;
await ctx . ReadToFileAsync ( tmpFile ) ;
if ( ctx . QueryParams . TryGetFirst ( "extra" , out var extra ) )
{
var _path = SanitizePath ( $"{extra.TrimStart('/')}" ) . TrimStart ( '/' ) ;
var _path2 = Path . Combine ( path , user , "movie" , movie , "extras" , _path ) ;
if ( File . Exists ( _path2 ) )
File . Delete ( _path2 ) ;
File . Move ( tmpFile , _path2 ) ;
ScheduleTask ( async ( ) = >
{
await GenerateBittorentFileMovieAsync ( user , movie ) ;
} ) ;
await ctx . SendJsonAsync ( new { success = true } ) ;
}
}
}
}
private async Task ApiPutShowExtraAsync ( ServerContext ctx )
{
if ( ctx . QueryParams . TryGetFirst ( "user" , out var user ) & & ctx . QueryParams . TryGetFirst ( "show" , out var show ) )
{
var me = GetAccount ( ctx , true ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
{
me = null ;
}
if ( me ! = null )
{
Directory . CreateDirectory ( Path . Combine ( path , user , "show" , show ) ) ;
var tmpFile = Path . Combine ( path , user , "show" , show , $"tmp{DateTime.Now.ToFileTime().ToString()}.bin" ) ;
await ctx . ReadToFileAsync ( tmpFile ) ;
if ( ctx . QueryParams . TryGetFirst ( "extra" , out var extra ) )
{
var _path = SanitizePath ( $"{extra.TrimStart('/')}" ) . TrimStart ( '/' ) ;
var _path2 = Path . Combine ( path , user , "show" , show , "extras" , _path ) ;
if ( File . Exists ( _path2 ) )
File . Delete ( _path2 ) ;
File . Move ( tmpFile , _path2 ) ;
ScheduleTask ( async ( ) = >
{
await GenerateBittorentFileShowAsync ( user , show ) ;
} ) ;
await ctx . SendJsonAsync ( new { success = true } ) ;
}
}
}
}
private async Task ApiPutAlbumExtraAsync ( ServerContext ctx )
{
if ( ctx . QueryParams . TryGetFirst ( "user" , out var user ) & & ctx . QueryParams . TryGetFirst ( "album" , out var album ) )
{
var me = GetAccount ( ctx , true ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
{
me = null ;
}
if ( me ! = null )
{
Directory . CreateDirectory ( Path . Combine ( path , user , "album" , album ) ) ;
var tmpFile = Path . Combine ( path , user , "album" , album , $"tmp{DateTime.Now.ToFileTime().ToString()}.bin" ) ;
await ctx . ReadToFileAsync ( tmpFile ) ;
if ( ctx . QueryParams . TryGetFirst ( "extra" , out var extra ) )
{
var _path = SanitizePath ( $"{extra.TrimStart('/')}" ) . TrimStart ( '/' ) ;
var _path2 = Path . Combine ( path , user , "album" , album , "extras" , _path ) ;
if ( File . Exists ( _path2 ) )
File . Delete ( _path2 ) ;
File . Move ( tmpFile , _path2 ) ;
ScheduleTask ( async ( ) = >
{
await GenerateBittorentFileAlbumAsync ( user , album ) ;
} ) ;
await ctx . SendJsonAsync ( new { success = true } ) ;
}
}
}
}
private IServer CreateSwagme ( )
{
SwagmeServer swagmeServer = new SwagmeServer ( ) ;
swagmeServer . AbsoluteUrl = true ;
swagmeServer . Add ( "/Branding" , async ( ctx ) = > {
await ctx . SendJsonAsync ( new {
title = Configuration . Title
} ) ;
} , 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 ( "/GetPublicUsers" , ApiGetPublicUsers , new SwagmeDocumentation ( "Get all public users" ) , "GET" , "Users" ) ;
swagmeServer . Add ( "/Updates" , ( ctx ) = >
{
SendEvents events = new SendEvents ( ) ;
void evthdlr ( object data ) { try { events . SendEvent ( data ) ; } catch ( Exception ex ) { _ = ex ; } }
SendEvents + = evthdlr ;
ctx . ServerSentEvents ( events ) ;
SendEvents - = evthdlr ;
} , new SwagmeDocumentation ( "Server sent events for updates" ) , "GET" , "Users" ) ;
swagmeServer . Add ( "/MovieFile" , ApiPutMovieFileAsync , new SwagmeDocumentation ( "Put the movie resource" ) , "PUT" , "Movies" ) ;
swagmeServer . Add ( "/MovieFile" , ApiMovieFileAsync , new SwagmeDocumentation ( "Get the movie resource" ) , "GET" , "Movies" ) ;
swagmeServer . Add ( "/MovieExtra" , ApiPutMovieExtraAsync , new SwagmeDocumentation ( "Put the movie extra" ) , "PUT" , "Movies" ) ;
swagmeServer . Add ( "/GetMovies" , ApiGetMoviesAsync , new SwagmeDocumentation ( "Get a list of movies" , "<b>user</b>: the user of the movies<br><b>type</b>: format of list (defaults to json): pls, wiimc, json, m3u8 or rss" ) , "GET" , "Movies" ) ;
swagmeServer . Add ( "/ShowExtra" , ApiPutShowExtraAsync , new SwagmeDocumentation ( "Put the show extra" ) , "PUT" , "Shows" ) ;
swagmeServer . Add ( "/NextEpisode" , ApiGetNextEpisodeAsync , new SwagmeDocumentation ( "Get the next episode if available" , "<b>user</b>: the user of the show<br><b>show</b>: the show name<br><b>season</b>: the season number starting from 1<br><b>episode</b>: the episode number starting from 1" ) , "GET" , "Shows" ) ;
swagmeServer . Add ( "/GetShows" , ApiGetShowsAsync , new SwagmeDocumentation ( "Get a list of shows" , "<b>user</b>: the user of the shows<br><b>type</b>: format of list (defaults to json): pls, wiimc, json, m3u8 or rss" ) , "GET" , "Shows" ) ;
swagmeServer . Add ( "/GetSeasons" , ApiGetSeasonsAsync , new SwagmeDocumentation ( "Get a list of episodes" , "<b>user</b>: the user of the show</br><b>show</b>: the show</br><b>type</b>: format of list (defaults to json): pls, wiimc, json, m3u8 or rss" ) , "GET" , "Shows" ) ;
swagmeServer . Add ( "/GetEpisodes" , ApiGetEpisodesAsync , new SwagmeDocumentation ( "Get a list of episodes" , "<b>user</b>: the user of the show</br><b>show</b>: the show</br><b>season</b>: the season<br><b>type</b>: format of list (defaults to json): pls, wiimc, json, m3u8 or rss" ) , "GET" , "Shows" ) ;
swagmeServer . Add ( "/ShowFile" , ApiShowFileAsync , new SwagmeDocumentation ( "Get the show resource" ) , "GET" , "Shows" ) ;
swagmeServer . Add ( "/SeasonFile" , ApiSeasonFileAsync , new SwagmeDocumentation ( "Get the season resource" ) , "GET" , "Shows" ) ;
swagmeServer . Add ( "/EpisodeFile" , ApiEpisodeFileAsync , new SwagmeDocumentation ( "Get the episode resource" ) , "GET" , "Shows" ) ;
swagmeServer . Add ( "/AlbumFile" , ApiAlbumFileAsync , new SwagmeDocumentation ( "" ) , "GET" , "Albums" ) ;
swagmeServer . Add ( "/AlbumFile" , ApiPutAlbumFileAsync , new SwagmeDocumentation ( "Put the album resource" ) , "PUT" , "Albums" ) ;
swagmeServer . Add ( "/AlbumExtra" , ApiPutAlbumExtraAsync , new SwagmeDocumentation ( "Put the album extra" ) , "PUT" , "Albums" ) ;
swagmeServer . Add ( "/GetAlbums" , ApiGetAlbumsAsync , new SwagmeDocumentation ( "Get a list of albums" , "<b>user</b>: the user of the albums<br><b>type</b>: format of list (defaults to json): json or rss" ) , "GET" , "Albums" ) ;
return swagmeServer ;
}
private async Task ApiLogin ( ServerContext ctx )
{
ctx . ParseBody ( ) ;
if ( ctx . QueryParams . TryGetFirst ( "email" , out var email ) & & ctx . QueryParams . TryGetFirst ( "password" , out var password ) & & ctx . QueryParams . TryGetFirst ( "type" , out var type ) & & ( type = = "json" | | type = = "cookie" ) )
{
foreach ( var a in provider . GetUsers ( ) )
{
if ( a . Email ! = email ) continue ;
if ( a . Email = = email & & a . PasswordCorrect ( password ) )
{
//we got it
byte [ ] bytes = new byte [ 32 ] ;
string cookie ;
using ( var rng = RandomNumberGenerator . Create ( ) )
do
{
rng . GetBytes ( bytes ) ;
cookie = Convert . ToBase64String ( bytes ) ;
} while ( provider . ContainsSession ( cookie ) ) ;
provider . CreateSession ( cookie , a . Id ) ;
if ( type = = "cookie" )
{
ctx . ResponseHeaders . Add ( "Set-Cookie" , $"Session={cookie}; Path=/" ) ;
await ctx . SendJsonAsync ( new { success = true } ) ;
}
else if ( type = = "json" )
{
await ctx . SendJsonAsync ( new { success = true , cookie } ) ;
}
return ;
}
}
}
await ctx . SendJsonAsync ( new { success = false } ) ;
}
private async Task ApiGetPublicUsers ( ServerContext ctx )
{
List < UserAccount > users = new List < UserAccount > ( ) ;
foreach ( var user in provider . GetUsers ( ) )
{
if ( ! user . IsAdmin & & Configuration . Publish = = CMSPublish . Admin )
{
//await ctx.SendTextAsync(await RenderHtmlAsync(ctx,"<h1>You can't upload content</h1>"));
continue ;
}
if ( ! ( user . IsAdmin | | user . IsInvited ) & & Configuration . Publish = = CMSPublish . RequireInvite )
{
//await ctx.SendTextAsync(await RenderHtmlAsync(ctx,"<h1>You can't upload content</h1>"));
continue ;
}
if ( ! ( user . IsAdmin | | user . IsInvited | | user . IsVerified ) )
{
//await ctx.SendTextAsync(await RenderHtmlAsync(ctx,"<h1>You can't upload content</h1>"));
continue ;
}
users . Add ( user ) ;
}
await ctx . SendJsonAsync ( users ) ;
}
private async Task ApiGetShowsAsync ( ServerContext ctx )
{
UserAccount a ;
if ( ! ctx . QueryParams . TryGetFirst ( "type" , out var type ) ) type = "json" ;
if ( ctx . QueryParams . TryGetFirst ( "user" , out var user ) )
{
a = provider . GetUserAccount ( user ) ;
}
else
{
a = provider . GetFirstUser ( ) ;
user = a . Username ;
}
List < Show > shows = new List < Show > ( ) ;
if ( a ! = null )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
shows . AddRange ( provider . GetShows ( a . Username ) ) ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
if ( type = = "json" )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
await ctx . SendJsonAsync ( shows ) ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
if ( type = = "pls" | | type = = "wiimc" )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
var episodes = GetEpisodesFromShows ( shows ) ;
StringBuilder b = new StringBuilder ( ) ;
b . AppendLine ( "[Playlist]" ) ;
int i = 1 ;
foreach ( var item in episodes )
{
var show = provider . GetShow ( item . UserId , item . ShowId ) ;
if ( type = = "wiimc" )
b . AppendLine ( $"File{i}={Configuration.Root.TrimEnd('/')}/content/{HttpUtility.UrlEncode(user)}/show/{show.Name}/Season%20{item.SeasonNumber.ToString(" D2 ")}/S{item.SeasonNumber.ToString(" D2 ")}E{item.EpisodeNumber.ToString(" D2 ")}.mp4" ) ;
else
b . AppendLine ( $"File{i}={Configuration.Root.TrimEnd('/')}/api/v1/EpisodeFile?user={HttpUtility.UrlEncode(user)}&show={HttpUtility.UrlEncode(show.Name)}&season={item.SeasonNumber}&episode={item.EpisodeNumber}&type=download" ) ;
b . AppendLine ( $"Length{i}=0" ) ;
b . AppendLine ( $"Title{i}={IniEscape(item.ProperName)}" ) ;
i + + ;
}
await ctx . SendTextAsync ( b . ToString ( ) , "audio/x-scpls" ) ;
}
if ( type = = "m3u8" )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
var episodes = GetEpisodesFromShows ( shows ) ;
M3uPlaylist playlist = new M3uPlaylist ( ) ;
foreach ( var item in episodes )
{
M3uPlaylistEntry entry = new M3uPlaylistEntry ( ) ;
var show = provider . GetShow ( item . UserId , item . ShowId ) ;
entry . Path = $"{Configuration.Root.TrimEnd('/')}/api/v1/EpisodeFile?user={HttpUtility.UrlEncode(user)}&show={HttpUtility.UrlEncode(show.Name)}&season={item.SeasonNumber}&episode={item.EpisodeNumber}&type=download" ;
entry . Title = item . ProperName ;
playlist . PlaylistEntries . Add ( entry ) ;
}
M3uContent content = new M3uContent ( ) ;
await ctx . SendTextAsync ( content . ToText ( playlist ) , "application/x-mpegurl" ) ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
if ( type = = "rss" )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
var episodes = GetEpisodesFromShows ( shows ) ;
StringWriter sw = new StringWriter ( ) ;
using ( XmlWriter xmlWriter = XmlWriter . Create ( sw , new XmlWriterSettings ( ) { Async = true , Indent = false , OmitXmlDeclaration = true , Encoding = Encoding . UTF8 } ) )
{
var rss = new RssFeedWriter ( xmlWriter ) ;
await rss . WriteTitle ( $"{a.ProperName}'s Movies" ) ;
await rss . WriteGenerator ( "TessesCMS" ) ;
await rss . WriteValue ( "link" , $"{Configuration.Root.TrimEnd('/')}/" ) ;
foreach ( var item in episodes )
{
var show = provider . GetShow ( item . UserId , item . ShowId ) ;
AtomEntry entry = new AtomEntry ( ) ;
entry . Title = item . ProperName ;
entry . Description = $"View <a href=\" { Configuration . Root . TrimEnd ( '/' ) } / user / { user } / show / { HttpUtility . UrlEncode ( show . Name ) } / season / { item . SeasonNumber } / episode / { item . EpisodeNumber } / \ ">here</a><br>{item.Description}" ;
entry . LastUpdated = item . LastUpdated ;
entry . Published = item . CreationTime ;
await rss . Write ( entry ) ;
}
}
await ctx . SendTextAsync ( sw . GetStringBuilder ( ) . ToString ( ) , "application/rss+xml" ) ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
}
public async Task ApiGetSeasonsAsync ( ServerContext ctx )
{
UserAccount a ;
Show s ;
if ( ! ctx . QueryParams . TryGetFirst ( "type" , out var type ) ) type = "json" ;
if ( ctx . QueryParams . TryGetFirst ( "user" , out var user ) & & ctx . QueryParams . TryGetFirst ( "show" , out var show ) )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
a = provider . GetUserAccount ( user ) ;
s = provider . GetShow ( user , show ) ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
else
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
ctx . StatusCode = 404 ;
await ctx . WriteHeadersAsync ( ) ;
return ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
if ( type = = "json" )
{
List < Season > seasons = new List < Season > ( ) ;
for ( int i = 1 ; i < provider . SeasonCount ( s . UserId , s . Id ) ; i + + )
{
var season = provider . GetSeason ( s . UserId , s . Id , i ) ;
if ( season ! = null )
seasons . Add ( season ) ;
}
await ctx . SendJsonAsync ( seasons ) ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
if ( type = = "pls" | | type = = "wiimc" )
{
var episodes = GetEpisodesFromShow ( s ) ;
StringBuilder b = new StringBuilder ( ) ;
b . AppendLine ( "[Playlist]" ) ;
int i = 1 ;
foreach ( var item in episodes )
{
2023-12-16 01:40:05 +00:00
2024-07-28 22:59:28 +00:00
if ( type = = "wiimc" )
b . AppendLine ( $"File{i}={Configuration.Root.TrimEnd('/')}/content/{HttpUtility.UrlEncode(user)}/show/{s.Name}/Season%20{item.SeasonNumber.ToString(" D2 ")}/S{item.SeasonNumber.ToString(" D2 ")}E{item.EpisodeNumber.ToString(" D2 ")}.mp4" ) ;
else
b . AppendLine ( $"File{i}={Configuration.Root.TrimEnd('/')}/api/v1/EpisodeFile?user={HttpUtility.UrlEncode(user)}&show={HttpUtility.UrlEncode(s.Name)}&season={item.SeasonNumber}&episode={item.EpisodeNumber}&type=download" ) ;
b . AppendLine ( $"Length{i}=0" ) ;
b . AppendLine ( $"Title{i}={IniEscape(item.ProperName)}" ) ;
i + + ;
}
await ctx . SendTextAsync ( b . ToString ( ) , "audio/x-scpls" ) ;
}
if ( type = = "m3u8" )
{
var episodes = GetEpisodesFromShow ( s ) ;
M3uPlaylist playlist = new M3uPlaylist ( ) ;
foreach ( var item in episodes )
{
M3uPlaylistEntry entry = new M3uPlaylistEntry ( ) ;
entry . Path = $"{Configuration.Root.TrimEnd('/')}/api/v1/EpisodeFile?user={HttpUtility.UrlEncode(user)}&show={HttpUtility.UrlEncode(s.Name)}&season={item.SeasonNumber}&episode={item.EpisodeNumber}&type=download" ;
entry . Title = item . ProperName ;
playlist . PlaylistEntries . Add ( entry ) ;
}
M3uContent content = new M3uContent ( ) ;
await ctx . SendTextAsync ( content . ToText ( playlist ) , "application/x-mpegurl" ) ;
}
if ( type = = "rss" )
{
var episodes = GetEpisodesFromShow ( s ) ;
StringWriter sw = new StringWriter ( ) ;
using ( XmlWriter xmlWriter = XmlWriter . Create ( sw , new XmlWriterSettings ( ) { Async = true , Indent = false , OmitXmlDeclaration = true , Encoding = Encoding . UTF8 } ) )
{
var rss = new RssFeedWriter ( xmlWriter ) ;
await rss . WriteTitle ( $"{a.ProperName}'s Movies" ) ;
await rss . WriteGenerator ( "TessesCMS" ) ;
await rss . WriteValue ( "link" , $"{Configuration.Root.TrimEnd('/')}/" ) ;
foreach ( var item in episodes )
{
AtomEntry entry = new AtomEntry ( ) ;
entry . Title = item . ProperName ;
entry . Description = $"View <a href=\" { Configuration . Root . TrimEnd ( '/' ) } / user / { user } / show / { HttpUtility . UrlEncode ( s . Name ) } / season / { item . SeasonNumber } / episode / { item . EpisodeNumber } / \ ">here</a><br>{item.Description}" ;
entry . LastUpdated = item . LastUpdated ;
entry . Published = item . CreationTime ;
await rss . Write ( entry ) ;
}
}
await ctx . SendTextAsync ( sw . GetStringBuilder ( ) . ToString ( ) , "application/rss+xml" ) ;
}
}
public async Task ApiGetEpisodesAsync ( ServerContext ctx )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
UserAccount a ;
Show s ;
if ( ! ctx . QueryParams . TryGetFirst ( "type" , out var type ) ) type = "json" ;
if ( ctx . QueryParams . TryGetFirst ( "user" , out var user ) & & ctx . QueryParams . TryGetFirst ( "show" , out var show ) & & ctx . QueryParams . TryGetFirstInt32 ( "season" , out var season ) )
{
a = provider . GetUserAccount ( user ) ;
s = provider . GetShow ( user , show ) ;
}
else
{
ctx . StatusCode = 404 ;
await ctx . WriteHeadersAsync ( ) ;
return ;
}
2023-12-16 01:40:05 +00:00
2024-07-28 22:59:28 +00:00
if ( type = = "json" )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
List < Episode > episodes = new List < Episode > ( ) ;
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 )
episodes . Add ( episode ) ;
}
await ctx . SendJsonAsync ( episodes ) ;
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
if ( type = = "pls" | | type = = "wiimc" )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
var episodes = GetEpisodesFromSeason ( s , season ) ;
StringBuilder b = new StringBuilder ( ) ;
b . AppendLine ( "[Playlist]" ) ;
int i = 1 ;
foreach ( var item in episodes )
{
if ( type = = "wiimc" )
b . AppendLine ( $"File{i}={Configuration.Root.TrimEnd('/')}/content/{HttpUtility.UrlEncode(user)}/show/{s.Name}/Season%20{item.SeasonNumber.ToString(" D2 ")}/S{item.SeasonNumber.ToString(" D2 ")}E{item.EpisodeNumber.ToString(" D2 ")}.mp4" ) ;
else
b . AppendLine ( $"File{i}={Configuration.Root.TrimEnd('/')}/api/v1/EpisodeFile?user={HttpUtility.UrlEncode(user)}&show={HttpUtility.UrlEncode(s.Name)}&season={item.SeasonNumber}&episode={item.EpisodeNumber}&type=download" ) ;
b . AppendLine ( $"Length{i}=0" ) ;
b . AppendLine ( $"Title{i}={IniEscape(item.ProperName)}" ) ;
i + + ;
}
await ctx . SendTextAsync ( b . ToString ( ) , "audio/x-scpls" ) ;
}
if ( type = = "m3u8" )
{
var episodes = GetEpisodesFromSeason ( s , season ) ;
M3uPlaylist playlist = new M3uPlaylist ( ) ;
foreach ( var item in episodes )
{
M3uPlaylistEntry entry = new M3uPlaylistEntry ( ) ;
entry . Path = $"{Configuration.Root.TrimEnd('/')}/api/v1/EpisodeFile?user={HttpUtility.UrlEncode(user)}&show={HttpUtility.UrlEncode(s.Name)}&season={item.SeasonNumber}&episode={item.EpisodeNumber}&type=download" ;
entry . Title = item . ProperName ;
playlist . PlaylistEntries . Add ( entry ) ;
}
M3uContent content = new M3uContent ( ) ;
await ctx . SendTextAsync ( content . ToText ( playlist ) , "application/x-mpegurl" ) ;
}
if ( type = = "rss" )
{
var episodes = GetEpisodesFromSeason ( s , season ) ;
StringWriter sw = new StringWriter ( ) ;
using ( XmlWriter xmlWriter = XmlWriter . Create ( sw , new XmlWriterSettings ( ) { Async = true , Indent = false , OmitXmlDeclaration = true , Encoding = Encoding . UTF8 } ) )
{
2023-12-16 01:40:05 +00:00
2024-07-28 22:59:28 +00:00
var rss = new RssFeedWriter ( xmlWriter ) ;
await rss . WriteTitle ( $"{a.ProperName}'s Movies" ) ;
await rss . WriteGenerator ( "TessesCMS" ) ;
await rss . WriteValue ( "link" , $"{Configuration.Root.TrimEnd('/')}/" ) ;
foreach ( var item in episodes )
{
AtomEntry entry = new AtomEntry ( ) ;
entry . Title = item . ProperName ;
entry . Description = $"View <a href=\" { Configuration . Root . TrimEnd ( '/' ) } / user / { user } / show / { HttpUtility . UrlEncode ( s . Name ) } / season / { item . SeasonNumber } / episode / { item . EpisodeNumber } / \ ">here</a><br>{item.Description}" ;
entry . LastUpdated = item . LastUpdated ;
entry . Published = item . CreationTime ;
await rss . Write ( entry ) ;
}
}
await ctx . SendTextAsync ( sw . GetStringBuilder ( ) . ToString ( ) , "application/rss+xml" ) ;
}
}
private async Task ApiGetNextEpisodeAsync ( ServerContext ctx )
{
if ( ctx . QueryParams . TryGetFirst ( "user" , out var user ) & & ctx . QueryParams . TryGetFirst ( "show" , out var show ) & & ctx . QueryParams . TryGetFirst ( "season" , out var seasonS ) & & ctx . QueryParams . TryGetFirst ( "episode" , out var episodeS ) )
{
if ( ! int . TryParse ( seasonS , out var season ) ) season = 1 ;
if ( ! int . TryParse ( episodeS , out var episode ) ) episode = 1 ;
var _show = provider . GetShow ( user , show ) ;
var _episode = provider . GetEpisode ( user , show , season , episode ) ;
bool hasnextepisode = false ;
int nextepisodeep = episode + 1 ;
int nextepisodeseason = season ;
while ( nextepisodeseason < = provider . SeasonCount ( user , show ) )
{
var daseason = provider . GetSeason ( user , show , nextepisodeseason ) ;
if ( daseason ! = null )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
while ( nextepisodeep < = provider . EpisodeCount ( user , show , nextepisodeseason ) )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
if ( File . Exists ( Path . Combine ( path , user , "show" , show , $"Season {nextepisodeseason.ToString(" D2 ")}" , $"S{nextepisodeseason.ToString(" D2 ")}E{nextepisodeep.ToString(" D2 ")}.mp4" ) ) )
{
hasnextepisode = true ;
2023-12-16 01:40:05 +00:00
break ;
2024-07-28 22:59:28 +00:00
}
nextepisodeep + + ;
2023-12-16 01:40:05 +00:00
}
}
2024-07-28 22:59:28 +00:00
if ( hasnextepisode )
{
break ;
}
nextepisodeep = 1 ;
nextepisodeseason + + ;
}
if ( hasnextepisode )
{
var _epn = provider . GetEpisode ( user , show , nextepisodeseason , nextepisodeep ) ;
string next_episode_page_url = $"{Configuration.Root.TrimEnd('/')}/user/{user}/show/{show}/season/{nextepisodeseason}/episode/{nextepisodeep}/play" ;
var data = GetEpisodeContentMetaData ( user , show , nextepisodeseason , nextepisodeep ) ;
StringBuilder b = new StringBuilder ( ) ;
foreach ( var subtitle in data . SubtitlesStreams )
{
string languageName = "Unknown" ;
string langCode = "" ;
foreach ( var lang in Languages )
{
if ( lang . LangCode = = subtitle . LanguageCode )
{
languageName = lang . LangTitle ;
langCode = lang . LangCodeVideo ;
}
}
b . Append ( $"<track label=\" { languageName } \ " kind=\"subtitles\" srclang=\"{langCode}\" src=\"{subtitle.VttUrl}\"/>" ) ;
2023-12-16 01:40:05 +00:00
2024-07-28 22:59:28 +00:00
}
await ctx . SendJsonAsync ( new { next_subtitles_html = b . ToString ( ) , has_next_episode = true , next_episode_episode = nextepisodeep , next_episode_season = nextepisodeseason , next_episode_name = _epn . EpisodeName , next_episode_url = data . BrowserStream , next_poster_url = data . PosterUrl , next_episode_page_url } ) ;
return ;
}
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
await ctx . SendJsonAsync ( new { has_next_episode = false } ) ;
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
private async Task ApiPutAlbumFileAsync ( ServerContext ctx )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
try
{
if ( ctx . QueryParams . TryGetFirst ( "user" , out var user ) & & ctx . QueryParams . TryGetFirst ( "album" , out var album ) )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
if ( ! ctx . QueryParams . TryGetFirst ( "type" , out var type ) )
type = "track" ;
if ( ! ctx . QueryParams . TryGetFirstInt32 ( "track_id" , out var track_id ) )
track_id = 1 ;
var me = GetAccount ( ctx , true ) ;
var _album = provider . GetAlbum ( user , album ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
me = null ;
}
if ( me ! = null )
{
Directory . CreateDirectory ( Path . Combine ( path , user , "album" , album ) ) ;
var tmpFile = Path . Combine ( path , user , "album" , album , $"tmp{DateTime.Now.ToFileTime().ToString()}.bin" ) ;
await ctx . ReadToFileAsync ( tmpFile ) ;
if ( _album ! = null )
{
switch ( type )
{
case "thumbnail" :
string thumb = Path . Combine ( path , user , "album" , album , "thumbnail.jpg" ) ;
if ( File . Exists ( thumb ) ) File . Delete ( thumb ) ;
File . Move ( tmpFile , thumb ) ;
break ;
case "poster" :
string poster = Path . Combine ( path , user , "album" , album , "poster.jpg" ) ;
if ( File . Exists ( poster ) ) File . Delete ( poster ) ;
File . Move ( tmpFile , poster ) ;
break ;
case "track" :
string oldtrack = _album . Tracks [ track_id ] ;
string flac = Path . Combine ( path , user , "album" , album , $"{(track_id + 1).ToString(" D2 ")} {_album.AlbumArtist} - {oldtrack}.flac" ) ;
File . Move ( tmpFile , flac ) ;
ScheduleTask ( async ( ) = >
{
await GenerateBittorentFileAlbumAsync ( user , album ) ;
} ) ;
string oldmp3 = Path . Combine ( path , user , "album" , album , $"{oldtrack}.mp3" ) ;
ScheduleFFmpeg ( $"-y -i \" { flac } \ " {Configuration.BrowserTranscodeMp3} \"{oldmp3}\"" ) ;
break ;
}
ScheduleTask ( async ( ) = >
{
await GenerateBittorentFileAlbumAsync ( user , album ) ;
} ) ;
await ctx . SendJsonAsync ( new { success = true } ) ;
return ;
}
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
}
catch ( Exception ex )
{
Console . WriteLine ( ex ) ;
}
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
private async Task ApiPutMovieFileAsync ( ServerContext ctx )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
try
{
if ( ctx . QueryParams . TryGetFirst ( "user" , out var user ) & & ctx . QueryParams . TryGetFirst ( "movie" , out var movie ) )
{
if ( ! ctx . QueryParams . TryGetFirst ( "type" , out var type ) )
type = "movie" ;
var me = GetAccount ( ctx , true ) ;
var _movie = provider . GetMovie ( user , movie ) ;
if ( me ! = null & & me . Username ! = user & & ! me . IsAdmin )
{
me = null ;
}
if ( me ! = null )
{
Directory . CreateDirectory ( Path . Combine ( path , user , "movie" , movie ) ) ;
var tmpFile = Path . Combine ( path , user , "movie" , movie , $"tmp{DateTime.Now.ToFileTime().ToString()}.bin" ) ;
await ctx . ReadToFileAsync ( tmpFile ) ;
if ( _movie ! = null )
{
switch ( type )
{
case "thumbnail" :
string thumb = Path . Combine ( path , user , "movie" , movie , "thumbnail.jpg" ) ;
if ( File . Exists ( thumb ) ) File . Delete ( thumb ) ;
File . Move ( tmpFile , thumb ) ;
break ;
case "poster" :
string poster = Path . Combine ( path , user , "movie" , movie , "poster.jpg" ) ;
if ( File . Exists ( poster ) ) File . Delete ( poster ) ;
File . Move ( tmpFile , poster ) ;
break ;
case "movie" :
string mov = Path . Combine ( path , user , "movie" , movie , $"{movie}.mp4" ) ;
if ( File . Exists ( mov ) ) File . Delete ( mov ) ;
File . Move ( tmpFile , mov ) ;
ScheduleFFmpeg ( $"-y -i \" { mov } \ " {Configuration.BrowserTranscode} \"{Path.Combine(path, user, " movie ", movie, " browser . mp4 ")}\"" ) ;
break ;
}
ScheduleTask ( async ( ) = >
{
await GenerateBittorentFileMovieAsync ( user , movie ) ;
} ) ;
await ctx . SendJsonAsync ( new { success = true } ) ;
return ;
}
}
}
}
catch ( Exception ex )
{
Console . WriteLine ( ex ) ;
}
}
private async Task ApiAlbumFileAsync ( ServerContext ctx )
{
if ( ctx . QueryParams . TryGetFirst ( "user" , out var user ) & & ctx . QueryParams . TryGetFirst ( "album" , out var album ) )
{
if ( ! ctx . QueryParams . TryGetFirst ( "type" , out var type ) )
type = "json" ;
var info = GetAlbumContentMetadata ( user , album ) ;
switch ( type )
{
case "thumbnail" :
await ctx . SendRedirectAsync ( info . ThumbnailUrl ) ;
break ;
case "poster" :
await ctx . SendRedirectAsync ( info . PosterUrl ) ;
break ;
case "torrent" :
await ctx . SendRedirectAsync ( info . AlbumTorrentUrl ) ;
break ;
case "torrent_extra" :
await ctx . SendRedirectAsync ( info . AlbumWithExtrasTorrentUrl ) ;
break ;
case "json" :
await ctx . SendJsonAsync ( info ) ;
break ;
case "wiimc" :
case "pls" :
{
StringBuilder b = new StringBuilder ( ) ;
b . AppendLine ( "[Playlist]" ) ;
int i = 1 ;
foreach ( var item in info . DownloadStreams )
{
b . AppendLine ( $"File{i}={IniEscape(item.Url)}" ) ;
b . AppendLine ( $"Length{i}=0" ) ;
b . AppendLine ( $"Title{i}={IniEscape(item.Name)}" ) ;
i + + ;
}
await ctx . SendTextAsync ( b . ToString ( ) , "audio/x-scpls" ) ;
}
break ;
case "m3u8" :
{
M3uPlaylist playlist = new M3uPlaylist ( ) ;
foreach ( var item in info . DownloadStreams )
{
M3uPlaylistEntry entry = new M3uPlaylistEntry ( ) ;
entry . Path = item . Url ;
entry . Title = item . Name ;
playlist . PlaylistEntries . Add ( entry ) ;
}
M3uContent content = new M3uContent ( ) ;
await ctx . SendTextAsync ( content . ToText ( playlist ) , "application/x-mpegurl" ) ;
}
break ;
case "browser" :
{
if ( ctx . QueryParams . TryGetFirstInt32 ( "track_number" , out var track_no ) )
{
var res = info . BrowserStreams . Find ( e = > e . TrackNumber = = track_no ) ;
if ( res ! = null )
await ctx . SendRedirectAsync ( res . Url ) ;
else
await ctx . SendNotFoundAsync ( ) ;
}
else
await ctx . SendNotFoundAsync ( ) ;
}
break ;
case "download" :
{
if ( ctx . QueryParams . TryGetFirstInt32 ( "track_number" , out var track_no ) )
{
var res = info . DownloadStreams . Find ( e = > e . TrackNumber = = track_no ) ;
if ( res ! = null )
await ctx . SendRedirectAsync ( res . Url ) ;
else
await ctx . SendNotFoundAsync ( ) ;
}
else
await ctx . SendNotFoundAsync ( ) ;
}
break ;
}
}
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
private async Task ApiMovieFileAsync ( ServerContext ctx )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
if ( ctx . QueryParams . TryGetFirst ( "user" , out var user ) & & ctx . QueryParams . TryGetFirst ( "movie" , out var movie ) )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
if ( ! ctx . QueryParams . TryGetFirst ( "type" , out var type ) )
type = "download" ;
2023-12-16 01:40:05 +00:00
2024-07-28 22:59:28 +00:00
var info = GetMovieContentMetaData ( user , movie ) ;
switch ( type )
{
case "download" :
await ctx . SendRedirectAsync ( info . DownloadStream ) ;
break ;
case "browser" :
await ctx . SendRedirectAsync ( info . BrowserStream ) ;
break ;
case "thumbnail" :
await ctx . SendRedirectAsync ( info . ThumbnailUrl ) ;
break ;
case "poster" :
await ctx . SendRedirectAsync ( info . PosterUrl ) ;
break ;
case "torrent" :
await ctx . SendRedirectAsync ( info . MovieTorrentUrl ) ;
break ;
case "torrent_extra" :
await ctx . SendRedirectAsync ( info . MovieWithExtrasTorrentUrl ) ;
break ;
case "json" :
await ctx . SendJsonAsync ( info ) ;
break ;
}
2023-12-16 01:40:05 +00:00
}
}
2024-07-28 22:59:28 +00:00
private async Task ApiEpisodeFileAsync ( ServerContext ctx )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
if ( ctx . QueryParams . TryGetFirst ( "user" , out var user ) & & ctx . QueryParams . TryGetFirst ( "show" , out var show ) & & ctx . QueryParams . TryGetFirstInt32 ( "season" , out var season ) & & ctx . QueryParams . TryGetFirstInt32 ( "episode" , out var episode ) )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
if ( ! ctx . QueryParams . TryGetFirst ( "type" , out var type ) )
type = "download" ;
2023-12-16 01:40:05 +00:00
2024-07-28 22:59:28 +00:00
var info = GetEpisodeContentMetaData ( user , show , season , episode ) ;
switch ( type )
{
case "download" :
await ctx . SendRedirectAsync ( info . DownloadStream ) ;
break ;
case "browser" :
await ctx . SendRedirectAsync ( info . BrowserStream ) ;
break ;
case "thumbnail" :
await ctx . SendRedirectAsync ( info . ThumbnailUrl ) ;
break ;
case "poster" :
await ctx . SendRedirectAsync ( info . PosterUrl ) ;
break ;
case "json" :
await ctx . SendJsonAsync ( info ) ;
break ;
}
2023-12-16 01:40:05 +00:00
}
}
2024-07-28 22:59:28 +00:00
private async Task ApiSeasonFileAsync ( ServerContext ctx )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
if ( ctx . QueryParams . TryGetFirst ( "user" , out var user ) & & ctx . QueryParams . TryGetFirst ( "show" , out var show ) & & ctx . QueryParams . TryGetFirstInt32 ( "season" , out var season ) )
{
if ( ! ctx . QueryParams . TryGetFirst ( "type" , out var type ) )
type = "json" ;
2024-01-04 02:53:13 +00:00
2024-07-28 22:59:28 +00:00
var info = GetSeasonContentMetaData ( user , show , season ) ;
switch ( type )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
case "thumbnail" :
await ctx . SendRedirectAsync ( info . ThumbnailUrl ) ;
break ;
case "poster" :
await ctx . SendRedirectAsync ( info . PosterUrl ) ;
break ;
case "json" :
await ctx . SendJsonAsync ( info ) ;
break ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
}
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
private async Task ApiShowFileAsync ( ServerContext ctx )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
if ( ctx . QueryParams . TryGetFirst ( "user" , out var user ) & & ctx . QueryParams . TryGetFirst ( "show" , out var show ) )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
if ( ! ctx . QueryParams . TryGetFirst ( "type" , out var type ) )
type = "json" ;
var info = GetShowContentMetaData ( user , show ) ;
switch ( type )
2023-12-16 01:40:05 +00:00
{
case "thumbnail" :
await ctx . SendRedirectAsync ( info . ThumbnailUrl ) ;
break ;
case "poster" :
await ctx . SendRedirectAsync ( info . PosterUrl ) ;
break ;
case "torrent" :
2024-07-28 22:59:28 +00:00
await ctx . SendRedirectAsync ( info . ShowTorrentUrl ) ;
2023-12-16 01:40:05 +00:00
break ;
case "torrent_extra" :
2024-07-28 22:59:28 +00:00
await ctx . SendRedirectAsync ( info . ShowWithExtrasTorrentUrl ) ;
2023-12-16 01:40:05 +00:00
break ;
case "json" :
await ctx . SendJsonAsync ( info ) ;
break ;
}
}
}
private async Task ApiGetMoviesAsync ( ServerContext ctx )
{
UserAccount a ;
2024-07-28 22:59:28 +00:00
if ( ! ctx . QueryParams . TryGetFirst ( "type" , out var type ) ) type = "json" ;
if ( ctx . QueryParams . TryGetFirst ( "user" , out var user ) )
2023-12-16 01:40:05 +00:00
{
a = provider . GetUserAccount ( user ) ;
}
else
{
a = provider . GetFirstUser ( ) ;
2024-01-04 02:53:13 +00:00
user = a . Username ;
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
List < Movie > movies = new List < Movie > ( ) ;
2023-12-16 01:40:05 +00:00
2024-07-28 22:59:28 +00:00
if ( a ! = null )
2023-12-16 01:40:05 +00:00
{
movies . AddRange ( provider . GetMovies ( a . Id ) ) ;
}
2024-07-28 22:59:28 +00:00
if ( type = = "json" )
2023-12-16 01:40:05 +00:00
{
await ctx . SendJsonAsync ( movies ) ;
}
2024-07-28 22:59:28 +00:00
if ( type = = "pls" | | type = = "wiimc" )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
StringBuilder b = new StringBuilder ( ) ;
2023-12-16 01:40:05 +00:00
b . AppendLine ( "[Playlist]" ) ;
int i = 1 ;
2024-07-28 22:59:28 +00:00
foreach ( var item in movies )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
if ( type = = "wiimc" )
2024-01-04 02:53:13 +00:00
b . AppendLine ( $"File{i}={Configuration.Root.TrimEnd('/')}/content/{HttpUtility.UrlEncode(user)}/movie/{item.Name}/browser.mp4" ) ;
else
b . AppendLine ( $"File{i}={Configuration.Root.TrimEnd('/')}/api/v1/MovieFile?user={HttpUtility.UrlEncode(user)}&movie={HttpUtility.UrlEncode(item.Name)}&type=download" ) ;
2023-12-16 01:40:05 +00:00
b . AppendLine ( $"Length{i}=0" ) ;
b . AppendLine ( $"Title{i}={IniEscape(item.ProperName)}" ) ;
i + + ;
}
2024-07-28 22:59:28 +00:00
await ctx . SendTextAsync ( b . ToString ( ) , "audio/x-scpls" ) ;
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
if ( type = = "m3u8" )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
M3uPlaylist playlist = new M3uPlaylist ( ) ;
foreach ( var item in movies )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
M3uPlaylistEntry entry = new M3uPlaylistEntry ( ) ;
2023-12-16 01:40:05 +00:00
entry . Path = $"{Configuration.Root.TrimEnd('/')}/api/v1/MovieFile?user={HttpUtility.UrlEncode(user)}&movie={HttpUtility.UrlEncode(item.Name)}&type=download" ;
entry . Title = item . ProperName ;
playlist . PlaylistEntries . Add ( entry ) ;
}
M3uContent content = new M3uContent ( ) ;
2024-07-28 22:59:28 +00:00
await ctx . SendTextAsync ( content . ToText ( playlist ) , "application/x-mpegurl" ) ;
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
if ( type = = "rss" )
2023-12-16 01:40:05 +00:00
{
StringWriter sw = new StringWriter ( ) ;
2024-07-28 22:59:28 +00:00
using ( XmlWriter xmlWriter = XmlWriter . Create ( sw , new XmlWriterSettings ( ) { Async = true , Indent = false , OmitXmlDeclaration = true , Encoding = Encoding . UTF8 } ) )
{
2023-12-16 01:40:05 +00:00
var rss = new RssFeedWriter ( xmlWriter ) ;
2024-07-28 22:59:28 +00:00
2023-12-16 01:40:05 +00:00
await rss . WriteTitle ( $"{a.ProperName}'s Movies" ) ;
await rss . WriteGenerator ( "TessesCMS" ) ;
2024-07-28 22:59:28 +00:00
await rss . WriteValue ( "link" , $"{Configuration.Root.TrimEnd('/')}/" ) ;
foreach ( var item in movies )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
AtomEntry entry = new AtomEntry ( ) ;
2023-12-16 01:40:05 +00:00
entry . Title = item . ProperName ;
entry . Description = $"View <a href=\" { Configuration . Root . TrimEnd ( '/' ) } / user / { user } / movie / { HttpUtility . UrlEncode ( item . Name ) } / \ ">here</a><br>{item.Description}" ;
entry . LastUpdated = item . LastUpdated ;
entry . Published = item . CreationTime ;
2024-07-28 22:59:28 +00:00
await rss . Write ( entry ) ;
}
}
await ctx . SendTextAsync ( sw . GetStringBuilder ( ) . ToString ( ) , "application/rss+xml" ) ;
}
}
private async Task ApiGetAlbumsAsync ( ServerContext ctx )
{
UserAccount a ;
if ( ! ctx . QueryParams . TryGetFirst ( "type" , out var type ) ) type = "json" ;
if ( ctx . QueryParams . TryGetFirst ( "user" , out var user ) )
{
a = provider . GetUserAccount ( user ) ;
}
else
{
a = provider . GetFirstUser ( ) ;
user = a . Username ;
}
List < Album > albums = new List < Album > ( ) ;
if ( a ! = null )
{
albums . AddRange ( provider . GetAlbums ( a . Id ) ) ;
}
if ( type = = "json" )
{
await ctx . SendJsonAsync ( albums ) ;
}
if ( type = = "rss" )
{
StringWriter sw = new StringWriter ( ) ;
using ( XmlWriter xmlWriter = XmlWriter . Create ( sw , new XmlWriterSettings ( ) { Async = true , Indent = false , OmitXmlDeclaration = true , Encoding = Encoding . UTF8 } ) )
{
var rss = new RssFeedWriter ( xmlWriter ) ;
await rss . WriteTitle ( $"{a.ProperName}'s Albums" ) ;
await rss . WriteGenerator ( "TessesCMS" ) ;
await rss . WriteValue ( "link" , $"{Configuration.Root.TrimEnd('/')}/" ) ;
foreach ( var item in albums )
{
AtomEntry entry = new AtomEntry ( ) ;
entry . Title = item . ProperName ;
entry . Description = $"View <a href=\" { Configuration . Root . TrimEnd ( '/' ) } / user / { user } / album / { HttpUtility . UrlEncode ( item . Name ) } / \ ">here</a><br>{item.Description}" ;
entry . LastUpdated = item . LastUpdated ;
entry . Published = item . CreationTime ;
2023-12-16 01:40:05 +00:00
await rss . Write ( entry ) ;
}
}
2024-07-28 22:59:28 +00:00
await ctx . SendTextAsync ( sw . GetStringBuilder ( ) . ToString ( ) , "application/rss+xml" ) ;
}
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
2023-12-16 01:40:05 +00:00
private string IniEscape ( string properName )
{
2024-07-28 22:59:28 +00:00
StringBuilder b = new StringBuilder ( ) ;
foreach ( var c in properName )
2023-12-16 01:40:05 +00:00
{
2024-07-28 22:59:28 +00:00
if ( c = = '\\' | | c = = ';' | | c = = '\"' | | c = = '\'' | | c = = '#' | | c = = '=' | | c = = ':' )
2023-12-16 01:40:05 +00:00
{
b . Append ( $"\\{c}" ) ;
}
2024-07-28 22:59:28 +00:00
else if ( c = = '\0' )
2023-12-16 01:40:05 +00:00
{
b . Append ( "\\0" ) ;
}
2024-07-28 22:59:28 +00:00
else if ( c = = '\b' )
2023-12-16 01:40:05 +00:00
{
b . Append ( "\\b" ) ;
}
2024-07-28 22:59:28 +00:00
else if ( c = = '\a' )
2023-12-16 01:40:05 +00:00
{
b . Append ( "\\a" ) ;
}
2024-07-28 22:59:28 +00:00
else if ( c = = '\t' )
2023-12-16 01:40:05 +00:00
{
b . Append ( "\\t" ) ;
}
2024-07-28 22:59:28 +00:00
else if ( c = = '\r' )
2023-12-16 01:40:05 +00:00
{
b . Append ( "\\r" ) ;
2024-07-28 22:59:28 +00:00
}
else if ( c = = '\n' )
2023-12-16 01:40:05 +00:00
{
b . Append ( "\\n" ) ;
}
2024-07-28 22:59:28 +00:00
else if ( c > sbyte . MaxValue )
2023-12-16 01:40:05 +00:00
{
b . Append ( $"\\x{((int)c).ToString(" X4 ")}" ) ;
}
2024-07-28 22:59:28 +00:00
else
{
2023-12-16 01:40:05 +00:00
b . Append ( c ) ;
}
}
return b . ToString ( ) ;
}
2024-07-28 22:59:28 +00:00
private async Task < string > RenderHtmlAsync ( ServerContext ctx , string body , bool isHome = false , bool isDevcenter = false , bool isLogin = false , bool isUpload = false )
2023-12-16 01:40:05 +00:00
{
List < object > _urls = new List < object > ( ) ;
2024-07-28 22:59:28 +00:00
var account = GetAccount ( ctx ) ;
CMSNavUrl accountLink = account ! = null ? Configuration . RelativeNavUrl ( account . ProperName , "account" ) : Configuration . RelativeNavUrl ( "Login" , "login" ) ;
accountLink . Active = isLogin ;
var dc = Configuration . RelativeNavUrl ( "Devcenter" , "devcenter" ) ;
dc . Active = isDevcenter ;
var upload = Configuration . RelativeNavUrl ( "Upload" , "upload" ) ;
upload . Active = isUpload ;
_urls . Add ( upload ) ;
_urls . Add ( dc ) ;
_urls . Add ( accountLink ) ;
foreach ( var item in Configuration . Urls )
{
_urls . Add ( new { text = item . Text , url = item . Url , active = item . Active } ) ;
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
return await pageShell . RenderAsync ( new
2023-12-16 01:40:05 +00:00
{
ishome = isHome ,
body = body ,
2024-07-28 22:59:28 +00:00
urls = _urls ,
rooturl = $"{Configuration.Root.TrimEnd('/')}/" ,
title = Configuration . Title
2023-12-16 01:40:05 +00:00
} ) ;
}
private async Task Index ( ServerContext ctx )
{
2024-07-28 22:59:28 +00:00
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , await RenderIndexAsync ( ) , true ) ) ;
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
2023-12-16 01:40:05 +00:00
private async Task Devcenter ( ServerContext ctx )
{
2024-07-28 22:59:28 +00:00
await ctx . SendTextAsync ( await RenderHtmlAsync ( ctx , await RenderDevcenterAsync ( ) , false , true ) ) ;
2023-12-16 01:40:05 +00:00
}
private async Task < string > RenderDevcenterAsync ( )
{
2024-07-28 22:59:28 +00:00
return await pageDevcenter . RenderAsync ( new { title = Configuration . Title , rooturl = $"{Configuration.Root.TrimEnd('/')}/" } ) ;
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
2023-12-16 01:40:05 +00:00
private async Task < string > RenderIndexAsync ( )
{
2024-07-28 22:59:28 +00:00
return await pageIndex . RenderAsync ( new { title = Configuration . Title , rooturl = $"{Configuration.Root.TrimEnd('/')}/" } ) ;
}
public async Task < string > RenderUpload1Async ( string csrf )
{
return await pageUpload . RenderAsync ( new { title = Configuration . Title , csrf , rooturl = $"{Configuration.Root.TrimEnd('/')}/" } ) ;
}
public CMSConfiguration Configuration { get ; set ; } = new CMSConfiguration ( ) ;
public IServer Server = > new CSRFCatcherServer ( routeServer ) ;
}
internal class CSRFCatcherServer : IServer
{
IServer inside ;
public CSRFCatcherServer ( IServer server )
{
this . inside = server ;
}
public async Task < bool > BeforeAsync ( ServerContext ctx )
{
try
{
return await inside . BeforeAsync ( ctx ) ;
}
catch ( InvalidCSRFException )
{
await ctx . SendTextAsync ( "<h1>CSRF token invalid</h1><p>Press back, refresh and try again</p>" ) ;
}
return true ;
}
public async Task PostAsync ( ServerContext ctx )
{
try
{
await inside . PostAsync ( ctx ) ;
}
catch ( InvalidCSRFException )
{
await ctx . SendTextAsync ( "<h1>CSRF token invalid</h1><p>Press back, refresh and try again</p>" ) ;
}
}
public async Task OptionsAsync ( ServerContext ctx )
{
try
{
await inside . OptionsAsync ( ctx ) ;
}
catch ( InvalidCSRFException )
{
await ctx . SendTextAsync ( "<h1>CSRF token invalid</h1><p>Press back, refresh and try again</p>" ) ;
}
}
public async Task OtherAsync ( ServerContext ctx )
{
try
{
await inside . OtherAsync ( ctx ) ;
}
catch ( InvalidCSRFException )
{
await ctx . SendTextAsync ( "<h1>CSRF token invalid</h1><p>Press back, refresh and try again</p>" ) ;
}
}
public async Task GetAsync ( ServerContext ctx )
{
try
{
await inside . GetAsync ( ctx ) ;
}
catch ( InvalidCSRFException )
{
await ctx . SendTextAsync ( "<h1>CSRF token invalid</h1><p>Press back, refresh and try again</p>" ) ;
}
}
public void AddCors ( ServerContext ctx )
{
}
}
[Serializable]
internal class InvalidCSRFException : Exception
{
public InvalidCSRFException ( )
{
}
public InvalidCSRFException ( string message ) : base ( message )
{
}
public InvalidCSRFException ( string message , Exception innerException ) : base ( message , innerException )
{
2023-12-16 01:40:05 +00:00
}
2024-07-28 22:59:28 +00:00
protected InvalidCSRFException ( SerializationInfo info , StreamingContext context ) : base ( info , context )
2023-12-16 01:40:05 +00:00
{
}
2024-07-28 22:59:28 +00:00
}
public class EpisodeContentMetaData
{
[JsonProperty("episode_info")]
public Episode Info { get ; set ; }
[JsonProperty("has_browser_stream")]
public bool HasBrowserStream { get ; set ; }
[JsonProperty("has_download_stream")]
public bool HasDownloadStream { get ; set ; }
[JsonProperty("has_poster")]
public bool HasPoster { get ; set ; }
[JsonProperty("has_thumbnail")]
public bool HasThumbnail { get ; set ; }
[JsonProperty("browser_stream")]
public string BrowserStream { get ; set ; }
[JsonProperty("download_stream")]
public string DownloadStream { get ; set ; }
[JsonProperty("poster_url")]
public string PosterUrl { get ; set ; }
[JsonProperty("thumbnail_url")]
public string ThumbnailUrl { get ; set ; }
[JsonProperty("subtitle_streams")]
public List < SubtitleStream > SubtitlesStreams { get ; set ; } = new List < SubtitleStream > ( ) ;
2023-12-16 01:40:05 +00:00
}
2024-01-04 02:53:13 +00:00
internal class EmailCreator
{
CMSConfiguration configuration ;
Template emailTemplate ;
Template verifyTemplate ;
2024-07-28 22:59:28 +00:00
Template emailMovie ;
Template emailShow ;
Template emailAlbum ;
2024-01-04 02:53:13 +00:00
public EmailCreator ( CMSConfiguration configuration )
{
this . configuration = configuration ;
emailTemplate = Template . Parse ( AssetProvider . ReadAllText ( "/EmailHtml.html" ) ) ;
verifyTemplate = Template . Parse ( AssetProvider . ReadAllText ( "/VerifyEmail.html" ) ) ;
2024-07-28 22:59:28 +00:00
emailMovie = Template . Parse ( AssetProvider . ReadAllText ( "/EmailMovie.html" ) ) ;
emailShow = Template . Parse ( AssetProvider . ReadAllText ( "/EmailShow.html" ) ) ;
emailAlbum = Template . Parse ( AssetProvider . ReadAllText ( "/EmailAlbum.html" ) ) ;
}
private async Task SendEmailAsync ( string email , string emailHtml , string subject )
{
if ( InternetAddress . TryParse ( email , out var to ) & & InternetAddress . TryParse ( this . configuration . Email . Email , out var from ) )
using ( var smtp = new SmtpClient ( ) )
{
await smtp . ConnectAsync ( configuration . Email . Host , configuration . Email . Port , configuration . Email . Encryption ) ;
await smtp . AuthenticateAsync ( configuration . Email . User , configuration . Email . Pass ) ;
MimeMessage message = new MimeMessage ( ) ;
message . From . Add ( from ) ;
message . To . Add ( to ) ;
message . Body = new TextPart ( MimeKit . Text . TextFormat . Html ) { Text = await emailTemplate . RenderAsync ( new { Body = emailHtml , Websitename = HttpUtility . HtmlEncode ( configuration . Title ) , Websiteurl = HttpUtility . HtmlAttributeEncode ( $"{configuration.Root.TrimEnd('/')}/" ) } ) } ;
message . Subject = subject ;
await smtp . SendAsync ( message ) ;
}
}
public async Task SendVerificationEmailAsync ( UserAccount account , string verificationCode )
{
string verifyLink = $"{configuration.Root.TrimEnd('/')}/verify?token={HttpUtility.UrlEncode(verificationCode)}" ;
await SendEmailAsync ( account . Email , await verifyTemplate . RenderAsync ( new { verifyurllink = HttpUtility . HtmlAttributeEncode ( verifyLink ) , verifyurl = HttpUtility . HtmlEncode ( verifyLink ) , Propername = HttpUtility . HtmlEncode ( account . ProperName ) } ) , $"Verify email for {configuration.Title}" ) ;
2024-01-04 02:53:13 +00:00
}
2024-07-28 22:59:28 +00:00
public async Task EmailShowAsync ( IContentProvider provider , UserAccount account , Show show , bool update = false , string body = "" )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
foreach ( var uAccount in account . AccountsToMail )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
if ( ! uAccount . EnableShows ) continue ;
if ( ! uAccount . EnableShows & & update ) continue ;
var user = provider . GetUserById ( uAccount . UserId ) ;
if ( user ! = null )
{
bool hasmessage = false ;
string message = "" ;
if ( ! string . IsNullOrWhiteSpace ( body ) )
{
message = CMSServer . DescriptLinkUtils ( body ) . Replace ( "\n" , "<br>" ) ;
hasmessage = true ;
}
await SendEmailAsync ( user . Email , await emailShow . RenderAsync ( new { hasmessage , message , propername = HttpUtility . HtmlEncode ( user . ProperName ) , showuserproper = HttpUtility . HtmlEncode ( account . ProperName ) , showproper = HttpUtility . HtmlEncode ( show . ProperName ) , updated = update , showurl = $"{configuration.Root.TrimEnd('/')}/user/{account.Username}/show/{show.Name}/" } ) , $"{account.ProperName} {(update ? " updated " : " created ")} the show {show.ProperName}" ) ;
}
2024-01-04 02:53:13 +00:00
}
}
2024-07-28 22:59:28 +00:00
public async Task EmailMovieAsync ( IContentProvider provider , UserAccount account , Movie movie , bool update = false , string body = "" )
2024-01-04 02:53:13 +00:00
{
2024-07-28 22:59:28 +00:00
foreach ( var uAccount in account . AccountsToMail )
{
if ( ! uAccount . EnableMovies ) continue ;
if ( ! uAccount . EnableUpdates & & update ) continue ;
var user = provider . GetUserById ( uAccount . UserId ) ;
if ( user ! = null )
{
bool hasmessage = false ;
string message = "" ;
if ( ! string . IsNullOrWhiteSpace ( body ) )
{
message = CMSServer . DescriptLinkUtils ( body ) . Replace ( "\n" , "<br>" ) ;
hasmessage = true ;
}
await SendEmailAsync ( user . Email , await emailMovie . RenderAsync ( new { hasmessage , message , propername = HttpUtility . HtmlEncode ( user . ProperName ) , movieuserproper = HttpUtility . HtmlEncode ( account . ProperName ) , movieproper = HttpUtility . HtmlEncode ( movie . ProperName ) , updated = update , movieurl = $"{configuration.Root.TrimEnd('/')}/user/{account.Username}/movie/{movie.Name}/" } ) , $"{account.ProperName} {(update ? " updated " : " created ")} the movie {movie.ProperName}" ) ;
}
}
}
internal async Task EmailAlbumAsync ( IContentProvider provider , UserAccount account , Album album , bool update = false , string body = "" )
{
foreach ( var uAccount in account . AccountsToMail )
{
if ( ! uAccount . EnableMovies ) continue ;
if ( ! uAccount . EnableUpdates & & update ) continue ;
var user = provider . GetUserById ( uAccount . UserId ) ;
if ( user ! = null )
{
bool hasmessage = false ;
string message = "" ;
if ( ! string . IsNullOrWhiteSpace ( body ) )
{
message = CMSServer . DescriptLinkUtils ( body ) . Replace ( "\n" , "<br>" ) ;
hasmessage = true ;
}
await SendEmailAsync ( user . Email , await emailAlbum . RenderAsync ( new { hasmessage , message , propername = HttpUtility . HtmlEncode ( user . ProperName ) , albumuserproper = HttpUtility . HtmlEncode ( account . ProperName ) , albumproper = HttpUtility . HtmlEncode ( album . ProperName ) , updated = update , albumurl = $"{configuration.Root.TrimEnd('/')}/user/{account.Username}/album/{album.Name}/" } ) , $"{account.ProperName} {(update ? " updated " : " created ")} the album {album.ProperName}" ) ;
}
}
2024-01-04 02:53:13 +00:00
}
}
2023-12-16 01:40:05 +00:00
}