First commit

This commit is contained in:
2025-10-15 00:07:35 -05:00
commit 5e354c05be
69 changed files with 4598 additions and 0 deletions

View File

@@ -0,0 +1,39 @@
func Pages.ChannelInfo(tytd,ctx)
{
var id = ctx.QueryParams.TryGetFirst("id");
var page = ctx.QueryParams.TryGetFirstInt("page");
if(TypeOf(page) != "Long") page = 1;
page--;
var html = <h1>Could not find channel</h1>;
var title = "N/A";
if(TypeOf(id) == "String")
{
id = TYTD.GetChannelId(id);
var res = tytd.GetChannelContents(id,page,20);
html = <null>
<div class="row">
<div class="max">
<h1>{res.authorName}</h1>
</div>
<div class="min">
<raw(Components.Subscribe(tytd,id))>
</div>
</div>
<each(var item : res.items)>
<raw(Components.DownloadedVideo(item))>
</each>
<footer class="row center-align">
<button hx-get={$"./channel?id={Net.Http.UrlEncode(id)}&page={page}"} hx-target="body" hx-push-url="true" >Prev</button>{page+1}<button hx-get={$"./channel?id={Net.Http.UrlEncode(id)}&type=videos&page={page+2}"} hx-target="body" hx-push-url="true" >Next</button>
</footer>
</null>;
title = res.authorName;
}
return Components.Shell($"Channel {title}",html,1);
}

View File

@@ -0,0 +1,34 @@
func Pages.Discover(tytd,ctx)
{
var q = ctx.QueryParams.TryGetFirst("q");
var res = null;
var q2 = "";
if(TypeOf(q) == "String")
{
q2 = q;
res = tytd.Discover(q);
}
var html = <null>
<form hx-get="./discover" hx-target="body" hx-push-url="true">
<div class="field large prefix round fill active">
<i class="front">search</i>
<input name="q" value={q2}>
</div>
</form>
<if(res != null)>
<true>
<ul>
<each(var item : res.items)>
<li><raw(Components.DiscoverEntry(item))></li>
</each>
</ul>
<button class="responsive">More</button>
</true></null>;
return Components.Shell($"Discover {q2}",html,1);
}

View File

@@ -0,0 +1,293 @@
func Pages.Downloads(tytd,ctx)
{
var type = ctx.QueryParams.TryGetFirst("type");
var q = ctx.QueryParams.TryGetFirst("q");
var page = ctx.QueryParams.TryGetFirstInt("page");
if(TypeOf(page) != "Long") page = 1;
page--;
if(TypeOf(q) != "String")
{
q = "";
}
if(TypeOf(type) != "String")
{
type = "videos";
}
var html ="";
switch(type) {
case "videos":
{
var res = tytd.GetVideos(q,page,20);
html = <null>
<form hx-get="./downloads" hx-target="body" hx-push-url="true" class="s m">
<div class="row">
<div class="max">
<div class="field label suffix border round fill">
<select name="type">
<option value="videos" selected>Videos</option>
<option value="playlists">Playlists</option>
<option value="channels">Channels</option>
<option value="personal">Personal List</option>
</select>
<label>Type</label>
<i>arrow_drop_down</i>
</div>
</div>
<div class="min">
<button>Change</button>
</div>
</div>
</form>
<nav class="tabbed l">
<a class="active" hx-get="./downloads?type=videos" hx-target="body" hx-push-url="true">
<i>movie</i>
<span>Videos</span>
</a>
<a hx-get="./downloads?type=playlists" hx-target="body" hx-push-url="true">
<i>list</i>
<span>Playlists</span>
</a>
<a hx-get="./downloads?type=channels" hx-target="body" hx-push-url="true">
<i>person</i>
<span>Channels</span>
</a>
<a hx-get="./downloads?type=personal" hx-target="body" hx-push-url="true">
<i>edit_note</i>
<span>Personal Lists</span>
</a>
</nav>
<form hx-get="./downloads" hx-target="body" hx-push-url="true">
<div class="field large prefix round fill active">
<i class="front">search</i>
<input name="q" value={q}>
<input name="type" type="hidden" value="videos">
</div>
</form>
<each(var item : res)>
<raw(Components.DownloadedVideo(item))>
</each>
<footer class="row center-align">
<button hx-get={$"./downloads?q={Net.Http.UrlEncode(q)}&type=videos&page={page}"} hx-target="body" hx-push-url="true" >Prev</button>{page+1}<button hx-get={$"./downloads?q={Net.Http.UrlEncode(q)}&type=videos&page={page+2}"} hx-target="body" hx-push-url="true" >Next</button>
</footer>
</null>;
}
break;
case "playlists":
{
var res = tytd.GetPlaylists(q,page,20);
html = <null>
<form hx-get="./downloads" hx-target="body" hx-push-url="true" class="s m">
<div class="row">
<div class="max">
<div class="field label suffix border round fill">
<select name="type">
<option value="videos">Videos</option>
<option value="playlists" selected>Playlists</option>
<option value="channels">Channels</option>
<option value="personal">Personal List</option>
</select>
<label>Type</label>
<i>arrow_drop_down</i>
</div>
</div>
<div class="min">
<button>Change</button>
</div>
</div>
</form>
<nav class="tabbed l">
<a hx-get="./downloads?type=videos" hx-target="body" hx-push-url="true">
<i>movie</i>
<span>Videos</span>
</a>
<a class="active" hx-get="./downloads?type=playlists" hx-target="body" hx-push-url="true">
<i>list</i>
<span>Playlists</span>
</a>
<a hx-get="./downloads?type=channels" hx-target="body" hx-push-url="true">
<i>person</i>
<span>Channels</span>
</a>
<a hx-get="./downloads?type=personal" hx-target="body" hx-push-url="true">
<i>edit_note</i>
<span>Personal Lists</span>
</a>
</nav>
<form hx-get="./downloads" hx-target="body" hx-push-url="true">
<div class="field large prefix round fill active">
<i class="front">search</i>
<input name="q" value={q}>
<input name="type" type="hidden" value="playlists">
</div>
</form>
<each(var item : res)>
<raw(Components.DownloadedPlaylist(item))>
</each>
<footer class="row center-align">
<button hx-get={$"./downloads?q={Net.Http.UrlEncode(q)}&type=playlists&page={page}"} hx-target="body" hx-push-url="true" >Prev</button>{page+1}<button hx-get={$"./downloads?q={Net.Http.UrlEncode(q)}&type=playlists&page={page+2}"} hx-target="body" hx-push-url="true" >Next</button>
</footer>
</null>;
}
break;
case "channels":
{
var res = tytd.GetChannels(q,page,20);
html = <null>
<form hx-get="./downloads" hx-target="body" hx-push-url="true" class="s m">
<div class="row">
<div class="max">
<div class="field label suffix border round fill">
<select name="type">
<option value="videos">Videos</option>
<option value="playlists">Playlists</option>
<option value="channels" selected>Channels</option>
<option value="personal">Personal List</option>
</select>
<label>Type</label>
<i>arrow_drop_down</i>
</div>
</div>
<div class="min">
<button>Change</button>
</div>
</div>
</form>
<nav class="tabbed l">
<a hx-get="./downloads?type=videos" hx-target="body" hx-push-url="true">
<i>movie</i>
<span>Videos</span>
</a>
<a hx-get="./downloads?type=playlists" hx-target="body" hx-push-url="true">
<i>list</i>
<span>Playlists</span>
</a>
<a class="active" hx-get="./downloads?type=channels" hx-target="body" hx-push-url="true">
<i>person</i>
<span>Channels</span>
</a>
<a hx-get="./downloads?type=personal" hx-target="body" hx-push-url="true">
<i>edit_note</i>
<span>Personal Lists</span>
</a>
</nav>
<form hx-get="./downloads" hx-target="body" hx-push-url="true">
<div class="field large prefix round fill active">
<i class="front">search</i>
<input name="q" value={q}>
<input name="type" type="hidden" value="channels">
</div>
</form>
<each(var item : res)>
<raw(Components.DownloadedChannel(item))>
</each>
<footer class="row center-align">
<button hx-get={$"./downloads?q={Net.Http.UrlEncode(q)}&type=channels&page={page}"} hx-target="body" hx-push-url="true" >Prev</button>{page+1}<button hx-get={$"./downloads?q={Net.Http.UrlEncode(q)}&type=channels&page={page+2}"} hx-target="body" hx-push-url="true" >Next</button>
</footer>
</null>;
}
break;
case "personal":
{
var res = tytd.GetPersonalLists();
html = <null>
<form hx-get="./downloads" hx-target="body" hx-push-url="true" class="s m">
<div class="row">
<div class="max">
<div class="field label suffix border round fill">
<select name="type">
<option value="videos">Videos</option>
<option value="playlists">Playlists</option>
<option value="channels">Channels</option>
<option value="personal" selected>Personal List</option>
</select>
<label>Type</label>
<i>arrow_drop_down</i>
</div>
</div>
<div class="min">
<button>Change</button>
</div>
</div>
</form>
<nav class="tabbed l">
<a hx-get="./downloads?type=videos" hx-target="body" hx-push-url="true">
<i>movie</i>
<span>Videos</span>
</a>
<a hx-get="./downloads?type=playlists" hx-target="body" hx-push-url="true">
<i>list</i>
<span>Playlists</span>
</a>
<a hx-get="./downloads?type=channels" hx-target="body" hx-push-url="true">
<i>person</i>
<span>Channels</span>
</a>
<a class="active" hx-get="./downloads?type=personal" hx-target="body" hx-push-url="true">
<i>edit_note</i>
<span>Personal Lists</span>
</a>
</nav>
<each(var item : res)>
<if(TypeOf(item.firstVideo) == "String")>
<true>
<div class="row">
<div class="min">
<img src={$"./api/v1/video-thumbnail?v={Net.Http.UrlEncode(item.firstVideo)}"} width="144" width="120">
</div>
<div class="max">
<a href={$"./list?name={Net.Http.UrlEncode(item.name)}"}>{item.name}</a>
</div>
</div>
</true>
<false>
<div><a href={$"./list?name={Net.Http.UrlEncode(item.name)}"}>{item.name}</a></div>
</false>
</if>
</each>
</null>;
}
break;
}
return Components.Shell($"Downloads {q}",html,1);
}

View File

@@ -0,0 +1,11 @@
func Pages.Index(tytd)
{
var html = <null>
<raw(Components.Add())>
<raw(Components.Progress(tytd))>
</null>;
return Components.Shell("Home",html,0);
}

View File

@@ -0,0 +1,36 @@
func Pages.List(tytd,ctx)
{
var name = ctx.QueryParams.TryGetFirst("name");
var page = ctx.QueryParams.TryGetFirstInt("page");
if(TypeOf(page) != "Long") page = 1;
page--;
if(TypeOf(name) != "String")
{
name = "";
}
var res = tytd.GetPersonalListContents(name, page, 20);
var html = <null>
<div class="row">
<div class="min">
<button hx-get="./downloads?type=personal" hx-target="body" hx-push-url="true"><i>arrow_back</i></button>
</div>
<div class="max">
<h1>{name}</h1>
</div>
</div>
<each(var item : res)>
<raw(Components.DownloadedVideo(item))>
</each>
<footer class="row center-align">
<button hx-get={$"./downloads?name={Net.Http.UrlEncode(name)}&page={page}"} hx-target="body" hx-push-url="true" >Prev</button>{page+1}<button hx-get={$"./downloads?name={Net.Http.UrlEncode(name)}&page={page+2}"} hx-target="body" hx-push-url="true" >Next</button>
</footer>
</null>;
return Components.Shell($"Personal List {name}",html,1);
}

View File

@@ -0,0 +1,25 @@
func Pages.Artist(music,ctx)
{
var id = ctx.QueryParams.TryGetFirst("id");
var res = music.GetArtistsAlbums(id);
if(TypeOf(id) != "String")
{
return Components.Shell("Error",<h1>Artist id not specified</h1>,pages);
}
var html = <null>
<h1>{res.name}</h1>
<ul>
<each(var item : res.items)>
<li><raw(Components.MusicAlbum(item))></li>
</each>
</ul>
</null>;
return Components.Shell($"Artist {res.name}",html,2);
}

View File

@@ -0,0 +1,33 @@
func Pages.Artists(music,ctx)
{
var q = ctx.QueryParams.TryGetFirst("q");
var res = null;
var q2 = "";
if(TypeOf(q) == "String")
{
q2 = q;
res = music.GetArtists(q);
}
var html = <null>
<form hx-get="./music-artists" hx-target="body" hx-push-url="true">
<div class="field large prefix round fill active">
<i class="front">search</i>
<input name="q" value={q2}>
</div>
</form>
<if(res != null)>
<true>
<ul>
<each(var item : res)>
<li><raw(Components.MusicArtist(item))></li>
</each>
</ul>
</true></null>;
return Components.Shell($"Search Artists {q2}",html,2);
}

View File

@@ -0,0 +1,8 @@
func Pages.Music(ctx)
{
var html = <ul>
<div><a href="./music-artists">Artists</a></div>
<div><a href="./music-downloaded">My Music</a></div>
</ul>;
return Components.Shell("Music",html,2);
}

View File

@@ -0,0 +1,39 @@
func Pages.PlaylistInfo(tytd,ctx)
{
var id = ctx.QueryParams.TryGetFirst("id");
var page = ctx.QueryParams.TryGetFirstInt("page");
if(TypeOf(page) != "Long") page = 1;
page--;
var html = <h1>Could not find playlist</h1>;
var title = "N/A";
if(TypeOf(id) == "String")
{
id = TYTD.GetPlaylistId(id);
var res = tytd.GetPlaylistContents(id,page,20);
html = <null>
<div class="col">
<div class="max">
<h1>{res.title}</h1>
</div>
<div class="max">
<a href={$"./channel?id={Net.Http.UrlEncode(res.channelId)}"}>{res.channelTitle}</a>
</div>
</div>
<each(var item : res.items)>
<raw(Components.DownloadedVideo(item))>
</each>
<footer class="row center-align">
<button hx-get={$"./playlist?id={Net.Http.UrlEncode(id)}&page={page}"} hx-target="body" hx-push-url="true" >Prev</button>{page+1}<button hx-get={$"./playlist?id={Net.Http.UrlEncode(id)}&type=videos&page={page+2}"} hx-target="body" hx-push-url="true" >Next</button>
</footer>
</null>;
title = res.authorName;
}
return Components.Shell($"Playlist {title}",html,1);
}

View File

@@ -0,0 +1,79 @@
func Pages.DownloadPlugins(tytd,ctx)
{
var q = ctx.QueryParams.TryGetFirst("q");
if(TypeOf(q) != "String")
{
q = "";
}
var server = ctx.QueryParams.TryGetFirst("server");
if(TypeOf(server) != "String") server = "https://cpkg.tesseslanguage.com/";
var items=[];
var items2 = [];
each(var item : tytd.PackageManager.Search(q,{server,type="lib",pluginHost="tytd2025"}))
{
items2.Add({
name = item.packageName,
version = item.version,
url = $"{server}/package?name={Net.Http.UrlEncode(item.packageName)}",
thumb = $"{server}/api/v1/package_icon.png?name={Net.Http.UrlEncode(item.packageName)}&version={Net.Http.UrlEncode(item.version)}"
});
}
each(var item : tytd.PackageManager.GetPackageServers())
{
items.Add({
active = items.Count == 0,
url = item
});
}
var html= <null><nav class="tabbed">
<a hx-get="./plugins" hx-target="body" hx-push-url="true">
<i>download_done</i>
<span>Installed</span>
</a>
<a hx-get="./plugins-download" hx-target="body" class="active" hx-push-url="true">
<i>download</i>
<span>Download</span>
</a>
</nav>
<form hx-get="./plugins-download" hx-target="body" hx-push-url="true">
<div class="field suffix border round">
<select name="server">
<each(var item : items)>
<if(item.active)>
<true>
<option value={item.url} selected>{item.url}</option>
</true>
<false>
<option value={item.url}>{item.url}</option>
</false>
</if>
</each>
</select>
<i>arrow_drop_down</i>
</div>
<div class="row no-space">
<div class="field border left-round max">
<input type="text" name="q" value={q}>
</div>
<button type="submit" class="large right-round min">Search</button>
</div>
</form>
<each(var item : items2)>
<raw(Components.PackageItem(tytd,item))>
</each>
</null>;
return Components.Shell("Download plugins",html ,2);
}

View File

@@ -0,0 +1,21 @@
func Pages.Plugins(tytd,ctx)
{
var html= <null><nav class="tabbed">
<a class="active" hx-get="./plugins" hx-target="body" hx-push-url="true">
<i>download_done</i>
<span>Installed</span>
</a>
<a hx-get="./plugins-download" hx-target="body" hx-push-url="true">
<i>download</i>
<span>Download</span>
</a>
</nav>
<each(var item : tytd.Plugins)>
<raw(Components.InstalledPlugin(item))>
</each>
</null>;
return Components.Shell("Installed plugins",html ,2);
}

View File

@@ -0,0 +1,66 @@
func Pages.Settings(tytd,ctx)
{
var totalSecs = tytd.Config.BellTimer ?? 10800;
var enablePlugins = tytd.Config.EnablePlugins ?? true;
var hours = totalSecs / 3600;
totalSecs -= hours * 3600;
var minutes = totalSecs / 60;
var seconds = totalSecs % 60;
var html = <form hx-post="./settings" hx-target="body" >
<div class="field middle-align">
<nav>
<div class="max">
<h6>Enable plugins</h6>
<div>Plugins allow you to extend tytd, but they have full access</div>
</div>
<label class="switch">
<if(enablePlugins)>
<true>
<input name="enablePlugins" type="checkbox" checked>
</true>
<false>
<input name="enablePlugins" type="checkbox">
</false>
</if>
<span></span>
</label>
</nav>
</div>
<div class="field label border">
<input type="text" name="tag" value={tytd.TYTDTag}>
<label>TYTD Tag</label>
</div>
<fieldset>
<legend>Subscriber Poll Rate</legend>
<div class="row">
<div class="max">
<div class="field label border">
<input type="number" name="hours" value={hours}>
<label>Hours</label>
</div>
</div>
<div class="max">
<div class="field label border">
<input type="number" name="minutes" value={minutes}>
<label>Minutes</label>
</div>
</div>
<div class="max">
<div class="field label border">
<input type="number" name="seconds" value={seconds}>
<label>Seconds</label>
</div>
</div>
</div>
</fieldset>
<footer>
<button>Save</button>
</footer>
</form>;
return Components.Shell("Settings",html ,3);
}

View File

@@ -0,0 +1,30 @@
func Pages.VideoInfo(tytd,ctx)
{
var vid = ctx.QueryParams.TryGetFirst("v");
tytd.PutVideoInfoIfNotExists(vid);
var vi = tytd.GetVideo(vid);
var html = <h1>Could not find video</h1>;
if(vi != null)
{
html = <div class="col">
<div class="min">
<img src={$"./api/v1/video-thumbnail?v={Net.Http.UrlEncode(vi.videoId)}"}>
</div>
<div class="min">
<raw(Components.AddVideo($"https://www.youtube.com/watch?v={vi.videoId}"))>
</div>
<div class="min">
<raw(Components.AddToPersonalList(tytd,vi.videoId))>
</div>
<div class="min">
<h4>{vi.title}</h4>
<a href={$"./channel?id={Net.Http.UrlEncode(vi.channelId)}"}>{vi.author}</a>
<p>{vi.shortDescription}</p>
</div>
</div>;
}
return Components.Shell(vi != null ? vi.title : "Could not find video", html, 1);
}