feat(userscript): add comix.to site adapter

This commit is contained in:
2026-08-03 16:57:14 +07:00
parent eeb601cbe2
commit e392ec3de0
2 changed files with 155 additions and 2 deletions
+69
View File
@@ -44,8 +44,10 @@ globalThis.document = {
const {
stripBuildHash,
comixSeriesId,
asura,
demonic,
comix,
anchorsFromHTML,
statusOf,
} = require("../manga-bookmark.user.js");
@@ -166,6 +168,73 @@ test("demonic.latestChapterFromAnchors parses chaptered.php links, including &am
assert.deepEqual(best, { num: 12, label: "Chapter 12" });
});
// ============================================================
// comix — the id prefix is the stable identity; the slug tail is a title
// rendering that changes when a series is renamed.
// ============================================================
test("comixSeriesId keeps only the prefix before the first dash", () => {
assert.equal(comixSeriesId("n8we-dungeons-and-crayons"), "n8we");
assert.equal(comixSeriesId("20xzd-the-baddest-villainess-is-back"), "20xzd");
});
test("comixSeriesId leaves a bare id untouched", () => {
assert.equal(comixSeriesId("n8we"), "n8we");
});
test("comix detects a series page", () => {
metaTags = { "og:title": "Dungeons and Crayons" };
const p = comix.detect(loc("https://comix.to/title/n8we-dungeons-and-crayons"));
assert.equal(p.type, "series");
assert.equal(p.site, "comix");
assert.equal(p.seriesId, "n8we");
assert.equal(p.title, "Dungeons and Crayons");
assert.equal(p.seriesUrl, "https://comix.to/title/n8we-dungeons-and-crayons");
assert.equal(p.chapterNum, null);
});
test("comix detects a chapter page and strips the Ch. suffix from the title", () => {
metaTags = { "og:title": "Dungeons and Crayons · Ch.80" };
const p = comix.detect(
loc("https://comix.to/title/n8we-dungeons-and-crayons/11139891-chapter-80")
);
assert.equal(p.type, "chapter");
assert.equal(p.seriesId, "n8we");
assert.equal(p.title, "Dungeons and Crayons");
assert.equal(p.chapterNum, 80);
assert.equal(p.chapterLabel, "Chapter 80");
assert.equal(p.seriesUrl, "https://comix.to/title/n8we-dungeons-and-crayons");
});
test("comix parses decimal chapter numbers", () => {
metaTags = { "og:title": "Dungeons and Crayons · Ch.80.5" };
const p = comix.detect(
loc("https://comix.to/title/n8we-dungeons-and-crayons/11139891-chapter-80.5")
);
assert.equal(p.chapterNum, 80.5);
});
test("comix ignores unrelated paths", () => {
assert.equal(comix.detect(loc("https://comix.to/browse")).type, "other");
});
test("comix takes the max chapter and ignores other series' links", () => {
const anchors = anchorsFromHTML(`
<a href="/title/n8we-dungeons-and-crayons/11123327-chapter-79">Chapter 79</a>
<a href="/title/n8we-dungeons-and-crayons/11139891-chapter-80">Chapter 80</a>
<a href="/title/n8we-dungeons-and-crayons/10794753-chapter-78">Chapter 78</a>
<a href="/title/qqwrm-full-time-awakening/99999999-chapter-999">Chapter 999</a>
`);
assert.deepEqual(comix.latestChapterFromAnchors(anchors, "n8we"), {
num: 80,
label: "Chapter 80",
});
});
test("comix latest returns null when no chapter links are present", () => {
assert.equal(comix.latestChapterFromAnchors(anchorsFromHTML("<a href='/browse'>x</a>"), "n8we"), null);
});
// ============================================================
// Shared helpers
// ============================================================