diff options
Diffstat (limited to 'content/sodysee/odysee.js')
-rw-r--r-- | content/sodysee/odysee.js | 414 |
1 files changed, 0 insertions, 414 deletions
diff --git a/content/sodysee/odysee.js b/content/sodysee/odysee.js deleted file mode 100644 index 5a06957..0000000 --- a/content/sodysee/odysee.js +++ /dev/null @@ -1,414 +0,0 @@ -/** - * Copyright 2021 Wojtek Kosior - * - * This program is free software; you can redistribute it - * and/or modify it under the terms of either: - * - the GNU General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at - * your option) any later version, or - * - the "A" license: <https://koszko.org/alicense.txt>; explained - * at: <https://koszko.org/en/articles/my-new-license.html> - * - * As additional permission under GNU GPL version 3 section 7, you - * may distribute forms of that code without the copy of the GNU - * GPL normally required by section 4, provided you include this - * license notice and, in case of non-source distribution, a URL - * through which recipients can access the Corresponding Source. - * If you modify file(s) with this exception, you may extend this - * exception to your version of the file(s), but you are not - * obligated to do so. If you do not wish to do so, delete this - * exception statement from your version. If you delete this - * exception statement from all source files in the program, then - * also delete it here. - * - * As a special exception to the GPL, any HTML file which merely - * makes function calls to this code, and for that purpose - * includes it by reference shall be deemed a separate work for - * copyright law purposes. If you modify this code, you may extend - * this exception to your version of the code, but you are not - * obligated to do so. If you do not wish to do so, delete this - * exception statement from your version. - */ - -/* use with https://odysee.com/*** */ - -/* Helper functions for ajax. */ - -function ajax_callback(xhttp, cb) -{ - cb(xhttp.response); -} - -function perform_ajax(method, url, callback, err_callback, data) -{ - const xhttp = new XMLHttpRequest(); - xhttp.onload = () => ajax_callback(xhttp, callback); - xhttp.onerror = err_callback; - xhttp.onabort = err_callback; - xhttp.open(method, url, true); - try { - xhttp.send(data); - } catch(e) { - err_callback(); - } -} - -/* Helper functions for strings with HTML entities (e.g. `"'). */ -function HTML_decode(text) -{ - const tmp_span = document.createElement("span"); - tmp_span.innerHTML = text; - return tmp_span.textContent; -} - -/* Odysee API servers. */ - -const odysee_resolve_url = "https://api.na-backend.odysee.com/api/v1/proxy?m=resolve"; -const lighthouse_search_url = "https://lighthouse.odysee.com/search"; - -/* - * If we're on a video page, show the video. Use JSON data embedded in <head> - * if possible. If not - fetch video data using Odysee API. - */ - -let data = null; - -function process_json_script(json_script) -{ - try { - data = JSON.parse(json_script.textContent); - } catch (e) { - console.log("Error parsing content data", e); - } -} - -for (const json_script of document.querySelectorAll("head script")) { - if (["blocked-type", "type"].map(a => json_script.getAttribute(a)) - .includes("application/ld+json")) - process_json_script(json_script); -} - -const body = document.createElement("body"); -const video_container = document.createElement("div"); - -body.appendChild(video_container); - -function show_video(content_url, title, upload_date, description) -{ - if (content_url) { - const video = document.createElement("video"); - const source = document.createElement("source"); - - source.src = content_url; - - video.setAttribute("width", "100%"); - video.setAttribute("height", "auto"); - video.setAttribute("controls", ""); - - video.appendChild(source); - - video_container.appendChild(video); - } - - if (title) { - const h1 = document.createElement("h1"); - - h1.textContent = HTML_decode(title); - h1.setAttribute("style", "color: #555;"); - - video_container.appendChild(h1); - } - - if (upload_date) { - try { - const date = new Date(upload_date).toString(); - const date_div = document.createElement("div"); - - date_div.textContent = `Uploaded: ${date}`; - date_div.setAttribute("style", "font-size: 14px; font-weight: bold; margin-bottom: 5px;"); - - video_container.appendChild(date_div); - } catch(e) { - console.log("Error parsing content upload date", e); - } - } - - if (description) { - const description_div = document.createElement("div"); - - description_div.textContent = HTML_decode(description); - description_div.setAttribute("style", "white-space: pre;"); - - video_container.appendChild(description_div); - } -} - -function show_video_from_query(response) -{ - try { - var result = Object.values(JSON.parse(response).result)[0]; - - if (result.value_type !== "stream") - return; - - var date = result.timestamp * 1000; - var description = result.value.description; - var title = result.value.title; - const name = encodeURIComponent(result.name); - var url = `https://odysee.com/$/stream/${name}/${result.claim_id}`; - } catch (e) { - return; - } - - show_video(url, title, date, description); -} - -function fetch_show_video(name, claim_id) -{ - const payload = { - jsonrpc: "2.0", - method: "resolve", - params: { - urls: [`lbry://${decodeURIComponent(name)}#${claim_id}`], - include_purchase_receipt: true - }, - id: Math.round(Math.random() * 10**14) - }; - - perform_ajax("POST", odysee_resolve_url, show_video_from_query, - () => null, JSON.stringify(payload)); -} - -if (data && typeof data === "object" && data["@type"] === "VideoObject") { - show_video(data.contentUrl, data.name, data.uploadDate, data.description); -} else { - const match = /\/([^/]+):([0-9a-f]+)$/.exec(document.URL); - if (match) - fetch_show_video(match[1], match[2]); -} - -/* Show search. */ - -const search_input = document.createElement("input"); -const search_submit = document.createElement("button"); -const search_form = document.createElement("form"); -const error_div = document.createElement("div"); - -search_submit.textContent = "Search Odysee"; - -search_form.setAttribute("style", "margin: 15px 0 0 0;"); - -search_form.appendChild(search_input); -search_form.appendChild(search_submit); - -error_div.textContent = "Failed to perform search :c"; -error_div.setAttribute("style", "display: none;"); - -body.appendChild(search_form); -body.appendChild(error_div); - -/* Replace the UI. */ - -document.documentElement.replaceChild(body, document.body); - -/* Add the logic of performing search and showing results. */ - -function show_error() -{ - error_div.setAttribute("style", "color: #b44;"); -} - -function clear_error() -{ - error_div.setAttribute("style", "display: none;"); -} - -let results_div = null; -const load_more_but = document.createElement("button"); - -load_more_but.textContent = "Load more"; - -function show_search_entries(new_results_div, response) -{ - try { - var results = Object.values(JSON.parse(response).result); - } catch (e) { - console.log("Failed to parse search response :c", - "Bad response format from api.na-backend.odysee.com."); - show_error(); - return; - } - - for (const result of results) { - try { - if (result.value_type !== "stream") - continue; - - let channel_specifier = ""; - let channel_name = null; - try { - channel_name = result.signing_channel.name; - const channel_name_enc = encodeURIComponent(channel_name); - const channel_digit = result.signing_channel.claim_id[0]; - channel_specifier = `${channel_name_enc}:${channel_digit}`; - } catch (e) { - } - const video_name = encodeURIComponent(result.name); - const video_id = result.claim_id[0]; - - const result_a = document.createElement("a"); - const thumbnail = document.createElement("img"); - const title_span = document.createElement("span"); - const uploader_div = document.createElement("div"); - const description_div = document.createElement("div"); - - thumbnail.setAttribute("style", "width: 100px; height: auto;"); - thumbnail.setAttribute("alt", result.value.thumbnail.url); - thumbnail.src = result.value.thumbnail.url; - - title_span.setAttribute("style", "font-weight: bold;"); - title_span.textContent = result.value.title; - - uploader_div.setAttribute("style", "margin-left: 5px; font-size: 21px; color: #555;"); - uploader_div.textContent = channel_name; - - description_div.setAttribute("style", "white-space: pre;"); - description_div.textContent = result.value.description; - - result_a.setAttribute("style", "display: block; width: 100%; text-decoration: none; color: #333; margin: 8px; border-style: solid; border-width: 3px 0 0 0; border-color: #7aa;"); - result_a.href = `https://odysee.com${channel_specifier}/${video_name}:${video_id}`; - - if (result.value.thumbnail.url) - result_a.appendChild(thumbnail); - result_a.appendChild(title_span); - if (channel_name) - result_a.appendChild(uploader_div); - result_a.appendChild(description_div); - - new_results_div.appendChild(result_a); - } - catch(e) { - console.log(e); - } - } - - clear_error(); - - if (results_div) - results_div.remove(); - - results_div = new_results_div; - - body.appendChild(results_div); - body.appendChild(load_more_but); - - enable_search_form(); -} - -function search_ajax_error(url) -{ - console.log(`Failed to query ${url} :c`); - show_error(); - enable_search_form(); -} - -function get_detailed_search_entries(new_results_div, response) -{ - /* TODO: Simplify JSON handling using sanitize_JSON.js from Hachette. */ - try { - var response_data = JSON.parse(response); - if (!Array.isArray(response_data)) - throw "Bad response format from lighthouse.odysee.com."; - } catch (e) { - show_error(); - console.log("Failed to parse search response :c", e); - enable_search_form(); - return; - } - - const callback = r => show_search_entries(new_results_div, r); - const lbry_urls = []; - - for (const search_result of response_data) { - if (!search_result.claimId || !search_result.name) - continue; - lbry_urls.push(`lbry://${search_result.name}#${search_result.claimId}`); - } - - const payload = { - jsonrpc: "2.0", - method: "resolve", - params: { - urls: lbry_urls, - include_purchase_receipt: true - }, - id: Math.round(Math.random() * 10**14) - }; - - const url = odysee_resolve_url; - - perform_ajax("POST", url, callback, () => search_ajax_error(url), - JSON.stringify(payload)); -} - -function get_search_entries(new_results_div, query, from) -{ - const callback = r => get_detailed_search_entries(new_results_div, r); - const url = `${lighthouse_search_url}?s=${encodeURIComponent(query)}&size=20&from=${from}&claimType=file,channel&nsfw=false&free_only=true`; - - new_results_div.setAttribute("data-fetched", parseInt(from) + 20); - - perform_ajax("GET", url, callback, () => search_ajax_error(url)); -} - -function search(event) -{ - if (event) - event.preventDefault(); - - if (!/[^\s]/.test(search_input.value)) - return; - - disable_search_form(); - - const new_results_div = document.createElement("div"); - - new_results_div.setAttribute("data-query", search_input.value); - - get_search_entries(new_results_div, search_input.value, 0); -} - -function search_more() -{ - disable_search_form(); - - get_search_entries(results_div, results_div.getAttribute("data-query"), - results_div.getAttribute("data-fetched")); -} - -load_more_but.addEventListener("click", search_more); - -function enable_search_form() -{ - search_form.addEventListener("submit", search); - search_submit.removeAttribute("disabled"); - if (results_div) - load_more_but.removeAttribute("disabled"); -} - -function disable_search_form() -{ - search_form.removeEventListener("submit", search); - search_submit.setAttribute("disabled", ""); - load_more_but.setAttribute("disabled", ""); -} - - -enable_search_form(); - - -const match = /^[^?]*search\?q=([^&]+)/.exec(document.URL) -if (match) { - search_input.value = decodeURIComponent(match[1]); - search(); -} |