From aeeaf1c2798548c35efc2f9b119c36f62ccbec93 Mon Sep 17 00:00:00 2001 From: Ethan Shen Date: Sat, 26 Sep 2020 22:26:00 +0800 Subject: [PATCH] feat: add JavDB (#5739) Co-authored-by: Henry Wang --- docs/multimedia.md | 110 +++++++++++++++++++++++++++++++++++ lib/router.js | 9 +++ lib/routes/javdb/actors.js | 19 ++++++ lib/routes/javdb/home.js | 32 ++++++++++ lib/routes/javdb/makers.js | 20 +++++++ lib/routes/javdb/rankings.js | 12 ++++ lib/routes/javdb/search.js | 26 +++++++++ lib/routes/javdb/series.js | 20 +++++++ lib/routes/javdb/tags.js | 12 ++++ lib/routes/javdb/utils.js | 72 +++++++++++++++++++++++ 10 files changed, 332 insertions(+) create mode 100644 lib/routes/javdb/actors.js create mode 100644 lib/routes/javdb/home.js create mode 100644 lib/routes/javdb/makers.js create mode 100644 lib/routes/javdb/rankings.js create mode 100644 lib/routes/javdb/search.js create mode 100644 lib/routes/javdb/series.js create mode 100644 lib/routes/javdb/tags.js create mode 100644 lib/routes/javdb/utils.js diff --git a/docs/multimedia.md b/docs/multimedia.md index 50cb939d5..f2d128e22 100644 --- a/docs/multimedia.md +++ b/docs/multimedia.md @@ -131,6 +131,116 @@ pageClass: routes +## JavDB + +### 主页 + + + +分类 + +| 有碼 | 無碼 | 歐美 | FC2 | +| -------- | ---------- | ------- | --- | +| censored | uncensored | western | fc2 | + +排序 + +| 发布日期排序 | 磁鏈更新排序 | +| ------------ | ------------ | +| 1 | 2 | + +过滤 + +| 全部 | 可下载 | 含字幕 | 含短評 | +| ---- | ------ | ------ | ------ | +| 0 | 1 | 2 | 3 | + + + +### 分類 + + + +::: tip 提示 + +在 [分類](https://javdb.com/tags) 中选定分类后,URL 中 `tags?` 后的字段即为筛选参数。 + +如 中 `c2=5&c10=1` 为筛选参数。 + +::: + +分类 + +| 有碼 | 無碼 | 歐美 | FC2 | +| -------- | ---------- | ------- | --- | +| censored | uncensored | western | fc2 | + + + +### 排行榜 + + + +分类 + +| 有碼 | 無碼 | 歐美 | FC2 | +| -------- | ---------- | ------- | --- | +| censored | uncensored | western | fc2 | + +时间 + +| 日榜 | 週榜 | 月榜 | +| ----- | ------ | ------- | +| daily | weekly | monthly | + + + +### 搜索 + + + +| 全部 | 可播放 | 單體作品 | 演員 | 片商 | 導演 | 系列 | 番號 | 可下載 | 字幕 | 預覽圖 | +| ---- | -------- | -------- | ----- | ----- | -------- | ------ | ---- | -------- | ----- | ------- | +| | playable | single | actor | maker | director | series | code | download | cnsub | preview | + + + +### 演員 + + + +| 全部 | 可播放 | 單體作品 | 可下載 | 含字幕 | +| ---- | ------ | -------- | ------ | ------ | +| | p | s | d | c | + +所有演员编号参见 [演員庫](https://javdb.com/actors) + + + +### 系列 + + + +| 全部 | 可播放 | 單體作品 | 可下載 | 字幕 | 預覽圖 | +| ---- | -------- | -------- | -------- | ----- | ------- | +| | playable | single | download | cnsub | preview | + +所有系列编号参见 [系列庫](https://javdb.com/series) + + + +### 片商 + + + +| 全部 | 可播放 | 單體作品 | 可下載 | 字幕 | 預覽圖 | +| ---- | -------- | -------- | -------- | ----- | ------- | +| | playable | single | download | cnsub | preview | + +所有片商编号参见 [片商庫](https://javdb.com/makers) + + + ## JavLibrary ### 影片 diff --git a/lib/router.js b/lib/router.js index 8f0ec72ab..25c0cee9c 100644 --- a/lib/router.js +++ b/lib/router.js @@ -3241,6 +3241,15 @@ router.get('/appsales/:caty?/:time?', require('./routes/appsales/index')); // CGTN router.get('/cgtn/top', require('./routes/cgtn/top')); +// JavDB +router.get('/javdb/home/:caty?/:sort?/:filter?', require('./routes/javdb/home')); +router.get('/javdb/search/:keyword?/:filter?', require('./routes/javdb/search')); +router.get('/javdb/tags/:query?/:caty?', require('./routes/javdb/tags')); +router.get('/javdb/actors/:id/:filter?', require('./routes/javdb/actors')); +router.get('/javdb/makers/:id/:filter?', require('./routes/javdb/makers')); +router.get('/javdb/series/:id/:filter?', require('./routes/javdb/series')); +router.get('/javdb/rankings/:caty?/:time?', require('./routes/javdb/rankings')); + // World Economic Forum router.get('/weforum/report/:lang?/:year?/:platform?', require('./routes/weforum/report')); diff --git a/lib/routes/javdb/actors.js b/lib/routes/javdb/actors.js new file mode 100644 index 000000000..0815709c5 --- /dev/null +++ b/lib/routes/javdb/actors.js @@ -0,0 +1,19 @@ +const utils = require('./utils'); + +module.exports = async (ctx) => { + ctx.params.filter = ctx.params.filter || ''; + + const currentUrl = `${utils.rootUrl}/actors/${ctx.params.id}?t=${ctx.params.filter}`; + + const filter = { + '': '', + p: '可播放', + s: '單體作品', + d: '可下載', + c: '含字幕', + }; + + const title = `JavDB${filter[ctx.params.filter] === '' ? '' : ` - ${filter[ctx.params.filter]}`} `; + + ctx.state.data = await utils.ProcessItems(ctx, currentUrl, title); +}; diff --git a/lib/routes/javdb/home.js b/lib/routes/javdb/home.js new file mode 100644 index 000000000..8d49953c3 --- /dev/null +++ b/lib/routes/javdb/home.js @@ -0,0 +1,32 @@ +const utils = require('./utils'); + +module.exports = async (ctx) => { + ctx.params.caty = ctx.params.caty || 'censored'; + ctx.params.sort = ctx.params.sort || '2'; + ctx.params.filter = ctx.params.filter || '1'; + + const currentUrl = `${utils.rootUrl}/${ctx.params.caty === 'censored' ? '' : ctx.params.caty}?vft=${ctx.params.filter}&vst=${ctx.params.sort}`; + + const category = { + censored: '有碼', + uncensored: '無碼', + western: '歐美', + fc2: 'FC2', + }; + + const filter = { + 0: '', + 1: '可下载', + 2: '含字幕', + 3: '含短評', + }; + + const sort = { + 1: '发布日期排序', + 2: '磁鏈更新排序', + }; + + const title = `${category[ctx.params.caty]} - JavDB - ${filter[ctx.params.filter] === '' ? '|' : `${filter[ctx.params.filter]} | `}${sort[ctx.params.sort]}`; + + ctx.state.data = await utils.ProcessItems(ctx, currentUrl, title); +}; diff --git a/lib/routes/javdb/makers.js b/lib/routes/javdb/makers.js new file mode 100644 index 000000000..c6b06f95f --- /dev/null +++ b/lib/routes/javdb/makers.js @@ -0,0 +1,20 @@ +const utils = require('./utils'); + +module.exports = async (ctx) => { + ctx.params.filter = ctx.params.filter || ''; + + const currentUrl = `${utils.rootUrl}/makers/${ctx.params.id}?f=${ctx.params.filter}`; + + const filter = { + '': '', + playable: '可播放', + single: '單體作品', + download: '可下載', + cnsub: '字幕', + preview: '預覽圖', + }; + + const title = `JavDB${filter[ctx.params.filter] === '' ? '' : ` - ${filter[ctx.params.filter]}`} `; + + ctx.state.data = await utils.ProcessItems(ctx, currentUrl, title); +}; diff --git a/lib/routes/javdb/rankings.js b/lib/routes/javdb/rankings.js new file mode 100644 index 000000000..ee429abc2 --- /dev/null +++ b/lib/routes/javdb/rankings.js @@ -0,0 +1,12 @@ +const utils = require('./utils'); + +module.exports = async (ctx) => { + ctx.params.caty = ctx.params.caty || 'censored'; + ctx.params.time = ctx.params.time || 'daily'; + + const currentUrl = `${utils.rootUrl}/rankings/video_${ctx.params.caty}?period=${ctx.params.time}`; + + const title = 'JavDB'; + + ctx.state.data = await utils.ProcessItems(ctx, currentUrl, title); +}; diff --git a/lib/routes/javdb/search.js b/lib/routes/javdb/search.js new file mode 100644 index 000000000..bdf0bc5ef --- /dev/null +++ b/lib/routes/javdb/search.js @@ -0,0 +1,26 @@ +const utils = require('./utils'); + +module.exports = async (ctx) => { + ctx.params.filter = ctx.params.filter || ''; + ctx.params.keyword = ctx.params.keyword || ''; + + const currentUrl = `${utils.rootUrl}/search?q=${ctx.params.keyword}&f=${ctx.params.filter}`; + + const filter = { + '': '', + playable: '可播放', + single: '單體作品', + actor: '演員', + maker: '片商', + director: '導演', + series: '系列', + code: '番號', + download: '可下載', + cnsub: '字幕', + preview: '預覽圖', + }; + + const title = `關鍵字 ${ctx.params.keyword} ${filter[ctx.params.filter] === '' ? '' : `+ ${filter[ctx.params.filter]}`} 搜索結果 - JavDB `; + + ctx.state.data = await utils.ProcessItems(ctx, currentUrl, title); +}; diff --git a/lib/routes/javdb/series.js b/lib/routes/javdb/series.js new file mode 100644 index 000000000..9189c21be --- /dev/null +++ b/lib/routes/javdb/series.js @@ -0,0 +1,20 @@ +const utils = require('./utils'); + +module.exports = async (ctx) => { + ctx.params.filter = ctx.params.filter || ''; + + const currentUrl = `${utils.rootUrl}/series/${ctx.params.id}?f=${ctx.params.filter}`; + + const filter = { + '': '', + playable: '可播放', + single: '單體作品', + download: '可下載', + cnsub: '字幕', + preview: '預覽圖', + }; + + const title = `JavDB${filter[ctx.params.filter] === '' ? '' : ` - ${filter[ctx.params.filter]}`} `; + + ctx.state.data = await utils.ProcessItems(ctx, currentUrl, title); +}; diff --git a/lib/routes/javdb/tags.js b/lib/routes/javdb/tags.js new file mode 100644 index 000000000..efec484cb --- /dev/null +++ b/lib/routes/javdb/tags.js @@ -0,0 +1,12 @@ +const utils = require('./utils'); + +module.exports = async (ctx) => { + ctx.params.caty = ctx.params.caty || 'censored'; + ctx.params.query = ctx.params.query || ''; + + const currentUrl = `${utils.rootUrl}/tags${ctx.params.caty === 'censored' ? '' : `/${ctx.params.caty}`}?${ctx.params.query}`; + + const title = `JavDB${ctx.params.query === '' ? '' : ` - ${ctx.params.query}`} `; + + ctx.state.data = await utils.ProcessItems(ctx, currentUrl, title); +}; diff --git a/lib/routes/javdb/utils.js b/lib/routes/javdb/utils.js new file mode 100644 index 000000000..78e5ad8ee --- /dev/null +++ b/lib/routes/javdb/utils.js @@ -0,0 +1,72 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); + +const rootUrl = 'https://javdb.com'; + +module.exports = { + rootUrl: rootUrl, + ProcessItems: async (ctx, currentUrl, title) => { + const response = await got({ + method: 'get', + url: currentUrl, + }); + + const $ = cheerio.load(response.data); + + $('.tags').remove(); + + const list = $('.grid-item a') + .slice(0, 5) + .map((_, item) => { + item = $(item); + return { + title: item.text(), + link: `${rootUrl}${item.attr('href')}`, + pubDate: new Date(item.find('.meta').text()).toUTCString(), + }; + }) + .get(); + + const items = await Promise.all( + list.map( + async (item) => + await ctx.cache.tryGet(item.link, async () => { + const detailResponse = await got({ + method: 'get', + url: item.link, + }); + const content = cheerio.load(detailResponse.data); + + item.enclosure_url = content('#magnets-content button[data-clipboard-text]').eq(0).attr('data-clipboard-text'); + item.enclosure_type = 'application/x-bittorrent'; + + content('icon, .review-buttons, .copy-to-clipboard').remove(); + content('#modal-review-watched, #modal-save-list').remove(); + content('.video-cover').eq(1).remove(); + + content('img.video-cover').attr('src', content(this).parent().attr('href')); + + content('.preview-images img').each(function () { + content(this).removeAttr('data-src'); + content(this).attr('src', content(this).parent().attr('href')); + }); + + content('#preview-video').css('display', 'block'); + + item.description = content('.movie-info-panel .columns').html() + content('#magnets-content').html() + content('.preview-images').html(); + + return item; + }) + ) + ); + + const htmlTitle = $('title').text(); + const subject = htmlTitle.indexOf('|') === -1 ? '' : htmlTitle.split('|')[0]; + + return { + title: subject === '' ? title : `${subject} - ${title}`, + link: currentUrl, + item: items, + }; + }, +};