mirror of
https://github.com/DIYgod/RSSHub.git
synced 2026-08-29 01:53:47 +08:00
refactor: enforce typecheck (#22917)
* feat(types): add upvotes, downvotes, and comments to DataItem * refactor: fix TS2339 * refactor: fix TS2322 * refactor: fix TS2322 * refactor: fix TS2345 * refactor: fix TS2339 * refactor: fix TS2322 * refactor: fix TS2345 * refactor: fix TS2531/2532/18048/18047 * refactor: fix TS18046/TS2571 * refactor: fix TS2538 * refactor: fix TS2554/2769/2558 * refactor: fix TS2362/2363 * refactor: fix TS2353/TS2561 * refactor: fix TS2741/2739/2740 * refactor: fix TS2304 TS2307 TS2305 TS2614 TS2552 TS2551 * refactor: fix TS2352 * refactor: fix TS2604 TS17001 * refactor: fix TS2367 TS2366 * refactor: fix TS2493 * refactor: fix TS2454 * refactor: fix TS2790 * refactor: fix TS2488 * refactor: fix TS2677 * refactor: fix TS18048/18049/2532 * refactor: fix TS2322 * refactor: fix TS2344 * refactor: fix TS2339 * refactor: fix TS2339 * refactor: fix TS2365 * refactor: fix TS1117 * refactor: fix TS2561 * refactor: fix TS2555 * refactor: fix TS2503 * refactor: fix TS2339 mobile api no longer work * fix: clean slop * fix: use Context instead of any * fix: fix more typing after merge * fix: add void return for ctx.redirect in handler * chore: add type check to lint and husky * fix: remove ts ignore * chore: add oxlint rule * fix: suppress build artifact * fix: update getArticles to use cache * fix: codeql * fix(route/typeless): use async gunzip * fix: address review * fix: address review * fix: double quotes escape
This commit is contained in:
@@ -29,6 +29,8 @@ jobs:
|
||||
- run: pnpm i
|
||||
- name: Install oxlint to SARIF converter
|
||||
run: pnpm i -g oxlint-json-to-sarif
|
||||
- name: Typecheck
|
||||
run: pnpm typecheck
|
||||
- name: Lint
|
||||
run: pnpm exec oxlint --type-aware --config=.oxlintrc.ci.json
|
||||
--format=json | oxlint-json-to-sarif > oxlint-results.sarif
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
lint-staged
|
||||
pnpm typecheck
|
||||
|
||||
+11
-1
@@ -641,7 +641,17 @@
|
||||
// #region --- TypeScript ---
|
||||
"@typescript-eslint/array-type": ["error", { "default": "array-simple" }],
|
||||
|
||||
"@typescript-eslint/ban-ts-comment": "off",
|
||||
"@typescript-eslint/ban-ts-comment": [
|
||||
"warn",
|
||||
{
|
||||
"ts-check": false,
|
||||
"ts-expect-error": "allow-with-description",
|
||||
"ts-ignore": "allow-with-description",
|
||||
"ts-nocheck": "allow-with-description",
|
||||
"minimumDescriptionLength": 3
|
||||
}
|
||||
],
|
||||
|
||||
"@typescript-eslint/consistent-indexed-object-style": "off", // stylistic
|
||||
"@typescript-eslint/consistent-type-definitions": "off", // stylistic
|
||||
"@typescript-eslint/dot-notation": "error", // type-aware
|
||||
|
||||
@@ -14,7 +14,7 @@ describe('api/follow/config', () => {
|
||||
json: (data: unknown) => data,
|
||||
};
|
||||
|
||||
const result = handler(ctx as any) as Record<string, unknown>;
|
||||
const result = (handler as (c: typeof ctx) => unknown)(ctx) as Record<string, unknown>;
|
||||
|
||||
expect(result).toMatchObject({
|
||||
ownerUserId: 'owner',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Next } from 'hono';
|
||||
import type { Context, Next } from 'hono';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { handler } from '@/api/radar/rules/one';
|
||||
@@ -14,7 +14,7 @@ describe('api/radar/rules/one', () => {
|
||||
json: vi.fn((value) => value),
|
||||
};
|
||||
|
||||
const result = await handler(ctx as any, noopNext);
|
||||
const result = await handler(ctx as unknown as Context, noopNext);
|
||||
|
||||
expect(ctx.req.valid).toHaveBeenCalledWith('param');
|
||||
expect(ctx.json).toHaveBeenCalledWith(undefined);
|
||||
|
||||
@@ -21,7 +21,7 @@ describe('app-bootstrap', () => {
|
||||
const before = new Set(process.listeners('uncaughtException'));
|
||||
await import('@/app-bootstrap');
|
||||
const after = process.listeners('uncaughtException');
|
||||
const listener = after.find((fn) => !before.has(fn));
|
||||
const listener = after.find((fn) => !before.has(fn)) as ((error: Error) => void) | undefined;
|
||||
|
||||
expect(listener).toBeDefined();
|
||||
listener?.(new Error('boom'));
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ describe('request-rewriter', () => {
|
||||
await app.request('/test/httperror');
|
||||
|
||||
// headers
|
||||
const headers: Headers = fetchSpy.mock.lastCall?.[0].headers;
|
||||
const headers: Headers = (fetchSpy.mock.lastCall as unknown as [Request])?.[0].headers;
|
||||
expect(headers.get('user-agent')).toMatch(/Chrome/);
|
||||
});
|
||||
});
|
||||
|
||||
+3
-3
@@ -2,7 +2,7 @@
|
||||
// This Worker manages the RSSHub container lifecycle and proxies requests
|
||||
|
||||
import { Container } from '@cloudflare/containers';
|
||||
import type { KVNamespace } from '@cloudflare/workers-types';
|
||||
import type { DurableObjectNamespace, KVNamespace } from '@cloudflare/workers-types';
|
||||
|
||||
const INSTANCE_COUNT = 20;
|
||||
|
||||
@@ -13,7 +13,7 @@ export class RSSHubContainer extends Container {
|
||||
}
|
||||
|
||||
interface Env {
|
||||
RSSHUB_CONTAINER: DurableObjectNamespace<RSSHubContainer>;
|
||||
RSSHUB_CONTAINER: DurableObjectNamespace;
|
||||
CONFIG: KVNamespace;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ export default {
|
||||
|
||||
// Randomly select an instance for load balancing
|
||||
const instanceIndex = Math.floor(Math.random() * INSTANCE_COUNT);
|
||||
const container = env.RSSHUB_CONTAINER.getByName(`rsshub-${instanceIndex}`);
|
||||
const container = env.RSSHUB_CONTAINER.getByName(`rsshub-${instanceIndex}`) as unknown as RSSHubContainer;
|
||||
|
||||
// Start container with env vars and wait for port to be ready
|
||||
await container.startAndWaitForPorts({
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { load } from 'cheerio';
|
||||
import type { Context } from 'hono';
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import app from '@/app';
|
||||
@@ -147,9 +148,9 @@ describe('error handler honeybadger', () => {
|
||||
header: vi.fn(),
|
||||
json: (payload: unknown) => payload,
|
||||
html: (payload: unknown) => payload,
|
||||
};
|
||||
} as unknown as Context;
|
||||
|
||||
errorHandler(new Error('boom'), ctx as any);
|
||||
errorHandler(new Error('boom'), ctx);
|
||||
|
||||
expect(notify).toHaveBeenCalledWith(expect.any(Error), {
|
||||
context: { name: 'test' },
|
||||
@@ -205,9 +206,9 @@ describe('error handler sentry', () => {
|
||||
header: vi.fn(),
|
||||
json: (payload: unknown) => payload,
|
||||
html: (payload: unknown) => payload,
|
||||
};
|
||||
} as unknown as Context;
|
||||
|
||||
errorHandler(new Error('boom'), ctx as any);
|
||||
errorHandler(new Error('boom'), ctx);
|
||||
|
||||
expect(setTag).toHaveBeenCalledWith('name', 'test');
|
||||
expect(captureException).toHaveBeenCalled();
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
const serve = vi.fn(() => ({ close: vi.fn() }));
|
||||
const serve = vi.fn<(...args: any[]) => any>(() => ({ close: vi.fn() }));
|
||||
const logger = {
|
||||
info: vi.fn(),
|
||||
warn: vi.fn(),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { Context } from 'hono';
|
||||
import Parser from 'rss-parser';
|
||||
import { afterAll, afterEach, beforeAll, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
@@ -451,7 +452,7 @@ describe('anti-hotlink edge cases', () => {
|
||||
},
|
||||
get: (key: string) => store.get(key),
|
||||
set: (key: string, value: unknown) => store.set(key, value),
|
||||
};
|
||||
} as unknown as Context;
|
||||
};
|
||||
|
||||
beforeAll(() => {
|
||||
@@ -479,7 +480,7 @@ describe('anti-hotlink edge cases', () => {
|
||||
};
|
||||
const ctx = createCtx({ image_hotlink_template: 'https://img.test/${href}' }, data);
|
||||
|
||||
await antiHotlink(ctx as any, async () => {});
|
||||
await antiHotlink(ctx, async () => {});
|
||||
|
||||
expect(data.image).toBe('http://invalid url');
|
||||
expect(errorSpy).toHaveBeenCalled();
|
||||
@@ -495,7 +496,7 @@ describe('anti-hotlink edge cases', () => {
|
||||
};
|
||||
const ctx = createCtx({ multimedia_hotlink_template: 'https://media.test/${href}' }, data);
|
||||
|
||||
await antiHotlink(ctx as any, async () => {});
|
||||
await antiHotlink(ctx, async () => {});
|
||||
|
||||
expect(data.image).toBe('https://example.com/img.jpg');
|
||||
});
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { Context } from 'hono';
|
||||
import Parser from 'rss-parser';
|
||||
import { afterAll, afterEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
@@ -190,7 +191,7 @@ describe('cache', () => {
|
||||
});
|
||||
|
||||
describe('cache middleware error handling', () => {
|
||||
const setSpy = vi.fn(() => null);
|
||||
const setSpy = vi.fn<(...args: any[]) => null>(() => null);
|
||||
const getSpy = vi.fn(() => null);
|
||||
|
||||
afterAll(() => {
|
||||
@@ -231,10 +232,10 @@ describe('cache middleware error handling', () => {
|
||||
header: vi.fn(),
|
||||
set: vi.fn(),
|
||||
get: vi.fn(),
|
||||
};
|
||||
} as unknown as Context;
|
||||
|
||||
await expect(
|
||||
cacheMiddleware(ctx as any, () => {
|
||||
cacheMiddleware(ctx, () => {
|
||||
throw new Error('boom');
|
||||
})
|
||||
).rejects.toThrow('boom');
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { Context } from 'hono';
|
||||
import Parser from 'rss-parser';
|
||||
import { afterAll, afterEach, beforeAll, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
@@ -19,8 +20,8 @@ const runMiddleware = async (data: any, query: Record<string, string | undefined
|
||||
},
|
||||
get: (key: string) => store.get(key),
|
||||
set: (key: string, value: unknown) => store.set(key, value),
|
||||
};
|
||||
await middleware(ctx as any, async () => {});
|
||||
} as unknown as Context;
|
||||
await middleware(ctx, async () => {});
|
||||
return store.get('data') as any;
|
||||
};
|
||||
|
||||
|
||||
@@ -201,7 +201,7 @@ const middleware: MiddlewareHandler = async (ctx, next) => {
|
||||
const title = item.title || '';
|
||||
const description = item.description || title;
|
||||
const author = getAuthorString(item);
|
||||
const category = item.category || [];
|
||||
const category = (item.category as string[] | undefined) || [];
|
||||
const isFilter =
|
||||
regex instanceof RE2JS
|
||||
? regex.matcher(title).find() || regex.matcher(description).find() || regex.matcher(author).find() || category.some((c) => regex.matcher(c).find())
|
||||
@@ -217,7 +217,7 @@ const middleware: MiddlewareHandler = async (ctx, next) => {
|
||||
const title = item.title || '';
|
||||
const description = item.description || title;
|
||||
const author = getAuthorString(item);
|
||||
const category = item.category || [];
|
||||
const category = (item.category as string[] | undefined) || [];
|
||||
let isFilter = true;
|
||||
|
||||
if (ctx.req.query('filter_title')) {
|
||||
@@ -246,7 +246,7 @@ const middleware: MiddlewareHandler = async (ctx, next) => {
|
||||
const title = item.title;
|
||||
const description = item.description || title;
|
||||
const author = getAuthorString(item);
|
||||
const category = item.category || [];
|
||||
const category = (item.category as string[] | undefined) || [];
|
||||
let isFilter = true;
|
||||
|
||||
if (ctx.req.query('filterout') || ctx.req.query('filterout_title')) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { Context } from 'hono';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { config } from '@/config';
|
||||
@@ -19,16 +20,16 @@ const createCtx = (query: Record<string, string | undefined>, data: any, extra:
|
||||
redirect: vi.fn((url: string, status: number) => ({ url, status })),
|
||||
header: vi.fn(),
|
||||
res: { headers: new Headers() },
|
||||
};
|
||||
} as unknown as Context & { json: ReturnType<typeof vi.fn>; html: ReturnType<typeof vi.fn>; render: ReturnType<typeof vi.fn>; body: ReturnType<typeof vi.fn>; redirect: ReturnType<typeof vi.fn>; header: ReturnType<typeof vi.fn> };
|
||||
};
|
||||
|
||||
describe('template middleware', () => {
|
||||
it('returns debug json when requested', async () => {
|
||||
const originalDebug = config.debugInfo;
|
||||
config.debugInfo = true;
|
||||
config.debugInfo = 'true';
|
||||
|
||||
const ctx = createCtx({ format: 'debug.json' }, { item: [] }, { json: { ok: true } });
|
||||
const result = await template(ctx as any, async () => {});
|
||||
const result = await template(ctx, async () => {});
|
||||
|
||||
expect(result).toEqual({ ok: true });
|
||||
expect(ctx.json).toHaveBeenCalled();
|
||||
@@ -38,7 +39,7 @@ describe('template middleware', () => {
|
||||
|
||||
it('returns api data without rendering', async () => {
|
||||
const ctx = createCtx({}, null, { apiData: { ok: true } });
|
||||
const result = await template(ctx as any, async () => {});
|
||||
const result = await template(ctx, async () => {});
|
||||
|
||||
expect(result).toEqual({ ok: true });
|
||||
expect(ctx.json).toHaveBeenCalledWith({ ok: true });
|
||||
@@ -46,10 +47,10 @@ describe('template middleware', () => {
|
||||
|
||||
it('renders debug html snippet when requested', async () => {
|
||||
const originalDebug = config.debugInfo;
|
||||
config.debugInfo = true;
|
||||
config.debugInfo = 'true';
|
||||
|
||||
const ctx = createCtx({ format: '0.debug.html' }, { item: [{ description: 'Hello' }] });
|
||||
const result = await template(ctx as any, async () => {});
|
||||
const result = await template(ctx, async () => {});
|
||||
|
||||
expect(result).toBe('Hello');
|
||||
expect(ctx.html).toHaveBeenCalled();
|
||||
@@ -72,7 +73,7 @@ describe('template middleware', () => {
|
||||
],
|
||||
};
|
||||
const ctx = createCtx({ format: 'rss' }, data);
|
||||
await template(ctx as any, async () => {});
|
||||
await template(ctx, async () => {});
|
||||
|
||||
expect(data.item[0].title).toBe('ABC...');
|
||||
expect(data.item[0].author).toBe('Alice, Bob');
|
||||
@@ -93,7 +94,7 @@ describe('template middleware', () => {
|
||||
],
|
||||
};
|
||||
const ctx = createCtx({ format: 'json' }, data);
|
||||
await template(ctx as any, async () => {});
|
||||
await template(ctx, async () => {});
|
||||
|
||||
expect(data.item[0].pubDate).toBe('');
|
||||
expect(data.item[0].updated).toBe('');
|
||||
@@ -101,7 +102,7 @@ describe('template middleware', () => {
|
||||
|
||||
it('returns redirect response when redirect is set', async () => {
|
||||
const ctx = createCtx({}, { item: [] }, { redirect: 'https://example.com' });
|
||||
const result = await template(ctx as any, async () => {});
|
||||
const result = await template(ctx, async () => {});
|
||||
|
||||
expect(result).toEqual({ url: 'https://example.com', status: 301 });
|
||||
expect(ctx.redirect).toHaveBeenCalledWith('https://example.com', 301);
|
||||
@@ -118,7 +119,7 @@ describe('template middleware', () => {
|
||||
],
|
||||
};
|
||||
const ctx = createCtx({ format: 'rss3' }, data);
|
||||
const result = await template(ctx as any, async () => {});
|
||||
const result = await template(ctx, async () => {});
|
||||
|
||||
expect(ctx.json).toHaveBeenCalled();
|
||||
expect(result).toHaveProperty('data');
|
||||
@@ -135,7 +136,7 @@ describe('template middleware', () => {
|
||||
],
|
||||
};
|
||||
const ctx = createCtx({ format: 'atom' }, data);
|
||||
await template(ctx as any, async () => {});
|
||||
await template(ctx, async () => {});
|
||||
|
||||
expect(ctx.render).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { Context, Next } from 'hono';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { config } from '@/config';
|
||||
@@ -6,7 +7,7 @@ import trace from '@/middleware/trace';
|
||||
describe('trace middleware', () => {
|
||||
it('skips tracing when debugInfo is disabled', async () => {
|
||||
const originalDebug = config.debugInfo;
|
||||
config.debugInfo = false;
|
||||
config.debugInfo = false as unknown as string;
|
||||
|
||||
let called = false;
|
||||
const ctx = {
|
||||
@@ -14,12 +15,13 @@ describe('trace middleware', () => {
|
||||
method: 'GET',
|
||||
raw: new Request('http://localhost/test'),
|
||||
},
|
||||
};
|
||||
const next = () => {
|
||||
} as unknown as Context;
|
||||
const next: Next = () => {
|
||||
called = true;
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
await trace(ctx as any, next);
|
||||
await trace(ctx, next);
|
||||
expect(called).toBe(true);
|
||||
|
||||
config.debugInfo = originalDebug;
|
||||
|
||||
+4
-2
@@ -1,5 +1,7 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
|
||||
describe('pkg', () => {
|
||||
beforeEach(() => {
|
||||
vi.resetModules();
|
||||
@@ -104,7 +106,7 @@ describe('pkg', () => {
|
||||
],
|
||||
allowEmpty: true,
|
||||
}),
|
||||
},
|
||||
} as unknown as Route,
|
||||
{
|
||||
name: 'Custom Namespace',
|
||||
url: 'https://example.com',
|
||||
@@ -128,7 +130,7 @@ describe('pkg', () => {
|
||||
path: '/hello',
|
||||
name: 'Custom Response',
|
||||
handler: () => new Response('ok'),
|
||||
});
|
||||
} as unknown as Route);
|
||||
|
||||
const app = (await import('@/app')).default;
|
||||
const response = await app.request('/custom-response/hello');
|
||||
|
||||
@@ -88,7 +88,7 @@ afterAll(() => {
|
||||
const buildApp = () => {
|
||||
const namespaces: NamespacesType = {};
|
||||
const dev = createDevRegistry({ routesDirectory, namespaces });
|
||||
const app = new Hono();
|
||||
const app = new Hono<{ Variables: { fromOuter: string; data: Record<string, unknown>; apiData: Record<string, unknown> } }>();
|
||||
app.use(async (ctx, next) => {
|
||||
ctx.set('fromOuter', 'bridged');
|
||||
await next();
|
||||
|
||||
@@ -64,6 +64,7 @@ describe('registry', () => {
|
||||
vi.stubEnv('DISABLE_NSFW', 'true');
|
||||
|
||||
const { namespaces } = await import('./registry');
|
||||
// @ts-ignore build artifact of pnpm build:routes
|
||||
const routesModule = await import('../assets/build/routes.json');
|
||||
const rawNamespaces = (routesModule.default ?? routesModule) as Record<string, { routes?: Record<string, { features?: { nsfw?: boolean } }> }>;
|
||||
const nsfwNamespaces = Object.entries(rawNamespaces).filter(([, namespace]) => Object.values(namespace.routes ?? {}).some((route) => route.features?.nsfw));
|
||||
@@ -165,7 +166,7 @@ const perDirectoryMock = (fakeDirectories: Record<string, Record<string, unknown
|
||||
};
|
||||
|
||||
const wrap = (registry: Hono) => {
|
||||
const app = new Hono();
|
||||
const app = new Hono<{ Variables: { data: Record<string, unknown>; apiData: Record<string, unknown> } }>();
|
||||
app.use(async (ctx, next) => {
|
||||
const response = await next();
|
||||
const apiData = ctx.get('apiData');
|
||||
|
||||
+4
-2
@@ -38,17 +38,19 @@ let namespaces: NamespacesType = {};
|
||||
let devRegistry: DevRegistry | undefined;
|
||||
|
||||
if (config.isPackage) {
|
||||
// @ts-ignore build artifact of pnpm build:routes
|
||||
namespaces = (await import('../assets/build/routes.js')).default;
|
||||
} else {
|
||||
switch (process.env.NODE_ENV || process.env.VERCEL_ENV) {
|
||||
case 'production':
|
||||
// @ts-ignore build artifact of pnpm build:routes
|
||||
namespaces = (await import('../assets/build/routes.js')).default;
|
||||
break;
|
||||
case 'test':
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error TS2322 the JSON module's inferred literal type is narrower than NamespacesType
|
||||
namespaces = await import('../assets/build/routes.json');
|
||||
if (namespaces.default) {
|
||||
// @ts-ignore
|
||||
// @ts-expect-error TS2322 the JSON module's default export does not satisfy NamespacesType
|
||||
namespaces = namespaces.default;
|
||||
}
|
||||
break;
|
||||
|
||||
+14
-14
@@ -1,7 +1,7 @@
|
||||
import { load } from 'cheerio';
|
||||
import { renderToString } from 'hono/jsx/dom/server';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { DataItem, Language, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
@@ -23,11 +23,11 @@ export const handler = async (ctx) => {
|
||||
let items = $('div.article-list ul li')
|
||||
.slice(0, limit)
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
.map((item): DataItem & { link: string } => {
|
||||
const $item = $(item);
|
||||
|
||||
const title = item.find('h3').text();
|
||||
const image = item.find('img').prop('src');
|
||||
const title = $item.find('h3').text();
|
||||
const image = $item.find('img').prop('src');
|
||||
|
||||
const description = renderToString(
|
||||
<>
|
||||
@@ -36,22 +36,22 @@ export const handler = async (ctx) => {
|
||||
<img src={image} alt={title} />
|
||||
</figure>
|
||||
) : null}
|
||||
{item.find('div.p-row').text() ? <blockquote>{item.find('div.p-row').text()}</blockquote> : null}
|
||||
{$item.find('div.p-row').text() ? <blockquote>{$item.find('div.p-row').text()}</blockquote> : null}
|
||||
</>
|
||||
);
|
||||
|
||||
return {
|
||||
title,
|
||||
description,
|
||||
pubDate: parseDate(item.find('span.time').text()),
|
||||
link: new URL(item.find('h3 a').prop('href'), rootUrl).href,
|
||||
pubDate: parseDate($item.find('span.time').text()),
|
||||
link: new URL($item.find('h3 a').prop('href')!, rootUrl).href,
|
||||
content: {
|
||||
html: description,
|
||||
text: item.find('div.p-row').text(),
|
||||
text: $item.find('div.p-row').text(),
|
||||
},
|
||||
image,
|
||||
banner: image,
|
||||
language,
|
||||
language: language as Language,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -66,14 +66,14 @@ export const handler = async (ctx) => {
|
||||
const description = $$('div.articleContent').html();
|
||||
|
||||
item.title = title;
|
||||
item.description = description;
|
||||
item.description = description ?? '';
|
||||
item.pubDate = timezone(parseDate($$('.time').text()), 8);
|
||||
item.category = $$('meta[name="keywords"]').prop('content').split(/,/);
|
||||
item.content = {
|
||||
html: description,
|
||||
html: description ?? '',
|
||||
text: $$('div.articleContent').text(),
|
||||
};
|
||||
item.language = language;
|
||||
item.language = language as Language;
|
||||
|
||||
return item;
|
||||
})
|
||||
@@ -91,7 +91,7 @@ export const handler = async (ctx) => {
|
||||
allowEmpty: true,
|
||||
image,
|
||||
author: title.split(/,/).pop(),
|
||||
language,
|
||||
language: language as Language,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { DataItem, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
@@ -37,18 +37,18 @@ async function handler(ctx) {
|
||||
|
||||
const list = $(listId === '3' ? '.col-xs-12 .thumbnail > a' : '.col-md-8 .list-group > a')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
.map((item): DataItem => {
|
||||
const $item = $(item);
|
||||
return {
|
||||
title: item.attr('title'),
|
||||
link: item.attr('href').startsWith('http') ? item.attr('href') : `${baseUrl}${item.attr('href')}`,
|
||||
title: $item.attr('title')!,
|
||||
link: $item.attr('href')!.startsWith('http') ? $item.attr('href') : `${baseUrl}${$item.attr('href')}`,
|
||||
};
|
||||
})
|
||||
.filter((i) => !i.link.includes('m.0818tuan.com/tb1111.php') && !i.link.includes('www.0818tuan.com/pdd/zudui.php'));
|
||||
.filter((i) => !i.link!.includes('m.0818tuan.com/tb1111.php') && !i.link!.includes('www.0818tuan.com/pdd/zudui.php'));
|
||||
|
||||
const items = await Promise.all(
|
||||
list.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
cache.tryGet(item.link!, async () => {
|
||||
const { data: response } = await got(item.link);
|
||||
const $ = load(response);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { DataItem, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
@@ -37,11 +37,11 @@ async function handler() {
|
||||
|
||||
const list = alist
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
.map((item): DataItem & { link: string } => {
|
||||
const $item = $(item);
|
||||
|
||||
const link = item.attr('href') || '';
|
||||
const title = item.text();
|
||||
const link = $item.attr('href') || '';
|
||||
const title = $item.text();
|
||||
const pubDate = extractDateFromURL(link);
|
||||
|
||||
return {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { load } from 'cheerio';
|
||||
import type { Element } from 'domhandler';
|
||||
import type { Context } from 'hono';
|
||||
|
||||
import type { Data, DataItem, Route } from '@/types';
|
||||
import type { Data, DataItem, Language, Route } from '@/types';
|
||||
import { ViewType } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import ofetch from '@/utils/ofetch';
|
||||
@@ -25,7 +25,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
let items: DataItem[] = $('table#home-table tr:not(.gore)')
|
||||
.slice(0, limit)
|
||||
.toArray()
|
||||
.map((el): Element => {
|
||||
.map((el) => {
|
||||
const $el: Cheerio<Element> = $(el);
|
||||
|
||||
const $categoryEl: Cheerio<Element> = $el.find('td.category');
|
||||
@@ -44,11 +44,11 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
},
|
||||
]
|
||||
: undefined,
|
||||
category: $categoryEl.html(),
|
||||
catalogue: $catalogueEl.html(),
|
||||
category: $categoryEl.html() ?? undefined,
|
||||
catalogue: $catalogueEl.html() ?? undefined,
|
||||
title,
|
||||
size: $el.find('td.size').text(),
|
||||
date: $dateEl.html(),
|
||||
date: $dateEl.html() ?? undefined,
|
||||
});
|
||||
const pubDateStr: string | undefined = $dateEl.text();
|
||||
const linkUrl: string | undefined = $el.find('td.title a').attr('href');
|
||||
@@ -68,7 +68,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
image,
|
||||
banner: image,
|
||||
updated: upDatedStr ? parseDate(upDatedStr, 'DD.MM.YYYY') : undefined,
|
||||
language,
|
||||
language: language as Language,
|
||||
};
|
||||
|
||||
return processedItem;
|
||||
@@ -81,7 +81,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
}
|
||||
|
||||
return cache.tryGet(item.link, async (): Promise<DataItem> => {
|
||||
const detailResponse = await ofetch(item.link);
|
||||
const detailResponse = await ofetch(item.link!);
|
||||
const $$: CheerioAPI = load(detailResponse);
|
||||
|
||||
const description: string | undefined =
|
||||
@@ -117,7 +117,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
allowEmpty: true,
|
||||
image: $('div.logo img').attr('src') ? new URL($('div.logo img').attr('src') as string, baseUrl).href : undefined,
|
||||
author: $('meta[property="og:site_name"]').attr('content'),
|
||||
language,
|
||||
language: language as Language,
|
||||
id: targetUrl,
|
||||
};
|
||||
};
|
||||
@@ -146,7 +146,7 @@ To subscribe to [Movie HD 1080p](https://0xxx.ws?category=Movie-HD-1080p), where
|
||||
supportBT: false,
|
||||
supportPodcast: false,
|
||||
supportScihub: false,
|
||||
nfsw: true,
|
||||
nsfw: true,
|
||||
},
|
||||
radar: [
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@ import { load } from 'cheerio';
|
||||
import type { Element } from 'domhandler';
|
||||
import type { Context } from 'hono';
|
||||
|
||||
import type { Data, DataItem, Route } from '@/types';
|
||||
import type { Data, DataItem, Language, Route } from '@/types';
|
||||
import { ViewType } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import ofetch from '@/utils/ofetch';
|
||||
@@ -25,7 +25,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
let items: DataItem[] = $('ul.l_newshot li dl.lhotnew2')
|
||||
.slice(0, limit)
|
||||
.toArray()
|
||||
.map((el): Element => {
|
||||
.map((el) => {
|
||||
const $el: Cheerio<Element> = $(el);
|
||||
const $aEl: Cheerio<Element> = $el.find('dd h1 a');
|
||||
|
||||
@@ -55,7 +55,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
image,
|
||||
banner: image,
|
||||
updated: upDatedStr ? parseRelativeDate(upDatedStr) : undefined,
|
||||
language,
|
||||
language: language as Language,
|
||||
};
|
||||
|
||||
return processedItem;
|
||||
@@ -69,14 +69,14 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
}
|
||||
|
||||
return cache.tryGet(item.link, async (): Promise<DataItem> => {
|
||||
const detailResponse = await ofetch(item.link);
|
||||
const detailResponse = await ofetch(item.link!);
|
||||
const $$: CheerioAPI = load(detailResponse);
|
||||
|
||||
const title: string = $$('div.entity_title h1 a').text();
|
||||
const image: string | undefined = $$('div.entity_thumb img.img-responsive').attr('src');
|
||||
|
||||
const description: string | undefined = renderDescription({
|
||||
description: $$('div.entity_content').html(),
|
||||
description: $$('div.entity_content').html() ?? undefined,
|
||||
});
|
||||
const pubDateStr: string | undefined = detailResponse.match(/var\stime\s=\s"(.*?)";/)?.[1];
|
||||
const categoryEls: Element[] = $$('div.entity_tag span a').toArray();
|
||||
@@ -95,7 +95,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
image,
|
||||
banner: image,
|
||||
updated: upDatedStr ? parseDate(upDatedStr) : item.updated,
|
||||
language,
|
||||
language: language as Language,
|
||||
};
|
||||
|
||||
return {
|
||||
@@ -118,7 +118,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
allowEmpty: true,
|
||||
image: $('a.navbar-brand img').attr('src') ? new URL($('a.navbar-brand img').attr('src') as string, baseUrl).href : undefined,
|
||||
author,
|
||||
language,
|
||||
language: language as Language,
|
||||
id: $('meta[property="og:url"]').attr('content'),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { load } from 'cheerio';
|
||||
import iconv from 'iconv-lite';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { Language, Route } from '@/types';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
|
||||
@@ -51,7 +51,7 @@ export const handler = async (ctx) => {
|
||||
image,
|
||||
banner: item.picUrl,
|
||||
updated: parseDate(item.rtime, 'X'),
|
||||
language,
|
||||
language: language as Language,
|
||||
};
|
||||
}) ?? [];
|
||||
|
||||
@@ -66,7 +66,7 @@ export const handler = async (ctx) => {
|
||||
allowEmpty: true,
|
||||
image,
|
||||
author: $('meta[property="og:site_name"]').prop('content'),
|
||||
language,
|
||||
language: language as Language,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { load } from 'cheerio';
|
||||
import type { Context } from 'hono';
|
||||
import { renderToString } from 'hono/jsx/dom/server';
|
||||
|
||||
import type { Data, DataItem, Route } from '@/types';
|
||||
import type { Data, DataItem, Language, Route } from '@/types';
|
||||
import { ViewType } from '@/types';
|
||||
import ofetch from '@/utils/ofetch';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
@@ -70,7 +70,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
image,
|
||||
banner: image,
|
||||
updated: updated ? parseDate(updated) : undefined,
|
||||
language,
|
||||
language: language as Language,
|
||||
};
|
||||
|
||||
return processedItem;
|
||||
@@ -86,7 +86,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
allowEmpty: true,
|
||||
image: $('img').first().attr('src') ? new URL($('img').first().attr('src') as string, baseUrl).href : undefined,
|
||||
author: $('div#webnameDiv').text(),
|
||||
language,
|
||||
language: language as Language,
|
||||
id: targetUrl,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { DataItem, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
@@ -42,9 +42,9 @@ async function handler(ctx) {
|
||||
|
||||
const list = $('#newList > ul > li')
|
||||
.toArray()
|
||||
.map((item) => ({
|
||||
.map((item): DataItem & { link: string } => ({
|
||||
title: $(item).find('a').text(),
|
||||
link: new URL($(item).find('a').attr('href'), link).href,
|
||||
link: new URL($(item).find('a').attr('href')!, link).href,
|
||||
pubDate: parseDate($(item).find('span').text().slice(1, -1)),
|
||||
}));
|
||||
|
||||
|
||||
+13
-13
@@ -68,29 +68,29 @@ async function handler(ctx) {
|
||||
const items = $('.columns')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
const $item = $(item);
|
||||
|
||||
const id = item.find('.title a').text();
|
||||
const size = item.find('.title span').text();
|
||||
const pubDate = item.find('.subtitle a').attr('href').split('/date/').pop();
|
||||
const description = item.find('.has-text-grey-dark').text();
|
||||
const actresses = item
|
||||
const id = $item.find('.title a').text();
|
||||
const size = $item.find('.title span').text();
|
||||
const pubDate = $item.find('.subtitle a').attr('href')!.split('/date/').pop();
|
||||
const description = $item.find('.has-text-grey-dark').text();
|
||||
const actresses = $item
|
||||
.find('.panel-block')
|
||||
.toArray()
|
||||
.map((a) => $(a).text().trim());
|
||||
const tags = item
|
||||
const tags = $item
|
||||
.find('.tag')
|
||||
.toArray()
|
||||
.map((t) => $(t).text().trim());
|
||||
const magnet = item.find('a[title="Magnet torrent"]').attr('href');
|
||||
const link = item.find('a[title="Download .torrent"]').attr('href');
|
||||
const image = item.find('.image').attr('src');
|
||||
const magnet = $item.find('a[title="Magnet torrent"]').attr('href');
|
||||
const link = $item.find('a[title="Download .torrent"]').attr('href');
|
||||
const image = $item.find('.image').attr('src');
|
||||
|
||||
return {
|
||||
title: `${id} ${size}`,
|
||||
pubDate: parseDate(pubDate, 'YYYY/MM/DD'),
|
||||
link: new URL(item.find('a').first().attr('href'), rootUrl).href,
|
||||
description: renderToString(<JavDescription image={image} id={id} size={size} pubDate={pubDate} description={description} actresses={actresses} tags={tags} magnet={magnet} link={link} />),
|
||||
pubDate: parseDate(pubDate!, 'YYYY/MM/DD'),
|
||||
link: new URL($item.find('a').first().attr('href')!, rootUrl).href,
|
||||
description: renderToString(<JavDescription image={image} id={id} size={size} pubDate={pubDate!} description={description} actresses={actresses} tags={tags} magnet={magnet} link={link} />),
|
||||
author: actresses.join(', '),
|
||||
category: [...tags, ...actresses],
|
||||
enclosure_type: 'application/x-bittorrent',
|
||||
|
||||
+14
-14
@@ -68,31 +68,31 @@ async function handler(ctx) {
|
||||
const items = $('.columns')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
const $item = $(item);
|
||||
|
||||
const id = item.find('.title a').text();
|
||||
const size = item.find('.title span').text();
|
||||
const pubDate = item.find('.subtitle a').attr('href').split('/date/').pop();
|
||||
const description = item.find('.has-text-grey-dark').text();
|
||||
const actresses = item
|
||||
const id = $item.find('.title a').text();
|
||||
const size = $item.find('.title span').text();
|
||||
const pubDate = $item.find('.subtitle a').attr('href')!.split('/date/').pop();
|
||||
const description = $item.find('.has-text-grey-dark').text();
|
||||
const actresses = $item
|
||||
.find('.panel-block')
|
||||
.toArray()
|
||||
.map((a) => $(a).text().trim());
|
||||
const tags = item
|
||||
const tags = $item
|
||||
.find('.tag')
|
||||
.toArray()
|
||||
.map((t) => $(t).text().trim());
|
||||
const magnet = item.find('a[title="Magnet torrent"]').attr('href');
|
||||
const link = item.find('a[title="Download .torrent"]').attr('href');
|
||||
const onErrorAttr = item.find('.image').attr('onerror');
|
||||
const magnet = $item.find('a[title="Magnet torrent"]').attr('href');
|
||||
const link = $item.find('a[title="Download .torrent"]').attr('href');
|
||||
const onErrorAttr = $item.find('.image').attr('onerror');
|
||||
const backupImageRegex = /this\.src='(.*?)'/;
|
||||
const match = backupImageRegex.exec(onErrorAttr);
|
||||
const image = match ? match[1] : item.find('.image').attr('src');
|
||||
const match = backupImageRegex.exec(onErrorAttr!);
|
||||
const image = match ? match[1] : $item.find('.image').attr('src');
|
||||
|
||||
return {
|
||||
title: `${id} ${size}`,
|
||||
pubDate: parseDate(pubDate, 'YYYY/MM/DD'),
|
||||
link: new URL(item.find('a').first().attr('href'), rootUrl).href,
|
||||
pubDate: parseDate(pubDate!, 'YYYY/MM/DD'),
|
||||
link: new URL($item.find('a').first().attr('href')!, rootUrl).href,
|
||||
description: renderToString(
|
||||
<>
|
||||
{image ? <img src={image} /> : null}
|
||||
|
||||
@@ -38,12 +38,12 @@ async function handler(ctx) {
|
||||
.slice(0, limit)
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
const itemImg = item.find('a.img img');
|
||||
const $item = $(item);
|
||||
const itemImg = $item.find('a.img img');
|
||||
return {
|
||||
title: item.find('h4 a').text(),
|
||||
link: item.find('a').first().attr('href'),
|
||||
pubDate: timezone(parseDate(item.find('.time').text()), 8),
|
||||
title: $item.find('h4 a').text(),
|
||||
link: $item.find('a').first().attr('href'),
|
||||
pubDate: timezone(parseDate($item.find('.time').text()), 8),
|
||||
imgsrc: itemImg.attr('src') ?? itemImg.attr('_src'),
|
||||
};
|
||||
});
|
||||
|
||||
@@ -42,7 +42,7 @@ const renderDescription = (pg, description, itunes_duration, info) =>
|
||||
</div>
|
||||
{info ? (
|
||||
<div>
|
||||
<audio src={`https://music.163.com/song/media/outer/url?id=${pg.mainTrackId}.mp3`} controls="controls"></audio>
|
||||
<audio src={`https://music.163.com/song/media/outer/url?id=${pg.mainTrackId}.mp3`} controls></audio>
|
||||
<p>时长: {itunes_duration}</p>
|
||||
<p>
|
||||
<a href={`https://music.163.com/program/${pg.id}`}>查看节目</a>
|
||||
|
||||
+12
-11
@@ -2,7 +2,7 @@ import { load } from 'cheerio';
|
||||
import iconv from 'iconv-lite';
|
||||
|
||||
import InvalidParameterError from '@/errors/types/invalid-parameter';
|
||||
import type { Route } from '@/types';
|
||||
import type { DataItem, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
@@ -140,24 +140,25 @@ async function handler(ctx) {
|
||||
.eq(timeRange[time].index + (category === 'whole' ? (type === 'click' ? -1 : 2) : type === 'click' ? 0 : 2))
|
||||
.find('table tbody tr td a')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
.map((item): DataItem => {
|
||||
const $item = $(item);
|
||||
|
||||
return {
|
||||
link: item.attr('href'),
|
||||
link: $item.attr('href'),
|
||||
title: '',
|
||||
};
|
||||
});
|
||||
|
||||
const items = await Promise.all(
|
||||
list.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
cache.tryGet(item.link!, async () => {
|
||||
try {
|
||||
let link;
|
||||
if (['auto', 'house', 'travel'].includes(category)) {
|
||||
const category = item.link.split('.163.com', 1)[0].split('//').pop().split('.').pop();
|
||||
link = `https://3g.163.com/${category}/article/${item.link.split('/').pop()}`;
|
||||
const category = item.link!.split('.163.com', 1)[0].split('//').pop()!.split('.').pop();
|
||||
link = `https://3g.163.com/${category}/article/${item.link!.split('/').pop()}`;
|
||||
} else {
|
||||
const pathname = new URL(item.link).pathname;
|
||||
const pathname = new URL(item.link!).pathname;
|
||||
link = `https://3g.163.com${pathname}`;
|
||||
}
|
||||
|
||||
@@ -175,8 +176,8 @@ async function handler(ctx) {
|
||||
elem.attribs.src = elem.attribs['data-src'] ?? elem.attribs.src;
|
||||
});
|
||||
|
||||
item.title = content('meta[property="og:title"]').attr('content').replace('_手机网易网', '');
|
||||
item.pubDate = parseDate(content('meta[property="og:release_date"]').attr('content'));
|
||||
item.title = content('meta[property="og:title"]').attr('content')!.replace('_手机网易网', '');
|
||||
item.pubDate = parseDate(content('meta[property="og:release_date"]').attr('content')!);
|
||||
item.description = content('.article-body').html();
|
||||
} catch {
|
||||
return '';
|
||||
@@ -190,6 +191,6 @@ async function handler(ctx) {
|
||||
return {
|
||||
title: `网易新闻${timeRange[time].title}${type === 'click' ? '点击' : '跟帖'}榜 - ${cfg.title}`,
|
||||
link: currentUrl,
|
||||
item: items.filter(Boolean),
|
||||
item: items.filter(Boolean) as DataItem[],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -65,10 +65,10 @@ async function handler() {
|
||||
const initialState = JSON.parse(
|
||||
$('script')
|
||||
.text()
|
||||
.match(/window\.__INITIAL_STATE__=(.*);\(function\(\)\{var/)[1]
|
||||
.match(/window\.__INITIAL_STATE__=(.*);\(function\(\)\{var/)![1]
|
||||
);
|
||||
|
||||
const list = Object.values(initialState.courseindex.myModules).flatMap((mod) =>
|
||||
const list = Object.values<Record<string, any>>(initialState.courseindex.myModules).flatMap((mod) =>
|
||||
mod.contents.map((item) => ({
|
||||
title: `${item.title} - ${item.subtitle}`,
|
||||
author: item.authorName,
|
||||
|
||||
@@ -61,8 +61,8 @@ async function handler(ctx) {
|
||||
|
||||
if (urls) {
|
||||
items = urls.slice(0, ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : 50).map((item) => ({
|
||||
link: item.match(/url:"(.*)",/)[1],
|
||||
}));
|
||||
link: item.match(/url:"(.*)",/)![1],
|
||||
})) as DataItem[];
|
||||
} else {
|
||||
const $ = load(data);
|
||||
|
||||
@@ -70,16 +70,16 @@ async function handler(ctx) {
|
||||
.slice(0, ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : 50)
|
||||
.toArray()
|
||||
.map((_, item) => {
|
||||
item = $(item);
|
||||
const $item = $(item as any);
|
||||
return {
|
||||
link: item.attr('href'),
|
||||
link: $item.attr('href'),
|
||||
};
|
||||
});
|
||||
}) as DataItem[];
|
||||
}
|
||||
|
||||
items = await Promise.all(
|
||||
items.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
cache.tryGet(item.link!, async () => {
|
||||
const detailResponse = await got({
|
||||
method: 'get',
|
||||
url: item.link,
|
||||
@@ -89,7 +89,7 @@ async function handler(ctx) {
|
||||
item.title = content('h1').text();
|
||||
item.author = content('script')
|
||||
.text()
|
||||
.match(/renjian_author = '(.*)'/)[1];
|
||||
.match(/renjian_author = '(.*)'/)![1];
|
||||
item.description = content('#endText').html() ?? content('#content').html();
|
||||
item.pubDate = timezone(parseDate(content('.pub_time').text() ?? content('.post_info').text().split('来源:', 1)[0].trim()), 8);
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ const parseDyArticle = (item) =>
|
||||
}
|
||||
const url = new URL(i.attribs.src);
|
||||
if (url.host === 'nimg.ws.126.net') {
|
||||
i.attribs.src = url.searchParams.get('url');
|
||||
i.attribs.src = url.searchParams.get('url') ?? '';
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Route } from '@/types';
|
||||
import type { DataItem, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
|
||||
import { renderDescription } from './templates/description';
|
||||
@@ -70,7 +70,7 @@ async function handler(ctx) {
|
||||
cache.tryGet(`18comic:album:${item.id}`, async () => {
|
||||
const chapterApiUrl = `${getApiUrl()}/chapter?id=${item.id}`;
|
||||
const chapterResult = await processApiItems(chapterApiUrl);
|
||||
const result = {};
|
||||
const result: DataItem = { title: '' };
|
||||
const chapterNum = index + 1;
|
||||
result.title = `第${chapterNum}話 ${item.name === '' ? chapterNum : item.name}`;
|
||||
result.link = `${rootUrl}/photo/${item.id}`;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { DataItem, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
@@ -53,13 +53,13 @@ async function handler(ctx) {
|
||||
|
||||
let items = $('.title')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
.map((item): DataItem & { guid: string } => {
|
||||
const $item = $(item);
|
||||
|
||||
return {
|
||||
title: item.text(),
|
||||
link: `${rootUrl}${item.parent().attr('href')}`,
|
||||
guid: `https://18comic.org${item.parent().attr('href')}`,
|
||||
title: $item.text(),
|
||||
link: `${rootUrl}${$item.parent().attr('href')}`,
|
||||
guid: `https://18comic.org${$item.parent().attr('href')}`,
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Route } from '@/types';
|
||||
import type { DataItem, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
|
||||
@@ -67,11 +67,17 @@ async function handler(ctx) {
|
||||
const results = await Promise.all(
|
||||
filteredItemsByCategory.map((item) =>
|
||||
cache.tryGet(`18comic:search:${item.id}`, async () => {
|
||||
const result = { title: item.name, link: `${rootUrl}/album/${item.id}`, guid: `18comic:/album/${item.id}`, updated: parseDate(item.update_at) };
|
||||
const result: DataItem = {
|
||||
title: item.name,
|
||||
link: `${rootUrl}/album/${item.id}`,
|
||||
guid: `18comic:/album/${item.id}`,
|
||||
updated: parseDate(item.update_at),
|
||||
};
|
||||
const apiUrl = `${getApiUrl()}/album?id=${item.id}`;
|
||||
const apiResult = await processApiItems(apiUrl);
|
||||
result.pubDate = new Date(apiResult.addtime * 1000);
|
||||
result.category = apiResult.tags.map((tag) => tag);
|
||||
const tags = apiResult.tags.map((tag) => tag);
|
||||
result.category = tags;
|
||||
result.author = apiResult.author.map((a) => a).join(', ');
|
||||
result.description = renderDescription({
|
||||
introduction: apiResult.description,
|
||||
@@ -83,7 +89,7 @@ async function handler(ctx) {
|
||||
// `https://cdn-msp3.${domain}/media/photos/${item.id}/00003.webp`,
|
||||
],
|
||||
cover: `https://cdn-msp3.${domain}/media/albums/${item.id}_3x4.jpg`,
|
||||
category: result.category,
|
||||
category: tags,
|
||||
});
|
||||
return result;
|
||||
})
|
||||
|
||||
@@ -3,6 +3,7 @@ import CryptoJS from 'crypto-js';
|
||||
|
||||
import { config } from '@/config';
|
||||
import ConfigNotFoundError from '@/errors/types/config-not-found';
|
||||
import type { DataItem } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import md5 from '@/utils/md5';
|
||||
@@ -99,13 +100,13 @@ const ProcessItems = async (ctx, currentUrl, rootUrl) => {
|
||||
let items = $('.video-title')
|
||||
.slice(0, ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : 20)
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
.map((item): DataItem & { guid: string } => {
|
||||
const $item = $(item);
|
||||
|
||||
return {
|
||||
title: item.text().trim(),
|
||||
link: `${rootUrl}${item.prev().find('a').attr('href')}`,
|
||||
guid: `18comic:${item.prev().find('a').attr('href')}`,
|
||||
title: $item.text().trim(),
|
||||
link: `${rootUrl}${$item.prev().find('a').attr('href')}`,
|
||||
guid: `18comic:${$item.prev().find('a').attr('href')}`,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -116,8 +117,8 @@ const ProcessItems = async (ctx, currentUrl, rootUrl) => {
|
||||
|
||||
const content = load(detailResponse.data);
|
||||
|
||||
item.pubDate = parseDate(content('div[itemprop="datePublished"]').first().attr('content'));
|
||||
item.updated = parseDate(content('div[itemprop="datePublished"]').last().attr('content'));
|
||||
item.pubDate = parseDate(content('div[itemprop="datePublished"]').first().attr('content')!);
|
||||
item.updated = parseDate(content('div[itemprop="datePublished"]').last().attr('content')!);
|
||||
item.category = content('span[data-type="tags"]')
|
||||
.first()
|
||||
.find('a')
|
||||
@@ -133,7 +134,7 @@ const ProcessItems = async (ctx, currentUrl, rootUrl) => {
|
||||
introduction: content('#intro-block .p-t-5').text(),
|
||||
images: content('.img_zoom_img img')
|
||||
.toArray()
|
||||
.map((image) => content(image).attr('data-original')),
|
||||
.map((image) => content(image).attr('data-original')!),
|
||||
cover: content('.thumb-overlay img').first().attr('src'),
|
||||
category: item.category,
|
||||
});
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { Element } from 'domhandler';
|
||||
import type { Context } from 'hono';
|
||||
import { renderToString } from 'hono/jsx/dom/server';
|
||||
|
||||
import type { Data, DataItem, Route } from '@/types';
|
||||
import type { Data, DataItem, Language, Route } from '@/types';
|
||||
import { ViewType } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import ofetch from '@/utils/ofetch';
|
||||
@@ -24,7 +24,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
let items: DataItem[] = $('article.newsplus')
|
||||
.slice(0, limit)
|
||||
.toArray()
|
||||
.map((el): Element => {
|
||||
.map((el) => {
|
||||
const $el: Cheerio<Element> = $(el);
|
||||
|
||||
const title: string = $el.find('h2.entry-title').text();
|
||||
@@ -43,7 +43,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
image,
|
||||
banner: image,
|
||||
updated: upDatedStr ? parseDate(upDatedStr) : undefined,
|
||||
language,
|
||||
language: language as Language,
|
||||
};
|
||||
|
||||
return processedItem;
|
||||
@@ -57,7 +57,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
}
|
||||
|
||||
return cache.tryGet(item.link, async (): Promise<DataItem> => {
|
||||
const detailResponse = await ofetch(item.link);
|
||||
const detailResponse = await ofetch(item.link!);
|
||||
const $$: CheerioAPI = load(detailResponse);
|
||||
|
||||
$$('div.entry-content img.alignnone').each((_, el) => {
|
||||
@@ -85,7 +85,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
pubDate: pubDateStr ? parseDate(pubDateStr) : item.pubDate,
|
||||
category: categories,
|
||||
updated: upDatedStr ? parseDate(upDatedStr) : item.updated,
|
||||
language,
|
||||
language: language as Language,
|
||||
};
|
||||
|
||||
const extraLinkEls: Element[] = $$('ul.related_post li a').toArray();
|
||||
@@ -112,7 +112,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
|
||||
$$('ul.related_post').parent().remove();
|
||||
|
||||
const description: string | undefined = $$('div.entry-content').html();
|
||||
const description: string | undefined = $$('div.entry-content').html() ?? undefined;
|
||||
|
||||
processedItem = {
|
||||
...processedItem,
|
||||
@@ -142,7 +142,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
allowEmpty: true,
|
||||
image: $('h3.site-title img').attr('src'),
|
||||
author: title.split(/-/).pop()?.trim(),
|
||||
language,
|
||||
language: language as Language,
|
||||
id: targetUrl,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ import { load } from 'cheerio';
|
||||
import iconv from 'iconv-lite';
|
||||
|
||||
import InvalidParameterError from '@/errors/types/invalid-parameter';
|
||||
import type { Route } from '@/types';
|
||||
import type { DataItem, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
@@ -10,12 +10,12 @@ import timezone from '@/utils/timezone';
|
||||
import { isValidHost } from '@/utils/valid-host';
|
||||
|
||||
const setCookie = function (cookieName, cookieValue, seconds, path, domain, secure?) {
|
||||
let expires = null;
|
||||
let expires: Date | null = null;
|
||||
if (seconds !== -1) {
|
||||
expires = new Date();
|
||||
expires.setTime(expires.getTime() + seconds);
|
||||
}
|
||||
return [encodeURI(cookieName), '=', encodeURI(cookieValue), expires ? '; expires=' + expires.toGMTString() : '', path ? '; path=' + path : '/', domain ? '; domain=' + domain : '', secure ? '; secure' : ''].join('');
|
||||
return [encodeURI(cookieName), '=', encodeURI(cookieValue), expires ? '; expires=' + expires.toUTCString() : '', path ? '; path=' + path : '/', domain ? '; domain=' + domain : '', secure ? '; secure' : ''].join('');
|
||||
};
|
||||
|
||||
export const route: Route = {
|
||||
@@ -72,12 +72,12 @@ async function handler(ctx) {
|
||||
let items = $('.center-center-jiazi')
|
||||
.find('a[title]')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
.map((item): DataItem & { link: string } => {
|
||||
const $item = $(item);
|
||||
|
||||
return {
|
||||
title: item.attr('title'),
|
||||
link: `https:${item.attr('href')}`,
|
||||
title: $item.attr('title')!,
|
||||
link: `https:${$item.attr('href')}`,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -100,7 +100,7 @@ async function handler(ctx) {
|
||||
|
||||
item.author = content('.uname, .user-name').first().text();
|
||||
item.description = content('.post-cont').first().html() || content('.thread-cont').html();
|
||||
item.pubDate = timezone(parseDate(content('.cont-top-left meta').attr('content')), 8);
|
||||
item.pubDate = timezone(parseDate(content('.cont-top-left meta').attr('content')!), 8);
|
||||
|
||||
return item;
|
||||
})
|
||||
|
||||
+18
-18
@@ -1,6 +1,6 @@
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { DataItem, Language, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
@@ -13,7 +13,7 @@ export const handler = async (ctx) => {
|
||||
const limit = ctx.req.query('limit') ? Number(ctx.req.query('limit')) : 50;
|
||||
|
||||
const queryString = Object.entries(ctx.req.query())
|
||||
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
|
||||
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value as string)}`)
|
||||
.join('&');
|
||||
|
||||
const currentUrl = new URL(`${params && params.endsWith('.htm') ? params : `${params}.htm`}${queryString ? `?${queryString}` : ''}`, rootUrl).href;
|
||||
@@ -27,24 +27,24 @@ export const handler = async (ctx) => {
|
||||
let items = $('li.media.thread.tap:not(li.hidden-sm)')
|
||||
.slice(0, limit)
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
.map((item): DataItem & { link: string } => {
|
||||
const $item = $(item);
|
||||
|
||||
const subjectEl = item.find('div.subject').children('a').first();
|
||||
const subjectEl = $item.find('div.subject').children('a').first();
|
||||
|
||||
return {
|
||||
title: subjectEl.text(),
|
||||
pubDate: timezone(parseDate(item.find('span.date').text()), 8),
|
||||
link: new URL(subjectEl.prop('href'), rootUrl).href,
|
||||
pubDate: timezone(parseDate($item.find('span.date').text()), 8),
|
||||
link: new URL(subjectEl.prop('href')!, rootUrl).href,
|
||||
category: [
|
||||
item.find('a.text-secondary').text().replaceAll('[]', ''),
|
||||
...item
|
||||
$item.find('a.text-secondary').text().replaceAll('[]', ''),
|
||||
...$item
|
||||
.find('a.badge')
|
||||
.toArray()
|
||||
.map((c) => $(c).text()),
|
||||
].filter(Boolean),
|
||||
author: item.find('a.username').text(),
|
||||
language,
|
||||
author: $item.find('a.username').text(),
|
||||
language: language as Language,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -59,7 +59,7 @@ export const handler = async (ctx) => {
|
||||
|
||||
if (title) {
|
||||
const description = $$('div.message.break-all').html();
|
||||
const image = new URL($$('img').first().prop('src'), rootUrl).href;
|
||||
const image = new URL($$('img').first().prop('src')!, rootUrl).href;
|
||||
|
||||
item.title = title;
|
||||
item.description = description;
|
||||
@@ -73,14 +73,14 @@ export const handler = async (ctx) => {
|
||||
};
|
||||
item.image = image;
|
||||
item.banner = image;
|
||||
item.language = language;
|
||||
item.language = language as Language;
|
||||
|
||||
const torrents = $$('ul.attachlist li a');
|
||||
|
||||
if (torrents.length > 0) {
|
||||
const torrent = torrents.first();
|
||||
|
||||
item.enclosure_url = new URL(torrent.prop('href'), rootUrl).href;
|
||||
item.enclosure_url = new URL(torrent.prop('href')!, rootUrl).href;
|
||||
item.enclosure_type = 'application/x-bittorrent';
|
||||
item.enclosure_title = torrent.text();
|
||||
}
|
||||
@@ -92,7 +92,7 @@ export const handler = async (ctx) => {
|
||||
);
|
||||
|
||||
const author = 'BT 之家 1LOU 站';
|
||||
const image = new URL($('img.logo-2').prop('src'), rootUrl).href;
|
||||
const image = new URL($('img.logo-2').prop('src')!, rootUrl).href;
|
||||
|
||||
return {
|
||||
title: `${$('title').text().split(/-/, 1)[0]} - ${author}`,
|
||||
@@ -102,7 +102,7 @@ export const handler = async (ctx) => {
|
||||
allowEmpty: true,
|
||||
image,
|
||||
author,
|
||||
language,
|
||||
language: language as Language,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -138,9 +138,9 @@ export const route: Route = {
|
||||
{
|
||||
source: ['1lou.me/:params'],
|
||||
target: (_, url) => {
|
||||
url = new URL(url);
|
||||
const parsedUrl = new URL(url);
|
||||
|
||||
return `/1lou${url.href.replace(rootUrl, '')}`;
|
||||
return `/1lou${parsedUrl.href.replace(rootUrl, '')}`;
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
@@ -2,7 +2,7 @@ import { load } from 'cheerio';
|
||||
import { raw } from 'hono/html';
|
||||
import { renderToString } from 'hono/jsx/dom/server';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { Language, Route } from '@/types';
|
||||
import got from '@/utils/got';
|
||||
|
||||
export const handler = async (ctx) => {
|
||||
@@ -27,11 +27,11 @@ export const handler = async (ctx) => {
|
||||
.slice(0, limit)
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
const $item = $(item);
|
||||
|
||||
const title = item.find('span.photos-feed-data-title').first().text() || 'Untitled';
|
||||
const image = item.find('img').prop('src');
|
||||
const author = item.find('span.photos-feed-data-name').first().text();
|
||||
const title = $item.find('span.photos-feed-data-title').first().text() || 'Untitled';
|
||||
const image = $item.find('img').prop('src');
|
||||
const author = $item.find('span.photos-feed-data-name').first().text();
|
||||
|
||||
const text = `${title} by ${author}`;
|
||||
|
||||
@@ -46,7 +46,7 @@ export const handler = async (ctx) => {
|
||||
</>
|
||||
);
|
||||
|
||||
const id = item.find('img[id]').prop('id').split(/-/).pop();
|
||||
const id = $item.find('img[id]').prop('id').split(/-/).pop();
|
||||
const guid = `1x-${id}`;
|
||||
|
||||
return {
|
||||
@@ -62,14 +62,14 @@ export const handler = async (ctx) => {
|
||||
},
|
||||
image,
|
||||
banner: image,
|
||||
language,
|
||||
language: language as Language,
|
||||
enclosure_url: image,
|
||||
enclosure_type: image ? `image/${image.split(/\./).pop()}` : undefined,
|
||||
enclosure_title: title,
|
||||
};
|
||||
});
|
||||
|
||||
const image = new URL($('img.themedlogo').prop('src'), rootUrl).href;
|
||||
const image = new URL($('img.themedlogo').prop('src')!, rootUrl).href;
|
||||
|
||||
return {
|
||||
title: $('title').text(),
|
||||
@@ -79,7 +79,7 @@ export const handler = async (ctx) => {
|
||||
allowEmpty: true,
|
||||
image,
|
||||
author: $('meta[property="og:site_name"]').prop('content'),
|
||||
language,
|
||||
language: language as Language,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { DataItem, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import ofetch from '@/utils/ofetch';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
@@ -71,7 +71,7 @@ async function handler(ctx) {
|
||||
const onclickValue = $('.button').first().attr('onclick');
|
||||
const targetUrl = onclickValue?.match(/window\.open\('([^']+)'/)?.[1];
|
||||
|
||||
return { url: new URL(targetUrl, 'https://2048.info').href };
|
||||
return { url: new URL(targetUrl!, 'https://2048.info').href };
|
||||
});
|
||||
// 获取重定向后的url
|
||||
const redirectResponse = await ofetch.raw(domainInfo.url);
|
||||
@@ -109,13 +109,13 @@ async function handler(ctx) {
|
||||
.last()
|
||||
.nextAll('.tr3')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item).find('a.subject');
|
||||
.map((item): DataItem & { link: string; guid: string } => {
|
||||
const $item = $(item).find('a.subject');
|
||||
|
||||
return {
|
||||
title: item.text(),
|
||||
link: `${currentHost}/${item.attr('href')}`,
|
||||
guid: `${rootUrl}/2048/${item.attr('href')}`,
|
||||
title: $item.text(),
|
||||
link: `${currentHost}/${$item.attr('href')}`,
|
||||
guid: `${rootUrl}/2048/${$item.attr('href')}`,
|
||||
};
|
||||
})
|
||||
.filter((item) => !item.link.includes('undefined'));
|
||||
@@ -143,7 +143,7 @@ async function handler(ctx) {
|
||||
});
|
||||
|
||||
item.author = content('.fl.black').first().text();
|
||||
item.pubDate = timezone(parseDate(content('span.fl.gray').first().attr('title')), 8);
|
||||
item.pubDate = timezone(parseDate(content('span.fl.gray').first().attr('title')!), 8);
|
||||
|
||||
const readTpc = content('#read_tpc').first();
|
||||
const copyLink = content('#copytext')?.first()?.text();
|
||||
|
||||
@@ -3,7 +3,7 @@ import { load } from 'cheerio';
|
||||
import type { Context } from 'hono';
|
||||
|
||||
import InvalidParameterError from '@/errors/types/invalid-parameter';
|
||||
import type { Data, DataItem, Route } from '@/types';
|
||||
import type { Data, DataItem, Language, Route } from '@/types';
|
||||
import { ViewType } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import ofetch from '@/utils/ofetch';
|
||||
@@ -110,7 +110,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
image,
|
||||
banner: image,
|
||||
updated: updated ? parseDate(updated, 'X') : undefined,
|
||||
language,
|
||||
language: language as Language,
|
||||
};
|
||||
|
||||
return processedItem;
|
||||
@@ -124,7 +124,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
}
|
||||
|
||||
return cache.tryGet(item.link, async (): Promise<DataItem> => {
|
||||
const detailResponse = await ofetch(item.link);
|
||||
const detailResponse = await ofetch(item.link!);
|
||||
const $$: CheerioAPI = load(detailResponse);
|
||||
|
||||
$$('div.rela-box').remove();
|
||||
@@ -135,7 +135,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
const pubDateStr: string | undefined = $$('div.author-infos span')
|
||||
.text()
|
||||
.match(/(\d{4}-\d{2}-\d{2}\s\d{2}:\d{2})/)?.[1];
|
||||
const categories: string[] = $$('meta[name="keywords"]').attr('content')?.split(/,/) ?? item.category ?? [];
|
||||
const categories: DataItem['category'] = $$('meta[name="keywords"]').attr('content')?.split(/,/) ?? item.category ?? [];
|
||||
const upDatedStr: string | undefined = pubDateStr;
|
||||
|
||||
const processedItem: DataItem = {
|
||||
@@ -148,7 +148,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
text: description,
|
||||
},
|
||||
updated: upDatedStr ? timezone(parseDate(upDatedStr), 8) : item.updated,
|
||||
language,
|
||||
language: language as Language,
|
||||
};
|
||||
|
||||
return {
|
||||
@@ -169,7 +169,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
item: items,
|
||||
allowEmpty: true,
|
||||
author,
|
||||
language,
|
||||
language: language as Language,
|
||||
id: targetUrl,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { load } from 'cheerio';
|
||||
import iconv from 'iconv-lite';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { DataItem, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
@@ -45,10 +45,10 @@ async function handler(ctx) {
|
||||
|
||||
const list = $('tbody[id^="normalthread_"]')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
const xst = item.find('a.s.xst');
|
||||
const author = item.find('td.by cite a').eq(0).text();
|
||||
.map((item): DataItem => {
|
||||
const $item = $(item);
|
||||
const xst = $item.find('a.s.xst');
|
||||
const author = $item.find('td.by cite a').eq(0).text();
|
||||
return {
|
||||
title: xst.text(),
|
||||
link: xst.attr('href'),
|
||||
@@ -58,7 +58,7 @@ async function handler(ctx) {
|
||||
// console.log(list);
|
||||
const items = await Promise.all(
|
||||
list.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
cache.tryGet(item.link!, async () => {
|
||||
const detailResponse = await got(item.link, {
|
||||
responseType: 'buffer',
|
||||
});
|
||||
@@ -67,7 +67,7 @@ async function handler(ctx) {
|
||||
const first_post = content('td[id^="postmessage_"]').first();
|
||||
const dateobj = content('em[id^="authorposton"]').first();
|
||||
item.description = first_post.html();
|
||||
item.pubDate = timezone(parseDate(dateobj.find('span').attr('title'), 'YYYY-M-D HH:mm:ss'), 8);
|
||||
item.pubDate = timezone(parseDate(dateobj.find('span').attr('title')!, 'YYYY-M-D HH:mm:ss'), 8);
|
||||
|
||||
return item;
|
||||
})
|
||||
|
||||
@@ -42,7 +42,7 @@ export const getWafTokenId = () =>
|
||||
const payload = $('script')
|
||||
.text()
|
||||
.match(/atob\('(.*?)'\)\),/)?.[1];
|
||||
const response = solveWafChallenge(payload);
|
||||
const response = solveWafChallenge(payload!);
|
||||
|
||||
const tokenIdResponse = await ofetch.raw(rootUrl, {
|
||||
headers: {
|
||||
|
||||
@@ -33,12 +33,12 @@ async function handler(ctx) {
|
||||
const listSelector = type === 'resource' ? $('.ZQ_Left .Llis_4 .lis li, .zq_left .rigtbox7 li').toArray() : $('.ZQ_Left .lis, .zq_left .newsleft li').toArray();
|
||||
|
||||
const list = listSelector.map((i) => {
|
||||
i = $(i);
|
||||
const a = i.find('a[href]').last();
|
||||
const time = i.find('.time');
|
||||
const $i = $(i);
|
||||
const a = $i.find('a[href]').last();
|
||||
const time = $i.find('.time');
|
||||
return {
|
||||
title: a.text(),
|
||||
description: i.find('.miaoshu').text(),
|
||||
description: $i.find('.miaoshu').text(),
|
||||
link: a.attr('href'),
|
||||
pubDate: time.length ? parseDate(time.text().trim()) : null, // 2020-12-31
|
||||
};
|
||||
|
||||
@@ -42,21 +42,21 @@ async function handler(ctx) {
|
||||
const list = $(isArcPost ? '.selectarcpost' : '.selectpost')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
const $item = $(item);
|
||||
if (isArcPost) {
|
||||
return {
|
||||
title: item.find('.bt').text(),
|
||||
link: item.attr('href'),
|
||||
description: item.find('p').text(),
|
||||
pubDate: timezone(parseDate(item.find('.time').text()), 8),
|
||||
title: $item.find('.bt').text(),
|
||||
link: $item.attr('href'),
|
||||
description: $item.find('p').text(),
|
||||
pubDate: timezone(parseDate($item.find('.time').text()), 8),
|
||||
};
|
||||
}
|
||||
const a = item.find('.text a');
|
||||
const a = $item.find('.text a');
|
||||
return {
|
||||
title: a.first().text(),
|
||||
link: a.attr('href'),
|
||||
description: item.find('.miaoshu').text(),
|
||||
pubDate: timezone(parseDate(item.find('.time').text()), 8),
|
||||
description: $item.find('.miaoshu').text(),
|
||||
pubDate: timezone(parseDate($item.find('.time').text()), 8),
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -12,9 +12,9 @@ const parseArticle = (item) =>
|
||||
|
||||
if (item.link.startsWith('https://dl.3dmgame.com/')) {
|
||||
const lis = $('.patchtop .lis');
|
||||
const [, category, pubDate, author] = lis.text().match(/补丁类型:([^\n]*)\n.*整理时间:([^\n]*)\n.*补丁制作:([^\n]*)\n/s);
|
||||
const [, category, pubDate, author] = lis.text().match(/补丁类型:([^\n]*)\n.*整理时间:([^\n]*)\n.*补丁制作:([^\n]*)\n/s)!;
|
||||
|
||||
item.description = lis.html() + $('.L_title').html() + $('.GmL_1').html();
|
||||
item.description = lis.html()! + $('.L_title').html()! + $('.GmL_1').html();
|
||||
item.category = category;
|
||||
item.pubDate = timezone(parseDate(pubDate), 8);
|
||||
item.author = author;
|
||||
|
||||
+18
-18
@@ -1,6 +1,6 @@
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { Language, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
@@ -24,19 +24,19 @@ export const handler = async (ctx) => {
|
||||
let items = $('ul.excerpt li')
|
||||
.toArray()
|
||||
.filter((item) => {
|
||||
item = $(item);
|
||||
const $item = $(item);
|
||||
|
||||
const link = item.find('h2 a').prop('href');
|
||||
const isAdItem = item.find('span.cat').text().includes('423Down');
|
||||
const link = $item.find('h2 a').prop('href');
|
||||
const isAdItem = $item.find('span.cat').text().includes('423Down');
|
||||
|
||||
return new RegExp(domain).test(link) && !isAdItem;
|
||||
return new RegExp(domain).test(link!) && !isAdItem;
|
||||
})
|
||||
.slice(0, limit)
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
const $item = $(item);
|
||||
|
||||
const title = item.find('h2').text();
|
||||
const image = item.find('a.pic img').prop('src');
|
||||
const title = $item.find('h2').text();
|
||||
const image = $item.find('a.pic img').prop('src');
|
||||
const description = renderDescription({
|
||||
images: image
|
||||
? [
|
||||
@@ -46,25 +46,25 @@ export const handler = async (ctx) => {
|
||||
},
|
||||
]
|
||||
: undefined,
|
||||
intro: item.find('div.note').text(),
|
||||
intro: $item.find('div.note').text(),
|
||||
});
|
||||
|
||||
return {
|
||||
title,
|
||||
description,
|
||||
pubDate: parseDate(item.find('span.time').text(), 'MM-DD'),
|
||||
link: item.find('h2 a').prop('href'),
|
||||
category: item
|
||||
pubDate: parseDate($item.find('span.time').text(), 'MM-DD'),
|
||||
link: $item.find('h2 a').prop('href'),
|
||||
category: $item
|
||||
.find('span.cat a')
|
||||
.toArray()
|
||||
.map((c) => $(c).text()),
|
||||
content: {
|
||||
html: description,
|
||||
text: item.find('div.note').text(),
|
||||
text: $item.find('div.note').text(),
|
||||
},
|
||||
image,
|
||||
banner: image,
|
||||
language,
|
||||
language: language as Language,
|
||||
enclosure_url: image,
|
||||
enclosure_type: image ? `image/${image.split(/\./).pop()}` : undefined,
|
||||
enclosure_title: title,
|
||||
@@ -73,13 +73,13 @@ export const handler = async (ctx) => {
|
||||
|
||||
items = await Promise.all(
|
||||
items.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
cache.tryGet(item.link!, async () => {
|
||||
const { data: detailResponse } = await got(item.link);
|
||||
|
||||
const $$ = load(detailResponse);
|
||||
|
||||
const title = $$('h1.meta-tit a').text();
|
||||
const description = item.description + renderDescription({ description: $$('div.entry').html() });
|
||||
const description = item.description + renderDescription({ description: $$('div.entry').html() ?? undefined });
|
||||
|
||||
item.title = title;
|
||||
item.description = description;
|
||||
@@ -91,7 +91,7 @@ export const handler = async (ctx) => {
|
||||
html: description,
|
||||
text: $$('div.entry').text(),
|
||||
};
|
||||
item.language = language;
|
||||
item.language = language as Language;
|
||||
|
||||
return item;
|
||||
})
|
||||
@@ -109,7 +109,7 @@ export const handler = async (ctx) => {
|
||||
allowEmpty: true,
|
||||
image,
|
||||
author: title.split(/-/).pop()?.trim(),
|
||||
language,
|
||||
language: language as Language,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
+21
-20
@@ -2,7 +2,7 @@ import { load } from 'cheerio';
|
||||
import { raw } from 'hono/html';
|
||||
import { renderToString } from 'hono/jsx/dom/server';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { DataItem, Language, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import md5 from '@/utils/md5';
|
||||
import ofetch from '@/utils/ofetch';
|
||||
@@ -98,11 +98,12 @@ async function handler(ctx) {
|
||||
let items = $('div.nex_cmo_piv a')
|
||||
.slice(0, limit)
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
.map((item): DataItem & { link: string } => {
|
||||
const $item = $(item);
|
||||
|
||||
return {
|
||||
link: new URL(item.prop('href'), rootUrl).href,
|
||||
link: new URL($item.prop('href')!, rootUrl).href,
|
||||
title: '',
|
||||
};
|
||||
});
|
||||
|
||||
@@ -145,28 +146,28 @@ async function handler(ctx) {
|
||||
|
||||
$$('div.nex_drama_intros em').first().remove();
|
||||
$$('strong font').each((_, el) => {
|
||||
el = $$(el);
|
||||
const $el = $$(el);
|
||||
|
||||
el.parent().remove();
|
||||
$el.parent().remove();
|
||||
});
|
||||
|
||||
const title = $$('div.nex_drama_Top h5').text();
|
||||
const description = $$('div.nex_drama_intros').html();
|
||||
const picture =
|
||||
$$('div.nex_drama_pic')
|
||||
.html()
|
||||
.html()!
|
||||
.match(/background:url\((.*?)\)/)?.[1] ?? '';
|
||||
|
||||
const details = $$('li.nex_drama_Detail_li, li.nex_drama_Detail_lis dd')
|
||||
.toArray()
|
||||
.map((li) => {
|
||||
li = $$(li);
|
||||
const $li = $$(li);
|
||||
|
||||
const key = li
|
||||
const key = $li
|
||||
.find('em')
|
||||
.text()
|
||||
.replaceAll(/:|\s/g, '');
|
||||
const value = li.find('span').length === 0 ? li.contents().last().text().trim() : li.find('span').text().trim();
|
||||
const value = $li.find('span').length === 0 ? $li.contents().last().text().trim() : $li.find('span').text().trim();
|
||||
|
||||
return { [key]: value };
|
||||
});
|
||||
@@ -177,10 +178,10 @@ async function handler(ctx) {
|
||||
? $$('td.t_f strong')
|
||||
.toArray()
|
||||
.map((l) => {
|
||||
l = $$(l);
|
||||
const $l = $$(l);
|
||||
|
||||
const title = l.contents().first().text();
|
||||
const link = l.next().prop('href') ?? l.nextUntil('a').next().prop('href');
|
||||
const title = $l.contents().first().text();
|
||||
const link = $l.next().prop('href') ?? $l.nextUntil('a').next().prop('href');
|
||||
|
||||
item.enclosure_url ??= link;
|
||||
item.enclosure_type ??= 'application/x-bittorrent';
|
||||
@@ -188,7 +189,7 @@ async function handler(ctx) {
|
||||
|
||||
return {
|
||||
title,
|
||||
tags: l
|
||||
tags: $l
|
||||
.contents()
|
||||
.last()
|
||||
.text()
|
||||
@@ -199,15 +200,15 @@ async function handler(ctx) {
|
||||
: $$('div.newfujian')
|
||||
.toArray()
|
||||
.map((l) => {
|
||||
l = $$(l);
|
||||
const $l = $$(l);
|
||||
|
||||
return {
|
||||
title: l.find('p.filename').prop('title') || l.find('p.filename').text(),
|
||||
tags: l
|
||||
title: $l.find('p.filename').prop('title') || $l.find('p.filename').text(),
|
||||
tags: $l
|
||||
.find('div.fileaq')
|
||||
.text()
|
||||
.match(/【(.*?)】/g),
|
||||
link: l.find('div.down_2 a').prop('href'),
|
||||
link: $l.find('div.down_2 a').prop('href'),
|
||||
};
|
||||
});
|
||||
|
||||
@@ -238,7 +239,7 @@ async function handler(ctx) {
|
||||
links,
|
||||
});
|
||||
item.pubDate = timezone(parseDate(pubDate, 'YYYY-M-D HH:mm:ss'), 8);
|
||||
item.category = Object.values(mergedDetails)
|
||||
item.category = Object.values<string>(mergedDetails)
|
||||
.flatMap((c) => c.split(/\s/))
|
||||
.filter(Boolean);
|
||||
item.author = mergedDetails['导演'];
|
||||
@@ -268,6 +269,6 @@ async function handler(ctx) {
|
||||
allowEmpty: true,
|
||||
image,
|
||||
author: $('meta[name="application-name"]').prop('content'),
|
||||
language,
|
||||
language: language as Language,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { DataItem, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
@@ -34,21 +34,21 @@ async function handler() {
|
||||
});
|
||||
const data = response.data;
|
||||
if (!data) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
const $ = load(data);
|
||||
let out = $('div.container div.list_list.mtop10 ul li')
|
||||
.find('a')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
const link = rootUrl + item.attr('href');
|
||||
.map((item): DataItem & { link: string } => {
|
||||
const $item = $(item);
|
||||
const link = rootUrl + $item.attr('href');
|
||||
const reg = /^(.+) - (.*) - (.+)$/;
|
||||
const keyword = reg.exec(item.text().trim());
|
||||
const keyword = reg.exec($item.text().trim());
|
||||
return {
|
||||
title: keyword[1],
|
||||
author: keyword[2],
|
||||
pubDate: timezone(parseDate(keyword[3], 'YYYY-MM-DD'), 8),
|
||||
title: keyword![1],
|
||||
author: keyword![2],
|
||||
pubDate: timezone(parseDate(keyword![3], 'YYYY-MM-DD'), 8),
|
||||
link,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -6,6 +6,7 @@ import got from '@/utils/got';
|
||||
import logger from '@/utils/logger';
|
||||
import ofetch from '@/utils/ofetch';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import timezone from '@/utils/timezone';
|
||||
|
||||
import { getToken, sign } from './utils';
|
||||
|
||||
@@ -53,7 +54,7 @@ async function getFullcontent(item, cookie = '') {
|
||||
return {
|
||||
title: item.title,
|
||||
link: item.url,
|
||||
pubDate: parseDate(item.pubdate, 8),
|
||||
pubDate: timezone(parseDate(item.pubdate), 8),
|
||||
description: fullContent || item.abstract, // Return item.abstract if fullContent is null
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import type { DataItem, Route } from '@/types';
|
||||
import type { DataItem, Language, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import ofetch from '@/utils/ofetch';
|
||||
|
||||
@@ -57,7 +57,7 @@ async function handler(ctx) {
|
||||
item,
|
||||
image: $book('.bi-img img').attr('src'),
|
||||
author: $book('.bi-wt a').text(),
|
||||
language: 'zh-cn',
|
||||
language: 'zh-CN' as Language,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+19
-18
@@ -2,6 +2,7 @@ import { load } from 'cheerio';
|
||||
import { renderToString } from 'hono/jsx/dom/server';
|
||||
import iconv from 'iconv-lite';
|
||||
|
||||
import type { DataItem, Language } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
@@ -18,21 +19,21 @@ const fetchItems = async (limit, currentUrl) => {
|
||||
|
||||
let items = $('p.line')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
.map((item): DataItem => {
|
||||
const $item = $(item);
|
||||
|
||||
const a = item.find('a');
|
||||
const a = $item.find('a');
|
||||
|
||||
return {
|
||||
title: a.text(),
|
||||
link: new URL(a.prop('href'), rootUrl).href,
|
||||
author: item.find('span').last().text(),
|
||||
link: new URL(a.prop('href')!, rootUrl).href,
|
||||
author: $item.find('span').last().text(),
|
||||
};
|
||||
});
|
||||
|
||||
items = await Promise.all(
|
||||
items.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
cache.tryGet(item.link!, async () => {
|
||||
try {
|
||||
const { data: detailResponse } = await got(item.link, {
|
||||
responseType: 'buffer',
|
||||
@@ -42,16 +43,16 @@ const fetchItems = async (limit, currentUrl) => {
|
||||
|
||||
const details = content('div.mohe-content p')
|
||||
.toArray()
|
||||
.map((detail) => {
|
||||
detail = content(detail);
|
||||
const as = detail.find('a');
|
||||
.map((detail): { label: string; value: any } => {
|
||||
const $detail = content(detail);
|
||||
const as = $detail.find('a');
|
||||
|
||||
return {
|
||||
label: detail.find('span.c-l-depths').text().split(/:/, 1)[0],
|
||||
label: $detail.find('span.c-l-depths').text().split(/:/, 1)[0],
|
||||
value:
|
||||
as.length === 0
|
||||
? content(
|
||||
detail
|
||||
$detail
|
||||
.contents()
|
||||
.toArray()
|
||||
.find((c) => c.nodeType === 3)
|
||||
@@ -59,27 +60,27 @@ const fetchItems = async (limit, currentUrl) => {
|
||||
.text()
|
||||
.trim()
|
||||
: {
|
||||
href: new URL(as.first().prop('href'), rootUrl).href,
|
||||
href: new URL(as.first().prop('href')!, rootUrl).href,
|
||||
text: as.first().text().trim(),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const pubDate = details.find((detail) => detail.label === '更新').value;
|
||||
const pubDate = details.find((detail) => detail.label === '更新')!.value;
|
||||
|
||||
item.title = content('h1').contents().first().text();
|
||||
item.description = renderDescription({
|
||||
images: [
|
||||
{
|
||||
src: new URL(content('a.mohe-imgs img').prop('src'), rootUrl).href,
|
||||
src: new URL(content('a.mohe-imgs img').prop('src')!, rootUrl).href,
|
||||
alt: item.title,
|
||||
},
|
||||
],
|
||||
details,
|
||||
});
|
||||
item.author = details.find((detail) => detail.label === '作者').value;
|
||||
item.category = [details.find((detail) => detail.label === '状态').value, details.find((detail) => detail.label === '类型').value.text].filter(Boolean);
|
||||
item.guid = `56kog-${item.link.match(/\/(\d+)\.html$/)[1]}#${pubDate}`;
|
||||
item.author = details.find((detail) => detail.label === '作者')!.value;
|
||||
item.category = [details.find((detail) => detail.label === '状态')!.value, details.find((detail) => detail.label === '类型')!.value.text].filter(Boolean);
|
||||
item.guid = `56kog-${item.link!.match(/\/(\d+)\.html$/)![1]}#${pubDate}`;
|
||||
item.pubDate = timezone(parseDate(pubDate), 8);
|
||||
} catch {
|
||||
// no-empty
|
||||
@@ -97,7 +98,7 @@ const fetchItems = async (limit, currentUrl) => {
|
||||
title: $('title').text(),
|
||||
link: currentUrl,
|
||||
description: $('meta[name="description"]').prop('content'),
|
||||
language: $('html').prop('lang'),
|
||||
language: $('html').prop('lang') as Language,
|
||||
icon,
|
||||
logo: icon,
|
||||
subtitle: $('meta[name="keywords"]').prop('content'),
|
||||
|
||||
@@ -24,7 +24,7 @@ function appendRentalAPIParams(urlString) {
|
||||
}
|
||||
|
||||
async function getToken() {
|
||||
const html = await client('https://rent.591.com.tw').text();
|
||||
const html = await (client('https://rent.591.com.tw') as any).text();
|
||||
|
||||
const $ = load(html);
|
||||
const csrfToken = $('meta[name="csrf-token"]').attr('content');
|
||||
@@ -39,12 +39,14 @@ async function getToken() {
|
||||
async function getHouseList(houseListURL) {
|
||||
const csrfToken = await getToken();
|
||||
|
||||
const data = await client({
|
||||
url: houseListURL,
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': csrfToken,
|
||||
},
|
||||
}).json();
|
||||
const data = await (
|
||||
client({
|
||||
url: houseListURL,
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': csrfToken,
|
||||
},
|
||||
}) as any
|
||||
).json();
|
||||
|
||||
const {
|
||||
data: { data: houseList },
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { Language, Route } from '@/types';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
|
||||
@@ -84,6 +84,6 @@ async function handler(ctx) {
|
||||
title: '五大唱片 - 新货上架',
|
||||
link: url,
|
||||
item: items,
|
||||
language: 'zh-tw',
|
||||
language: 'zh-TW' as Language,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ export const route: Route = {
|
||||
item,
|
||||
image: $('.bookimg2>img').attr('src'),
|
||||
author: $('.booknav2>p:first-of-type>a').text(),
|
||||
language: 'zh-cn',
|
||||
language: 'zh-CN',
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { DataItem, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
@@ -45,19 +45,20 @@ async function handler(ctx) {
|
||||
let items = $('#d_list ul li, #thread_list li, .t_l .t_subject')
|
||||
.toArray()
|
||||
.slice(0, limit)
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
.map((item): DataItem => {
|
||||
const $item = $(item);
|
||||
|
||||
const a = item.find('a').first();
|
||||
const a = $item.find('a').first();
|
||||
|
||||
return {
|
||||
link: `${rootUrl}/${id}/${a.attr('href')}`,
|
||||
title: '',
|
||||
};
|
||||
});
|
||||
|
||||
items = await Promise.all(
|
||||
items.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
cache.tryGet(item.link!, async () => {
|
||||
const detailResponse = await got({
|
||||
method: 'get',
|
||||
url: item.link,
|
||||
@@ -69,7 +70,7 @@ async function handler(ctx) {
|
||||
item.author = detailResponse.data.match(/送交者:[^>]*>([^<]*)<\/a>/)[1].trim();
|
||||
item.pubDate = timezone(parseDate(detailResponse.data.match(/于 (.*) 已读/)[1], 'YYYY-MM-DD h:m'), 8);
|
||||
item.description = content('pre')
|
||||
.html()
|
||||
.html()!
|
||||
.replaceAll('<p></p>', '')
|
||||
.replaceAll(/<font color="#E6E6DD">6park.com<\/font>/g, '');
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { DataItem, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
@@ -58,23 +58,23 @@ async function handler(ctx) {
|
||||
let items = $('#d_list ul li, #thread_list li, .t_l .t_subject')
|
||||
.toArray()
|
||||
.slice(0, limit)
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
.map((item): DataItem => {
|
||||
const $item = $(item);
|
||||
|
||||
const a = item.find('a').first();
|
||||
const a = $item.find('a').first();
|
||||
const link = a.attr('href');
|
||||
|
||||
return {
|
||||
title: a.text(),
|
||||
link: link.startsWith('http') ? link : `${rootUrl}/${link.startsWith('view') ? `newspark/${link}` : link}`,
|
||||
link: link!.startsWith('http') ? link : `${rootUrl}/${link!.startsWith('view') ? `newspark/${link}` : link}`,
|
||||
};
|
||||
});
|
||||
|
||||
items = await Promise.all(
|
||||
items
|
||||
.filter((item) => /6parknews\.com/.test(item.link))
|
||||
.filter((item) => /6parknews\.com/.test(item.link!))
|
||||
.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
cache.tryGet(item.link!, async () => {
|
||||
try {
|
||||
const detailResponse = await got({
|
||||
method: 'get',
|
||||
@@ -88,7 +88,7 @@ async function handler(ctx) {
|
||||
item.title = content('h2').text();
|
||||
item.author = matches[1].trim();
|
||||
item.pubDate = timezone(parseDate(matches[2], 'YYYY-MM-DD h:m'), 8);
|
||||
item.description = content('#shownewsc').html().replaceAll('<p></p>', '');
|
||||
item.description = content('#shownewsc').html()!.replaceAll('<p></p>', '');
|
||||
} catch {
|
||||
// no-empty
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { Element } from 'domhandler';
|
||||
import type { Context } from 'hono';
|
||||
import iconv from 'iconv-lite';
|
||||
|
||||
import type { Data, DataItem, Route } from '@/types';
|
||||
import type { Data, DataItem, Language, Route } from '@/types';
|
||||
import { ViewType } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import ofetch from '@/utils/ofetch';
|
||||
@@ -28,7 +28,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
let items: DataItem[] = $('ul.list li')
|
||||
.slice(0, limit)
|
||||
.toArray()
|
||||
.map((el): Element => {
|
||||
.map((el) => {
|
||||
const $el: Cheerio<Element> = $(el);
|
||||
|
||||
const title: string = $el.find('a').text();
|
||||
@@ -47,7 +47,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
guid,
|
||||
id: guid,
|
||||
updated: upDatedStr ? parseDate(upDatedStr, ['MM-DD', 'YYYY-MM-DD']) : undefined,
|
||||
language,
|
||||
language: language as Language,
|
||||
};
|
||||
|
||||
return processedItem;
|
||||
@@ -60,7 +60,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
}
|
||||
|
||||
return cache.tryGet(item.link, async (): Promise<DataItem> => {
|
||||
const detailResponse = await ofetch(item.link, {
|
||||
const detailResponse = await ofetch(item.link!, {
|
||||
responseType: 'arrayBuffer',
|
||||
});
|
||||
const $$: CheerioAPI = load(iconv.decode(Buffer.from(detailResponse), encoding));
|
||||
@@ -92,7 +92,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
image,
|
||||
banner: image,
|
||||
updated: upDatedStr ? parseDate(upDatedStr) : item.updated,
|
||||
language,
|
||||
language: language as Language,
|
||||
};
|
||||
|
||||
const $enclosureEl: Cheerio<Element> = $$('td a[href^="magnet"]').last();
|
||||
@@ -125,7 +125,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
item: items,
|
||||
allowEmpty: true,
|
||||
image: new URL('images/logo.gif', baseUrl).href,
|
||||
language,
|
||||
language: language as Language,
|
||||
id: targetUrl,
|
||||
};
|
||||
};
|
||||
|
||||
+19
-19
@@ -1,6 +1,6 @@
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { DataItem, Language, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
@@ -24,12 +24,12 @@ export const handler = async (ctx) => {
|
||||
let items = $('section.box-content div.card a.card-title')
|
||||
.slice(0, limit)
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item).parent();
|
||||
.map((item): DataItem => {
|
||||
const $item = $(item).parent();
|
||||
|
||||
const title = item.find('a.card-title').text();
|
||||
const title = $item.find('a.card-title').text();
|
||||
|
||||
const src = item.find('a.card-image img').prop('data-src');
|
||||
const src = $item.find('a.card-image img').prop('data-src');
|
||||
const image = src?.startsWith('//') ? `https:${src}` : src;
|
||||
|
||||
const description = renderDescription({
|
||||
@@ -42,9 +42,9 @@ export const handler = async (ctx) => {
|
||||
]
|
||||
: undefined,
|
||||
});
|
||||
const pubDate = item.find('div.card-info span.item').last().text();
|
||||
const pubDate = $item.find('div.card-info span.item').last().text();
|
||||
|
||||
const href = item.find('a.card-title').prop('href');
|
||||
const href = $item.find('a.card-title').prop('href');
|
||||
|
||||
return {
|
||||
title,
|
||||
@@ -53,22 +53,22 @@ export const handler = async (ctx) => {
|
||||
link: href?.startsWith('//') ? `https:${href}` : href,
|
||||
category: [
|
||||
...new Set([
|
||||
...item
|
||||
...$item
|
||||
.find('span.tag-title')
|
||||
.toArray()
|
||||
.map((c) => $(c).text()),
|
||||
item.find('div.card-info span.item').first().text(),
|
||||
$item.find('div.card-info span.item').first().text(),
|
||||
]),
|
||||
].filter(Boolean),
|
||||
image,
|
||||
banner: image,
|
||||
language,
|
||||
language: language as Language,
|
||||
};
|
||||
});
|
||||
|
||||
items = await Promise.all(
|
||||
items.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
cache.tryGet(item.link!, async () => {
|
||||
const { data: detailResponse } = await got(item.link);
|
||||
|
||||
const $$ = load(detailResponse);
|
||||
@@ -76,18 +76,18 @@ export const handler = async (ctx) => {
|
||||
$$('i.p-status').remove();
|
||||
|
||||
$$('div.image-text-content p img.lazy').each((_, el) => {
|
||||
el = $$(el);
|
||||
const $el = $$(el);
|
||||
|
||||
const src = el.prop('data-src');
|
||||
const src = $el.prop('data-src');
|
||||
const image = src?.startsWith('//') ? `https:${src}` : src;
|
||||
|
||||
el.parent().replaceWith(
|
||||
$el.parent().replaceWith(
|
||||
renderDescription({
|
||||
images: image
|
||||
? [
|
||||
{
|
||||
src: image,
|
||||
alt: el.prop('title') ?? '',
|
||||
alt: $el.prop('title') ?? '',
|
||||
},
|
||||
]
|
||||
: undefined,
|
||||
@@ -104,13 +104,13 @@ export const handler = async (ctx) => {
|
||||
|
||||
item.title = title;
|
||||
item.description = description;
|
||||
item.pubDate = timezone(parseDate($$('p.push-time').text().split(/:/).pop()), 8);
|
||||
item.pubDate = timezone(parseDate($$('p.push-time').text().split(/:/).pop()!), 8);
|
||||
item.author = $$('a.push-username').contents().first().text();
|
||||
item.content = {
|
||||
html: description,
|
||||
text: $$('div.image-text-content').first().text(),
|
||||
};
|
||||
item.language = language;
|
||||
item.language = language as Language;
|
||||
|
||||
return item;
|
||||
})
|
||||
@@ -118,7 +118,7 @@ export const handler = async (ctx) => {
|
||||
);
|
||||
|
||||
const title = $('title').text();
|
||||
const image = new URL($('a.logo img').prop('src'), rootUrl).href;
|
||||
const image = new URL($('a.logo img').prop('src')!, rootUrl).href;
|
||||
|
||||
return {
|
||||
title: `${title} | ${$('div.actived').text()}`,
|
||||
@@ -128,7 +128,7 @@ export const handler = async (ctx) => {
|
||||
allowEmpty: true,
|
||||
image,
|
||||
author: $('meta[property="og:site_name"]').prop('content'),
|
||||
language,
|
||||
language: language as Language,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { load } from 'cheerio';
|
||||
import { raw } from 'hono/html';
|
||||
import { renderToString } from 'hono/jsx/dom/server';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { DataItem, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
@@ -64,23 +64,23 @@ async function handler(ctx) {
|
||||
|
||||
let items = $('.video')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
.map((item): DataItem & { poster?: string; video?: string } => {
|
||||
const $item = $(item);
|
||||
|
||||
const title = item.find('.video-title a');
|
||||
const title = $item.find('.video-title a');
|
||||
return {
|
||||
title: title.text(),
|
||||
author: item.find('.video-channel').text(),
|
||||
pubDate: parseDate(item.find('.small').text()),
|
||||
author: $item.find('.video-channel').text(),
|
||||
pubDate: parseDate($item.find('.small').text()),
|
||||
link: title.attr('href'),
|
||||
poster: item.find('img').attr('data-src'),
|
||||
video: item.find('video').attr('data-src'),
|
||||
poster: $item.find('img').attr('data-src'),
|
||||
video: $item.find('video').attr('data-src'),
|
||||
};
|
||||
});
|
||||
|
||||
items = await Promise.all(
|
||||
items.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
cache.tryGet(item.link!, async () => {
|
||||
const detailResponse = await got({
|
||||
method: 'get',
|
||||
url: item.link,
|
||||
|
||||
+10
-10
@@ -1,6 +1,6 @@
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { DataItem, Language, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
@@ -22,20 +22,20 @@ export const handler = async (ctx) => {
|
||||
let items = $('div.left-news ul li')
|
||||
.slice(0, limit)
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
.map((item): DataItem => {
|
||||
const $item = $(item);
|
||||
|
||||
return {
|
||||
title: item.find('a').text(),
|
||||
pubDate: timezone(parseDate(item.find('span').text()), 8),
|
||||
link: item.find('a').prop('href'),
|
||||
language,
|
||||
title: $item.find('a').text(),
|
||||
pubDate: timezone(parseDate($item.find('span').text()), 8),
|
||||
link: $item.find('a').prop('href'),
|
||||
language: language as Language,
|
||||
};
|
||||
});
|
||||
|
||||
items = await Promise.all(
|
||||
items.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
cache.tryGet(item.link!, async () => {
|
||||
const { data: detailResponse } = await got(item.link);
|
||||
|
||||
const $$ = load(detailResponse);
|
||||
@@ -50,7 +50,7 @@ export const handler = async (ctx) => {
|
||||
html: description,
|
||||
text: $$('div.txt').text(),
|
||||
};
|
||||
item.language = language;
|
||||
item.language = language as Language;
|
||||
|
||||
return item;
|
||||
})
|
||||
@@ -68,7 +68,7 @@ export const handler = async (ctx) => {
|
||||
allowEmpty: true,
|
||||
image,
|
||||
author: title.split(/-/).pop()?.trim(),
|
||||
language,
|
||||
language: language as Language,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { load } from 'cheerio';
|
||||
import { renderToString } from 'hono/jsx/dom/server';
|
||||
import iconv from 'iconv-lite';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { DataItem, Language, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
@@ -103,20 +103,20 @@ async function handler(ctx) {
|
||||
.find('a')
|
||||
.slice(0, limit)
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
.map((item): DataItem => {
|
||||
const $item = $(item);
|
||||
|
||||
const link = item.prop('href');
|
||||
const link = $item.prop('href');
|
||||
|
||||
return {
|
||||
title: item.text(),
|
||||
link: link.startsWith('http') ? link : new URL(link, rootUrl).href,
|
||||
title: $item.text(),
|
||||
link: link!.startsWith('http') ? link : new URL(link!, rootUrl).href,
|
||||
};
|
||||
});
|
||||
|
||||
items = await Promise.all(
|
||||
items.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
cache.tryGet(item.link!, async () => {
|
||||
const { data: detailResponse } = await got(item.link, {
|
||||
responseType: 'buffer',
|
||||
});
|
||||
@@ -127,7 +127,7 @@ async function handler(ctx) {
|
||||
content('i.pstatus').remove();
|
||||
content('div.crly').remove();
|
||||
|
||||
const pubDate = content('span.pub-time').text() || content('span.fby span').first().prop('title') || content('span.fby').first().text().split('发表于').pop().trim();
|
||||
const pubDate = content('span.pub-time').text() || content('span.fby span').first().prop('title') || content('span.fby').first().text().split('发表于').pop()!.trim();
|
||||
|
||||
content('img').each((_, el) => {
|
||||
content(el).replaceWith(
|
||||
@@ -160,7 +160,7 @@ async function handler(ctx) {
|
||||
title: `${$('span.country, h2').text()} - ${description.split(',').pop()}`,
|
||||
link: currentUrl,
|
||||
description,
|
||||
language: 'zh-cn',
|
||||
language: 'zh-CN' as Language,
|
||||
icon,
|
||||
logo: icon,
|
||||
subtitle: $('meta[name="keywords"]').prop('content').trim(),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { DataItem, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import { getSubPath } from '@/utils/common-utils';
|
||||
import got from '@/utils/got';
|
||||
@@ -41,18 +41,18 @@ export async function handler(ctx) {
|
||||
|
||||
let items = $('div[data-column="Two-Third"] .article-title .article-link')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
.map((item): DataItem => {
|
||||
const $item = $(item);
|
||||
|
||||
return {
|
||||
title: item.text(),
|
||||
link: `${rootUrl}${item.attr('href')}`,
|
||||
title: $item.text(),
|
||||
link: `${rootUrl}${$item.attr('href')}`,
|
||||
};
|
||||
});
|
||||
|
||||
items = await Promise.all(
|
||||
items.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
cache.tryGet(item.link!, async () => {
|
||||
const detailResponse = await got({
|
||||
method: 'get',
|
||||
url: item.link,
|
||||
@@ -61,12 +61,12 @@ export async function handler(ctx) {
|
||||
const content = load(detailResponse.data);
|
||||
|
||||
item.description = content('.text-long').html();
|
||||
item.title = content('meta[name="cXenseParse:mdc-title"]').attr('content');
|
||||
item.title = content('meta[name="cXenseParse:mdc-title"]').attr('content')!;
|
||||
item.author = content('meta[name="cXenseParse:author"]').attr('content');
|
||||
item.pubDate = parseDate(content('meta[name="cXenseParse:recs:publishtime"]').attr('content'));
|
||||
item.pubDate = parseDate(content('meta[name="cXenseParse:recs:publishtime"]').attr('content')!);
|
||||
item.category = content('meta[name="cXenseParse:mdc-keywords"]')
|
||||
.toArray()
|
||||
.map((keyword) => content(keyword).attr('content'));
|
||||
.map((keyword) => content(keyword).attr('content')!);
|
||||
|
||||
return item;
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { DataItem, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
@@ -53,25 +53,25 @@ async function handler(ctx) {
|
||||
|
||||
let items = $('.row .well')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
.map((item): DataItem & { poster?: string } => {
|
||||
const $item = $(item);
|
||||
return {
|
||||
title: item.find('.video-title').text(),
|
||||
link: item.find('a').attr('href'),
|
||||
poster: item.find('.img-responsive').attr('src'),
|
||||
title: $item.find('.video-title').text(),
|
||||
link: $item.find('a').attr('href'),
|
||||
poster: $item.find('.img-responsive').attr('src'),
|
||||
};
|
||||
});
|
||||
|
||||
items = await Promise.all(
|
||||
items.map((item) =>
|
||||
cache.tryGet(`91porn:${lang}:${new URL(item.link).searchParams.get('viewkey')}`, async () => {
|
||||
cache.tryGet(`91porn:${lang}:${new URL(item.link!).searchParams.get('viewkey')}`, async () => {
|
||||
const { data } = await got(item.link);
|
||||
const $ = load(data);
|
||||
|
||||
item.pubDate = parseDate($('.title-yakov').eq(0).text(), 'YYYY-MM-DD');
|
||||
item.description = renderIndexDescription({
|
||||
link: item.link,
|
||||
poster: item.poster,
|
||||
link: item.link!,
|
||||
poster: item.poster!,
|
||||
});
|
||||
item.author = $('.title-yakov a span').text();
|
||||
delete item.poster;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { DataItem, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
@@ -56,25 +56,25 @@ async function handler(ctx) {
|
||||
|
||||
let items = $('.row .well')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
.map((item): DataItem & { poster?: string } => {
|
||||
const $item = $(item);
|
||||
return {
|
||||
title: item.find('.video-title').text(),
|
||||
link: item.find('a').attr('href'),
|
||||
poster: item.find('.img-responsive').attr('src'),
|
||||
title: $item.find('.video-title').text(),
|
||||
link: $item.find('a').attr('href'),
|
||||
poster: $item.find('.img-responsive').attr('src'),
|
||||
};
|
||||
});
|
||||
|
||||
items = await Promise.all(
|
||||
items.map((item) =>
|
||||
cache.tryGet(`91porn:${lang}:${new URL(item.link).searchParams.get('viewkey')}`, async () => {
|
||||
cache.tryGet(`91porn:${lang}:${new URL(item.link!).searchParams.get('viewkey')}`, async () => {
|
||||
const { data } = await got(item.link);
|
||||
const $ = load(data);
|
||||
|
||||
item.pubDate = parseDate($('.title-yakov').eq(0).text(), 'YYYY-MM-DD');
|
||||
item.description = renderIndexDescription({
|
||||
link: item.link,
|
||||
poster: item.poster,
|
||||
link: item.link!,
|
||||
poster: item.poster!,
|
||||
});
|
||||
item.author = $('.title-yakov a span').text();
|
||||
delete item.poster;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { load } from 'cheerio';
|
||||
import { renderToString } from 'hono/jsx/dom/server';
|
||||
|
||||
import type { DataItem } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
|
||||
@@ -19,21 +20,21 @@ const ProcessItems = async (ctx, title, currentUrl) => {
|
||||
|
||||
let items = $('div.list-body')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
.map((item): DataItem => {
|
||||
const $item = $(item);
|
||||
|
||||
const a = item.find('a');
|
||||
const a = $item.find('a');
|
||||
|
||||
return {
|
||||
title: a.text(),
|
||||
link: a.attr('href'),
|
||||
guid: a.attr('href').replace('95mm.vip', '95mm.org'),
|
||||
guid: a.attr('href')!.replace('95mm.vip', '95mm.org'),
|
||||
};
|
||||
});
|
||||
|
||||
items = await Promise.all(
|
||||
items.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
cache.tryGet(item.link!, async () => {
|
||||
const detailResponse = await got({
|
||||
method: 'get',
|
||||
url: item.link,
|
||||
|
||||
@@ -64,7 +64,7 @@ async function handler(ctx) {
|
||||
|
||||
const items = await Promise.all(
|
||||
feed.items.splice(0, limit).map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
cache.tryGet(item.link!, async () => {
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
url: item.link,
|
||||
@@ -72,7 +72,7 @@ async function handler(ctx) {
|
||||
const description = utils.ProcessFeed(response.data);
|
||||
|
||||
const single = {
|
||||
title: item.title,
|
||||
title: item.title!,
|
||||
description,
|
||||
pubDate: item.pubDate,
|
||||
link: item.link,
|
||||
|
||||
@@ -6,7 +6,7 @@ const ProcessFeed = (data) => {
|
||||
|
||||
const cover = $('meta[property="og:image"]');
|
||||
if (cover.length > 0) {
|
||||
$(`<img src=${cover[0].attribs.content}>`).insertBefore(content[0].firstChild);
|
||||
$(`<img src=${cover[0].attribs.content}>`).insertBefore(content[0].firstChild!);
|
||||
}
|
||||
|
||||
// remove useless DOMs
|
||||
|
||||
+17
-17
@@ -1,6 +1,6 @@
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { DataItem, Language, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
@@ -24,15 +24,15 @@ export const handler = async (ctx) => {
|
||||
let items = $('a.a9-rich-card-list_item')
|
||||
.slice(0, limit)
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
.map((item): DataItem => {
|
||||
const $item = $(item);
|
||||
|
||||
const image = item.find('img.a9-rich-card-list_image');
|
||||
const title = item.find('div.a9-rich-card-list_label').text();
|
||||
const image = $item.find('img.a9-rich-card-list_image');
|
||||
const title = $item.find('div.a9-rich-card-list_label').text();
|
||||
|
||||
return {
|
||||
title,
|
||||
link: new URL(item.prop('href'), rootUrl).href,
|
||||
link: new URL($item.prop('href')!, rootUrl).href,
|
||||
description: renderDescription({
|
||||
images: image
|
||||
? [
|
||||
@@ -43,28 +43,28 @@ export const handler = async (ctx) => {
|
||||
]
|
||||
: undefined,
|
||||
}),
|
||||
pubDate: timezone(parseDate(item.find('div.a9-rich-card-list_infos').text()), 8),
|
||||
language,
|
||||
pubDate: timezone(parseDate($item.find('div.a9-rich-card-list_infos').text()), 8),
|
||||
language: language as Language,
|
||||
};
|
||||
});
|
||||
|
||||
items = await Promise.all(
|
||||
items.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
cache.tryGet(item.link!, async () => {
|
||||
const { data: detailResponse } = await got(item.link);
|
||||
|
||||
const $$ = load(detailResponse);
|
||||
|
||||
$$('ignore_js_op img, p img').each((_, el) => {
|
||||
el = $$(el);
|
||||
const $el = $$(el);
|
||||
|
||||
el.parent().replaceWith(
|
||||
$el.parent().replaceWith(
|
||||
renderDescription({
|
||||
images: el.prop('file')
|
||||
images: $el.prop('file')
|
||||
? [
|
||||
{
|
||||
src: el.prop('file'),
|
||||
alt: el.next().find('div.xs0 p').first().text(),
|
||||
src: $el.prop('file'),
|
||||
alt: $el.next().find('div.xs0 p').first().text(),
|
||||
},
|
||||
]
|
||||
: undefined,
|
||||
@@ -74,7 +74,7 @@ export const handler = async (ctx) => {
|
||||
|
||||
item.title = $$('h1.ts, div.c-article-main_content-title').text();
|
||||
item.description = renderDescription({
|
||||
description: $$('td.t_f, div.c-article-main_contentraw').first().html(),
|
||||
description: $$('td.t_f, div.c-article-main_contentraw').first().html() ?? undefined,
|
||||
});
|
||||
item.author =
|
||||
$$('b a.blue').first().text() ||
|
||||
@@ -96,7 +96,7 @@ export const handler = async (ctx) => {
|
||||
),
|
||||
8
|
||||
);
|
||||
item.language = language;
|
||||
item.language = language as Language;
|
||||
|
||||
return item;
|
||||
})
|
||||
@@ -114,7 +114,7 @@ export const handler = async (ctx) => {
|
||||
allowEmpty: true,
|
||||
image,
|
||||
author: title.split(/-/).pop(),
|
||||
language,
|
||||
language: language as Language,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { CheerioAPI } from 'cheerio';
|
||||
import { load } from 'cheerio';
|
||||
import type { Context } from 'hono';
|
||||
|
||||
import type { Data, DataItem, Route } from '@/types';
|
||||
import type { Data, DataItem, Language, Route } from '@/types';
|
||||
import { ViewType } from '@/types';
|
||||
import ofetch from '@/utils/ofetch';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
@@ -76,7 +76,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
image,
|
||||
banner: image,
|
||||
updated: updated ? parseDate(updated) : undefined,
|
||||
language,
|
||||
language: language as Language,
|
||||
};
|
||||
|
||||
return processedItem;
|
||||
@@ -92,7 +92,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
allowEmpty: true,
|
||||
image: $('header#header-div img').attr('src'),
|
||||
author: title.split(/-/).pop(),
|
||||
language,
|
||||
language: language as Language,
|
||||
id: targetUrl,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { DataItem, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
@@ -56,18 +56,18 @@ async function handler(ctx) {
|
||||
|
||||
const list = $('post-title a')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
.map((item): DataItem => {
|
||||
const $item = $(item);
|
||||
|
||||
return {
|
||||
title: item.text(),
|
||||
link: item.attr('href'),
|
||||
title: $item.text(),
|
||||
link: $item.attr('href'),
|
||||
};
|
||||
});
|
||||
|
||||
const items = await Promise.all(
|
||||
list.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
cache.tryGet(item.link!, async () => {
|
||||
const detailResponse = await got({
|
||||
method: 'get',
|
||||
url: item.link,
|
||||
@@ -79,7 +79,7 @@ async function handler(ctx) {
|
||||
|
||||
item.description = content('#contentleft').html();
|
||||
item.author = content('meta[itemprop="author"]').attr('content');
|
||||
item.pubDate = parseDate(content('meta[property="article:published_time"]').attr('content'));
|
||||
item.pubDate = parseDate(content('meta[property="article:published_time"]').attr('content')!);
|
||||
|
||||
return item;
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { DataItem, Language, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import ofetch from '@/utils/ofetch';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
@@ -67,7 +67,7 @@ async function handler(ctx) {
|
||||
});
|
||||
|
||||
let items = response.collection.slice(0, limit).map((i) => {
|
||||
const item = {
|
||||
const item: DataItem = {
|
||||
title: i.title.children ?? i.title,
|
||||
link: i.link.startsWith('https://') ? i.link : new URL(i.link, rootUrl).href,
|
||||
description: renderDescription({
|
||||
@@ -107,11 +107,11 @@ async function handler(ctx) {
|
||||
.children()
|
||||
.each((_, el) => {
|
||||
const element = content(el);
|
||||
if (element.prop('tagName').toLowerCase() === 'figure') {
|
||||
if (element.prop('tagName')!.toLowerCase() === 'figure') {
|
||||
element.replaceWith(
|
||||
renderDescription({
|
||||
image: {
|
||||
src: element.find('img').prop('src').split(/\?/, 1)[0],
|
||||
src: element.find('img').prop('src')!.split(/\?/, 1)[0],
|
||||
alt: element.find('figcaption').text().trim(),
|
||||
},
|
||||
})
|
||||
@@ -178,7 +178,7 @@ async function handler(ctx) {
|
||||
title: $('title').first().text(),
|
||||
link: currentUrl,
|
||||
description: $('meta[property="og:description"]').prop('content'),
|
||||
language: $('html').prop('lang'),
|
||||
language: $('html').prop('lang') as Language,
|
||||
image: $('meta[property="og:image"]').prop('content').split('?', 1)[0],
|
||||
icon,
|
||||
logo: icon,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { raw } from 'hono/html';
|
||||
import type { FC } from 'hono/jsx';
|
||||
import { renderToString } from 'hono/jsx/dom/server';
|
||||
import type { JSX } from 'hono/jsx/jsx-runtime';
|
||||
|
||||
type DescriptionData = {
|
||||
image?: {
|
||||
@@ -15,7 +15,7 @@ type DescriptionData = {
|
||||
};
|
||||
|
||||
const AbcDescription = ({ image, enclosure, description }: DescriptionData) => {
|
||||
const enclosureTag = enclosure?.type?.split('/', 1)[0] as keyof JSX.IntrinsicElements | undefined;
|
||||
const enclosureTag = enclosure?.type?.split('/', 1)[0] as unknown as FC | undefined;
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { Language, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
@@ -64,7 +64,7 @@ export const handler = async (ctx) => {
|
||||
},
|
||||
image,
|
||||
banner: image,
|
||||
language,
|
||||
language: language as Language,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -79,7 +79,7 @@ export const handler = async (ctx) => {
|
||||
const description =
|
||||
item.description +
|
||||
renderDescription({
|
||||
description: $$('div.khl-article-page-storybody').html(),
|
||||
description: $$('div.khl-article-page-storybody').html() ?? undefined,
|
||||
});
|
||||
|
||||
item.title = title;
|
||||
@@ -99,7 +99,7 @@ export const handler = async (ctx) => {
|
||||
)
|
||||
);
|
||||
|
||||
const image = new URL($('a.navbar-brand img').prop('src'), rootUrl).href;
|
||||
const image = new URL($('a.navbar-brand img').prop('src')!, rootUrl).href;
|
||||
|
||||
return {
|
||||
title: $('title').text(),
|
||||
@@ -109,7 +109,7 @@ export const handler = async (ctx) => {
|
||||
allowEmpty: true,
|
||||
image,
|
||||
author: $('meta[property="og:site_name"]').prop('content'),
|
||||
language,
|
||||
language: language as Language,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ const AccessBriefingDescription = ({ images, intro, description }: DescriptionDa
|
||||
? images.map((image) =>
|
||||
image?.src ? (
|
||||
<figure>
|
||||
<img alt={image.height ?? image.width ?? image.alt} src={image.src} />
|
||||
<img alt={(image.height ?? image.width ?? image.alt) as string | undefined} src={image.src} />
|
||||
</figure>
|
||||
) : null
|
||||
)
|
||||
|
||||
@@ -133,7 +133,7 @@ async function handler(ctx) {
|
||||
const $ = load(response.data);
|
||||
const articleInfo = $('.main script')
|
||||
.text()
|
||||
.match(/window.articleInfo = (.*);\n\s*window.likeDomain/)[1];
|
||||
.match(/window.articleInfo = (.*);\n\s*window.likeDomain/)![1];
|
||||
const data = JSON.parse(articleInfo);
|
||||
|
||||
item.description = data.parts[0].content;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { DataItem, Language, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
@@ -38,19 +38,19 @@ async function handler(ctx) {
|
||||
let items = $('div.text01 ul li a[title]')
|
||||
.slice(0, limit)
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
.map((item): DataItem => {
|
||||
const $item = $(item);
|
||||
|
||||
return {
|
||||
title: item.prop('title'),
|
||||
link: new URL(item.prop('href'), rootUrl).href,
|
||||
pubDate: timezone(parseDate(item.find('span[title]').prop('title')), 8),
|
||||
title: $item.prop('title')!,
|
||||
link: new URL($item.prop('href')!, rootUrl).href,
|
||||
pubDate: timezone(parseDate($item.find('span[title]').prop('title')), 8),
|
||||
};
|
||||
});
|
||||
|
||||
items = await Promise.all(
|
||||
items.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
cache.tryGet(item.link!, async () => {
|
||||
const { data: detailResponse } = await got(item.link);
|
||||
|
||||
const content = load(detailResponse);
|
||||
@@ -71,7 +71,7 @@ async function handler(ctx) {
|
||||
title: `${author} - ${subtitle}`,
|
||||
link: currentUrl,
|
||||
description: $('meta[property="og:description"]').prop('content'),
|
||||
language: 'zh',
|
||||
language: 'zh' as Language,
|
||||
subtitle,
|
||||
author,
|
||||
};
|
||||
|
||||
@@ -56,28 +56,28 @@ async function handler(ctx) {
|
||||
|
||||
const $ = load(html);
|
||||
|
||||
title = $('meta[property="og:title"]').attr('content');
|
||||
title = $('meta[property="og:title"]').attr('content')!;
|
||||
|
||||
return $('.issue-item')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
const $item = $(item);
|
||||
|
||||
const a = item.find('.issue-item_title a');
|
||||
const doi = item.find('input[name="doi"]').attr('value');
|
||||
const a = $item.find('.issue-item_title a');
|
||||
const doi = $item.find('input[name="doi"]').attr('value');
|
||||
|
||||
return {
|
||||
doi,
|
||||
guid: doi,
|
||||
title: a.text(),
|
||||
link: `${rootUrl}${a.attr('href')}`,
|
||||
pubDate: parseDate(item.find('.pub-date-value').text(), 'MMMM D, YYYY'),
|
||||
author: item
|
||||
pubDate: parseDate($item.find('.pub-date-value').text(), 'MMMM D, YYYY'),
|
||||
author: $item
|
||||
.find('.issue-item_loa li')
|
||||
.toArray()
|
||||
.map((a) => $(a).text())
|
||||
.join(', '),
|
||||
description: renderDescription(item.find('.issue-item_img').html(), item.find('.hlFld-Abstract').html()),
|
||||
description: renderDescription($item.find('.issue-item_img').html(), $item.find('.hlFld-Abstract').html()),
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
@@ -3,7 +3,7 @@ import { load } from 'cheerio';
|
||||
import type { Element } from 'domhandler';
|
||||
import type { Context } from 'hono';
|
||||
|
||||
import type { Data, DataItem, Route } from '@/types';
|
||||
import type { Data, DataItem, Language, Route } from '@/types';
|
||||
import { ViewType } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import ofetch from '@/utils/ofetch';
|
||||
@@ -25,7 +25,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
let items: DataItem[] = $('div.article_1')
|
||||
.slice(0, limit)
|
||||
.toArray()
|
||||
.map((el): Element => {
|
||||
.map((el) => {
|
||||
const $el: Cheerio<Element> = $(el);
|
||||
|
||||
const title: string = $el.find('p.article_2_p').text();
|
||||
@@ -51,7 +51,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
image,
|
||||
banner: image,
|
||||
updated: upDatedStr ? parseDate(upDatedStr) : undefined,
|
||||
language,
|
||||
language: language as Language,
|
||||
};
|
||||
|
||||
return processedItem;
|
||||
@@ -65,7 +65,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
}
|
||||
|
||||
return cache.tryGet(item.link, async (): Promise<DataItem> => {
|
||||
const detailResponse = await ofetch(item.link);
|
||||
const detailResponse = await ofetch(item.link!);
|
||||
const $$: CheerioAPI = load(detailResponse);
|
||||
|
||||
const title: string = $$('p.infoTitle_left').text();
|
||||
@@ -89,7 +89,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
text: description,
|
||||
},
|
||||
updated: upDatedStr ? timezone(parseDate(upDatedStr), 8) : item.updated,
|
||||
language,
|
||||
language: language as Language,
|
||||
};
|
||||
|
||||
return {
|
||||
@@ -109,7 +109,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
allowEmpty: true,
|
||||
image: $('img.navi_logo').attr('src'),
|
||||
author: $('meta[name="author"]').attr('content'),
|
||||
language,
|
||||
language: language as Language,
|
||||
id: targetUrl,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@ import { load } from 'cheerio';
|
||||
import type { Element } from 'domhandler';
|
||||
import type { Context } from 'hono';
|
||||
|
||||
import type { Data, DataItem, Route } from '@/types';
|
||||
import type { Data, DataItem, Language, Route } from '@/types';
|
||||
import { ViewType } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import ofetch from '@/utils/ofetch';
|
||||
@@ -25,7 +25,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
let items: DataItem[] = $('div.article_1')
|
||||
.slice(0, limit)
|
||||
.toArray()
|
||||
.map((el): Element => {
|
||||
.map((el) => {
|
||||
const $el: Cheerio<Element> = $(el);
|
||||
|
||||
const title: string = $el.find('p.article_2_p').text();
|
||||
@@ -51,7 +51,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
image,
|
||||
banner: image,
|
||||
updated: upDatedStr ? parseDate(upDatedStr) : undefined,
|
||||
language,
|
||||
language: language as Language,
|
||||
};
|
||||
|
||||
return processedItem;
|
||||
@@ -65,7 +65,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
}
|
||||
|
||||
return cache.tryGet(item.link, async (): Promise<DataItem> => {
|
||||
const detailResponse = await ofetch(item.link);
|
||||
const detailResponse = await ofetch(item.link!);
|
||||
const $$: CheerioAPI = load(detailResponse);
|
||||
|
||||
const title: string = $$('p.infoTitle_left').text();
|
||||
@@ -89,7 +89,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
text: description,
|
||||
},
|
||||
updated: upDatedStr ? timezone(parseDate(upDatedStr), 8) : item.updated,
|
||||
language,
|
||||
language: language as Language,
|
||||
};
|
||||
|
||||
return {
|
||||
@@ -109,7 +109,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
allowEmpty: true,
|
||||
image: $('img.navi_logo').attr('src'),
|
||||
author: $('meta[name="author"]').attr('content'),
|
||||
language,
|
||||
language: language as Language,
|
||||
id: targetUrl,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { load } from 'cheerio';
|
||||
import { renderToString } from 'hono/jsx/dom/server';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { DataItem, Language, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
@@ -64,17 +64,18 @@ async function handler(ctx) {
|
||||
|
||||
let items = $('h4.title a')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
.map((item): DataItem => {
|
||||
const $item = $(item);
|
||||
|
||||
return {
|
||||
link: `${rootUrl}${item.attr('href').split('&', 1)[0]}`,
|
||||
title: '',
|
||||
link: `${rootUrl}${$item.attr('href')!.split('&', 1)[0]}`,
|
||||
};
|
||||
});
|
||||
|
||||
items = await Promise.all(
|
||||
items.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
cache.tryGet(item.link!, async () => {
|
||||
const detailResponse = await got({
|
||||
method: 'get',
|
||||
url: item.link,
|
||||
@@ -85,16 +86,16 @@ async function handler(ctx) {
|
||||
item.doi = content('meta[name="citation_doi"]').attr('content');
|
||||
|
||||
item.guid = item.doi;
|
||||
item.title = content('meta[name="citation_title"]').attr('content');
|
||||
item.title = content('meta[name="citation_title"]').attr('content')!;
|
||||
item.author = content('.author')
|
||||
.toArray()
|
||||
.map((a) => content(a).text().trim())
|
||||
.join(', ');
|
||||
item.pubDate = parseDate(content('meta[name="citation_publication_date"]').attr('content'), 'YYYY/MM');
|
||||
item.pubDate = parseDate(content('meta[name="citation_publication_date"]').attr('content')!, 'YYYY/MM');
|
||||
item.description = renderToString(
|
||||
<AeawebDescription
|
||||
description={content('meta[name="twitter:description"]')
|
||||
.attr('content')
|
||||
.attr('content')!
|
||||
.replace(/\(\w+ \d+\)( - )?/, '')}
|
||||
/>
|
||||
);
|
||||
@@ -109,7 +110,7 @@ async function handler(ctx) {
|
||||
description,
|
||||
link: currentUrl,
|
||||
item: items,
|
||||
language: $('html').attr('lang'),
|
||||
language: $('html').attr('lang') as Language,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { Route } from '@/types';
|
||||
import got from '@/utils/got';
|
||||
|
||||
const categoryMap = {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { load } from 'cheerio';
|
||||
import type { Element } from 'domhandler';
|
||||
import type { Context } from 'hono';
|
||||
|
||||
import type { Data, DataItem, Route } from '@/types';
|
||||
import type { Data, DataItem, Language, Route } from '@/types';
|
||||
import { ViewType } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import ofetch from '@/utils/ofetch';
|
||||
@@ -22,7 +22,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
let items: DataItem[] = $('article.article')
|
||||
.slice(0, limit)
|
||||
.toArray()
|
||||
.map((el): Element => {
|
||||
.map((el) => {
|
||||
const $el: Cheerio<Element> = $(el);
|
||||
const $aEl: Cheerio<Element> = $el.find('header.container h1 a').first();
|
||||
|
||||
@@ -56,7 +56,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
image,
|
||||
banner: image,
|
||||
updated: upDatedStr ? parseDate(upDatedStr) : undefined,
|
||||
language,
|
||||
language: language as Language,
|
||||
};
|
||||
|
||||
return processedItem;
|
||||
@@ -70,7 +70,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
}
|
||||
|
||||
return cache.tryGet(item.link, async (): Promise<DataItem> => {
|
||||
const detailResponse = await ofetch(item.link);
|
||||
const detailResponse = await ofetch(item.link!);
|
||||
const $$: CheerioAPI = load(detailResponse);
|
||||
|
||||
const title: string = $$('header.article-header h1').text();
|
||||
@@ -101,7 +101,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
image,
|
||||
banner: image,
|
||||
updated: upDatedStr ? parseDate(upDatedStr) : item.updated,
|
||||
language,
|
||||
language: language as Language,
|
||||
};
|
||||
|
||||
return {
|
||||
@@ -123,7 +123,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
allowEmpty: true,
|
||||
image: $('img.main-logo').attr('src') ? new URL($('img.main-logo').attr('src') as string, baseUrl).href : undefined,
|
||||
author: title.split(/\|/).pop(),
|
||||
language,
|
||||
language: language as Language,
|
||||
id: targetUrl,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -39,11 +39,11 @@ async function handler(ctx) {
|
||||
.find('li')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
const a = item.find('a');
|
||||
const $item = $(item);
|
||||
const a = $item.find('a');
|
||||
return {
|
||||
title: a.text(),
|
||||
link: a.attr('href').replace('http://', 'https://'),
|
||||
link: a.attr('href')!.replace('http://', 'https://'),
|
||||
};
|
||||
})
|
||||
.toReversed();
|
||||
|
||||
@@ -39,20 +39,20 @@ async function handler() {
|
||||
|
||||
const list = $('.video_item')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
const link = item.find('a').attr('href').replace('http://', 'https://');
|
||||
.map((item): DataItem => {
|
||||
const $item = $(item);
|
||||
const link = $item.find('a').attr('href')!.replace('http://', 'https://');
|
||||
return {
|
||||
title: item.text(),
|
||||
title: $item.text(),
|
||||
link,
|
||||
guid: `${link}#${item.find('.video_item--info').text()}`,
|
||||
guid: `${link}#${$item.find('.video_item--info').text()}`,
|
||||
};
|
||||
});
|
||||
|
||||
const items: DataItem[] = await pMap(
|
||||
list,
|
||||
(item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
cache.tryGet(item.link!, async () => {
|
||||
const detailResponse = await got(item.link);
|
||||
const content = load(detailResponse.data);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { Language, Route } from '@/types';
|
||||
import ofetch from '@/utils/ofetch';
|
||||
|
||||
import { baseUrl } from './utils';
|
||||
@@ -40,11 +40,11 @@ async function handler() {
|
||||
const items = $('.ag-topic')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
const $item = $(item);
|
||||
return {
|
||||
title: item.find('.ag-topic__link').text(),
|
||||
description: item.find('.ag-topic__summery').text(),
|
||||
link: `${baseUrl}${item.find('.ag-topic__link').attr('href')}`,
|
||||
title: $item.find('.ag-topic__link').text(),
|
||||
description: $item.find('.ag-topic__summery').text(),
|
||||
link: `${baseUrl}${$item.find('.ag-topic__link').attr('href')}`,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -53,6 +53,6 @@ async function handler() {
|
||||
link,
|
||||
description: $('head meta[name=description]').attr('content'),
|
||||
item: items,
|
||||
language: $('html').attr('lang'),
|
||||
language: $('html').attr('lang') as Language,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { Language, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import ofetch from '@/utils/ofetch';
|
||||
|
||||
@@ -39,10 +39,10 @@ async function handler(ctx) {
|
||||
const list = $('.ag-post-item__link')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
const $item = $(item);
|
||||
return {
|
||||
title: item.text(),
|
||||
link: `${baseUrl}${item.attr('href')}`,
|
||||
title: $item.text(),
|
||||
link: `${baseUrl}${$item.attr('href')}`,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -53,6 +53,6 @@ async function handler(ctx) {
|
||||
link,
|
||||
description: ldJson['@graph'][0].description,
|
||||
item: items,
|
||||
language: $('html').attr('lang'),
|
||||
language: $('html').attr('lang') as Language,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { Language, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import ofetch from '@/utils/ofetch';
|
||||
|
||||
@@ -43,10 +43,10 @@ async function handler(ctx) {
|
||||
const list = $('.ag-post-list .ag-post-item__link')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
const $item = $(item);
|
||||
return {
|
||||
title: item.text(),
|
||||
link: `${baseUrl}${item.attr('href')}`,
|
||||
title: $item.text(),
|
||||
link: `${baseUrl}${$item.attr('href')}`,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -57,6 +57,6 @@ async function handler(ctx) {
|
||||
link,
|
||||
description: $('head meta[name=description]').attr('content'),
|
||||
item: items,
|
||||
language: $('html').attr('lang'),
|
||||
language: $('html').attr('lang') as Language,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { DataItem, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
@@ -48,18 +48,18 @@ async function handler(ctx) {
|
||||
let items = $('.card span:not(.comments) a')
|
||||
.slice(0, ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : 50)
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
.map((item): DataItem => {
|
||||
const $item = $(item);
|
||||
|
||||
return {
|
||||
title: item.text(),
|
||||
link: item.attr('href'),
|
||||
title: $item.text(),
|
||||
link: $item.attr('href'),
|
||||
};
|
||||
});
|
||||
|
||||
items = await Promise.all(
|
||||
items.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
cache.tryGet(item.link!, async () => {
|
||||
const detailResponse = await got({
|
||||
method: 'get',
|
||||
url: item.link,
|
||||
@@ -68,7 +68,7 @@ async function handler(ctx) {
|
||||
const content = load(detailResponse.data);
|
||||
|
||||
item.author = content('meta[name="author"]').attr('content');
|
||||
item.pubDate = parseDate(content('meta[property="article:published_time"]').attr('content'));
|
||||
item.pubDate = parseDate(content('meta[property="article:published_time"]').attr('content')!);
|
||||
item.description = content('.post-content').html();
|
||||
|
||||
return item;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { DataItem, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
@@ -37,12 +37,12 @@ async function handler() {
|
||||
const list = $('div article')
|
||||
.toArray()
|
||||
.slice(0, -1) // last one is a dummy
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
const meta = item.find('h5').first().text();
|
||||
.map((item): DataItem => {
|
||||
const $item = $(item);
|
||||
const meta = $item.find('h5').first().text();
|
||||
return {
|
||||
title: item.find('h3').text(),
|
||||
link: item.find('h3 a').attr('href'),
|
||||
title: $item.find('h3').text(),
|
||||
link: $item.find('h3 a').attr('href'),
|
||||
author: meta.split('|', 1)[0].trim(),
|
||||
pubDate: parseDate(meta.split('|', 2)[1].trim()),
|
||||
};
|
||||
@@ -50,7 +50,7 @@ async function handler() {
|
||||
|
||||
const items = await Promise.all(
|
||||
list.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
cache.tryGet(item.link!, async () => {
|
||||
const response = await got(item.link);
|
||||
const $ = load(response.data);
|
||||
$('h1').remove();
|
||||
|
||||
+14
-14
@@ -1,6 +1,6 @@
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { DataItem, Language, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
@@ -24,15 +24,15 @@ export const handler = async (ctx) => {
|
||||
let items = $('div.list_li_con, div.nxw_video_com')
|
||||
.slice(0, limit)
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
.map((item): DataItem => {
|
||||
const $item = $(item);
|
||||
|
||||
const a = item.find('a').first();
|
||||
const a = $item.find('a').first();
|
||||
|
||||
const title = a.text();
|
||||
const image = item.find('img').first().prop('src') ? new URL(item.find('img').first().prop('src'), rootUrl).href : undefined;
|
||||
const image = $item.find('img').first().prop('src') ? new URL($item.find('img').first().prop('src')!, rootUrl).href : undefined;
|
||||
const description = renderDescription({
|
||||
intro: item.find('p.con_text').text() || undefined,
|
||||
intro: $item.find('p.con_text').text() || undefined,
|
||||
images: image
|
||||
? [
|
||||
{
|
||||
@@ -46,21 +46,21 @@ export const handler = async (ctx) => {
|
||||
return {
|
||||
title,
|
||||
description,
|
||||
pubDate: parseDate(item.find('span.con_date_span').text() || `${item.find('div.com_time_p2').text().trim()}${item.find('div.com_time_p1').text()}`, ['YYYY-MM-DD', 'YYYY.MM.DD']),
|
||||
link: new URL(a.prop('href'), currentUrl).href,
|
||||
pubDate: parseDate($item.find('span.con_date_span').text() || `${$item.find('div.com_time_p2').text().trim()}${$item.find('div.com_time_p1').text()}`, ['YYYY-MM-DD', 'YYYY.MM.DD']),
|
||||
link: new URL(a.prop('href')!, currentUrl).href,
|
||||
content: {
|
||||
html: description,
|
||||
text: item.find('p.con_text').text() || undefined,
|
||||
text: $item.find('p.con_text').text() || undefined,
|
||||
},
|
||||
image,
|
||||
banner: image,
|
||||
language,
|
||||
language: language as Language,
|
||||
};
|
||||
});
|
||||
|
||||
items = await Promise.all(
|
||||
items.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
cache.tryGet(item.link!, async () => {
|
||||
const { data: detailResponse } = await got(item.link);
|
||||
|
||||
const $$ = load(detailResponse);
|
||||
@@ -78,7 +78,7 @@ export const handler = async (ctx) => {
|
||||
html: description,
|
||||
text: $$('div.content_body_box').text(),
|
||||
};
|
||||
item.language = language;
|
||||
item.language = language as Language;
|
||||
|
||||
item.enclosure_url = $$('div.content_body_box video').prop('src') ?? undefined;
|
||||
item.enclosure_type = item.enclosure_url ? 'video/mp4' : undefined;
|
||||
@@ -89,7 +89,7 @@ export const handler = async (ctx) => {
|
||||
)
|
||||
);
|
||||
|
||||
const image = new URL($('div.logo img').prop('src'), rootUrl).href;
|
||||
const image = new URL($('div.logo img').prop('src')!, rootUrl).href;
|
||||
|
||||
return {
|
||||
title: $('title').text(),
|
||||
@@ -97,7 +97,7 @@ export const handler = async (ctx) => {
|
||||
item: items,
|
||||
allowEmpty: true,
|
||||
image,
|
||||
language,
|
||||
language: language as Language,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import type { Route } from '@/types';
|
||||
import type { DataItem, Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
@@ -44,15 +44,15 @@ async function handler() {
|
||||
const list = $('#wp_news_w9')
|
||||
.find('li')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
const date = item.find('.column-news-date').text();
|
||||
.map((item): DataItem => {
|
||||
const $item = $(item);
|
||||
const date = $item.find('.column-news-date').text();
|
||||
|
||||
// 置顶链接自带http前缀,其他不带,需要手动判断
|
||||
const a = item.find('a').attr('href');
|
||||
const link = a.slice(0, 4) === 'http' ? a : rootUrl + a;
|
||||
const a = $item.find('a').attr('href');
|
||||
const link = a!.startsWith('http') ? a : rootUrl + a;
|
||||
return {
|
||||
title: item.find('a').attr('title'),
|
||||
title: $item.find('a').attr('title')!,
|
||||
link,
|
||||
pubDate: timezone(parseDate(date), 8),
|
||||
};
|
||||
@@ -60,7 +60,7 @@ async function handler() {
|
||||
|
||||
const items = await Promise.all(
|
||||
list.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
cache.tryGet(item.link!, async () => {
|
||||
const detailResponse = await got({
|
||||
method: 'get',
|
||||
url: item.link,
|
||||
|
||||
@@ -61,7 +61,7 @@ export const route: Route = {
|
||||
return {
|
||||
title: 'AI日报',
|
||||
description: '每天三分钟关注AI行业趋势',
|
||||
language: 'zh-cn',
|
||||
language: 'zh-CN',
|
||||
link: 'https://www.aibase.com/zh/daily',
|
||||
item: items,
|
||||
allowEmpty: true,
|
||||
|
||||
@@ -63,7 +63,7 @@ export const handler = async (ctx) => {
|
||||
|
||||
const items = processItems(apiProcs?.slice(0, limit) ?? []);
|
||||
|
||||
const image = new URL($('img.logo').prop('src'), rootUrl).href;
|
||||
const image = new URL($('img.logo').prop('src')!, rootUrl).href;
|
||||
|
||||
const author = $('title').text().split(/_/).pop();
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ export const route: Route = {
|
||||
return {
|
||||
title: 'AI新闻资讯',
|
||||
description: 'AI新闻资讯 - 不错过全球AI革新的每一个时刻',
|
||||
language: 'zh-cn',
|
||||
language: 'zh-CN',
|
||||
link: 'https://www.aibase.com/zh/news',
|
||||
item: items,
|
||||
allowEmpty: true,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user