diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Types.hx | 21 | ||||
| -rw-r--r-- | src/server/Main.hx | 34 | ||||
| -rw-r--r-- | src/server/cache/YoutubeCache.hx | 42 | ||||
| -rw-r--r-- | src/utils/macro/Macro.hx | 35 |
4 files changed, 100 insertions, 32 deletions
diff --git a/src/Types.hx b/src/Types.hx index 60ce612..22b6ec2 100644 --- a/src/Types.hx +++ b/src/Types.hx @@ -29,28 +29,35 @@ typedef VideoData = { var ?playerType:PlayerType; } +typedef ServerConfig = Config & { + serverChatHistory:Int, + localAdmins:Bool, + allowProxyIps:Bool, + localNetworkOnly:Bool, + sslKeyPemPath:String, + sslCertPemPath:String, + cacheStorageLimitGiB:Float, + ytDlp:{ + channel:String, jsRuntime:String, + }, +} + typedef Config = { port:Int, channelName:String, maxLoginLength:Int, maxMessageLength:Int, - serverChatHistory:Int, totalVideoLimit:Int, userVideoLimit:Int, requestLeaderOnPause:Bool, unpauseWithoutLeader:Bool, - localAdmins:Bool, - allowProxyIps:Bool, - localNetworkOnly:Bool, - sslKeyPemPath:String, - sslCertPemPath:String, templateUrl:String, youtubeApiKey:String, youtubePlaylistLimit:Int, - cacheStorageLimitGiB:Float, permissions:Permissions, emotes:Array<Emote>, filters:Array<Filter>, + ?serverVersion:Int, ?isVerbose:Bool, ?salt:String } diff --git a/src/server/Main.hx b/src/server/Main.hx index e67fbcb..8b9ade1 100644 --- a/src/server/Main.hx +++ b/src/server/Main.hx @@ -6,6 +6,7 @@ import Types.FlashbackItem; import Types.Message; import Types.Permission; import Types.PlayerType; +import Types.ServerConfig; import Types.UserList; import Types.VideoItem; import Types.WsEvent; @@ -26,6 +27,7 @@ import json2object.JsonParser; import server.cache.Cache; import sys.FileSystem; import sys.io.File; +import utils.macro.Macro; private typedef MainOptions = { loadState:Bool @@ -34,6 +36,7 @@ private typedef MainOptions = { class Main { public static inline var MIN_PASSWORD_LENGTH = 4; public static inline var MAX_PASSWORD_LENGTH = 50; + static inline var SERVER_VERSION = 2; static inline var VIDEO_START_MAX_DELAY = 3000; static inline var VIDEO_SKIP_DELAY = 1000; static inline var FLASHBACKS_COUNT = 50; @@ -44,7 +47,7 @@ class Main { public final userDir:String; public final logsDir:String; - public final config:Config; + public final config:ServerConfig; public final isNoState:Bool; final verbose:Bool; @@ -120,6 +123,12 @@ class Main { exit(); }); + config = loadUserConfig(); + config.serverVersion = SERVER_VERSION; + config.isVerbose = verbose; + userList = loadUsers(); + config.salt = generateConfigSalt(userList); + logger = new Logger(logsDir, 10, verbose); consoleInput = new ConsoleInput(this); consoleInput.initConsoleInput(); @@ -127,11 +136,8 @@ class Main { if (cache.isYtReady) playersCacheSupport.push(YoutubeType); initIntergationHandlers(); loadState(); - config = loadUserConfig(); cache.setStorageLimit(cast config.cacheStorageLimitGiB * 1024 * 1024 * 1024); - userList = loadUsers(); - config.isVerbose = verbose; - config.salt = generateConfigSalt(); + if (config.localNetworkOnly) localIp = "127.0.0.1"; else localIp = Utils.getLocalIp(); globalIp = localIp; @@ -235,7 +241,7 @@ class Main { }; } - function getSslConfig(config:Config):Null<{key:String, cert:String}> { + function getSslConfig(config:ServerConfig):Null<{key:String, cert:String}> { final c = config; if (c.sslKeyPemPath.length == 0 && c.sslCertPemPath.length == 0) return null; final hasBoth = FileSystem.exists(c.sslKeyPemPath) @@ -264,12 +270,12 @@ class Main { process.exit(); } - function generateConfigSalt():String { - userList.salt ??= Sha256.encode('${Math.random()}'); - return userList.salt; + function generateConfigSalt(users:UserList):String { + users.salt ??= Sha256.encode('${Math.random()}'); + return users.salt; } - function loadUserConfig():Config { + function loadUserConfig():ServerConfig { final config = getUserConfig(); inline function getPermissions(type:Permission):Array<Permission> { return Reflect.field(config.permissions, cast type); @@ -289,12 +295,12 @@ class Main { return config; } - function getUserConfig():Config { - final config:Config = Json.parse(File.getContent('$rootDir/default-config.json')); + function getUserConfig():ServerConfig { + final config:ServerConfig = Json.parse(File.getContent('$rootDir/default-config.json')); if (isNoState) return config; final customPath = '$userDir/config.json'; if (!FileSystem.exists(customPath)) return config; - final customConfig:Config = Json.parse(File.getContent(customPath)); + final customConfig:ServerConfig = Json.parse(File.getContent(customPath)); for (field in Reflect.fields(customConfig)) { if (Reflect.field(config, field) == null) { trace('Warning: config field "$field" is unknown'); @@ -563,7 +569,7 @@ class Main { type: Connected, connected: { uuid: client.uuid, - config: config, + config: Macro.getTypedObject(config, Config), history: messages, isUnknownClient: true, clientName: client.name, diff --git a/src/server/cache/YoutubeCache.hx b/src/server/cache/YoutubeCache.hx index c7053f9..0618d00 100644 --- a/src/server/cache/YoutubeCache.hx +++ b/src/server/cache/YoutubeCache.hx @@ -1,6 +1,6 @@ package server.cache; -import haxe.Json; +import haxe.io.Path; import js.lib.Promise; import js.node.ChildProcess; import sys.FileSystem; @@ -30,7 +30,8 @@ class YoutubeCache { } public function checkUpdate():Void { - ytDlp.execAsync("-U", { + ytDlp.execAsync("", { + updateTo: main.config.ytDlp.channel, onData: d -> { trace(d); } @@ -136,36 +137,51 @@ class YoutubeCache { } if (!checkEnoughSpace(getTotalFormatsSize() * 2)) return; - final formatIds = if (videoFormat.format_id == audioFormat.format_id) { + final isMuxed = videoFormat.format_id == audioFormat.format_id; + final formatIds = if (isMuxed) { videoFormat.format_id; } else { '${videoFormat.format_id}+${audioFormat.format_id}'; } - var totalSize = getTotalFormatsSize().limitMin(10); + final totalSize = getTotalFormatsSize().limitMin(10); var videoSizeRatio = (videoFormat.filesize ?? 0).limitMin(8) / totalSize; var audioSizeRatio = (audioFormat.filesize ?? 0).limitMin(2) / totalSize; - var isVideoFormatDownloading = true; + if (isMuxed) { + videoSizeRatio = 1; + audioSizeRatio = 0; + } + trace(formatIds, toMibString(totalSize), videoSizeRatio.toFixed(), audioSizeRatio.toFixed()); + + var videoRatioCache = 0.0; + var audioRatioCache = 0.0; final dlVideo:Promise<String> = ytDlp.downloadAsync(url, { format: formatIds, output: '${cache.cacheDir}/$inVideoName', remuxVideo: "mp4", + additionalOptions: ["--no-js-runtimes", "--js-runtimes", main.config.ytDlp.jsRuntime], + // verbose: true, cookies: useCookies ? getCookiesPathOrNull() : null, forceIpv4: true, socketTimeout: 2, extractorRetries: 0, onProgress: p -> { final isFinished = p.status == "finished"; + if (isFinished) { + final filename = Path.withoutDirectory(p.filename); + trace('$filename format file downloaded'); + } var ratio = if (isFinished) { 1; } else { (p.downloaded / p.total).clamp(0, 1); } - if (isVideoFormatDownloading) { - ratio = ratio * videoSizeRatio; - } else { - ratio = videoSizeRatio + ratio * audioSizeRatio; - } - if (isFinished) isVideoFormatDownloading = false; + + final isVideo = p.filename.contains('f${videoFormat.format_id}'); + if (isVideo) videoRatioCache = ratio; + else audioRatioCache = ratio; + + ratio = videoRatioCache * videoSizeRatio + audioRatioCache * audioSizeRatio; + main.sendByName(clientName, { type: Progress, progress: { @@ -249,6 +265,10 @@ class YoutubeCache { return format.format_note ?? '${resolution}p'; } + inline function toMibString(bytes:Int):String { + return '${(bytes / 1024 / 1024).toFixed()} MiB'; + } + function log(clientName:String, msg:String):Void { cache.logByName(clientName, msg); } diff --git a/src/utils/macro/Macro.hx b/src/utils/macro/Macro.hx new file mode 100644 index 0000000..118f0e8 --- /dev/null +++ b/src/utils/macro/Macro.hx @@ -0,0 +1,35 @@ +package utils.macro; + +import haxe.macro.Context; +import haxe.macro.Expr; + +using haxe.macro.Tools; + +class Macro { + macro public static function getTypedObject(obj:Expr, typePath:Expr):Expr { + final type = Context.getType(typePath.toString()); + switch (type.follow()) { + case TAnonymous(_.get() => td): + final name = obj.toString(); + if (obj.expr.match(EObjectDecl(_))) { + throw new Error('$name should be passed as reference (inside of variable)', obj.pos); + } + final e:Expr = { + expr: EObjectDecl([ + for (field in td.fields) { + field: field.name, + expr: macro $p{['$name', '${field.name}']}, + } + ]), + pos: Context.currentPos() + } + return e; + default: + throw new Error(type.toString() + " should be typedef structure", typePath.pos); + } + } + + macro public static function getBuildTime():Expr { + return macro $v{Date.now().toString()}; + } +} |
