Skip to content

Commit eae1b39

Browse files
committed
Update neo-scraper to 0.9.0 + post.uploadMode changes
1 parent 9843f0b commit eae1b39

File tree

6 files changed

+107
-69
lines changed

6 files changed

+107
-69
lines changed

.github/workflows/build.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ jobs:
7070
runs-on: ubuntu-20.04
7171
# Doesn't really need the Chrome build, but we can reuse its cache.
7272
needs: build_chrome
73-
# Only run on master branch AND if tagging or manually dispatching.
73+
# Only run (on master branch && if tagged) or (manually dispatching).
7474
if: startsWith(github.ref, 'refs/tags/v') || github.event.inputs.publish_amo_listed == true
7575
steps:
7676
- name: Checkout

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
"deepmerge": "^4.3.1",
3333
"lodash": "^4.17.21",
3434
"markdown-it": "^14.0.0",
35-
"neo-scraper": "^0.8.0",
35+
"neo-scraper": "^0.9.0",
3636
"normalize.css": "^8.0.1",
3737
"pinia": "^2.1.7",
3838
"primeflex": "^3.3.1",

pnpm-lock.yaml

+5-5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/models/index.ts

+12-11
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export class TagDetails {
88
public names: string[],
99
public category?: string,
1010
public usages?: number,
11-
) {}
11+
) { }
1212

1313
get name() {
1414
return this.names[0];
@@ -38,7 +38,7 @@ export class PoolDetails {
3838
public names: string[],
3939
public category?: string,
4040
public postCount?: number,
41-
) {}
41+
) { }
4242

4343
get name() {
4444
return this.names[0];
@@ -73,11 +73,11 @@ export class ScrapedPostDetails {
7373
contentType: ContentType;
7474
contentSubType: string | undefined;
7575
rating: BooruTypes.SafetyRating;
76-
source = "";
76+
source;
77+
uploadMode: UploadMode;
7778
referrer?: string;
7879
resolution?: [number, number];
7980
instanceSpecificData: MappedInstanceSpecificData = {};
80-
uploadMode: UploadMode = "url";
8181

8282
constructor(post: ScrapedPost) {
8383
this.contentUrl = post.contentUrl;
@@ -91,6 +91,7 @@ export class ScrapedPostDetails {
9191
this.tags = post.tags.map((x) => TagDetails.fromScapedTag(x));
9292
this.notes = post.notes;
9393
this.resolution = post.resolution;
94+
this.uploadMode = post.uploadMode;
9495
}
9596
}
9697

@@ -108,7 +109,7 @@ export class SimilarPostInfo {
108109
constructor(
109110
public readonly id: number,
110111
public readonly percentage: number,
111-
) {}
112+
) { }
112113
}
113114

114115
export type PostUploadState = "uploading" | "uploaded" | "error";
@@ -147,38 +148,38 @@ export class PostUploadCommandData {
147148
constructor(
148149
public readonly post: ScrapedPostDetails,
149150
public readonly selectedSite: SzuruSiteConfig,
150-
) {}
151+
) { }
151152
}
152153

153154
export class SetPostUploadInfoData {
154155
constructor(
155156
public instanceId: string,
156157
public postId: string,
157158
public info: PostUploadInfo,
158-
) {}
159+
) { }
159160
}
160161

161162
export class SetExactPostId {
162163
constructor(
163164
public readonly instanceId: string,
164165
public readonly postId: string,
165166
public readonly exactPostId: number,
166-
) {}
167+
) { }
167168
}
168169

169170
export class PostUpdateCommandData {
170171
constructor(
171172
public readonly postId: number,
172173
public readonly updateRequest: UpdatePostRequest,
173174
public readonly selectedSite: SzuruSiteConfig,
174-
) {}
175+
) { }
175176
}
176177

177178
export class FetchCommandData {
178179
constructor(
179180
public readonly url: string,
180181
public readonly options: RequestInit | undefined = undefined,
181-
) {}
182+
) { }
182183
}
183184

184185
export class SzuruSiteConfig {
@@ -192,7 +193,7 @@ export class TagCategoryColor {
192193
constructor(
193194
public name: string,
194195
public color: string,
195-
) {}
196+
) { }
196197
}
197198

198199
export const getDefaultTagCategories = () => [

src/options/App.vue

+28-9
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import Column from "primevue/column";
1111
import { SzuruSiteConfig, TagCategoryColor, getDefaultTagCategories } from "~/models";
1212
import SzurubooruApi from "~/api";
1313
14+
type StatusType = "success" | "error" | "quiet";
15+
1416
const statusText = ref("");
1517
const statusType = ref("status-quiet");
1618
const versionInfo = "Version: " + (import.meta.env.VITE_SZ_VERSION ?? browser.runtime.getManifest().version);
@@ -26,9 +28,7 @@ const selectedSite = computed(() => {
2628
}
2729
});
2830
29-
type StatusType = "success" | "error" | "quiet";
30-
31-
let mode = useColorMode({ emitAuto: true });
31+
const mode = useColorMode({ emitAuto: true });
3232
3333
async function testConnection() {
3434
if (
@@ -221,8 +221,13 @@ wnd.szc_set_config_version = (v = 0) => (cfg.value.version = v);
221221
<template v-if="selectedSite">
222222
<div class="field col-12">
223223
<label>URL</label>
224-
<input v-if="selectedSite" text="Szurubooru URL" type="text" name="domain"
225-
v-model="selectedSite.domain" />
224+
<input
225+
v-if="selectedSite"
226+
text="Szurubooru URL"
227+
type="text"
228+
name="domain"
229+
v-model="selectedSite.domain"
230+
/>
226231
</div>
227232

228233
<div class="field col-12 md:col-6">
@@ -251,10 +256,14 @@ wnd.szc_set_config_version = (v = 0) => (cfg.value.version = v);
251256
<template v-if="field == 'color'">
252257
<div class="color-preview">
253258
<input type="text" class="color" v-model="data[field]" />
254-
<div class="preview background-preview"
255-
:style="{ 'border-color': data[field], 'background-color': data[field] }"></div>
256-
<div class="preview text-preview" :style="{ 'border-color': data[field], color: data[field] }">
257-
</div>
259+
<div
260+
class="preview background-preview"
261+
:style="{ 'border-color': data[field], 'background-color': data[field] }"
262+
></div>
263+
<div
264+
class="preview text-preview"
265+
:style="{ 'border-color': data[field], color: data[field] }"
266+
></div>
258267
</div>
259268
</template>
260269

@@ -285,6 +294,16 @@ wnd.szc_set_config_version = (v = 0) => (cfg.value.version = v);
285294
<!-- TODO: Category ignore list -->
286295
</TabPanel>
287296

297+
<!-- <TabPanel header="About">
298+
<div class="grid">
299+
<div v-for="engine in scraper.engines" :key="engine.name" class="col-12 md:col-4 flex flex-column">
300+
<span class="font-bold">{{ engine.name }}</span>
301+
<span>Features: {{ engine.features.join(", ") }}</span>
302+
<span>Hosts: {{ engine.supportedHosts.join(", ") }}</span>
303+
</div>
304+
</div>
305+
</TabPanel> -->
306+
288307
<!--
289308
<TabPanel header="Developer">
290309
<div class="flex flex-column gap-2">

src/popup/pages/PopupMain.vue

+60-42
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<script setup lang="ts">
22
import { useDark } from "@vueuse/core";
33
import { cloneDeep } from "lodash";
4-
import { NeoScraper, ScrapeResults } from "neo-scraper";
4+
import { ScrapeResults } from "neo-scraper";
55
import { getUrl, encodeTagName, getErrorMessage, getPostInfoSummary } from "~/utils";
66
import {
77
BrowserCommand,
@@ -14,7 +14,6 @@ import {
1414
SzuruSiteConfig,
1515
PoolDetails,
1616
} from "~/models";
17-
import { ImageSearchResult } from "~/api/models";
1817
import { isMobile } from "~/env";
1918
import { DeepReadonly } from "vue";
2019
import { cfg, usePopupStore } from "~/stores";
@@ -99,14 +98,11 @@ async function grabPost() {
9998
// Clear current posts array
10099
pop.posts.splice(0);
101100
102-
const scraper = new NeoScraper();
103-
104101
for (const result of res.results) {
105-
const engine = scraper.engines.find((x) => x.name == result.engine);
106-
107102
for (const i in result.posts) {
108103
const vm = new ScrapedPostDetails(result.posts[i]);
109-
vm.name = `[${result.engine}] Post ${parseInt(i) + 1}`; // parseInt() is required!
104+
const name = result.posts[i].name ?? `Post ${parseInt(i) + 1}`; // parseInt() is required!
105+
vm.name = `[${result.engine}] ${name}`;
110106
111107
if (!cfg.value.addAllParsedTags) {
112108
vm.tags.splice(0);
@@ -125,10 +121,6 @@ async function grabPost() {
125121
vm.instanceSpecificData[site.id] = {};
126122
}
127123
128-
if (engine) {
129-
vm.uploadMode = engine.uploadMode;
130-
}
131-
132124
pop.posts.push(vm);
133125
}
134126
}
@@ -145,7 +137,7 @@ async function grabPost() {
145137
}
146138
147139
if (cfg.value.fetchPostInfo) {
148-
await fetchPostInfo();
140+
await fetchPostsInfo();
149141
}
150142
151143
// Delayed call to findSimilar, as fetchPostInfo might change the post's contentUrl.
@@ -168,7 +160,7 @@ async function upload() {
168160
}
169161
170162
try {
171-
const post: ScrapedPostDetails = cloneDeep(pop.selectedPost);
163+
const post: ScrapedPostDetails = cloneDeep(pop.selectedPost)!;
172164
173165
// uploadMode "content" requires a content token to work. So ensure it is set.
174166
if (post.uploadMode == "content") {
@@ -291,10 +283,10 @@ async function findSimilar(post: ScrapedPostDetails | undefined) {
291283
292284
isSearchingForSimilarPosts.value++;
293285
294-
await ensurePostHasContentToken(post);
295-
296286
try {
297-
const res = await selectedInstance.reverseSearchToken(instanceSpecificData.contentToken);
287+
await ensurePostHasContentToken(post);
288+
289+
const res = await selectedInstance.reverseSearchToken(instanceSpecificData.contentToken!);
298290
299291
instanceSpecificData.reverseSearchResult = {
300292
exactPostId: res.exactPost?.id,
@@ -331,33 +323,58 @@ async function loadTagCounts() {
331323
}
332324
}
333325
334-
async function fetchPostInfo() {
326+
async function updatePostWithRemoteInfo(post: ScrapedPostDetails, contentUrl: string) {
327+
// We are missing cookies/etc which means that the request might fail.
328+
// If you want access to the cookies/session/etc then you need to execute this code inside the content script.
329+
try {
330+
// This request follows redirects.
331+
const res = await fetch(contentUrl, { method: "HEAD" });
332+
const size = res.headers.get("Content-Length");
333+
const type = res.headers.get("Content-Type");
334+
335+
if (type) {
336+
if (type.indexOf("text/html") != -1) {
337+
// If we get a HTML page back it usually means that the request failed.
338+
// Not all sites (e.g. e-hentai) reply with a 403.
339+
throw new Error(
340+
"Received a text/html content type. This probably means that we don't have permission to access the resource.",
341+
);
342+
}
343+
344+
const [_main, sub] = type.split("/");
345+
if (sub) post.contentSubType = sub.toUpperCase();
346+
}
347+
348+
// This should be after the type check, because the type check also checks whether the response we get is valid/unsable.
349+
if (size) post.contentSize = parseInt(size);
350+
351+
// Update url if it changes. The url can change when:
352+
// a. the extraContentUrl was successfully loaded
353+
// b. because of redirects
354+
if (res.url != post.contentUrl) {
355+
// The developer needs to make sure that the remote server can load this URL if `post.uploadMode == 'url'`!
356+
console.log(`Updating post.contentUrl to '${res.url}'`);
357+
post.contentUrl = res.url;
358+
}
359+
360+
return true;
361+
} catch (ex) {
362+
console.error(ex);
363+
return false;
364+
}
365+
}
366+
367+
async function fetchPostsInfo() {
335368
for (const post of pop.posts) {
336369
if (!post.contentSize || post.extraContentUrl) {
337-
// We are missing cookies/etc which means that the request might fail.
338-
// If you want access to the cookies/session/etc then you need to execute this code inside the content script.
339-
try {
340-
const contentUrl = post.extraContentUrl ?? post.contentUrl;
341-
342-
// TODO: Check whether we need to call this in the background page, or if it is fine to call it from the popup.
343-
const res = await fetch(contentUrl, { method: "HEAD" });
344-
const size = res.headers.get("Content-Length");
345-
const type = res.headers.get("Content-Type");
346-
347-
if (size) post.contentSize = parseInt(size);
348-
349-
if (type) {
350-
const [_main, sub] = type.split("/");
351-
if (sub) post.contentSubType = sub.toUpperCase();
352-
}
353-
354-
// Resolve extraContentUrl redirects.
355-
if (post.extraContentUrl && res.url != post.contentUrl) {
356-
post.contentUrl = res.url;
357-
}
358-
} catch (ex) {
359-
// TODO: Maybe display an error in the UI.
360-
console.error(ex);
370+
let ok = false;
371+
if (post.extraContentUrl) {
372+
// Prioritize info from extraContentUrl.
373+
ok = await updatePostWithRemoteInfo(post, post.extraContentUrl);
374+
}
375+
if (!ok) {
376+
// Fall back to normal contentUrl if we can't get the data from the extraContentUrl.
377+
await updatePostWithRemoteInfo(post, post.contentUrl);
361378
}
362379
}
363380
}
@@ -369,7 +386,8 @@ function getUpdatedTagsText(count: number) {
369386
}
370387
371388
function onResolutionLoaded(res: any) {
372-
if (pop.selectedPost && !pop.selectedPost.resolution) {
389+
// This no longer checks for `!pop.selectedPost.resolution` because the resolution can change if the contentUrl is updated.
390+
if (pop.selectedPost) {
373391
pop.selectedPost.resolution = res;
374392
}
375393
}

0 commit comments

Comments
 (0)