Make it a little faster, queue is in sqlite now, fix db bug and more
Some checks failed
Build and Deploy on Tag / 🔨 Build for everything else (push) Failing after 11s
Build and Deploy on Tag / 🔨 Build for PowerPC (push) Failing after 20s

This commit is contained in:
2026-06-25 15:35:39 -05:00
parent ede1f92981
commit c82957cc61
53 changed files with 661 additions and 888 deletions

View File

@@ -1,35 +0,0 @@
class TYTD.Queue
{
private ls = [];
private mtx = new Muxex();
public getCount()
{
this.mtx.Lock();
var c = this.ls.Count;
this.mtx.Unlock();
return c;
}
public Pop()
{
var item = null;
this.mtx.Lock();
if(this.ls.Count > 0)
{
item = ls[ls.Count-1];
this.ls.RemoveAt(ls.Count-1);
}
this.mtx.Unlock();
return item;
}
public Push(val)
{
this.mtx.Lock();
this.ls.Add(val);
this.mtx.Unlock();
}
}

View File

@@ -4,33 +4,21 @@ class Resolution
static getNoDownload() "NoDownload";
/^ Get the video/audio mp4 (muxed by YouTube) ^/
static getLowVideo() "LowVideo";
/^ Get the highest video stream ^/
static getVideoOnly() "VideoOnly";
/^ Get the highest audio stream ^/
static getAudioOnly() "AudioOnly";
/^ Get the highest audio stream (and convert to mp3) ^/
/^ Get the LowVideo stream (and convert to mp3) ^/
static getMP3() "MP3";
/^ Get the highest audio stream (and convert to flac) ^/
/^ Get the LowVideo stream (and convert to flac) ^/
static getFLAC() "FLAC";
/^ Get the highest video and then audio stream (and convert to mp4) ^/
static getMP4() "MP4";
/^ Get the highest video and then audio stream (and mux to a mkv file) ^/
static getMKV() "MKV";
/^ Get the highest video and then audio stream (dont convert or mux) ^/
static getDontConvert() "DontConvert";
/^ Get the LowVideo stream (and convert to AMV for mp4 players like: https://www.ebay.com/sch/i.html?_nkw=AMV+mp3+player) ^/
static getAMV() "AMV";
static getResolutions()
{
return [
{name="Don't Download", value=Resolution.NoDownload},
{name="Low (muxed by YouTube)", value=Resolution.LowVideo,default=true},
{name="Highest video (no audio)", value=Resolution.VideoOnly},
{name="Highest audio (no video)", value=Resolution.AudioOnly},
{name="Convert to MP3", value=Resolution.MP3},
{name="Convert to FLAC", value=Resolution.FLAC},
{name="Convert to MP4", value=Resolution.MP4},
{name="Mux to MKV (no transcoding)",value=Resolution.MKV},
{name="Don't convert or Mux",value=Resolution.DontConvert}
{name="Don't Download", value=Resolution.NoDownload,filename=null},
{name="Low (muxed by YouTube)", value=Resolution.LowVideo,default=true,filename="ytmux.mp4"},
{name="Convert to MP3", value=Resolution.MP3,filename="conv.mp3"},
{name="Convert to FLAC", value=Resolution.FLAC,filename="conv.flac"},
{name="Convert To AMV (for generic mp4 players)", value=Resolution.AMV,filename="conv.amv"}
];
}
}

View File

@@ -67,6 +67,50 @@ class TYTD.Downloader {
this.Storage = vfs;
this.DatabaseDirectory = dbDir;
}
private PopQueue()
{
Mutex.Lock();
const db = OpenDB();
var res = Sqlite.Exec(db,"SELECT * FROM queue ORDER BY id DESC LIMIT 1;");
if(TypeIsList(res) && res.Length > 0)
{
Sqlite.Exec(db,$"DELETE FROM queue WHERE id = {Sqlite.Escape(res[0].id)};");
res = res[0];
}
else { res = null;}
Sqlite.Close(db);
Mutex.Unlock();
if(TypeIsDictionary(res))
{
switch(res.resolution)
{
case Resolution.NoDownload:
{
this.PutVideoInfoIfNotExists(res.videoId);
return null;
}
case Resolution.MP3:
return new TYTD.TranscodeAudio(res.videoId,".mp3");
case Resolution.FLAC:
return new TYTD.TranscodeAudio(res.videoId,".flac");
case Resolution.AMV:
return new TYTD.TranscodeAMV(res.videoId);
default:
return new TYTD.SDVideoDownload(res.videoId);
}
}
return null;
}
/^
Download a video
id: video id or url
@@ -77,6 +121,8 @@ class TYTD.Downloader {
const theVideoId = TYTD.GetVideoId(id);
if(TypeIsString(theVideoId))
{
if(!TypeIsDefined(res)) res = Resolution.LowVideo;
const ent = {
Id = theVideoId,
Resolution = res,
@@ -89,43 +135,20 @@ class TYTD.Downloader {
return;
}
}
this.LOG($"Adding video: {TYTD.GetVideoId(id)}, original val: {id}");
switch(res)
{
case Resolution.NoDownload:
{
var id = TYTD.GetVideoId(id);
if(id != null)
this.PutVideoInfoIfNotExists(id);
}
break;
case Resolution.LowVideo:
this.Queue.Push(new TYTD.SDVideoDownload(id));
break;
case Resolution.VideoOnly:
this.Queue.Push(new TYTD.VOVideoDownload(id));
break;
case Resolution.AudioOnly:
this.Queue.Push(new TYTD.AOVideoDownload(id));
break;
case Resolution.MP4:
this.Queue.Push(new TYTD.TranscodeVideo(id,".mp4"));
break;
case Resolution.MKV:
this.Queue.Push(new TYTD.TranscodeVideo(id,".mkv"));
break;
case Resolution.MP3:
this.Queue.Push(new TYTD.TranscodeAudio(id,".mp3"));
break;
case Resolution.FLAC:
this.Queue.Push(new TYTD.TranscodeAudio(id,".flac"));
break;
case Resolution.DontConvert:
this.Queue.Push(new TYTD.NoConvertVideoDownload(id));
break;
else {
this.LOG($"Malformed video id {id}");
return;
}
this.LOG($"Adding video: https://www.youtube.com/watch?v={theVideoId}");
//Sqlite.Exec(db,"CREATE TABLE IF NOT EXISTS queue (id INTEGER PRIMARY KEY AUTOINCREMENT, videoId TEXT, resolution TEXT);");
Mutex.Lock();
const db = OpenDB();
Sqlite.Exec(db, $"INSERT INTO queue (videoId, resolution) VALUES ({Sqlite.Escape(theVideoId)},{Sqlite.Escape(res)});");
Sqlite.Close(db);
Mutex.Unlock();
}
/^
Download a playlist
@@ -287,6 +310,18 @@ class TYTD.Downloader {
if(views < 1000000000000) return $"{views/1000000000}B views";
return $"{views/1000000000000}T views";
}
public GetQueueItems(offset, count)
{
this.Mutex.Lock();
var db = this.OpenDB();
const vals = Sqlite.Exec(db,$"SELECT * FROM queue ORDER BY id DESC LIMIT {count} OFFSET {offset*count};");
Sqlite.Close(db);
this.Mutex.Unlock();
if(TypeIsList(vals))
return vals;
return [];
}
/^
Get videos
@@ -295,7 +330,7 @@ class TYTD.Downloader {
^/
public GetVideos(query, offset, count)
{
this.Muxex.Lock();
this.Mutex.Lock();
var db = this.OpenDB();
var q = Sqlite.Escape($"%{query}%");
@@ -330,7 +365,7 @@ class TYTD.Downloader {
^/
public GetPlaylists(query, offset, count)
{
this.Muxex.Lock();
this.Mutex.Lock();
var db = this.OpenDB();
var q = Sqlite.Escape($"%{query}%");
var res = Sqlite.Exec(db, $"SELECT * FROM playlists v WHERE (v.title LIKE {q}) LIMIT {count} OFFSET {offset*count};");
@@ -356,7 +391,7 @@ class TYTD.Downloader {
channelTitle="N/A",
items = []
};
this.Muxex.Lock();
this.Mutex.Lock();
var db = this.OpenDB();
var channelTitle = "";
var title = "";
@@ -420,7 +455,7 @@ class TYTD.Downloader {
authorName = "N/A",
items = []
};
this.Muxex.Lock();
this.Mutex.Lock();
var db = this.OpenDB();
var authorName = "";
@@ -464,7 +499,7 @@ class TYTD.Downloader {
^/
public GetChannels(query, offset, count)
{
this.Muxex.Lock();
this.Mutex.Lock();
var db = this.OpenDB();
var q = Sqlite.Escape($"%{query}%");
var res = Sqlite.Exec(db, $"SELECT * FROM channels v WHERE (v.title LIKE {q}) LIMIT {count} OFFSET {offset*count};");
@@ -524,7 +559,7 @@ class TYTD.Downloader {
var id = TYTD.GetVideoId(vid);
if(id == null) return null;
this.Muxex.Lock();
this.Mutex.Lock();
var db = this.OpenDB();
var res = Sqlite.Exec(db, $"SELECT * FROM videos WHERE videoId = {Sqlite.Escape(id)};");
@@ -560,7 +595,7 @@ class TYTD.Downloader {
{
var id = TYTD.GetPlaylistId(vid);
if(id == null) return null;
this.Muxex.Lock();
this.Mutex.Lock();
var db = this.OpenDB();
var res = Sqlite.Exec(db, $"SELECT * FROM playlists WHERE playlistId = {Sqlite.Escape(id)};");
@@ -582,7 +617,7 @@ class TYTD.Downloader {
{
var id = TYTD.GetChannelId(vid);
if(id == null) return null;
this.Muxex.Lock();
this.Mutex.Lock();
var db = this.OpenDB();
var res = Sqlite.Exec(db, $"SELECT * FROM channels WHERE channelId = {Sqlite.Escape(id)};");
@@ -599,7 +634,7 @@ class TYTD.Downloader {
/^ Get the list of personal list names^/
public GetPersonalLists()
{
this.Muxex.Lock();
this.Mutex.Lock();
var db = this.OpenDB();
var items = [];
@@ -621,7 +656,7 @@ class TYTD.Downloader {
/^ Set the description of a personal list ^/
public SetPersonalListDescription(name,description)
{
this.Muxex.Lock();
this.Mutex.Lock();
var db = this.OpenDB();
Sqlite.Exec(db, $"UPDATE personal_lists SET description = {Sqlite.Escape(description)} WHERE name = {Sqlite.Escape(name)};");
@@ -631,7 +666,7 @@ class TYTD.Downloader {
/^ Get the description of a personal list ^/
public GetPersonalListDescription(name)
{
this.Muxex.Lock();
this.Mutex.Lock();
var db = this.OpenDB();
var res = Sqlite.Exec(db, $"SELECT * FROM personal_lists WHERE name = {Sqlite.Escape(name)};");
@@ -648,7 +683,7 @@ class TYTD.Downloader {
}
public GetPersonalListTempUrl(name)
{
this.Muxex.Lock();
this.Mutex.Lock();
var db = this.OpenDB();
var items = [];
@@ -672,7 +707,7 @@ class TYTD.Downloader {
/^ ^/
public GetPersonalListContents(name, offset, count)
{
this.Muxex.Lock();
this.Mutex.Lock();
var db = this.OpenDB();
var items = [];
@@ -700,6 +735,23 @@ class TYTD.Downloader {
return items;
}
public QueueRemoveItem(id)
{
this.Mutex.Lock();
const db = OpenDB();
Sqlite.Exec(db,$"DELETE FROM queue WHERE id = {Sqlite.Escape(id)};");
Sqlite.Close(db);
this.Mutex.Unlock();
}
public QueueClear()
{
this.Mutex.Lock();
const db = OpenDB();
Sqlite.Exec(db,$"DELETE FROM queue;");
Sqlite.Close(db);
this.Mutex.Unlock();
}
public AddToPersonalList(name, id)
{
@@ -822,12 +874,27 @@ class TYTD.Downloader {
private DownloaderThreadHandle;
private Queue = new TYTD.Queue();
/^
Get Video Queue count
^/
public getVideoQueueCount() this.Queue.Count;
public getVideoQueueCount() {
Mutex.Lock();
const db = OpenDB();
const res = Sqlite.Exec(db, "SELECT COUNT(*) FROM queue;");
Sqlite.Close(db);
Mutex.Unlock();
const queueCount = res[0].["COUNT(*)"];
if(TypeIsString(queueCount))
{
return ParseLong(queueCount);
}
return 0;
}
private PlaylistThreadHandle;
@@ -851,7 +918,7 @@ class TYTD.Downloader {
this.Mutex.Lock();
var db = this.OpenDB();
var _res = Sqlite.Exec(db,$"SELECT * FROM playlists p INNER JOIN playlist_entries e ON p.id = e.playlistId WHERE p.playlistId = {Sqlite.Escape(id)} LIMIT 1;");
Sqlite.Close(db);
this.Mutex.Unlock();
if(TypeOf(_res) == "List" && _res.Length > 0)
{
@@ -868,7 +935,7 @@ class TYTD.Downloader {
this.Mutex.Lock();
var db = this.OpenDB();
var _res = Sqlite.Exec(db,$"SELECT * FROM videos WHERE channelId = {Sqlite.Escape(id)} LIMIT 1;");
Sqlite.Close(db);
this.Mutex.Unlock();
if(TypeOf(_res) == "List" && _res.Length > 0)
{
@@ -1090,7 +1157,12 @@ class TYTD.Downloader {
var res = this.GetVideo(videoId);
if(res != null)
this.Bell.Invoke(this,{
Video = res
Video = {
VideoId = res.videoId,
ChannelId = res.channelId,
Title = res.title,
Channel = res.author
}
});
}
if(downloadRes != Resolution.NoDownload)
@@ -1134,11 +1206,13 @@ class TYTD.Downloader {
while(this.Running)
{
try {
var res = this.Queue.Pop();
var res = PopQueue();
//Console.WriteLine(res);
if(TypeOf(res) != "Null")
{
if(TypeIsDefined(res.TYTD = this)){
res.Progress = (progress)=>{
this.CurrentVideoProgress = progress;
@@ -1153,13 +1227,14 @@ class TYTD.Downloader {
this.VideoStarted.Invoke(this,{
Video = res.Video
});
res.Start();
this.VideoEnded.Invoke(this,{
Video = res.Video
});
}
}
} catch(ex) {
try{
@@ -1402,7 +1477,7 @@ class TYTD.Downloader {
^/
public PutVideoInfo(info)
{
this.Muxex.Lock();
this.Mutex.Lock();
var db = this.OpenDB();
var keywords = info.keywords;
@@ -1420,7 +1495,7 @@ class TYTD.Downloader {
private InitDatabase()
{
this.Muxex.Lock();
this.Mutex.Lock();
var db = this.OpenDB();
Sqlite.Exec(db,"CREATE TABLE IF NOT EXISTS videos (id INTEGER PRIMARY KEY AUTOINCREMENT, videoId TEXT UNIQUE, title TEXT, lengthSeconds INTEGER, keywords TEXT, channelId TEXT, shortDescription TEXT, viewCount INTEGER, author TEXT, addDate INTEGER, tytdTag TEXT);");
Sqlite.Exec(db,"CREATE TABLE IF NOT EXISTS playlists (id INTEGER PRIMARY KEY AUTOINCREMENT, playlistId TEXT UNIQUE,channelId TEXT,channelTitle TEXT, title TEXT);");
@@ -1433,6 +1508,7 @@ class TYTD.Downloader {
Sqlite.Exec(db,"CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT UNIQUE, password_hash TEXT, password_salt TEXT, flags INTEGER);");
Sqlite.Exec(db,"CREATE TABLE IF NOT EXISTS sessions (id INTEGER PRIMARY KEY AUTOINCREMENT, accountId INTEGER, key TEXT UNIQUE, expires INTEGER);");
Sqlite.Exec(db,"CREATE TABLE IF NOT EXISTS sso (id INTEGER PRIMARY KEY AUTOINCREMENT, service_name TEXT UNIQUE, service_pretty_name TEXT, sso_app_key TEXT UNIQUE, service_auth_post TEXT, service_auth_redirect TEXT);");
Sqlite.Exec(db,"CREATE TABLE IF NOT EXISTS queue (id INTEGER PRIMARY KEY AUTOINCREMENT, videoId TEXT, resolution TEXT);");
Sqlite.Exec(db,"ALTER TABLE sessions ADD expires INTEGER;");
Sqlite.Exec(db,"DELETE FROM sessions WHERE expires IS NULL;");
var config=Sqlite.Exec(db,"SELECT * FROM plugin_settings WHERE extension = '' AND key = 'settings';");
@@ -1455,7 +1531,7 @@ class TYTD.Downloader {
}
private _setPluginValue(extension,key,value)
{
this.Muxex.Lock();
this.Mutex.Lock();
var db = this.OpenDB();
Sqlite.Exec(db, $"INSERT OR REPLACE INTO plugin_settings (extension,key,value) VALUES ({Sqlite.Escape(extension)},{Sqlite.Escape(key)},{Sqlite.Escape(value)});");
Sqlite.Close(db);
@@ -1701,7 +1777,6 @@ class TYTD.Downloader {
],
Body = Net.Http.TextHttpRequestBody(embed("request2.json").ToString().Replace("VIDEO_ID_HERE", id).Replace("VISITOR_DATA",visitor),"application/json")
};
this.RateLimit();
var response = Net.Http.MakeRequest(url,requestData);
if(response.StatusCode < 200 || response.StatusCode > 299) {
@@ -1734,13 +1809,14 @@ class TYTD.Downloader {
if(!TypeIsDictionary(jsonResp.playerResponse.videoDetails))
{
Console.WriteLine("YEY");
throw new VideoDownloadError(id, "videoDetails is missing");
}
if(!TypeIsList(jsonResp.playerResponse.streamingData.adaptiveFormats))
{
throw new VideoDownloadError(id, "adaptiveFormats is missing");
}
//if(!TypeIsList(jsonResp.playerResponse.streamingData.adaptiveFormats))
//{
// throw new VideoDownloadError(id, "adaptiveFormats is missing");
//}
this.DownloadCaptions(jsonResp);
return jsonResp;
}
@@ -1835,7 +1911,7 @@ class TYTD.Downloader {
var first = true;
/*this.Muxex.Lock();
/*this.Mutex.Lock();
var db = this.OpenDB();
var d = $"INSERT INTO videos (videoId,title,lengthSeconds,keywords,channelId,shortDescription,viewCount,author,addDate,tytdTag) VALUES ({Sqlite.Escape(info.videoId)},{Sqlite.Escape(info.title)},{info.lengthSeconds},{Sqlite.Escape(info.keywords.ToString())},{Sqlite.Escape(info.channelId)},{Sqlite.Escape(info.shortDescription)},{info.viewCount},{Sqlite.Escape(info.author)},{DateTime.NowEpoch},{Sqlite.Escape(this.TYTDTag)});";
Sqlite.Exec(db, d);
@@ -1862,7 +1938,7 @@ class TYTD.Downloader {
};
*/
if(first) {
this.Muxex.Lock();
this.Mutex.Lock();
var db = this.OpenDB();
if(isPlaylist)
{
@@ -1898,7 +1974,7 @@ class TYTD.Downloader {
ids.Add(vid);
if(TypeOf(dbRow) == "Long")
{
this.Muxex.Lock();
this.Mutex.Lock();
var db = this.OpenDB();
Sqlite.Exec(db,$"INSERT INTO playlist_entries (playlistId,videoId) VALUES ({dbRow},{Sqlite.Escape(vid)});");
Sqlite.Close(db);
@@ -1919,21 +1995,21 @@ class TYTD.Downloader {
private requests = 0;
private rlm=new Muxex();
private rlm=new Mutex();
private RateLimit()
{
this.rlm.Lock();
var curRequest = DateTime.NowEpoch;
if((curRequest - this.lastRequest) > 60)
if((curRequest - this.lastRequest) > 10)
{
this.requests = 0;
}
this.requests++;
if(this.requests > 5)
if(this.requests >= 1)
{
DateTime.Sleep(25000);
DateTime.Sleep(1500);
this.requests=0;
curRequest = DateTime.NowEpoch;
}

View File

@@ -1,122 +0,0 @@
class TYTD.AOVideoDownload : IVideoDownload {
private info;
private tytd;
private progress;
private video_stream_url;
private done=false;
public AOVideoDownload(id)
{
this.info = {
Title = "",
Channel = "",
VideoId = TYTD.GetVideoId(id),
ChannelId = ""
};
}
public setTYTD(tytd)
{
this.tytd = tytd;
var id = this.info.VideoId;
var path = /"Streams"/id.Substring(0,4)/id.Substring(4)/"ao.bin";
if(this.tytd.Storage.FileExists(path)) {
this.done = true;
return null;
}
var req = this.tytd.ManifestRequest(id).playerResponse;
this.info.Title = req.videoDetails.title;
tytd.LOG($"Downloading: {this.info.Title} with id: {id} Highest Audio");
Console.WriteLine($"Downloading: {this.info.Title} with id: {id} Highest Audio");
this.info.Channel = req.videoDetails.author;
this.info.ChannelId = req.videoDetails.channelId;
this.tytd.PutVideoInfo(req.videoDetails);
var sampleRate = 0;
var bitrate = 0;
var url = "";
each(var item : req.streamingData.adaptiveFormats)
{
if(TypeOf(item.height) != "Long")
{
item.audioSampleRate = ParseLong(item.audioSampleRate);
if(item.audioSampleRate >= sampleRate && item.bitrate >= bitrate)
{
url = item.url;
sampleRate = item.audioSampleRate;
bitrate = item.bitrate;
}
}
}
this.video_stream_url = url;
return tytd;
}
public setProgress(p)
{
this.progress = p;
}
public getVideo()
{
return this.info;
}
public Start()
{
if(this.done) return;
for(var i = 0; i < 5; i++)
{
var req = {
FollowRedirects = true,
RequestHeaders = [
{
Key = "User-Agent",
Value = "com.google.android.youtube/19.28.35 (Linux; U; Android 15; GB) gzip"
}
]
};
var resp = Net.Http.MakeRequest(this.video_stream_url,req);
if(resp.StatusCode >= 200 && resp.StatusCode <= 299)
{
var id = this.info.VideoId;
var path = /"Streams"/id.Substring(0,4)/id.Substring(4)/"ao.bin";
this.tytd.Storage.CreateDirectory(path.GetParent());
var strm = this.tytd.Storage.OpenFile(path+".part","wb");
var src = resp.ReadAsStream();
Helpers.CopyToProgress(src,strm,this.progress,100.0);
strm.Close();
src.Close();
this.tytd.Storage.MoveFile(path+".part",path);
break;
}else {
var req = this.tytd.ManifestRequest(this.info.VideoId).playerResponse;
var sampleRate = 0;
var bitrate = 0;
var url = "";
each(var item : req.streamingData.adaptiveFormats)
{
if(TypeOf(item.height) != "Long")
{
item.audioSampleRate = ParseLong(item.audioSampleRate);
if(item.audioSampleRate >= sampleRate && item.bitrate >= bitrate)
{
url = item.url;
sampleRate = item.audioSampleRate;
bitrate = item.bitrate;
}
}
}
this.video_stream_url = url;
}
}
}
}

View File

@@ -1,228 +0,0 @@
class TYTD.NoConvertVideoDownload : IVideoDownload {
private info;
private tytd;
private progress;
private video_stream_url;
private audio_stream_url;
private done=false;
public NoConvertVideoDownload(id)
{
this.info = {
Title = "",
Channel = "",
VideoId = TYTD.GetVideoId(id),
ChannelId = ""
};
}
public getVideo()
{
return this.info;
}
public setTYTD(tytd)
{
this.tytd = tytd;
var id = this.info.VideoId;
var path = /"Streams"/id.Substring(0,4)/id.Substring(4)/"vo.bin";
var pathA = /"Streams"/id.Substring(0,4)/id.Substring(4)/"ao.bin";
if(this.tytd.Storage.FileExists(path) && this.tytd.Storage.FileExists(pathA)) {
this.done = true;
return null;
}
var req = this.tytd.ManifestRequest(id).playerResponse;
this.info.Title = req.videoDetails.title;
tytd.LOG($"Downloading: {this.info.Title} with id: {id} Highest Video/Audio");
Console.WriteLine($"Downloading: {this.info.Title} with id: {id} Highest Video/Audio");
this.info.Channel = req.videoDetails.author;
this.info.ChannelId = req.videoDetails.channelId;
this.tytd.PutVideoInfo(req.videoDetails);
var width = 0;
var height = 0;
var sampleRate = 0;
var bitrate = 0;
var vurl = "";
var aurl = "";
each(var item : req.streamingData.adaptiveFormats)
{
if(TypeOf(item.height) == "Long")
{
if(item.width >= width && item.height >= height)
{
vurl = item.url;
width = item.width;
height = item.height;
}
}
else {
item.audioSampleRate = ParseLong(item.audioSampleRate);
if(item.audioSampleRate >= sampleRate && item.bitrate >= bitrate)
{
aurl = item.url;
sampleRate = item.audioSampleRate;
bitrate = item.bitrate;
}
}
}
this.video_stream_url = vurl;
this.audio_stream_url = aurl;
return tytd;
}
public setProgress(p)
{
this.progress = p;
}
public Start()
{
if(this.done) return;
var id = this.info.VideoId;
var path = /"Streams"/id.Substring(0,4)/id.Substring(4)/"vo.bin";
var pathA = /"Streams"/id.Substring(0,4)/id.Substring(4)/"ao.bin";
if(!this.tytd.Storage.FileExists(path))
{
for(var i = 0; i < 5; i++)
{
var req = {
FollowRedirects = true,
RequestHeaders = [
{
Key = "User-Agent",
Value = "com.google.android.youtube/19.28.35 (Linux; U; Android 15; GB) gzip"
}
]
};
var resp = Net.Http.MakeRequest(this.video_stream_url,req);
if(resp.StatusCode >= 200 && resp.StatusCode <= 299)
{
this.tytd.Storage.CreateDirectory(path.GetParent());
var strm = this.tytd.Storage.OpenFile(path+".part","wb");
var src = resp.ReadAsStream();
Helpers.CopyToProgress(src,strm,(p)=>{
this.progress(p/2);
},100.0);
strm.Close();
src.Close();
this.tytd.Storage.MoveFile(path+".part",path);
break;
}
else {
var req = this.tytd.ManifestRequest(this.info.VideoId).playerResponse;
var width = 0;
var height = 0;
var sampleRate = 0;
var bitrate = 0;
var vurl = "";
var aurl = "";
each(var item : req.streamingData.adaptiveFormats)
{
if(TypeOf(item.height) == "Long")
{
if(item.width >= width && item.height >= height)
{
vurl = item.url;
width = item.width;
height = item.height;
}
}
else {
item.audioSampleRate = ParseLong(item.audioSampleRate);
if(item.audioSampleRate >= sampleRate && item.bitrate >= bitrate)
{
aurl = item.url;
sampleRate = item.audioSampleRate;
bitrate = item.bitrate;
}
}
}
this.video_stream_url = vurl;
this.audio_stream_url = aurl;
}
}
}
if(!this.tytd.Storage.FileExists(pathA))
{
for(var i = 0; i < 5; i++)
{
var req = {
FollowRedirects = true,
RequestHeaders = [
{
Key = "User-Agent",
Value = "com.google.android.youtube/19.28.35 (Linux; U; Android 15; GB) gzip"
}
]
};
var resp = Net.Http.MakeRequest(this.audio_stream_url,req);
if(resp.StatusCode >= 200 && resp.StatusCode <= 299)
{
this.tytd.Storage.CreateDirectory(pathA.GetParent());
var strm = this.tytd.Storage.OpenFile(pathA+".part","wb");
var src = resp.ReadAsStream();
Helpers.CopyToProgress(src,strm,(p)=>{
this.progress((p/2)+0.5);
},100.0);
strm.Close();
src.Close();
this.tytd.Storage.MoveFile(pathA+".part",pathA);
break;
}
else {
var req = this.tytd.ManifestRequest(this.info.VideoId).playerResponse;
var width = 0;
var height = 0;
var sampleRate = 0;
var bitrate = 0;
var vurl = "";
var aurl = "";
each(var item : req.streamingData.adaptiveFormats)
{
if(TypeOf(item.height) == "Long")
{
if(item.width >= width && item.height >= height)
{
vurl = item.url;
width = item.width;
height = item.height;
}
}
else {
item.audioSampleRate = ParseLong(item.audioSampleRate);
if(item.audioSampleRate >= sampleRate && item.bitrate >= bitrate)
{
aurl = item.url;
sampleRate = item.audioSampleRate;
bitrate = item.bitrate;
}
}
}
this.video_stream_url = vurl;
this.audio_stream_url = aurl;
}
}
}
this.progress(1.0);
return;
}
}

View File

@@ -20,8 +20,16 @@ class TYTD.SDVideoDownload : IVideoDownload {
this.tytd = tytd;
var id = this.info.VideoId;
var path = /"Streams"/id.Substring(0,4)/id.Substring(4)/"ytmux.mp4";
if(this.tytd.Storage.FileExists(path)) {
if(this.tytd.Storage.FileExists(path)) {
this.done = true;
const vinfo = this.tytd.GetVideo(id);
this.info = {
Title = vinfo.title,
VideoId = vinfo.videoId,
ChannelId = vinfo.channelId,
Channel = vinfo.author
};
return null;
}

View File

@@ -0,0 +1,84 @@
class TYTD.TranscodeAMV : IVideoDownload {
private id;
private ncv;
private tytd;
private done;
public TranscodeAMV(id)
{
this.id = id;
this.ncv = new TYTD.SDVideoDownload(id);
}
public setTYTD(tytd)
{
this.tytd = tytd;
this.ncv.TYTD = tytd;
if(TypeIsDefined(tytd))
{
var dir = this.tytd.DatabaseDirectory / "Streams"/this.id.Substring(0,4)/this.id.Substring(4);
var ao = dir / "ytmux.mp4";
var out = dir /"conv.amv";
if(FS.Local.FileExists(out)) return null;
return tytd;
}
return null;
}
public setProgress(p)
{
return this.ncv.Progress = p;
}
public getVideo()
{
return this.ncv.Video;
}
public Start()
{
var id = this.id;
this.ncv.Start();
var p = new Process();
p.FileName = Env.GetRealExecutablePath("ffmpeg").ToString();
var dir = this.tytd.DatabaseDirectory / "Streams"/this.id.Substring(0,4)/this.id.Substring(4);
var ao = dir / "ytmux.mp4";
var out = dir / $"conv.amv";
if(FS.Local.FileExists(out) || !FS.Local.FileExists(ao)) return;
var args=["-y","-i",ao.ToString()];
//-c:v amv -c:a adpcm_ima_amv -pix_fmt yuvj420p -vstrict -1 -s 160x120 -ac 1 -ar 22050 -r 16 -block_size 882
args.Add("-c:v");
args.Add("amv");
args.Add("-c:a");
args.Add("adpcm_ima_amv");
args.Add("-pix_fmt");
args.Add("yuvj420p");
args.Add("-vstrict");
args.Add("-1");
args.Add("-s");
args.Add("160x120");
args.Add("-ac");
args.Add("1");
args.Add("-ar");
args.Add("22050");
args.Add("-r");
args.Add("15");
args.Add("-block_size");
args.Add("1470");
args.Add("-preset");
args.Add("ultrafast");
args.Add(out.ToString());
p.Arguments = args;
if(p.Start())
p.Join();
}
}

View File

@@ -9,13 +9,24 @@ class TYTD.TranscodeAudio : IVideoDownload {
{
this.id = id;
this.ext = ext;
this.ncv = new TYTD.AOVideoDownload(id);
this.ncv = new TYTD.SDVideoDownload(id);
}
public setTYTD(tytd)
{
this.tytd = tytd;
return this.ncv.TYTD = tytd;
this.ncv.TYTD = tytd;
if(TypeIsDefined(tytd))
{
var dir = this.tytd.DatabaseDirectory / "Streams"/this.id.Substring(0,4)/this.id.Substring(4);
var out = dir /"conv.{this.ext}";
if(FS.Local.FileExists(out)) return null;
return tytd;
}
return null;
}
public setProgress(p)
@@ -31,15 +42,15 @@ class TYTD.TranscodeAudio : IVideoDownload {
public Start()
{
var id = this.id;
this.mcv.Start();
this.ncv.Start();
var p = new Process();
p.FileName = Env.GetRealExecutablePath("ffmpeg").ToString();
var dir = this.tytd.DatabaseDirectory / "Streams"/this.id.Substring(0,4)/this.id.Substring(4);
var ao = dir / "ao.bin";
var ao = dir / "ytmux.mp4";
var out = dir / $"conv{this.ext}";
if(FS.Local.FileExists(out)) return;
if(FS.Local.FileExists(out) && !FS.Local.FileExists(ao)) return;
var args=["-y","-i",ao.ToString()];

View File

@@ -1,63 +0,0 @@
class TYTD.TranscodeVideo : IVideoDownload {
private id;
private ncv;
private tytd;
private ext;
public TranscodeVideo(id,ext)
{
this.id = id;
this.ext = ext;
this.ncv = new TYTD.NoConvertVideoDownload(id);
}
public setTYTD(tytd)
{
this.tytd = tytd;
return this.ncv.TYTD = tytd;
}
public setProgress(p)
{
return this.ncv.Progress = p;
}
public getVideo()
{
return this.ncv.Video;
}
public Start()
{
var id = this.id;
this.mcv.Start();
var p = new Process();
p.FileName = Env.GetRealExecutablePath("ffmpeg").ToString();
var dir = this.tytd.DatabaseDirectory / "Streams"/this.id.Substring(0,4)/this.id.Substring(4);
var vo = dir / "vo.bin";
var ao = dir / "ao.bin";
var out = dir / $"conv{this.ext}";
if(FS.Local.FileExists(out)) return;
var args=["-y","-i",vo.ToString(),"-i",ao.ToString()];
if(this.ext == ".mkv")
{
args.Add("-c");
args.Add("copy");
}
args.Add("-map");
args.Add("0:v");
args.Add("-map");
args.Add("1:a");
args.Add("-preset");
args.Add("ultrafast");
args.Add(out.ToString());
p.Arguments = args;
if(p.Start())
p.Join();
}
}

View File

@@ -1,115 +0,0 @@
class TYTD.VOVideoDownload : IVideoDownload {
private info;
private tytd;
private progress;
private video_stream_url;
private done=false;
public VOVideoDownload(id)
{
this.info = {
Title = "",
Channel = "",
VideoId = TYTD.GetVideoId(id),
ChannelId = ""
};
}
public setTYTD(tytd)
{
this.tytd = tytd;
var id = this.info.VideoId;
var path = /"Streams"/id.Substring(0,4)/id.Substring(4)/"vo.bin";
if(this.tytd.Storage.FileExists(path)) {
this.done = true;
return null;
}
var req = this.tytd.ManifestRequest(id).playerResponse;
this.info.Title = req.videoDetails.title;
this.info.Channel = req.videoDetails.author;
this.info.ChannelId = req.videoDetails.channelId;
tytd.LOG($"Downloading: {this.info.Title} with id: {id} Highest Video");
Console.WriteLine($"Downloading: {this.info.Title} with id: {id} Highest Video");
this.tytd.PutVideoInfo(req.videoDetails);
var width = 0;
var height = 0;
var url = "";
each(var item : req.streamingData.adaptiveFormats)
{
if(TypeOf(item.height) == "Long")
{
if(item.width >= width && item.height >= height)
{
url = item.url;
width = item.width;
height = item.height;
}
}
}
this.video_stream_url = url;
return tytd;
}
public setProgress(p)
{
this.progress = p;
}
public getVideo()
{
return this.info;
}
public Start()
{
if(this.done) return;
var req = {
FollowRedirects = true,
RequestHeaders = [
{
Key = "User-Agent",
Value = "com.google.android.youtube/19.28.35 (Linux; U; Android 15; GB) gzip"
}
]
};
var resp = Net.Http.MakeRequest(this.video_stream_url,req);
if(resp.StatusCode >= 200 && resp.StatusCode <= 299)
{
var id = this.info.VideoId;
var path = /"Streams"/id.Substring(0,4)/id.Substring(4)/"vo.bin";
this.tytd.Storage.CreateDirectory(path.GetParent());
var strm = this.tytd.Storage.OpenFile(path+".part","wb");
var src = resp.ReadAsStream();
Helpers.CopyToProgress(src,strm,this.progress,100.0);
strm.Close();
src.Close();
this.tytd.Storage.MoveFile(path+".part",path);
}
else {
var req = this.tytd.ManifestRequest(this.info.VideoId).playerResponse;
var width = 0;
var height = 0;
var url = "";
each(var item : req.streamingData.adaptiveFormats)
{
if(TypeOf(item.height) == "Long")
{
if(item.width >= width && item.height >= height)
{
url = item.url;
width = item.width;
height = item.height;
}
}
}
this.video_stream_url = url;
}
}
}