summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--index.html66
-rw-r--r--main.js128
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 &amp; Animation</option>
+ <option value="2">Cars &amp; Vehicles</option>
+ <option value="10">Music</option>
+ <option value="15">Pets &amp; Animals</option>
+ <option value="17">Sports</option>
+ <option value="18">Short Films</option>
+ <option value="19">Travel &amp; Events</option>
+ <option value="20">Gaming</option>
+ <option value="21">Videoblogging</option>
+ <option value="22">People &amp; Blogs</option>
+ <option value="23">Comedy</option>
+ <option value="24">Entertainment</option>
+ <option value="25">News &amp; Politics</option>
+ <option value="26">How-to &amp; Style</option>
+ <option value="27">Education</option>
+ <option value="28">Science &amp; 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>
diff --git a/main.js b/main.js
new file mode 100644
index 0000000..53640a5
--- /dev/null
+++ b/main.js
@@ -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);
+}