UploadMode tweaks + add Nozomi + add x.com as twitter domain

pull/17/head
neobooru 2024-06-25 23:37:35 +02:00
parent df9b1b2cfe
commit 17c84b16db
10 changed files with 387 additions and 250 deletions

View File

@ -1,6 +1,6 @@
{
"name": "neo-scraper",
"version": "0.8.0",
"version": "0.9.0",
"description": "Scrape a booru-like post object from the DOM.",
"type": "module",
"main": "dist/index.js",
@ -39,7 +39,7 @@
"jest-ts-webcompat-resolver": "^1.0.0",
"jsdom": "^15.2.1",
"prettier": "2.5.1",
"puppeteer": "^21.5.0",
"puppeteer": "^22.12.0",
"ts-jest": "^29.1.1",
"ts-node": "^10.9.1",
"typescript": "^4.9.5"
@ -52,7 +52,12 @@
"preset": "./jest.preset.cjs",
"resolver": "jest-ts-webcompat-resolver",
"transform": {
"^.+\\.tsx?$": "ts-jest"
"^.+\\.tsx?$": [
"ts-jest",
{
"tsconfig": "tsconfig.test.json"
}
]
},
"moduleFileExtensions": [
"ts",
@ -62,11 +67,6 @@
"testRegex": "^.+\\.test\\.ts$",
"setupFilesAfterEnv": [
"./src/test/jest.setup.ts"
],
"globals": {
"ts-jest": {
"tsconfig": "tsconfig.test.json"
}
}
]
}
}

File diff suppressed because it is too large Load Diff

View File

@ -16,6 +16,7 @@ export default class NeoScraper {
new engines.Gelbooru(),
new engines.Inkbunny(),
new engines.Moebooru(),
new engines.Nozomi(),
new engines.Philomena(),
new engines.Pixiv(),
new engines.Reddit(),

View File

@ -5,6 +5,7 @@ export type ContentType = "image" | "video";
export type UploadMode = "content" | "url";
export class ScrapedPost {
name: string | undefined = undefined;
contentUrl = "";
pageUrl = "";
contentType: ContentType = "image";
@ -17,6 +18,7 @@ export class ScrapedPost {
referrer: string | undefined;
extraContentUrl: string | undefined;
cookies: Cookies | undefined;
uploadMode: UploadMode = "url";
}
export class ScrapedTag {
@ -82,8 +84,6 @@ export interface ScrapeEngine {
notes: string[];
supportedHosts: string[];
get uploadMode(): UploadMode;
canImport(url: Location): boolean;
scrapeDocument(document: Document): ScrapeResult;
}
@ -94,10 +94,6 @@ export abstract class ScrapeEngineBase implements ScrapeEngine {
abstract notes: string[];
abstract supportedHosts: string[];
get uploadMode(): UploadMode {
return "url";
}
canImport(url: Location): boolean {
return this.supportedHosts.indexOf(url.host) != -1;
}

View File

@ -1,4 +1,4 @@
import { ScrapeEngineBase, ScrapeResult, ScrapedPost, ScrapedTag, ScrapeEngineFeature, UploadMode } from "../ScrapeEngine.js";
import { ScrapeEngineBase, ScrapeResult, ScrapedPost, ScrapedTag, ScrapeEngineFeature } from "../ScrapeEngine.js";
import { TagCategory } from "../BooruTypes.js";
import { createNoteFromDanbooruArticle, guessContentType } from "../Utility.js";
@ -8,13 +8,10 @@ export default class Danbooru extends ScrapeEngineBase {
notes = [];
supportedHosts = ["danbooru.donmai.us", "safebooru.donmai.us"];
override get uploadMode(): UploadMode {
return "content";
}
scrapeDocument(document: Document): ScrapeResult {
const result = new ScrapeResult(this.name);
const post = new ScrapedPost();
post.uploadMode = "content";
post.pageUrl = document.location.href;
// Set image url

View File

@ -1,4 +1,4 @@
import { ScrapeEngineBase, ScrapeResult, ScrapedPost, ScrapeEngineFeature, UploadMode } from "../ScrapeEngine.js";
import { ScrapeEngineBase, ScrapeResult, ScrapedPost, ScrapeEngineFeature } from "../ScrapeEngine.js";
import { parseResolutionString } from "../Utility.js";
import Cookies from "js-cookie";
@ -8,10 +8,6 @@ export default class Ehentai extends ScrapeEngineBase {
notes = ["Rating is assumed to be unsafe."];
supportedHosts = ["e-hentai.org", "exhentai.org"];
override get uploadMode(): UploadMode {
return "content";
}
scrapeDocument(document: Document): ScrapeResult {
const result = new ScrapeResult(this.name);
const post = new ScrapedPost();

View File

@ -27,7 +27,7 @@ export default class Fallback extends ScrapeEngineBase {
post.pageUrl = document.location.href;
post.contentUrl = document.location.href;
post.contentType = "video";
result.posts.push(post);
result.tryAddPost(post);
return result;
}
@ -50,10 +50,16 @@ export default class Fallback extends ScrapeEngineBase {
if (largestMediaElement) {
const post = new ScrapedPost();
post.name = "Upload as URL";
post.pageUrl = document.location.href;
post.contentUrl = largestMediaElement.contentUrl;
post.contentType = largestMediaElement.contentType;
result.posts.push(post);
result.tryAddPost(post);
const clone = Object.assign({}, post);
clone.name = "Upload as content";
clone.uploadMode = "content";
result.tryAddPost(clone);
}
return result;

49
src/engines/Nozomi.ts Normal file
View File

@ -0,0 +1,49 @@
import { ScrapeEngineBase, ScrapeResult, ScrapedPost, ScrapedTag, ScrapeEngineFeature } from "../ScrapeEngine.js";
import { TagCategory } from "../BooruTypes.js";
export default class e621 extends ScrapeEngineBase {
name = "nozomi";
features: ScrapeEngineFeature[] = ["content", "tags", "tag_category"];
notes = ["Image preview might not work due to hotlink protection."];
supportedHosts = ["nozomi.la"];
scrapeDocument(document: Document): ScrapeResult {
const result = new ScrapeResult(this.name);
const post = new ScrapedPost();
post.pageUrl = document.location.href;
// Set image url
const downloadEl = document.querySelector(".post a") as HTMLAnchorElement;
post.contentUrl = downloadEl?.href;
// Set tags
const tagEls = Array.from(document.querySelectorAll(".sidebar li")).map((x) => x as HTMLLIElement);
for (const el of tagEls) {
const tagName = el.innerText;
let category: TagCategory | undefined;
switch (el.querySelector("a")?.className) {
// https://e621.net/help/api#tags_listing
case "copyright":
category = "copyright";
break;
case "character":
category = "character";
break;
case "artist":
category = "artist";
break;
}
if (tagName) {
const tag = new ScrapedTag(tagName, category);
post.tags.push(tag);
}
}
result.tryAddPost(post);
return result;
}
}

View File

@ -15,7 +15,7 @@ export default class Twitter extends ScrapeEngineBase {
name = "twitter";
features: ScrapeEngineFeature[] = ["content"];
notes = [];
supportedHosts = ["twitter.com", "mobile.twitter.com"];
supportedHosts = ["twitter.com", "mobile.twitter.com", "x.com"];
scrapeDocument(document: Document): ScrapeResult {
const result = new ScrapeResult(this.name);

View File

@ -7,6 +7,7 @@ export { default as FurAffinity } from "./FurAffinity.js";
export { default as Gelbooru } from "./Gelbooru.js";
export { default as Inkbunny } from "./Inkbunny.js";
export { default as Moebooru } from "./Moebooru.js";
export { default as Nozomi } from "./Nozomi.js";
export { default as Philomena } from "./Philomena.js";
export { default as Pixiv } from "./Pixiv.js";
export { default as Reddit } from "./Reddit.js";