diff --git a/public/index.js b/public/index.js index 82fc023..b42d5a5 100644 --- a/public/index.js +++ b/public/index.js @@ -19,4 +19,4 @@ VideoInput.oninput = () => Socket.on('VideoListResolution', (req) => console.log(req)); -Socket.on('VideoListResolved') +Socket.on('VideoListResolved', (req) => console.log(req)); diff --git a/src/config.js b/src/config.js index 76849e9..5d5800a 100644 --- a/src/config.js +++ b/src/config.js @@ -1,13 +1,16 @@ +const Logger = require('./logger'); module.exports.Configuration = {} module.exports.Load = () => { - module.exports.Configuration = { + this.Configuration = { LogFile: 'logs.log', ListenPort: 8080, PublicDirectory: 'public', StorageDirectory: './tmp/', - CacheCleanInterval: 2 + CacheCleanInterval: 30000, // 5 mins + CacheTimeToUse: 60000, // 10 mins } + Logger.Log('Configuration loaded'); } diff --git a/src/server.js b/src/server.js index b4b14cf..e1facea 100644 --- a/src/server.js +++ b/src/server.js @@ -1,6 +1,9 @@ const Logger = require('./logger') const Config = require('./config'); +const YoutubeHelper = require('./youtubehelper'); +const YoutubeDownloader = require('./youtubedownloader'); + const express = require('express'); let app; @@ -73,16 +76,18 @@ async function VideoListUpdate(socket, req) const YoutubeRegex = /^((?:https?:)?\/\/)?((?:www|m)\.)?((?:youtube\.com|youtu.be))(\/(?:[\w\-]+\?v=|embed\/|v\/)?)([\w\-]+)(\S+)?$/; let ResolveQueue = []; - + + Res.Error = false; Res.Content = []; for (video of VideoArray) { if (YoutubeRegex.exec(video)) { + let VideoID = video.match(YoutubeRegex)[5]; // generate ID lol - ResolveQueue.push(video); + ResolveQueue.push(VideoID); Res.Content.push({ - id: 1, + id: VideoID, url: video, valid: true, action: 'Resolving' @@ -100,7 +105,17 @@ async function VideoListUpdate(socket, req) socket.emit('VideoListResolution', Res); - + if (ResolveQueue.length == 0) + return; + + const Resolution = await YoutubeHelper.GetVideoInfoArr(ResolveQueue); + + const ResolutionRes = { + Error: false, + Content: Resolution + }; + + socket.emit('VideoListResolved', ResolutionRes); } diff --git a/src/youtubehelper.js b/src/youtubehelper.js index 1213235..cc4abd6 100644 --- a/src/youtubehelper.js +++ b/src/youtubehelper.js @@ -1,30 +1,124 @@ +const Config = require('./config'); +const Logger = require('./logger'); + const YTDL = require('ytdl-core'); // TODO: does the video resolver need a queue? // cache +let ResolutionCache = []; -function CheckCache() +function HitCache(id) { + if (ResolutionCache[id]) + { + Logger.Log(`Cache hit! ${id}`) + ResolutionCache[id].LastUsed = Date.now(); + return ResolutionCache[id].Video; + } else + { + return false; + } +} +function RegisterCache(video) +{ + ResolutionCache[video.player_response.videoDetails.videoId] = { + Id: video.player_response.videoDetails.videoId, + Video: video, + LastUsed: Date.now(), + TimeCreated: Date.now() + } } function CleanCache() { + // TODO: fix weird bug where a cleaned + // entry's timeused lingers + let ExpiredEntrys = []; + for (id in ResolutionCache) + { + entry = ResolutionCache[id]; + // if cache entry has expired + const LastUsed = Date.now() - entry.LastUsed; + if (LastUsed > Config.Configuration.CacheTimeToUse) + { + // remove expired entry + Logger.Log(`Cache entry '${id}' expired`); + ExpiredEntrys.push(id); + delete entry; + } + } + for (expiredEntry of ExpiredEntrys) + { + delete ResolutionCache[expiredEntry]; + } } module.exports.InitResolverCache = async () => { - + setInterval(CleanCache, Config.Configuration.CacheCleanInterval); + Logger.Log('Video resolver cache settup') } module.exports.GetVideoInfoArr = async (arr) => { - + let ret = []; + // TODO: make async AND retain order + for (video of arr) + { + ret.push(await this.GetVideoInfo(video)); + } + return ret; } module.exports.GetVideoInfo = async (video) => { + try + { + const CacheHit = HitCache(video); + let Video = {}; + + if (CacheHit) + { + Video = CacheHit + } else + { + // TODO: is the YouTube API faster for this? + Logger.Log(`Resolving '${video}'`) + Video = await YTDL.getInfo(video); + // register the info into the cache + RegisterCache(Video); + } + + + let Res = BuildBasicInfoFromInfo(Video); + return Res; + + } catch (e) + { + Logger.Log(`Error resolving video '${video}', ${e}`); + return { Error: "Video cannot resolve" }; + } +} + +function BuildBasicInfoFromInfo(info) +{ + let ret = {}; + ret.id = info.player_response.videoDetails.videoId; + ret.title = info.player_response.videoDetails.title; + ret.desc = info.player_response.videoDetails.shortDescription; + ret.views = info.player_response.videoDetails.viewCount; + if (!info.player_response.videoDetails.thumbnail.thumbnails[0]) + { + ret.thumbnail = info.player_response.videoDetails.thumbnail.thumbnails[1].url; + } else + { + ret.thumbnail = info.player_response.videoDetails.thumbnail.thumbnails[0].url; + } + ret.channel = info.player_response.videoDetails.author; + ret.runtime = info.player_response.videoDetails.lengthSeconds; + return ret; }