Commit e92ed5e1 authored by TheTechRobo's avatar TheTechRobo
Browse files

Support multiple links on frontend

parent 1ea97c3f
Loading
Loading
Loading
Loading
+9 −2
Original line number Diff line number Diff line
import dataclasses, itertools
from quart import Quart, render_template, request, Response, redirect, send_from_directory, url_for
import re, yaml, json
import lostmediafinder
@@ -126,8 +127,14 @@ async def coerce_to_id_endpoint():
async def load_thing():
    if not request.args.get("id"):
        return "Missing id parameter", 400
    t = await youtube(3, request.args['id'], "youtube", jsn=False)
    return await render_template("noscript/fid.j2", resp=t)
    t = await youtube(5, request.args['id'], "youtube", jsn=False)
    assert isinstance(t, lostmediafinder.YouTubeResponse)
    t.keys = list(itertools.chain(
        (k for k in t.keys if k.archived and not k.error),
        (k for k in t.keys if k.error),
        (k for k in t.keys if not k.error and not k.archived)
    ))
    return await render_template("noscript/fid.j2", resp=t, list=list, asd=dataclasses.asdict)

@app.route("/")
async def index():
+6 −4
Original line number Diff line number Diff line
@@ -200,12 +200,12 @@ class ArchiveOrgDetails(YouTubeService):
                archived = True
                j = await resp.json()
                lien = f"https://archive.org/details/{j['item']}"
                note = "This is a generic channel item. It may contain multiple videos."
                lnote = "This is a generic channel item. It may contain multiple videos."
                yield Link(
                    url = lien,
                    contains = LinkContains(True, True, True, True, True),
                    title = "Item",
                    note = note,
                    note = lnote,
                )

        if not archived:
@@ -271,11 +271,13 @@ class ArchiveOrgCDX(YouTubeService):
        results.sort(key=lambda x: get_int(x[2]))

        archived = False
        for result in results:
        # Limit to one result
        # TODO: maybe add a note about this?
        for result in results[:1]:
            yield Link(
                url = f"https://web.archive.org/web/{result[1]}/{result[2]}",
                contains = LinkContains(thumbnail = True),
                title = "Thumbnail"
                title = "Thumbnail",
            )
            archived = True

+7 −3
Original line number Diff line number Diff line
@@ -91,6 +91,7 @@ class Service(JSONDataclass):
                    if not includeRaw:
                        i.rawraw = None
                    i.available = links
                    i.__post_init__()
                yield i
        except Exception as ename: # pylint: disable=broad-except
            note = f"An error occured while retrieving data from {cls.getName()}."
@@ -249,6 +250,7 @@ class Link(JSONDataclass):

    note: typing.Optional[str] = None
    type: str = "link"
    classname: str = dataclasses.field(init = False)


@dataclasses.dataclass
@@ -372,10 +374,12 @@ class YouTubeResponse(JSONDataclass):
            headers["User-Agent"] = user_agent
        done = asyncio.Event()

        async def iterate(gen):
        async def iterate(name, gen):
            nonlocal taskCount
            try:
                async for i in gen:
                    if isinstance(i, Link):
                        i.classname = name
                    await queue.put(i)
            finally:
                taskCount -= 1
@@ -386,9 +390,9 @@ class YouTubeResponse(JSONDataclass):
            svcs = {}
            for service in services:
                svcs[service.__name__] = service.getName()
                coroutines.append(service.run(id, session, includeRaw=includeRaw))
                coroutines.append((service.__name__, service.run(id, session, includeRaw=includeRaw)))
            taskCount = len(svcs)
            coroutines = [asyncio.create_task(iterate(coro)) for coro in coroutines]
            coroutines = [asyncio.create_task(iterate(name, coro)) for name, coro in coroutines]
            yield svcs

            while not done.is_set() or not queue.empty():
+89 −33
Original line number Diff line number Diff line
@@ -26,8 +26,71 @@ function getVideoId(videoInput) {
    return false;
}

function makeLinkElement(link) {
    let url = link.url;
    let contains = link.contains;
    let title = link.title;
    let note = link.note;

    let elem = document.createElement("li");
    let span = document.createElement("span");
    let span2 = document.createElement("span");
    let abbr = document.createElement("abbr");
    let a = document.createElement("a");
    span.appendChild(abbr);
    span.appendChild(span2);
    elem.appendChild(span);
    elem.appendChild(a);

    const possible_contains = ["video", "metadata", "comments", "thumbnail", "captions"];
    let actual_contains = [];
    possible_contains.forEach((i) => {
        if (contains[i]) actual_contains.push(i);
    });
    let contains_str;
    if (actual_contains.length == 1) {
        contains_str = "Contains " + actual_contains[0];
    } else {
        let last = actual_contains.pop();
        contains_str = "May contain " + actual_contains.join(", ") + ", and " + last;
    }
    abbr.title = contains_str;

    let br = title.indexOf(" (");
    if (br == -1) br = title.length;
    abbr.innerText = title.substring(0, br);
    span2.innerText = title.substring(br) + ": ";

    a.href = url;
    if (url.length > 50) url = url.substring(0, 50) + "";
    a.innerText = url;

    if (note !== null && note !== "") {
        elem.appendChild(document.createElement("br"));
        let ne = document.createElement("p");
        ne.innerText = note;
        elem.appendChild(ne);
    }

    return elem;
}

function makeLoadingElement(title) {
    const li = document.createElement("li");
    // I suppose we could put the list of links inline like how we used to do it with the single link.
    // But that wouldn't allow for adding a note underneath, and I kind of like having the actual URL shown.
    // Perhaps a "compact mode" should be added?
    li.innerHTML = `
        <b>${escapeHTML(title)}</b>:
        <span class="result"><img src="/static/loading.gif" style="height: 1em;" /> Loading...</span>
        <ul class="links"></ul>
    `;
    li.setAttribute("data-status", "loading");
    return li;
}

function makeServiceEntry(result) {
    var colour;
    let colour;
    if (result.error) {
        colour = "white";
    } else if (result.archived && result.metaonly) {
@@ -38,7 +101,7 @@ function makeServiceEntry(result) {
        colour = "red";
    }

    var isarchived = result.archived ? "Available" : "Not Available";
    let isarchived = result.archived ? "Available" : "Not Available";
    if (result.error !== null) {
        isarchived = "Unknown";
        result.note = result.note + result.error;
@@ -46,9 +109,8 @@ function makeServiceEntry(result) {

    let archived = `<span class='${colour}'>${isarchived}</span>`;
    let metaonly = (result.metaonly && result.archived) ? " (metadata only) " : " ";
    let comments = (result.archived && result.comments) ? " (incl. comments) " : " ";
    let lien = result.available ? `<a href="${result.available}">(link)</a>` : "";
    return `${archived}${metaonly}${comments}${lien}<br />${result.note}`;
    let comments = (result.archived && result.comments) ? " (may include comments) " : " ";
    return `${archived}${metaonly}${comments}<br />${result.note}`;
}

// https://stackoverflow.com/a/48054293/9654083
@@ -58,16 +120,6 @@ function escapeHTML(unsafeText) {
    return div.innerHTML;
}

function makeLoadingElement(title) {
    const li = document.createElement("li");
    li.innerHTML = `
        <b>${escapeHTML(title)}</b>:
        <span class="result"><img src="/static/loading.gif" style="height: 1em;" /> Loading...</span>
    `;
    li.setAttribute("data-status", "loading");
    return li;
}

let g_stream = null;

function finish(vid1) {
@@ -93,7 +145,7 @@ function finish(vid1) {

    // https://www.behance.net/gallery/31234507/Open-source-Loading-GIF-Icons-Vol-1
    dataDiv.innerHTML += `<div style="display: flex; gap: 12px;"><img src="/static/loading.gif" width="25" height="25" /> Loading could take up to 30 seconds.</div>`;
    fetch(`api/v4/youtube/${vid}?stream`)
    fetch(`api/v5/youtube/${vid}?stream`)
        .then((response) => {
            if (response.status === 410 || response.status === 404) {
                dataDiv.innerHTML = `<span style="color: red;">API version is not supported - this should never happen, please report this!</span>`;
@@ -162,6 +214,7 @@ function finish(vid1) {
                            return;
                        }
                        const cln = data.classname;
                        if (data.type === "service") {
                            if (!data.archived) {
                                numArchived--;
                                if (data.error === null) {
@@ -181,6 +234,9 @@ function finish(vid1) {
                            }
                            elements[cln].querySelector(".result").innerHTML = makeServiceEntry(data);
                            elements[cln].setAttribute("data-status", "done");
                        } else if (data.type === "link") {
                            elements[cln].querySelector(".links").appendChild(makeLinkElement(data));
                        }
                        break;
                    }
                    case possible_states.Verdict: {
@@ -231,7 +287,7 @@ function finish(vid1) {
            return pump();
        })
        .catch((e) => {
            dataDiv.innerHTML = '<span class="red" style="background-color: #fff;">An error occurred, check your internet connection</span>';
            dataDiv.innerHTML = '<span class="red" style="background-color: #fff;">An error occurred. Please check your internet connection.</span>';
            throw (e);
        })
        .finally(() => {
+6 −1
Original line number Diff line number Diff line
@@ -162,6 +162,11 @@ p {
  }
}

#data > ul {
#data ul, .links {
  margin-bottom: 0;
  margin-top: 0.75rem;
}

#data > ul {
  margin-top: 0;
}
Loading