Ctrl K
ComunidadGuías…

tests/videoEmbed.test.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
// FILM IN A NOTE — the pure half (shared/mediaEmbeds.ts, shared/videoEmbeds.ts,
// shared/fileKinds.ts, shared/attachments.ts, shared/limits.ts,
// shared/embedActions.ts): which
// names are films, what `#t=` and `|poster=` say, the fallback decision a
// browser's `canPlayType` makes, what the server calls each film, and the
// embed menu's rows for one.
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import { isAudioName, isTimedMediaName, isVideoName } from "../shared/mediaEmbeds.ts";
import {
  mediaFragmentHash,
  parseMediaFragment,
  parseVideoAlias,
  posterNamesIn,
  videoPlayable,
  videoProbeTypes,
} from "../shared/videoEmbeds.ts";
import { attachmentKindOf, contentTypeFor, isAcceptedAttachment } from "../shared/attachments.ts";
import { UPLOAD_MAX_MB, VIDEO_UPLOAD_MAX_MB, uploadCapMb } from "../shared/limits.ts";
import { embedMenuActions } from "../shared/embedActions.ts";

describe("the film kind", () => {
  it("knows the six containers, case-blind, and nothing else", () => {
    for (const name of ["clip.mp4", "Clip.MOV", "a b.webm", "x.m4v", "film.mkv", "old.ogv", "  media/clip.mp4 "]) {
      assert.equal(isVideoName(name), true, name);
    }
    for (const name of ["lecture.mp3", "pic.png", "notes.md", "mp4", "clip.mp4.md"]) assert.equal(isVideoName(name), false, name);
  });
  it("a WebM is both: a film to draw, a sound a `#t=` link may seek", () => {
    assert.equal(isVideoName("2026-09-23 1402.webm"), true);
    assert.equal(isAudioName("2026-09-23 1402.webm"), true);
    assert.equal(isTimedMediaName("clip.mp4"), true);
    assert.equal(isTimedMediaName("lecture.mp3"), true);
    assert.equal(isTimedMediaName("paper.pdf"), false);
  });
  it("every film extension is a video in the tree and is served with its own type", () => {
    const want: Record<string, string> = {
      mp4: "video/mp4",
      m4v: "video/mp4",
      webm: "video/webm",
      mov: "video/quicktime",
      mkv: "video/x-matroska",
      ogv: "video/ogg",
    };
    for (const [ext, type] of Object.entries(want)) {
      assert.equal(attachmentKindOf(`clip.${ext}`), "video", ext);
      assert.equal(contentTypeFor(`clip.${ext}`), type, ext);
      assert.equal(isAcceptedAttachment(`clip.${ext}`), true, `${ext} may be uploaded`);
    }
  });
  it("a film has its own upload cap, larger than a picture's", () => {
    assert.ok(VIDEO_UPLOAD_MAX_MB > UPLOAD_MAX_MB);
    assert.equal(uploadCapMb("mp4"), VIDEO_UPLOAD_MAX_MB);
    assert.equal(uploadCapMb("MKV"), VIDEO_UPLOAD_MAX_MB);
    assert.equal(uploadCapMb("png"), UPLOAD_MAX_MB);
    assert.equal(uploadCapMb(""), UPLOAD_MAX_MB);
  });
});

describe("`#t=` on a film", () => {
  it("reads a start, a range, a range from the top, clock times and Arabic digits", () => {
    assert.deepEqual(parseMediaFragment("t=12"), { start: 12, end: null });
    assert.deepEqual(parseMediaFragment("t=12,30"), { start: 12, end: 30 });
    assert.deepEqual(parseMediaFragment("t=1:05,1:30"), { start: 65, end: 90 });
    assert.deepEqual(parseMediaFragment("t=,30"), { start: 0, end: 30 });
    assert.deepEqual(parseMediaFragment("t=١٢,٣٠"), { start: 12, end: 30 });
  });
  it("refuses what is not a time, and a range that ends before it starts", () => {
    for (const bad of [null, "", "t=", "t=a", "t=30,12", "t=12,12", "t=12,", "page=3", "Heading"]) {
      assert.equal(parseMediaFragment(bad), null, String(bad));
    }
  });
  it("writes the fragment back as the URL hash the player loads", () => {
    assert.equal(mediaFragmentHash({ start: 12, end: null }), "#t=12");
    assert.equal(mediaFragmentHash({ start: 12, end: 30 }), "#t=12,30");
    assert.equal(mediaFragmentHash({ start: 1.23456, end: null }), "#t=1.235");
    // No time named: the first frame, which is what makes it the poster.
    assert.equal(mediaFragmentHash(null), "#t=0.001");
  });
});

describe("`|…` on a film", () => {
  it("is a width, a poster, both in either order, and nothing else", () => {
    assert.deepEqual(parseVideoAlias(null), { width: null, poster: null });
    assert.deepEqual(parseVideoAlias("480"), { width: 480, poster: null });
    assert.deepEqual(parseVideoAlias("poster=frame.jpg"), { width: null, poster: "frame.jpg" });
    assert.deepEqual(parseVideoAlias("480|poster=stills/a frame.png"), { width: 480, poster: "stills/a frame.png" });
    assert.deepEqual(parseVideoAlias("poster = f.jpg | 320"), { width: 320, poster: "f.jpg" });
    assert.deepEqual(parseVideoAlias("My holiday"), { width: null, poster: null }, "a caption does no harm");
    assert.deepEqual(parseVideoAlias("poster="), { width: null, poster: null });
  });
  it("finds every poster a body's film embeds name — and no picture's alias", () => {
    const body = "![[clip.mp4|poster=a.jpg]]\n![[b.webm#t=3|480|poster=b.png]] and ![[pic.png|poster=no.jpg]]\n![[clip.mp4|poster=a.jpg]]";
    assert.deepEqual(posterNamesIn(body), ["a.jpg", "b.png"]);
  });
});

describe("the fallback decision", () => {
  // A stand-in for HTMLMediaElement.canPlayType on a browser that plays
  // WebM and MP4 and says nothing for QuickTime or Matroska.
  const chromeLike = (type: string): string => (type === "video/webm" || type === "video/mp4" ? "maybe" : "");
  const nothing = (): string => "";
  it("asks the containers a film is most likely to be", () => {
    assert.deepEqual(videoProbeTypes("a.mov"), ["video/quicktime", "video/mp4"]);
    assert.deepEqual(videoProbeTypes("a.mkv"), ["video/x-matroska", "video/webm"]);
    assert.deepEqual(videoProbeTypes("a.txt"), []);
  });
  it("draws a player for anything the browser says it may play", () => {
    for (const name of ["a.mp4", "a.m4v", "a.webm", "a.mov", "a.mkv"]) assert.equal(videoPlayable(name, chromeLike), true, name);
  });
  it("falls back to the card when the browser has no answer", () => {
    assert.equal(videoPlayable("a.ogv", chromeLike), false);
    for (const name of ["a.mp4", "a.mkv"]) assert.equal(videoPlayable(name, nothing), false, name);
    assert.equal(videoPlayable("notes.md", () => "probably"), false, "not a film at all");
  });
});

describe("the embed menu on a film", () => {
  const base = { admin: true, resolved: true, clipboardImage: true, clipboardText: true, canEdit: true, touch: false };
  it("offers the file's verbs and never Copy image", () => {
    const rows = embedMenuActions({ ...base, kind: "video" });
    assert.ok(!rows.includes("copyImage"));
    for (const verb of ["copyLink", "copyMarkdown", "copyPath", "open", "reveal", "saveAs", "rename", "remove"] as const) {
      assert.ok(rows.includes(verb), verb);
    }
  });
  it("on a finger, Move… stands in for the drag and Reveal goes", () => {
    const rows = embedMenuActions({ ...base, kind: "video", touch: true });
    assert.ok(rows.includes("move"));
    assert.ok(!rows.includes("reveal"));
  });
  it("a visitor gets Copy link, Open and Save as", () => {
    const rows = embedMenuActions({ ...base, kind: "video", admin: false, canEdit: false }).filter((r) => r !== null);
    assert.deepEqual(rows, ["copyLink", "open", "saveAs"]);
  });
});