feat(route): add maoyan (猫眼电影) routes (#20956)

* feat(route): add LinuxDo RSS routes

- Add /linux-do/posts route for latest posts
- Add /linux-do/top/:period route for trending topics with period filter
- Optimize /linux-do/latest route
- Update namespace documentation with descriptions
- Handle Zstandard compression by using Accept-Encoding: identity

* revert: remove linux-do routes (PR rejected)

* feat(route): add codefather (编程导航) routes

- Add posts route with hot/new/recommend sorting and category filter
- Add questions route with new/hot sorting
- Support for 编程导航 programming community

* fix: address all PR review comments

- Reorder path params: category before sort
- Remove config.trueUA (not needed)
- Use upvotes/comments fields instead of description
- Remove title slicing
- Change default sort to 'new'
- Remove title from description
- Remove content truncation

* feat(route): add maoyan (猫眼电影) routes

Add three new routes for Maoyan:
- /maoyan/box - Real-time box office ranking
- /maoyan/hot - Currently showing movies
- /maoyan/coming - Upcoming movies

* fix: address PR review comments

- Remove author field from box.ts (releaseInfo is not author)
- Remove unnecessary mobile User-Agent from coming.ts and hot.ts
This commit is contained in:
jxtan 2026-01-24 13:43:07 +08:00 committed by GitHub
parent 417b943241
commit 71d5ded520
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 231 additions and 0 deletions

83
lib/routes/maoyan/box.ts Normal file
View File

@ -0,0 +1,83 @@
import type { Route } from '@/types';
import ofetch from '@/utils/ofetch';
export const route: Route = {
path: '/box',
categories: ['multimedia'],
example: '/maoyan/box',
parameters: {},
features: {
requireConfig: false,
requirePuppeteer: false,
antiCrawler: false,
supportBT: false,
supportPodcast: false,
supportScihub: false,
},
radar: [
{
source: ['piaofang.maoyan.com/dashboard'],
target: '/box',
},
],
name: '实时票房榜',
maintainers: ['JackyST0'],
handler,
};
interface MovieItem {
movieInfo: {
movieId: number;
movieName: string;
releaseInfo: string;
};
boxRate: string;
sumBoxDesc: string;
showCount: number;
showCountRate: string;
avgSeatView: string;
avgShowView: string;
splitBoxRate: string;
}
interface BoxResponse {
movieList: {
status: boolean;
data: {
list: MovieItem[];
};
};
}
async function handler() {
const apiUrl = 'https://piaofang.maoyan.com/dashboard-ajax';
const response = await ofetch<BoxResponse>(apiUrl, {
headers: {
Referer: 'https://piaofang.maoyan.com/dashboard',
},
});
const movies = response.movieList?.data?.list || [];
const items = movies.map((movie, index) => ({
title: `${index + 1}. ${movie.movieInfo.movieName} - ${movie.sumBoxDesc}`,
link: `https://www.maoyan.com/films/${movie.movieInfo.movieId}`,
description: `
<p><strong>${movie.movieInfo.movieName}</strong></p>
<p>${movie.movieInfo.releaseInfo}</p>
<p>${movie.sumBoxDesc}</p>
<p>${movie.boxRate}</p>
<p>${movie.showCount} (${movie.showCountRate})</p>
<p>${movie.avgSeatView}</p>
<p>${movie.avgShowView}</p>
`,
}));
return {
title: '猫眼实时票房榜',
link: 'https://piaofang.maoyan.com/dashboard',
description: '猫眼电影实时票房排行榜',
item: items,
};
}

View File

@ -0,0 +1,70 @@
import type { Route } from '@/types';
import ofetch from '@/utils/ofetch';
interface MovieItem {
id: number;
nm: string;
img: string;
sc: number;
star: string;
rt: string;
showInfo?: string;
wish: number;
comingTitle: string;
}
interface ComingResponse {
coming: MovieItem[];
}
export const route: Route = {
path: '/coming',
categories: ['multimedia'],
example: '/maoyan/coming',
parameters: {},
features: {
requireConfig: false,
requirePuppeteer: false,
antiCrawler: false,
supportBT: false,
supportPodcast: false,
supportScihub: false,
},
radar: [
{
source: ['www.maoyan.com/films?showType=2', 'www.maoyan.com/films'],
target: '/coming',
},
],
name: '即将上映',
maintainers: ['JackyST0'],
handler,
};
async function handler() {
const apiUrl = 'https://m.maoyan.com/ajax/comingList?ci=1&limit=30&movieIds=&token=';
const response = await ofetch<ComingResponse>(apiUrl);
const movies = response.coming || [];
const items = movies.map((movie) => ({
title: `[${movie.comingTitle}] ${movie.nm}`,
link: `https://www.maoyan.com/films/${movie.id}`,
description: `
<img src="${movie.img}" />
<p><strong>${movie.nm}</strong></p>
<p>${movie.rt}</p>
<p>${movie.star}</p>
<p>${movie.wish}</p>
${movie.showInfo ? `<p>${movie.showInfo}</p>` : ''}
`,
}));
return {
title: '猫眼电影 - 即将上映',
link: 'https://www.maoyan.com/films?showType=2',
description: '猫眼电影即将上映列表',
item: items,
};
}

71
lib/routes/maoyan/hot.ts Normal file
View File

@ -0,0 +1,71 @@
import type { Route } from '@/types';
import ofetch from '@/utils/ofetch';
interface MovieItem {
id: number;
nm: string;
img: string;
sc: number;
star: string;
rt: string;
showInfo: string;
wish: number;
version?: string;
}
interface HotResponse {
movieList: MovieItem[];
}
export const route: Route = {
path: '/hot',
categories: ['multimedia'],
example: '/maoyan/hot',
parameters: {},
features: {
requireConfig: false,
requirePuppeteer: false,
antiCrawler: false,
supportBT: false,
supportPodcast: false,
supportScihub: false,
},
radar: [
{
source: ['www.maoyan.com/films?showType=1'],
target: '/hot',
},
],
name: '正在热映',
maintainers: ['JackyST0'],
handler,
};
async function handler() {
const apiUrl = 'https://m.maoyan.com/ajax/movieOnInfoList';
const response = await ofetch<HotResponse>(apiUrl);
const movies = response.movieList || [];
const items = movies.map((movie) => ({
title: `${movie.sc ? `[${movie.sc}分] ` : ''}${movie.nm}`,
link: `https://www.maoyan.com/films/${movie.id}`,
description: `
<img src="${movie.img}" />
<p><strong>${movie.nm}</strong></p>
${movie.sc ? `<p>评分:${movie.sc}</p>` : ''}
<p>${movie.rt}</p>
<p>${movie.star}</p>
<p>${movie.wish}</p>
<p>${movie.showInfo}</p>
`,
}));
return {
title: '猫眼电影 - 正在热映',
link: 'https://www.maoyan.com/films?showType=1',
description: '猫眼电影正在热映列表',
item: items,
};
}

View File

@ -0,0 +1,7 @@
import type { Namespace } from '@/types';
export const namespace: Namespace = {
name: '猫眼电影',
url: 'maoyan.com',
lang: 'zh-CN',
};