diff options
| -rw-r--r-- | package.json | 2 | ||||
| -rw-r--r-- | src/api/e621/index.ts | 41 | ||||
| -rw-r--r-- | src/index.ts | 2 | ||||
| -rw-r--r-- | src/services/dedupe.ts | 65 | ||||
| -rw-r--r-- | src/services/jobs.ts (renamed from src/jobs.ts) | 6 | ||||
| -rw-r--r-- | tsconfig.json | 1 | ||||
| -rw-r--r-- | yarn.lock | 10 | 
7 files changed, 85 insertions, 42 deletions
diff --git a/package.json b/package.json index b6632bb..8cf504a 100644 --- a/package.json +++ b/package.json  | |||
| @@ -12,7 +12,9 @@ | |||
| 12 | "@types/sharp": "^0.29.2", | 12 | "@types/sharp": "^0.29.2", | 
| 13 | "file-type": "^16.5.3", | 13 | "file-type": "^16.5.3", | 
| 14 | "form-data": "^4.0.0", | 14 | "form-data": "^4.0.0", | 
| 15 | "fp-ts": "^2.11.5", | ||
| 15 | "got": "^11.8.2", | 16 | "got": "^11.8.2", | 
| 17 | "io-ts": "^2.2.16", | ||
| 16 | "nanoid": "^3.1.30", | 18 | "nanoid": "^3.1.30", | 
| 17 | "sharp": "^0.29.1", | 19 | "sharp": "^0.29.1", | 
| 18 | "ts-command-line-args": "^2.1.0", | 20 | "ts-command-line-args": "^2.1.0", | 
diff --git a/src/api/e621/index.ts b/src/api/e621/index.ts index 5c5fd2a..a8abbcf 100644 --- a/src/api/e621/index.ts +++ b/src/api/e621/index.ts  | |||
| @@ -1,8 +1,7 @@ | |||
| 1 | import got from "got"; | 1 | import got from "got"; | 
| 2 | import config from "../../config"; | 2 | import config from "../../config"; | 
| 3 | import fs from "fs/promises"; | ||
| 4 | import path from "path"; | ||
| 5 | import delay from "../../util/delay"; | 3 | import delay from "../../util/delay"; | 
| 4 | import dedupe from "../../services/dedupe"; | ||
| 6 | 5 | ||
| 7 | export interface GetPostQuery { | 6 | export interface GetPostQuery { | 
| 8 | tags: readonly string[]; | 7 | tags: readonly string[]; | 
| @@ -34,35 +33,6 @@ export const client = got.extend({ | |||
| 34 | }, | 33 | }, | 
| 35 | }); | 34 | }); | 
| 36 | 35 | ||
| 37 | const dedupePath = path.join(__dirname, "e926dedupe.json"); | ||
| 38 | const dedupeMax = 50; | ||
| 39 | let dedupeDb: number[] | undefined; | ||
| 40 | |||
| 41 | async function loadDedupeDb() { | ||
| 42 | if (dedupeDb) { | ||
| 43 | return; | ||
| 44 | } | ||
| 45 | |||
| 46 | try { | ||
| 47 | await fs.stat(dedupePath); | ||
| 48 | } catch { | ||
| 49 | await saveDedupeDb(); | ||
| 50 | } | ||
| 51 | |||
| 52 | const d = await fs.readFile(dedupePath, "utf8"); | ||
| 53 | const dd = JSON.parse(d); | ||
| 54 | |||
| 55 | if (dd instanceof Array) { | ||
| 56 | dedupeDb = dd.slice(-1 * dedupeMax); | ||
| 57 | } else { | ||
| 58 | dedupeDb = []; | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | async function saveDedupeDb() { | ||
| 63 | await fs.writeFile(dedupePath, JSON.stringify(dedupeDb ?? []), "utf8"); | ||
| 64 | } | ||
| 65 | |||
| 66 | export async function getPostById(id: number) { | 36 | export async function getPostById(id: number) { | 
| 67 | const response = await client | 37 | const response = await client | 
| 68 | .get("https://e926.net/posts.json", { | 38 | .get("https://e926.net/posts.json", { | 
| @@ -80,8 +50,6 @@ export async function getPostById(id: number) { | |||
| 80 | } | 50 | } | 
| 81 | 51 | ||
| 82 | export async function getRandomPost(query: GetPostQuery) { | 52 | export async function getRandomPost(query: GetPostQuery) { | 
| 83 | await loadDedupeDb(); | ||
| 84 | |||
| 85 | const page = Math.floor(Math.random() * (query.maxPage - 1)) + 1; | 53 | const page = Math.floor(Math.random() * (query.maxPage - 1)) + 1; | 
| 86 | 54 | ||
| 87 | const response = await client | 55 | const response = await client | 
| @@ -101,13 +69,12 @@ export async function getRandomPost(query: GetPostQuery) { | |||
| 101 | const postIndex = Math.floor(Math.random() * response.posts.length); | 69 | const postIndex = Math.floor(Math.random() * response.posts.length); | 
| 102 | const post = response.posts[postIndex]; | 70 | const post = response.posts[postIndex]; | 
| 103 | 71 | ||
| 104 | if (dedupeDb.includes(post.id)) { | 72 | const isDupe = await dedupe.check({ provider: "e926", id: post.id }); | 
| 73 | |||
| 74 | if (isDupe) { | ||
| 105 | await delay(1000); | 75 | await delay(1000); | 
| 106 | return getRandomPost(query); | 76 | return getRandomPost(query); | 
| 107 | } | 77 | } | 
| 108 | 78 | ||
| 109 | dedupeDb.push(post.id); | ||
| 110 | await saveDedupeDb(); | ||
| 111 | |||
| 112 | return post; | 79 | return post; | 
| 113 | } | 80 | } | 
diff --git a/src/index.ts b/src/index.ts index 6e9ad2e..5558540 100644 --- a/src/index.ts +++ b/src/index.ts  | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | import config from "./config"; | 1 | import config from "./config"; | 
| 2 | import * as jobs from "./jobs"; | 2 | import * as jobs from "./services/jobs"; | 
| 3 | import * as cliArgs from "ts-command-line-args"; | 3 | import * as cliArgs from "ts-command-line-args"; | 
| 4 | 4 | ||
| 5 | const args = cliArgs.parse<{ | 5 | const args = cliArgs.parse<{ | 
diff --git a/src/services/dedupe.ts b/src/services/dedupe.ts new file mode 100644 index 0000000..2eeb5ee --- /dev/null +++ b/src/services/dedupe.ts  | |||
| @@ -0,0 +1,65 @@ | |||
| 1 | import fs from "fs/promises"; | ||
| 2 | import path from "path"; | ||
| 3 | import * as f from "fp-ts"; | ||
| 4 | import * as t from "io-ts"; | ||
| 5 | |||
| 6 | export const E926DedupeEntryC = t.type({ | ||
| 7 | provider: t.literal("e926"), | ||
| 8 | id: t.number, | ||
| 9 | }); | ||
| 10 | |||
| 11 | export const DedupeEntryC = E926DedupeEntryC; | ||
| 12 | |||
| 13 | export type E926DedupeEntry = t.TypeOf<typeof E926DedupeEntryC>; | ||
| 14 | |||
| 15 | export type DedupeEntry = t.TypeOf<typeof DedupeEntryC>; | ||
| 16 | |||
| 17 | export class Dedupe { | ||
| 18 | private entries: DedupeEntry[] = []; | ||
| 19 | |||
| 20 | private readonly filePath: string; | ||
| 21 | |||
| 22 | private isLoaded = false; | ||
| 23 | |||
| 24 | constructor(private max: number, filename: string) { | ||
| 25 | this.filePath = path.join(process.cwd(), filename); | ||
| 26 | } | ||
| 27 | |||
| 28 | private async load() { | ||
| 29 | if (this.isLoaded) { | ||
| 30 | return; | ||
| 31 | } | ||
| 32 | |||
| 33 | try { | ||
| 34 | await fs.stat(this.filePath); | ||
| 35 | } catch { | ||
| 36 | await this.save(); | ||
| 37 | } | ||
| 38 | |||
| 39 | const fileContent = await fs.readFile(this.filePath, "utf8"); | ||
| 40 | const entries = t.array(DedupeEntryC).decode(fileContent); | ||
| 41 | |||
| 42 | if (f.either.isRight(entries)) { | ||
| 43 | this.entries = entries.right; | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 47 | private async save() { | ||
| 48 | await fs.writeFile(this.filePath, JSON.stringify(this.entries ?? []), "utf8"); | ||
| 49 | } | ||
| 50 | |||
| 51 | async check(entry: DedupeEntry) { | ||
| 52 | await this.load(); | ||
| 53 | |||
| 54 | const has = !!this.entries.find((e) => e.provider === entry.provider && e.id === entry.id); | ||
| 55 | |||
| 56 | if (!has) { | ||
| 57 | this.entries.push(entry); | ||
| 58 | await this.save(); | ||
| 59 | } | ||
| 60 | |||
| 61 | return has; | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | export default new Dedupe(50, "dedupe.json"); | ||
diff --git a/src/jobs.ts b/src/services/jobs.ts index d77104f..cf3b894 100644 --- a/src/jobs.ts +++ b/src/services/jobs.ts  | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | import * as e621 from "./api/e621"; | 1 | import * as e621 from "../api/e621"; | 
| 2 | import * as mastodon from "./api/mastodon"; | 2 | import * as mastodon from "../api/mastodon"; | 
| 3 | import config from "./config"; | 3 | import config from "../config"; | 
| 4 | import Sharp from "sharp"; | 4 | import Sharp from "sharp"; | 
| 5 | 5 | ||
| 6 | export async function postRandomPicture() { | 6 | export async function postRandomPicture() { | 
diff --git a/tsconfig.json b/tsconfig.json index ad89216..10b9c28 100644 --- a/tsconfig.json +++ b/tsconfig.json  | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | { | 1 | { | 
| 2 | "compilerOptions": { | 2 | "compilerOptions": { | 
| 3 | "lib": ["es2020"], | 3 | "lib": ["es2020"], | 
| 4 | "module": "ESNext", | ||
| 5 | "moduleResolution": "node", | 4 | "moduleResolution": "node", | 
| 6 | "target": "ES2020", | 5 | "target": "ES2020", | 
| 7 | "esModuleInterop": true, | 6 | "esModuleInterop": true, | 
| @@ -406,6 +406,11 @@ form-data@^4.0.0: | |||
| 406 | combined-stream "^1.0.8" | 406 | combined-stream "^1.0.8" | 
| 407 | mime-types "^2.1.12" | 407 | mime-types "^2.1.12" | 
| 408 | 408 | ||
| 409 | fp-ts@^2.11.5: | ||
| 410 | version "2.11.5" | ||
| 411 | resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-2.11.5.tgz#97cceb26655b1452d7088d6fb0864f84cceffbe4" | ||
| 412 | integrity sha512-OqlwJq1BdpB83BZXTqI+dNcA6uYk6qk4u9Cgnt64Y+XS7dwdbp/mobx8S2KXf2AXH+scNmA/UVK3SEFHR3vHZA== | ||
| 413 | |||
| 409 | fs-constants@^1.0.0: | 414 | fs-constants@^1.0.0: | 
| 410 | version "1.0.0" | 415 | version "1.0.0" | 
| 411 | resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" | 416 | resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" | 
| @@ -497,6 +502,11 @@ ini@~1.3.0: | |||
| 497 | resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" | 502 | resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" | 
| 498 | integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== | 503 | integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== | 
| 499 | 504 | ||
| 505 | io-ts@^2.2.16: | ||
| 506 | version "2.2.16" | ||
| 507 | resolved "https://registry.yarnpkg.com/io-ts/-/io-ts-2.2.16.tgz#597dffa03db1913fc318c9c6df6931cb4ed808b2" | ||
| 508 | integrity sha512-y5TTSa6VP6le0hhmIyN0dqEXkrZeJLeC5KApJq6VLci3UEKF80lZ+KuoUs02RhBxNWlrqSNxzfI7otLX1Euv8Q== | ||
| 509 | |||
| 500 | is-arrayish@^0.3.1: | 510 | is-arrayish@^0.3.1: | 
| 501 | version "0.3.2" | 511 | version "0.3.2" | 
| 502 | resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" | 512 | resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" | 
