diff options
author | Tom Harley | 2020-01-24 05:20:59 +0000 |
---|---|---|
committer | Tom Harley | 2020-01-24 05:20:59 +0000 |
commit | 3a3244224d24b8c515fbd99d7621e06368723a1b (patch) | |
tree | 271e2373c1ef1d51672cfe5b2df76e498e1448d0 | |
download | ytduration-3a3244224d24b8c515fbd99d7621e06368723a1b.tar.gz ytduration-3a3244224d24b8c515fbd99d7621e06368723a1b.zip |
-rw-r--r-- | index.html | 66 | ||||
-rw-r--r-- | main.js | 128 |
2 files changed, 194 insertions, 0 deletions
diff --git a/index.html b/index.html new file mode 100644 index 0000000..acc5aca --- /dev/null +++ b/index.html @@ -0,0 +1,66 @@ +<html> + <head> + <script src="./main.js"></script> + <style> + input.time { + width: 3em; + text-align: right; + } + </style> + </head> + <body> + <form name="search"> + Keywords: <input type="text" name="q"> + Category: <select name="category"> + <option value="" selected>any</option> + <option value="1">Film & Animation</option> + <option value="2">Cars & Vehicles</option> + <option value="10">Music</option> + <option value="15">Pets & Animals</option> + <option value="17">Sports</option> + <option value="18">Short Films</option> + <option value="19">Travel & Events</option> + <option value="20">Gaming</option> + <option value="21">Videoblogging</option> + <option value="22">People & Blogs</option> + <option value="23">Comedy</option> + <option value="24">Entertainment</option> + <option value="25">News & Politics</option> + <option value="26">How-to & Style</option> + <option value="27">Education</option> + <option value="28">Science & Technology</option> + <option value="30">Films</option> + <option value="31">Anime/Animation</option> + <option value="32">Action/Adventure</option> + <option value="33">Classics</option> + <option value="34">Comedy</option> + <option value="35">Documentary</option> + <option value="36">Drama</option> + <option value="37">Family</option> + <option value="38">Foreign</option> + <option value="39">Horror</option> + <option value="40">Sci-Fi/Fantasy</option> + <option value="41">Thriller</option> + <option value="42">Shorts</option> + <option value="43">Shows</option> + <option value="44">Trailers</option> + </select> + <br> + Duration: + <input type="number" class="time" value="0" name="hrs">h + <input type="number" class="time" value="0" name="mins">m + <input type="number" class="time" value="0" name="secs">s + give or take + <input type="number" class="time" value="0" name="dhrs">h + <input type="number" class="time" value="0" name="dmins">m + <input type="number" class="time" value="0" name="dsecs">s + <br> + <input type="button" name="go" value="Search" + onclick="startSearch()"> + </form> + <table> + <tbody id="results"> + </tbody> + </table> + </body> +</html> @@ -0,0 +1,128 @@ +const api_key = "AIzaSyAAmnkuQN5XgLYaVQyiLh_Sj08zxLRXOTI" + +function makeUrl(base, data) { + if (data.length == 0) { + return data; + } else { + return base + "?" + data + .filter(x => x[1]) + .map(x => `${x[0]}=${x[1]}`) + .join("&"); + } +} + +const init = { + method: "GET", + referrer: "https://magnostherobot.xyz" +}; + +async function getInfos(ids) { + let data = [ + [ "part", "contentDetails,snippet" ], + [ "key", api_key ], + [ "id", ids.join(",") ] + ]; + + let url = makeUrl("https://www.googleapis.com/youtube/v3/videos", data); + return fetch(url, init).then(res => res.json()).then(res => res.items); +} + +async function getResultPage(q, cat, page, n) { + let data = [ + [ "part", "snippet" ], + [ "key", api_key ], + [ "eventType", "completed" ], + [ "maxResults", n ], + [ "order", "relevance" ], + [ "type", "video" ], + [ "q", q ], + [ "pageToken", page ], + [ "videoCategoryId", cat ] + ]; + + let nextPageToken = null; + + let url = makeUrl("https://www.googleapis.com/youtube/v3/search", data); + let res = await fetch(url, init).then(res => res.json()) + + let result = {}; + + if (res.items.length == 0) { + result.items = []; + } else { + result.items = await getInfos(res.items.map(x => x.id.videoId)); + } + + result.nextPageToken = res.nextPageToken; + + return result; +} + +function timeFrom(arr) { + let n = arr.length; + let result = 0; + for (let i = 1; i <= n; ++i) { + let m = n - i; + result += arr[m] * Math.pow(60, i - 1); + } + return result; +} + +function iso8601(str) { + return str.match(/\d+/g); +} + +async function getMoreResults(q, cat, t, dt, n) { + const maxQueryResults = 50; + let nextPage = null; + + let oldTbody = document.getElementById("results"); + let tbody = document.createElement("tbody"); + tbody.setAttribute("id", "results"); + oldTbody.parentNode.replaceChild(tbody, oldTbody); + + let results = []; + while (results.length < n) { + let moreResults = await getResultPage(q, cat, nextPage, maxQueryResults); + nextPage = moreResults.nextPageToken; + let filteredResults = moreResults.items.filter(x => { + let duration = iso8601(x.contentDetails.duration); + x.duration = duration; + duration = timeFrom(duration); + let mint = t - dt; + let maxt = t + dt; + return duration > mint && duration < maxt; + }); + + filteredResults.forEach(x => { + let row = tbody.insertRow(); + + let thumbCell = row.insertCell(); + let a = document.createElement("a"); + a.setAttribute("href", `https://youtu.be/${x.id}`); + let img = document.createElement("img"); + img.setAttribute("src", x.snippet.thumbnails.default.url); + a.appendChild(img); + thumbCell.appendChild(a); + + let nameCell = row.insertCell(); + nameCell.appendChild(document.createTextNode(x.snippet.title)); + nameCell.appendChild(document.createElement("br")); + nameCell.appendChild(document.createTextNode(x.duration.join(":"))); + }); + + results = results.concat(filteredResults); + console.log(results.length); + } + + console.log(results); + return results; +} + +function startSearch() { + let time = timeFrom([search.hrs.value, search.mins.value, + search.secs.value]); + let dtime = timeFrom([search.dhrs.value, search.dmins.value, + search.dsecs.value]); + getMoreResults(search.q.value, search.category.value, time, dtime, 30); +} |