2024-10-11 22:59:37 +00:00
|
|
|
|
using Tesses.WebServer;
|
|
|
|
|
using Scriban;
|
|
|
|
|
using System.Web;
|
|
|
|
|
using System.Text.Json.Serialization;
|
|
|
|
|
using System.Net.Http.Json;
|
|
|
|
|
using System.Text.Json;
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
|
|
|
|
|
Directory.CreateDirectory("data/cache/movie");
|
2024-10-11 23:16:37 +00:00
|
|
|
|
Directory.CreateDirectory("data/torrents");
|
2024-10-11 22:59:37 +00:00
|
|
|
|
|
|
|
|
|
HttpClient client = new HttpClient();
|
|
|
|
|
MountableServer msvr=new MountableServer(new StaticServer("data/wwwroot"));
|
|
|
|
|
msvr.Mount("/torrents/",new StaticServer("data/torrents",true));
|
|
|
|
|
RouteServer routeServer=new RouteServer(msvr);
|
|
|
|
|
|
|
|
|
|
routeServer.Add("/",async(ctx)=>{
|
|
|
|
|
var template = Template.Parse(File.ReadAllText("data/wwwroot/template.html"));
|
|
|
|
|
var index = Template.Parse(File.ReadAllText("data/wwwroot/index.html"));
|
|
|
|
|
await ctx.SendTextAsync(await template.RenderAsync(new{title="Request Movies", body=index.RenderAsync()}));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
routeServer.Add("/torrents.json",async(ctx)=>{
|
|
|
|
|
List<string> torrents = new List<string>();
|
|
|
|
|
foreach(var item in Directory.EnumerateFiles("data/torrents","*.torrent"))
|
|
|
|
|
{
|
|
|
|
|
torrents.Add(Path.GetFileName(item));
|
|
|
|
|
}
|
|
|
|
|
await ctx.SendJsonAsync(torrents);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
routeServer.Add("/add_torrent",async(ctx)=>{
|
|
|
|
|
if(ctx.QueryParams.TryGetFirst("url",out var url))
|
|
|
|
|
{
|
|
|
|
|
using(var res=await client.GetAsync(url))
|
|
|
|
|
{
|
|
|
|
|
if(res.IsSuccessStatusCode)
|
|
|
|
|
{
|
|
|
|
|
var hdr = res.Content.Headers.ContentDisposition;
|
|
|
|
|
if(hdr != null)
|
|
|
|
|
{
|
|
|
|
|
string? file=hdr.FileName;
|
|
|
|
|
if(!string.IsNullOrWhiteSpace(file))
|
|
|
|
|
{
|
|
|
|
|
file = file.TrimStart('\"').TrimEnd('\"');
|
|
|
|
|
if(!File.Exists($"data/torrents/{file}.part") && !File.Exists($"data/torrents/{file}"))
|
|
|
|
|
{
|
|
|
|
|
await File.WriteAllBytesAsync($"data/torrents/{file}.part", await res.Content.ReadAsByteArrayAsync());
|
|
|
|
|
File.Move($"data/torrents/{file}.part",$"data/torrents/{file}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(!ctx.RequestHeaders.TryGetFirst("Referer",out var referer))
|
|
|
|
|
{
|
|
|
|
|
referer="/";
|
|
|
|
|
}
|
|
|
|
|
await ctx.SendRedirectAsync(referer);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
routeServer.Add("/movie",async(ctx)=>{
|
|
|
|
|
var template = Template.Parse(File.ReadAllText("data/wwwroot/template.html"));
|
|
|
|
|
var index = Template.Parse(File.ReadAllText("data/wwwroot/movie/index.html"));
|
|
|
|
|
|
|
|
|
|
if(ctx.QueryParams.TryGetFirstInt64("id",out var id))
|
|
|
|
|
{
|
|
|
|
|
string file = $"data/cache/movie/{id}.json";
|
|
|
|
|
YTSMovie? movie=null;
|
|
|
|
|
if(File.Exists(file))
|
|
|
|
|
{
|
|
|
|
|
using(var jsonStrm = File.OpenRead(file))
|
|
|
|
|
movie=await JsonSerializer.DeserializeAsync<YTSMovie>(jsonStrm);
|
|
|
|
|
}
|
|
|
|
|
if(movie != null)
|
|
|
|
|
{
|
|
|
|
|
List<object> torrents=new List<object>();
|
|
|
|
|
|
|
|
|
|
foreach(var item in movie.Torrents)
|
|
|
|
|
{
|
|
|
|
|
torrents.Add(new{quality=HttpUtility.HtmlEncode(item.Quality),url=HttpUtility.HtmlAttributeEncode(item.Url),size = HttpUtility.HtmlEncode(item.Size), addurl=$"./add_torrent?url={HttpUtility.UrlEncode(item.Url)}"});
|
|
|
|
|
}
|
|
|
|
|
int hrs=movie.Runtime / 60;
|
|
|
|
|
int mins=movie.Runtime % 60;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
string runtime = $"{hrs}:{mins.ToString("D2")}";
|
|
|
|
|
|
|
|
|
|
var body=await index.RenderAsync(new{yts_url =HttpUtility.HtmlAttributeEncode(movie.Url) ,mpa_rating =HttpUtility.HtmlEncode(movie.MpaRating),runtime,thumbnail = HttpUtility.HtmlAttributeEncode(movie.MediumCoverImage), name=HttpUtility.HtmlEncode(movie.TitleLong),torrents});
|
|
|
|
|
string title = $"{HttpUtility.HtmlEncode(movie.TitleLong)} - Request Movies";
|
|
|
|
|
await ctx.SendTextAsync(await template.RenderAsync(new{body,title}));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
await ctx.SendNotFoundAsync();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
routeServer.Add("/search",async(ctx)=>{
|
|
|
|
|
var template = Template.Parse(File.ReadAllText("data/wwwroot/template.html"));
|
|
|
|
|
var index = Template.Parse(File.ReadAllText("data/wwwroot/search/index.html"));
|
|
|
|
|
int page = 1;
|
|
|
|
|
|
|
|
|
|
if(!ctx.QueryParams.TryGetFirstInt32("page",out page))
|
|
|
|
|
{
|
|
|
|
|
page = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List<object> results = new List<object>();
|
|
|
|
|
|
|
|
|
|
if(ctx.QueryParams.TryGetFirst("q",out var q))
|
|
|
|
|
{
|
|
|
|
|
var res=await client.GetFromJsonAsync<YTSSearchResponse>($"https://yts.mx/api/v2/list_movies.json?query_term={HttpUtility.UrlEncode(q)}&page={page}");
|
|
|
|
|
if(res != null)
|
|
|
|
|
{
|
|
|
|
|
if(res.Status == "ok")
|
|
|
|
|
{
|
|
|
|
|
foreach(var item in res.Data.Movies)
|
|
|
|
|
{
|
|
|
|
|
string file = $"data/cache/movie/{item.Id}.json";
|
|
|
|
|
if(!File.Exists(file))
|
|
|
|
|
{
|
|
|
|
|
using(var f = File.Create(file))
|
|
|
|
|
{
|
|
|
|
|
await System.Text.Json.JsonSerializer.SerializeAsync(f,item);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
results.Add(new{url=$"./movie?id={item.Id}", title=HttpUtility.HtmlEncode(item.Title),thumbnail=HttpUtility.HtmlAttributeEncode(item.SmallCoverImage)});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
string body = await index.RenderAsync(new{results,search_text=HttpUtility.HtmlEncode(q), search_text_attr=HttpUtility.HtmlAttributeEncode(q)});
|
|
|
|
|
await ctx.SendTextAsync(await template.RenderAsync(new{title = $"{HttpUtility.HtmlEncode(q)} - Request Movies",body}));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
routeServer.StartServer(9204);
|
|
|
|
|
|
|
|
|
|
public class YTSMovie
|
|
|
|
|
{
|
|
|
|
|
[JsonPropertyName("id")]
|
|
|
|
|
public long Id {get;set;}=0;
|
|
|
|
|
|
|
|
|
|
[JsonPropertyName("url")]
|
|
|
|
|
public string Url {get;set;}="";
|
|
|
|
|
|
|
|
|
|
[JsonPropertyName("imdb_code")]
|
|
|
|
|
public string ImdbCode {get;set;}="";
|
|
|
|
|
|
|
|
|
|
[JsonPropertyName("title")]
|
|
|
|
|
public string Title {get;set;}="";
|
|
|
|
|
|
|
|
|
|
[JsonPropertyName("title_english")]
|
|
|
|
|
public string TitleEnglish {get;set;}="";
|
|
|
|
|
|
|
|
|
|
[JsonPropertyName("title_long")]
|
|
|
|
|
public string TitleLong {get;set;}="";
|
|
|
|
|
|
|
|
|
|
[JsonPropertyName("slug")]
|
|
|
|
|
public string Slug {get;set;}="";
|
|
|
|
|
|
|
|
|
|
[JsonPropertyName("year")]
|
|
|
|
|
public int Year {get;set;}=0;
|
|
|
|
|
|
|
|
|
|
[JsonPropertyName("rating")]
|
|
|
|
|
public double Rating {get;set;}=0.0;
|
|
|
|
|
|
|
|
|
|
[JsonPropertyName("runtime")]
|
|
|
|
|
public int Runtime {get;set;}=0;
|
|
|
|
|
|
|
|
|
|
[JsonPropertyName("genres")]
|
|
|
|
|
public List<string> Genres {get;set;}=new List<string>();
|
|
|
|
|
|
|
|
|
|
[JsonPropertyName("summary")]
|
|
|
|
|
public string Summary {get;set;}="";
|
|
|
|
|
|
|
|
|
|
[JsonPropertyName("description_full")]
|
|
|
|
|
public string DescriptionFull {get;set;}="";
|
|
|
|
|
|
|
|
|
|
[JsonPropertyName("synopsis")]
|
|
|
|
|
public string Synopsis {get;set;}="";
|
|
|
|
|
|
|
|
|
|
[JsonPropertyName("yt_trailer_code")]
|
|
|
|
|
public string TrailerVideoId {get;set;}="";
|
|
|
|
|
|
|
|
|
|
[JsonPropertyName("language")]
|
|
|
|
|
public string Language {get;set;}="";
|
|
|
|
|
|
|
|
|
|
[JsonPropertyName("mpa_rating")]
|
|
|
|
|
public string MpaRating {get;set;}="";
|
|
|
|
|
|
|
|
|
|
[JsonPropertyName("background_image")]
|
|
|
|
|
public string BackgroundImage {get;set;}="";
|
|
|
|
|
[JsonPropertyName("background_image_original")]
|
|
|
|
|
public string BackgroundImageOriginal {get;set;}="";
|
|
|
|
|
[JsonPropertyName("small_cover_image")]
|
|
|
|
|
public string SmallCoverImage {get;set;}="";
|
|
|
|
|
[JsonPropertyName("medium_cover_image")]
|
|
|
|
|
public string MediumCoverImage {get;set;}="";
|
|
|
|
|
[JsonPropertyName("large_cover_image")]
|
|
|
|
|
public string LargeCoverImage {get;set;}="";
|
|
|
|
|
|
|
|
|
|
[JsonPropertyName("torrents")]
|
|
|
|
|
public List<YTSTorrent> Torrents {get;set;}=new List<YTSTorrent>();
|
|
|
|
|
|
|
|
|
|
[JsonPropertyName("state")]
|
|
|
|
|
public string State {get;set;}="";
|
|
|
|
|
|
|
|
|
|
[JsonPropertyName("date_uploaded_unix")]
|
|
|
|
|
public long DateUploadedUnix {get;set;}=0;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class YTSTorrent
|
|
|
|
|
{
|
|
|
|
|
[JsonPropertyName("url")]
|
|
|
|
|
public string Url {get;set;}="";
|
|
|
|
|
|
|
|
|
|
[JsonPropertyName("hash")]
|
|
|
|
|
public string Hash {get;set;}="";
|
|
|
|
|
|
|
|
|
|
[JsonPropertyName("quality")]
|
|
|
|
|
public string Quality {get;set;}="";
|
|
|
|
|
|
|
|
|
|
[JsonPropertyName("type")]
|
|
|
|
|
public string Type {get;set;}="";
|
|
|
|
|
|
|
|
|
|
[JsonPropertyName("is_repack")]
|
|
|
|
|
public string IsRepackStr {get;set;}="";
|
|
|
|
|
|
|
|
|
|
[JsonIgnore]
|
|
|
|
|
public bool IsRepack {get=>IsRepackStr=="1"; set=>IsRepackStr = value ? "1" : "0";}
|
|
|
|
|
|
|
|
|
|
[JsonPropertyName("video_codec")]
|
|
|
|
|
public string VideoCodec {get;set;}="";
|
|
|
|
|
|
|
|
|
|
[JsonPropertyName("bit_depth")]
|
|
|
|
|
public string BitDepth {get;set;}="";
|
|
|
|
|
|
|
|
|
|
[JsonPropertyName("audio_channels")]
|
|
|
|
|
public string AudioChannels {get;set;}="";
|
|
|
|
|
|
|
|
|
|
[JsonPropertyName("seeds")]
|
|
|
|
|
public long Seeds {get;set;}=0;
|
|
|
|
|
|
|
|
|
|
[JsonPropertyName("peers")]
|
|
|
|
|
public long Peers {get;set;}=0;
|
|
|
|
|
|
|
|
|
|
[JsonPropertyName("size")]
|
|
|
|
|
|
|
|
|
|
public string Size {get;set;}="";
|
|
|
|
|
|
|
|
|
|
[JsonPropertyName("size_bytes")]
|
|
|
|
|
|
|
|
|
|
public long SizeBytes {get;set;}=0;
|
|
|
|
|
|
|
|
|
|
[JsonPropertyName("date_uploaded_unix")]
|
|
|
|
|
public long DateUploadedUnix {get;set;}=0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class YTSSearchResponseData
|
|
|
|
|
{
|
|
|
|
|
[JsonPropertyName("movies")]
|
|
|
|
|
public List<YTSMovie> Movies {get;set;}=new List<YTSMovie>();
|
|
|
|
|
}
|
|
|
|
|
public class YTSSearchResponse {
|
|
|
|
|
[JsonPropertyName("status")]
|
|
|
|
|
public string Status {get;set;}="";
|
|
|
|
|
|
|
|
|
|
[JsonPropertyName("data")]
|
|
|
|
|
public YTSSearchResponseData Data {get;set;}=new YTSSearchResponseData();
|
|
|
|
|
}
|