feat(route): add themoviedb (#12308)

* feat(route): add tmdb

* refactor(route): rename parameter

* fix(route): themoviedb
This commit is contained in:
x2cf 2023-04-15 00:16:05 +08:00 committed by GitHub
parent cf1fe23d7c
commit d6162ae973
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 376 additions and 0 deletions

View File

@ -523,6 +523,46 @@ Refer to [Pornhub F.A.Qs](https://help.pornhub.com/hc/en-us/articles/36004432703
<RouteEn author="outloudvi" example="/spotify/top/artists" path="/spotify/top/artists" />
## The Movie Database
::: tip Tips
Refer to <https://developers.themoviedb.org/3/getting-started/languages> for the language parameter in the route.
:::
### Collection
<RouteEn author="x2cf" example="/themoviedb/collection/131292/en-US" path="/themoviedb/collection/:id/:lang?" :paramsDesc="['Collection ID', 'Language']" radar="1" rssbud="1" />
### Trending
<RouteEn author="x2cf" example="/themoviedb/trending/tv/day/en-US" path="/themoviedb/trending/:mediaType/:timeWindow/:lang?" :paramsDesc="['`movie` or `tv`', '`day` or `week`', 'Language']" radar="1" rssbud="1" />
### TV Show Seasons
<RouteEn author="x2cf" example="/themoviedb/tv/70593/seasons/en-US" path="/themoviedb/tv/:id/seasons/:lang?" :paramsDesc="['TV show ID', 'Language']" radar="1" rssbud="1" />
### TV Show Episodes
<RouteEn author="x2cf" example="/themoviedb/tv/70593/seasons/1/episodes/en-US" path="/themoviedb/tv/:id/seasons/:seasonNumber/episodes/:lang?" :paramsDesc="['TV show ID', 'Season number', 'Language']" radar="1" rssbud="1" />
### Sheet
<RouteEn author="x2cf" example="/themoviedb/tv/top-rated/en-US" path="/themoviedb/:mediaType/:sheet/:lang?" :paramsDesc="['`movie` or `tv`', 'Sheet, see below', 'Language']" radar="1" rssbud="1">
When `mediaType` is `tv`, `sheet` should be:
| Airing Today | On TV | Top Rated |
| ------------ | ---------- | --------- |
| airing-today | on-the-air | top-rated |
When `mediaType` is `movie`, `sheet` should be:
| Now Playing | Upcoming | Top Rated |
| ----------- | -------- | --------- |
| now-playing | upcoming | top-rated |
</RouteEn>
## Trakt.tv
### User Collection

View File

@ -1179,6 +1179,46 @@ JavDB 有多个备用域名,本路由默认使用永久域名 <https://javdb.c
</Route>
## The Movie Database
::: tip 提示
路由中的语言参数可参考 <https://developers.themoviedb.org/3/getting-started/languages>
:::
### 系列
<Route author="x2cf" example="/themoviedb/collection/131292/zh" path="/themoviedb/collection/:id/:lang?" :paramsDesc="['系列 ID', '语言']" radar="1" rssbud="1" />
### 热门
<Route author="x2cf" example="/themoviedb/trending/tv/day/zh" path="/themoviedb/trending/:mediaType/:timeWindow/:lang?" :paramsDesc="['`movie` 或 `tv`', '`day` 或 `week`', '语言']" radar="1" rssbud="1" />
### 剧集系列
<Route author="x2cf" example="/themoviedb/tv/70593/seasons/zh" path="/themoviedb/tv/:id/seasons/:lang?" :paramsDesc="['剧集 ID', '语言']" radar="1" rssbud="1" />
### 剧集章节
<Route author="x2cf" example="/themoviedb/tv/70593/seasons/1/episodes/zh" path="/themoviedb/tv/:id/seasons/:seasonNumber/episodes/:lang?" :paramsDesc="['剧集 ID', '季号', '语言']" radar="1" rssbud="1" />
### 片单
<Route author="x2cf" example="/themoviedb/tv/top-rated/zh" path="/themoviedb/:mediaType/:sheet/:lang?" :paramsDesc="['`movie` 或 `tv`', '片单,见下表', '语言']" radar="1" rssbud="1">
`mediaType``tv` 时,`sheet` 的值如下:
| 今日播出 | 电视播出中 | 高分 |
| ------------ | ---------- | --------- |
| airing-today | on-the-air | top-rated |
`mediaType``movie` 时,`sheet` 的值如下:
| 正在上映 | 即将上映 | 高分 |
| ----------- | -------- | --------- |
| now-playing | upcoming | top-rated |
</Route>
## Trakt.tv
### 用户收藏

View File

@ -0,0 +1,23 @@
// https://github.com/rickylawson/freekeys/blob/master/index.js
const KEYS = [
'fb7bb23f03b6994dafc674c074d01761',
'e55425032d3d0f371fc776f302e7c09b',
'8301a21598f8b45668d5711a814f01f6',
'8cf43ad9c085135b9479ad5cf6bbcbda',
'da63548086e399ffc910fbc08526df05',
'13e53ff644a8bd4ba37b3e1044ad24f3',
'269890f657dddf4635473cf4cf456576',
'a2f888b27315e62e471b2d587048f32e',
'8476a7ab80ad76f0936744df0430e67c',
'5622cafbfe8f8cfe358a29c53e19bba0',
'ae4bd1b6fce2a5648671bfc171d15ba4',
'257654f35e3dff105574f97fb4b97035',
'2f4038e83265214a0dcd6ec2eb3276f5',
'9e43f45f94705cc8e1d5a0400d19a7b7',
'af6887753365e14160254ac7f4345dd2',
'06f10fc8741a672af455421c239a1ffc',
'fb7bb23f03b6994dafc674c074d01761',
'09ad8ace66eec34302943272db0e8d2c',
];
module.exports = () => KEYS[Math.floor(Math.random() * KEYS.length)];

View File

@ -0,0 +1,21 @@
const got = require('@/utils/got');
const apiKey = require('./api-key');
const { handleMovieItem } = require('./utils');
module.exports = async (ctx) => {
const { id, lang } = ctx.params;
const { data } = await got(`https://api.themoviedb.org/3/collection/${id}`, {
searchParams: {
language: lang,
api_key: apiKey(),
},
});
ctx.state.data = {
title: `${data.name} — TMDB`,
description: data.overview.trim(),
image: `https://image.tmdb.org/t/p/original${data.poster_path}`,
link: `https://www.themoviedb.org/collection/${data.id}`,
item: data.parts.map((item) => handleMovieItem(item, lang)),
};
};

View File

@ -0,0 +1,27 @@
const got = require('@/utils/got');
const { parseDate } = require('@/utils/parse-date');
const apiKey = require('./api-key');
const { handleDescription } = require('./utils');
module.exports = async (ctx) => {
const { id, seasonNumber, lang } = ctx.params;
const searchParams = {
language: lang,
api_key: apiKey(),
};
const { data: tvShowDetails } = await got(`https://api.themoviedb.org/3/tv/${id}`, { searchParams });
const { data: seasonDetails } = await got(`https://api.themoviedb.org/3/tv/${id}/season/${seasonNumber}`, { searchParams });
ctx.state.data = {
title: `${tvShowDetails.name} ${seasonDetails.name} — TMDB`,
description: seasonDetails.overview.trim(),
image: `https://image.tmdb.org/t/p/original${seasonDetails.poster_path}`,
link: `https://www.themoviedb.org/tv/${tvShowDetails.id}/season/${seasonDetails.season_number}`,
item: seasonDetails.episodes.reverse().map((item) => ({
title: `${item.episode_number} ${item.name}`,
link: `https://www.themoviedb.org/tv/${tvShowDetails.id}/season/${item.season_number}/episode/${item.episode_number}`,
description: handleDescription(item),
pubDate: parseDate(item.air_date),
})),
};
};

View File

@ -0,0 +1,7 @@
module.exports = {
'/collection/:id/:lang?': ['x2cf'],
'/trending/:mediaType/:timeWindow/:lang?': ['x2cf'],
'/tv/:id/seasons/:lang?': ['x2cf'],
'/tv/:id/seasons/:seasonNumber/episodes/:lang?': ['x2cf'],
'/:mediaType/:sheet/:lang?': ['x2cf'],
};

View File

@ -0,0 +1,73 @@
module.exports = {
'themoviedb.org': {
_name: 'The Movie Database',
'.': [
{
title: 'Collection',
docs: 'https://docs.rsshub.app/multimedia.html#the-movie-database',
source: ['/collection/:name'],
target: (params) => `/themoviedb/collection/${params.name.split('-')[0]}`,
},
{
title: 'Popular Movies',
docs: 'https://docs.rsshub.app/multimedia.html#the-movie-database',
source: ['/movie'],
target: '/themoviedb/trending/movie/week',
},
{
title: 'Popular TV Shows',
docs: 'https://docs.rsshub.app/multimedia.html#the-movie-database',
source: ['/tv'],
target: '/themoviedb/trending/tv/week',
},
{
title: 'TV Show Seasons',
docs: 'https://docs.rsshub.app/multimedia.html#the-movie-database',
source: ['/tv/:id/seasons', '/tv/:id'],
target: (params) => `/themoviedb/tv/${params.id.split('-')[0]}/seasons`,
},
{
title: 'TV Show Episodes',
docs: 'https://docs.rsshub.app/multimedia.html#the-movie-database',
source: ['/tv/:id/season/:seasonNumber'],
target: (params) => `/themoviedb/tv/${params.id.split('-')[0]}/seasons/${params.seasonNumber}/episodes`,
},
{
title: 'TV Shows Airing Today',
docs: 'https://docs.rsshub.app/multimedia.html#the-movie-database',
source: ['/tv/airing-today'],
target: '/themoviedb/tv/airing-today',
},
{
title: 'Currently Airing TV Shows',
docs: 'https://docs.rsshub.app/multimedia.html#the-movie-database',
source: ['/tv/on-the-air'],
target: '/themoviedb/tv/on-the-air',
},
{
title: 'Top Rated TV Shows',
docs: 'https://docs.rsshub.app/multimedia.html#the-movie-database',
source: ['/tv/top-rated'],
target: '/themoviedb/tv/top-rated',
},
{
title: 'Now Playing Movies',
docs: 'https://docs.rsshub.app/multimedia.html#the-movie-database',
source: ['/movie/now-playing'],
target: '/themoviedb/movie/now-playing',
},
{
title: 'Upcoming Movies',
docs: 'https://docs.rsshub.app/multimedia.html#the-movie-database',
source: ['/movie/upcoming'],
target: '/themoviedb/movie/upcoming',
},
{
title: 'Top Rated Movies',
docs: 'https://docs.rsshub.app/multimedia.html#the-movie-database',
source: ['/movie/top-rated'],
target: '/themoviedb/movie/top-rated',
},
],
},
};

View File

@ -0,0 +1,7 @@
module.exports = (router) => {
router.get('/collection/:id/:lang?', require('./collection'));
router.get('/trending/:mediaType/:timeWindow/:lang?', require('./trending'));
router.get('/tv/:id/seasons/:lang?', require('./seasons'));
router.get('/tv/:id/seasons/:seasonNumber/episodes/:lang?', require('./episodes'));
router.get('/:mediaType/:sheet/:lang?', require('./sheet'));
};

View File

@ -0,0 +1,31 @@
const got = require('@/utils/got');
const { parseDate } = require('@/utils/parse-date');
const apiKey = require('./api-key');
const { handleDescription } = require('./utils');
module.exports = async (ctx) => {
const { id, lang } = ctx.params;
const { data } = await got(`https://api.themoviedb.org/3/tv/${id}`, {
searchParams: {
language: lang,
api_key: apiKey(),
},
});
ctx.state.data = {
title: `${data.name} - Seasons — TMDB`,
description: data.overview.trim(),
image: `https://image.tmdb.org/t/p/original${data.poster_path}`,
link: `https://www.themoviedb.org/tv/${data.id}/seasons`,
item: data.seasons.map((item) => {
item.vote_average = data.vote_average;
item.vote_count = data.vote_count;
return {
title: item.name,
link: `https://www.themoviedb.org/tv/${data.id}/season/${item.season_number}`,
description: handleDescription(item),
pubDate: parseDate(item.air_date),
};
}),
};
};

View File

@ -0,0 +1,45 @@
const got = require('@/utils/got');
const apiKey = require('./api-key');
const { MEDIA_TYPE_TO_ITEM_HANDLE } = require('./utils');
const API_PATH = {
movie: {
'now-playing': 'movie/now_playing',
upcoming: 'movie/upcoming',
'top-rated': 'movie/top_rated',
},
tv: {
'airing-today': 'tv/airing_today',
'on-the-air': 'tv/on_the_air',
'top-rated': 'tv/top_rated',
},
};
const TITLE = {
movie: {
'now-playing': 'Now Playing Movies',
upcoming: 'Upcoming Movies',
'top-rated': 'Top Rated Movies',
},
tv: {
'airing-today': 'TV Shows Airing Today',
'on-the-air': 'Currently Airing TV Shows',
'top-rated': 'Top Rated TV Shows',
},
};
module.exports = async (ctx) => {
const { mediaType, sheet, lang } = ctx.params;
const { data } = await got(`https://api.themoviedb.org/3/${API_PATH[mediaType][sheet]}`, {
searchParams: {
language: lang,
api_key: apiKey(),
},
});
ctx.state.data = {
title: `${TITLE[mediaType][sheet]} — TMDB`,
link: `https://www.themoviedb.org/${mediaType}/${sheet}`,
item: data.results.map((item) => MEDIA_TYPE_TO_ITEM_HANDLE[mediaType](item, lang)),
};
};

View File

@ -0,0 +1,6 @@
<img src="{{poster}}" />
<p>
User Score: {{vote_average}}<br/>
Vote Count: {{vote_count}}<br/>
</p>
<p>{{description}}</p>

View File

@ -0,0 +1,24 @@
const got = require('@/utils/got');
const apiKey = require('./api-key');
const { MEDIA_TYPE_TO_ITEM_HANDLE } = require('./utils');
const MEDIA_TYPE_TO_TITLE = {
tv: 'TV Shows',
movie: 'Movies',
};
module.exports = async (ctx) => {
const { mediaType, timeWindow, lang } = ctx.params;
const { data } = await got(`https://api.themoviedb.org/3/trending/${mediaType}/${timeWindow}`, {
searchParams: {
language: lang,
api_key: apiKey(),
},
});
ctx.state.data = {
title: `Popular ${MEDIA_TYPE_TO_TITLE[mediaType]} — TMDB`,
link: `https://www.themoviedb.org/${mediaType}`,
item: data.results.map((item) => MEDIA_TYPE_TO_ITEM_HANDLE[mediaType](item, lang)),
};
};

View File

@ -0,0 +1,32 @@
const path = require('path');
const { art } = require('@/utils/render');
const { parseDate } = require('@/utils/parse-date');
const handleDescription = (item) =>
art(path.join(__dirname, 'templates/description.art'), {
poster: `https://image.tmdb.org/t/p/original${item.poster_path ?? item.still_path}`,
description: item.overview.trim(),
vote_average: item.vote_average,
vote_count: item.vote_count,
});
const handleMovieItem = (item, lang) => ({
title: lang ? item.title : item.original_title,
link: `https://www.themoviedb.org/movie/${item.id}`,
description: handleDescription(item),
pubDate: parseDate(item.release_date),
});
const handleTVShowItem = (item, lang) => ({
title: lang ? item.name : item.original_name,
link: `https://www.themoviedb.org/tv/${item.id}`,
description: handleDescription(item),
pubDate: parseDate(item.first_air_date),
});
const MEDIA_TYPE_TO_ITEM_HANDLE = {
tv: handleTVShowItem,
movie: handleMovieItem,
};
module.exports = { handleDescription, handleMovieItem, handleTVShowItem, MEDIA_TYPE_TO_ITEM_HANDLE };