First commit

This commit is contained in:
2026-03-15 22:15:34 -05:00
commit 0858a8a751
79 changed files with 6010 additions and 0 deletions
+15
View File
@@ -0,0 +1,15 @@
{
"$schema": "https:\/\/crosslang.tesseslanguage.com\/\/schema\/cross-json-schema.json",
"dependencies": [
],
"icon": "icon.png",
"info": {
"license": "GPLv3-or-later",
"plugin_host": "tytd2025",
"short_name": "tytdcompanion",
"short_name_pretty": "TYTD Companion",
"type": "lib"
},
"name": "Tesses.YouTubeDownloader.Plugins.TYTDCompanion",
"version": "1.0.0.0-dev"
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

+1
View File
@@ -0,0 +1 @@
func PluginInit() new Plugin();
+97
View File
@@ -0,0 +1,97 @@
/^
%PROJECT_NAME Class
^/
class Plugin {
public Plugin()
{
/*
You can access these anywhere in the plugin
TYTD.GetVideoId(id): get the youtube video id from url or id
TYTD.GetPlaylistId(id): get the youtube playlist id from url or id
TYTD.GetChannelId(id): get the youtube channel id from url or id
TYTD.Config[key]: get a string setting for this plugin
TYTD.Config[key] = value: set a string setting for this plugin (is presistant)
TYTD.Config.Directory: a crosslang SubdirFilesystem for the Files directory in plugin directory
TYTD.Config.DirectoryPath: same directory but the actual path of it for FS.Local
Resolution, SubscriptionBell, TYTD.Downloader (the instance, you can't create your own instance of it): See https://cpkg.tesseslanguage.com/package_docs?name=Tesses.YoutubeDownloader&version=1.0.0.0-prod
*/
TYTD.Config.Directory.CreateDirectory(/"AlbumThumbnails");
TYTD.Config.Directory.CreateDirectory(/"ArtistThumbnails");
TYTD.Downloader.Bell += this.OnBell;
TYTD.Downloader.VideoStarted += this.OnVideoStarted;
TYTD.Downloader.VideoEnded += this.OnVideoFinished;
this.Server = new PluginServer(this);
this.SendStart();
}
private SendStart()
{
this.SendMessage({
Type = "Started"
});
}
private OnVideoStarted(sender, e)
{
this.SendMessage({
Type = "VideoStarted",
Video = e.Video
});
}
private OnVideoFinished(sender, e)
{
this.SendMessage({
Type = "VideoFinished",
Video = e.Video
});
}
private OnBell(sender, e)
{
this.SendMessage({
Type = "Bell",
Video = {
Channel = e.author,
ChannelId = e.channelId,
Title = e.title,
VideoId = e.videoId
}
});
}
private SendMessage(msg)
{
const conf = TYTD.Config["conf"];
const jo = Json.Decode(conf);
if(TypeIsString(jo.url))
{
const request = {
Method = "POST",
Body = new JsonHttpRequestBody(msg)
};
if(TypeIsString(jo.token))
{
request.RequestHeaders = [
{
Key = "Authorization",
Value = $"TYTD {jo.token}"
}
];
}
Net.Http.MakeRequest($"{jo.url.TrimEnd('/')}/api/v1/webhook", request).Close();
}
}
public Server;
public Close()
{
TYTD.Downloader.Bell -= this.OnBell;
TYTD.Downloader.VideoStarted -= this.OnVideoStarted;
TYTD.Downloader.VideoEnded -= this.OnVideoFinished;
}
}
+119
View File
@@ -0,0 +1,119 @@
class PluginServer
{
public Server;
public PluginServer(svr)
{
this.Server = svr;
}
public Handle(ctx)
{
if(ctx.Path == "/")
{
const conf = TYTD.Config["conf"];
if(TypeIsString(conf))
{
const jo = Json.Decode(conf);
if(TypeIsString(jo.url))
{
ctx.SendRedirect($"{jo.url.TrimEnd('/')}/",303);
return true;
}
}
ctx.WithMimeType("text/html").SendText(<h1>Not configured</h1>);
return true;
}
else if(ctx.Path == "/artist-thumbnail")
{
const id = ctx.QueryParams.TryGetFirst("id");
if(TypeIsString(id))
{
if(!TYTD.Config.Directory.FileExists(/"ArtistThumbnails"/$"{id}.jpg"))
{
var resp = Net.Http.MakeRequest($"https://www.theaudiodb.com/api/v1/json/123/artist-mb.php?i={Net.Http.UrlEncode(id)}",{FollowRedirects=true});
if(resp.StatusCode >= 200 && resp.StatusCode <= 299)
{
const url = resp.ReadAsJson().artists[0].strArtistThumb;
if(TypeIsString(url))
{
var resp2 = Net.Http.MakeRequest(url,{FollowRedirects=true});
if(resp.StatusCode >= 200 && resp.StatusCode <= 299)
{
var strm=TYTD.Config.Directory.OpenFile(/"ArtistThumbnails"/$"{id}.jpg","wb");
resp2.CopyToStream(strm);
strm.Close();
}
}
}
}
if(TYTD.Config.Directory.FileExists(/"ArtistThumbnails"/$"{id}.jpg"))
{
var strm=TYTD.Config.Directory.OpenFile(/"ArtistThumbnails"/$"{id}.jpg","rb");
ctx.WithMimeType("image/jpg").SendStream(strm);
strm.Close();
return true;
}
return false;
}
}
else if(ctx.Path == "/artist-thumbnail")
{
const id = ctx.QueryParams.TryGetFirst("id");
if(TypeIsString(id))
{
if(!TYTD.Config.Directory.FileExists(/"AlbumThumbnails"/$"{id}.jpg"))
{
var resp2 = Net.Http.MakeRequest($"https://coverartarchive.org/release/{Net.Http.UrlEncode(id)}/front",{FollowRedirects=true});
if(resp.StatusCode >= 200 && resp.StatusCode <= 299)
{
var strm=TYTD.Config.Directory.OpenFile(/"AlbumThumbnails"/$"{id}.jpg","wb");
resp2.CopyToStream(strm);
strm.Close();
}
}
if(TYTD.Config.Directory.FileExists(/"AlbumThumbnails"/$"{id}.jpg"))
{
var strm=TYTD.Config.Directory.OpenFile(/"AlbumThumbnails"/$"{id}.jpg","rb");
ctx.WithMimeType("image/jpg").SendStream(strm);
strm.Close();
return true;
}
return false;
}
}
else if(ctx.Path == "/config")
{
if(ctx.Method == "GET")
{
const conf = TYTD.Config["conf"];
if(TypeIsString(conf))
{
const jo = Json.Decode(conf);
if(TypeIsString(jo.url))
{
ctx.WithMimeType("application/json").SendJson({url = jo.url});
return true;
}
}
ctx.WithMimeType("application/json").SendText("null");
return true;
}
else if(ctx.Method == "PUT")
{
TYTD.Config["conf"]=Json.Encode(ctx.ReadJson());
ctx.StatusCode = 204;
ctx.WriteHeaders();
this.SendStart();
return true;
}
}
return true;
}
}