feat(route): add netflix (#20453)

* feat(route): add netflix

* feat: add research

* fix: remove migrated entries

* fix: clean up

* fix: remove optional chaining for embedLink and title in render function

* fix: remove optional chaining for embedLink

* fix: image url

* fix: remove empty target field in radar configuration
This commit is contained in:
Tony
2025-11-09 23:00:07 +08:00
committed by GitHub
parent eae0ba88ad
commit da32313da8
6 changed files with 373 additions and 313 deletions
-180
View File
@@ -20,41 +20,18 @@ const lazyloadRouteHandler = (routeHandlerPath) => (ctx) => {
// Benedict Evans
router.get('/benedictevans', lazyloadRouteHandler('./routes/benedictevans/recent.js'));
// 简书
// router.get('/jianshu/home', lazyloadRouteHandler('./routes/jianshu/home'));
// router.get('/jianshu/collection/:id', lazyloadRouteHandler('./routes/jianshu/collection'));
// router.get('/jianshu/user/:id', lazyloadRouteHandler('./routes/jianshu/user'));
// Disqus
router.get('/disqus/posts/:forum', lazyloadRouteHandler('./routes/disqus/posts'));
// 极客时间
router.get('/geektime/column/:cid', lazyloadRouteHandler('./routes/geektime/column'));
// Dribbble
// router.get('/dribbble/popular/:timeframe?', lazyloadRouteHandler('./routes/dribbble/popular'));
// router.get('/dribbble/user/:name', lazyloadRouteHandler('./routes/dribbble/user'));
// router.get('/dribbble/keyword/:keyword', lazyloadRouteHandler('./routes/dribbble/keyword'));
// 虎牙
router.get('/huya/live/:id', lazyloadRouteHandler('./routes/huya/live'));
// v2ex
// router.get('/v2ex/topics/:type', lazyloadRouteHandler('./routes/v2ex/topics'));
// router.get('/v2ex/post/:postid', lazyloadRouteHandler('./routes/v2ex/post'));
// router.get('/v2ex/tab/:tabid', lazyloadRouteHandler('./routes/v2ex/tab'));
// f-droid
// router.get('/fdroid/apprelease/:app', lazyloadRouteHandler('./routes/fdroid/apprelease'));
// PornHub
// router.get('/pornhub/category/:caty', lazyloadRouteHandler('./routes/pornhub/category'));
// router.get('/pornhub/search/:keyword', lazyloadRouteHandler('./routes/pornhub/search'));
// router.get('/pornhub/:language?/category_url/:url?', lazyloadRouteHandler('./routes/pornhub/category_url'));
// router.get('/pornhub/:language?/users/:username', lazyloadRouteHandler('./routes/pornhub/users'));
// router.get('/pornhub/:language?/model/:username/:sort?', lazyloadRouteHandler('./routes/pornhub/model'));
// router.get('/pornhub/:language?/pornstar/:username/:sort?', lazyloadRouteHandler('./routes/pornhub/pornstar'));
// EZTV
router.get('/eztv/torrents/:imdb_id', lazyloadRouteHandler('./routes/eztv/imdb'));
@@ -62,20 +39,12 @@ router.get('/eztv/torrents/:imdb_id', lazyloadRouteHandler('./routes/eztv/imdb')
router.get('/mihoyo/bh3/:type', lazyloadRouteHandler('./routes/mihoyo/bh3'));
router.get('/mihoyo/bh2/:type', lazyloadRouteHandler('./routes/mihoyo/bh2'));
// 草榴社区
// router.get('/t66y/post/:tid', lazyloadRouteHandler('./routes/t66y/post'));
// router.get('/t66y/:id/:type?', lazyloadRouteHandler('./routes/t66y/index'));
// 色中色
router.get('/sexinsex/:id/:type?', lazyloadRouteHandler('./routes/sexinsex/index'));
// 一个
router.get('/one', lazyloadRouteHandler('./routes/one/index'));
// Firefox
// router.get('/firefox/release/:platform', lazyloadRouteHandler('./routes/firefox/release'));
// router.get('/firefox/addons/:id', lazyloadRouteHandler('./routes/firefox/addons'));
// Thunderbird
router.get('/thunderbird/release', lazyloadRouteHandler('./routes/thunderbird/release'));
@@ -134,9 +103,6 @@ router.get('/mafengwo/ziyouxing/:code', lazyloadRouteHandler('./routes/mafengwo/
// router.get('/novel/biqugeinfo/:id/:limit?', lazyloadRouteHandler('./routes/novel/biqugeinfo'));
router.get('/novel/uukanshu/:uid', lazyloadRouteHandler('./routes/novel/uukanshu'));
// 中国气象网
// router.get('/weatheralarm/:province?', lazyloadRouteHandler('./routes/weatheralarm'));
// Gitlab
router.get('/gitlab/explore/:type/:host?', lazyloadRouteHandler('./routes/gitlab/explore'));
router.get('/gitlab/release/:namespace/:project/:host?', lazyloadRouteHandler('./routes/gitlab/release'));
@@ -257,9 +223,6 @@ router.get('/henu/:type?', lazyloadRouteHandler('./routes/universities/henu/news
// 南开大学
router.get('/nku/jwc/:type?', lazyloadRouteHandler('./routes/universities/nku/jwc/index'));
// 北京航空航天大学
// router.get('/buaa/news/:type', lazyloadRouteHandler('./routes/universities/buaa/news/index'));
// 浙江工业大学
router.get('/zjut/:type', lazyloadRouteHandler('./routes/universities/zjut/index'));
router.get('/zjut/design/:type', lazyloadRouteHandler('./routes/universities/zjut/design'));
@@ -293,12 +256,6 @@ router.get('/fzu_min/:type', lazyloadRouteHandler('./routes/universities/fzu/new
// 厦门大学
router.get('/xmu/aero/:type', lazyloadRouteHandler('./routes/universities/xmu/aero'));
// ifanr
// router.get('/ifanr/:channel?', lazyloadRouteHandler('./routes/ifanr/index'));
// IPSW.me
// router.get('/ipsw/index/:ptype/:pname', lazyloadRouteHandler('./routes/ipsw/index'));
// 异次元软件世界
router.get('/iplay/home', lazyloadRouteHandler('./routes/iplay/home'));
@@ -312,12 +269,6 @@ router.get('/dytt/index', lazyloadRouteHandler('./routes/dytt/index')); // 废
// 趣头条
router.get('/qutoutiao/category/:cid', lazyloadRouteHandler('./routes/qutoutiao/category'));
// BBC
// router.get('/bbc/:site?/:channel?', lazyloadRouteHandler('./routes/bbc/index'));
// 看雪
// router.get('/pediy/topic/:category?/:type?', lazyloadRouteHandler('./routes/pediy/topic'));
// 老司机
router.get('/laosiji/hot', lazyloadRouteHandler('./routes/laosiji/hot'));
router.get('/laosiji/feed', lazyloadRouteHandler('./routes/laosiji/feed'));
@@ -352,21 +303,12 @@ router.get('/ltaaa/:category?', lazyloadRouteHandler('./routes/ltaaa/index'));
// Auto Trader
router.get('/autotrader/:query', lazyloadRouteHandler('./routes/autotrader'));
// 极客公园
// router.get('/geekpark/breakingnews', lazyloadRouteHandler('./routes/geekpark/breakingnews'));
// 搜狗
// router.get('/sogou/doodles', lazyloadRouteHandler('./routes/sogou/doodles'));
// 香港天文台
router.get('/hko/weather', lazyloadRouteHandler('./routes/hko/weather'));
// gnn游戏新闻
router.get('/gnn/gnn', lazyloadRouteHandler('./routes/gnn/gnn'));
// a9vg游戏新闻
// router.get('/a9vg/a9vg', lazyloadRouteHandler('./routes/a9vg/a9vg'));
// The Guardian
router.get('/guardian/:type', lazyloadRouteHandler('./routes/guardian/guardian'));
@@ -417,9 +359,6 @@ router.get('/cpu/yjsy', lazyloadRouteHandler('./routes/universities/cpu/yjsy'));
// 字幕库
router.get('/zimuku/:type?', lazyloadRouteHandler('./routes/zimuku/index'));
// Steam
// router.get('/steam/search/:params', lazyloadRouteHandler('./routes/steam/search'));
// Steamgifts
router.get('/steamgifts/discussions/:category?', lazyloadRouteHandler('./routes/steam/steamgifts/discussions'));
@@ -444,10 +383,6 @@ router.get('/patchwork.kernel.org/comments/:id', lazyloadRouteHandler('./routes/
// All Poetry
router.get('/allpoetry/:order?', lazyloadRouteHandler('./routes/allpoetry/order'));
// 创业邦
// router.get('/cyzone/author/:id', lazyloadRouteHandler('./routes/cyzone/author'));
// router.get('/cyzone/label/:name', lazyloadRouteHandler('./routes/cyzone/label'));
// 政府
// router.get('/gov/zhengce/zuixin', lazyloadRouteHandler('./routes/gov/zhengce/zuixin'));
// router.get('/gov/zhengce/wenjian/:pcodeJiguan?', lazyloadRouteHandler('./routes/gov/zhengce/wenjian'));
@@ -499,9 +434,6 @@ router.get('/go.jp/mofa', lazyloadRouteHandler('./routes/go.jp/mofa/main'));
// ebb
router.get('/ebb', lazyloadRouteHandler('./routes/ebb'));
// Indienova
// router.get('/indienova/:type', lazyloadRouteHandler('./routes/indienova/article'));
// JPMorgan Chase Institute
router.get('/jpmorganchase', lazyloadRouteHandler('./routes/jpmorganchase/research'));
@@ -545,9 +477,6 @@ router.get('/blogs/wang54/:id?', lazyloadRouteHandler('./routes/blogs/wang54'));
// WordPress
router.get('/blogs/wordpress/:domain/:https?', lazyloadRouteHandler('./routes/blogs/wordpress'));
// 今日热榜 migrated to v2
// router.get('/tophub/:id', lazyloadRouteHandler('./routes/tophub'));
// 親子王國
router.get('/babykingdom/:id/:order?', lazyloadRouteHandler('./routes/babykingdom'));
@@ -574,9 +503,6 @@ router.get('/checkee/:dispdate', lazyloadRouteHandler('./routes/checkee/index'))
// 古诗文网
router.get('/gushiwen/recommend/:annotation?', lazyloadRouteHandler('./routes/gushiwen/recommend'));
// 21财经
// router.get('/21caijing/channel/:name', lazyloadRouteHandler('./routes/21caijing/channel'));
// 北京邮电大学
router.get('/bupt/yz/:type', lazyloadRouteHandler('./routes/universities/bupt/yz'));
router.get('/bupt/grs', lazyloadRouteHandler('./routes/universities/bupt/grs'));
@@ -609,9 +535,6 @@ router.get('/paidai', lazyloadRouteHandler('./routes/paidai/index'));
router.get('/paidai/bbs', lazyloadRouteHandler('./routes/paidai/bbs'));
router.get('/paidai/news', lazyloadRouteHandler('./routes/paidai/news'));
// 中国银行
// router.get('/boc/whpj/:format?', lazyloadRouteHandler('./routes/boc/whpj'));
// 漫画db
router.get('/manhuadb/comics/:id', lazyloadRouteHandler('./routes/manhuadb/comics'));
@@ -632,9 +555,6 @@ router.get('/digitaling/articles/:category/:subcate?', lazyloadRouteHandler('./r
// 数英网项目专题
router.get('/digitaling/projects/:category', lazyloadRouteHandler('./routes/digitaling/project'));
// Bing壁纸
// router.get('/bing', lazyloadRouteHandler('./routes/bing/index'));
// AlgoCasts
router.get('/algocasts', lazyloadRouteHandler('./routes/algocasts/all'));
@@ -666,12 +586,6 @@ router.get('/polimi/news/:language?', lazyloadRouteHandler('./routes/polimi/news
// dekudeals
router.get('/dekudeals/:type', lazyloadRouteHandler('./routes/dekudeals'));
// Metacritic
// router.get('/metacritic/release/:platform/:type/:sort?', lazyloadRouteHandler('./routes/metacritic/release'));
// 快科技(原驱动之家)
// router.get('/kkj/news', lazyloadRouteHandler('./routes/kkj/news'));
// AI研习社
router.get('/aiyanxishe/:id/:sort?', lazyloadRouteHandler('./routes/aiyanxishe/home'));
@@ -713,10 +627,6 @@ router.get('/nosetime/home', lazyloadRouteHandler('./routes/nosetime/home'));
// 大侠阿木
router.get('/daxiaamu/home', lazyloadRouteHandler('./routes/daxiaamu/home'));
// 爱发电
// router.get('/afdian/explore/:type?/:category?', lazyloadRouteHandler('./routes/afdian/explore'));
// router.get('/afdian/dynamic/:uid', lazyloadRouteHandler('./routes/afdian/dynamic'));
// Simons Foundation
router.get('/simonsfoundation/articles', lazyloadRouteHandler('./routes/simonsfoundation/articles'));
router.get('/simonsfoundation/recommend', lazyloadRouteHandler('./routes/simonsfoundation/recommend'));
@@ -728,10 +638,6 @@ router.get('/siren/news', lazyloadRouteHandler('./routes/siren/index'));
router.get('/xuetangx/course/:cid/:type', lazyloadRouteHandler('./routes/xuetangx/course-info'));
router.get('/xuetangx/course/list/:mode/:credential/:status/:type?', lazyloadRouteHandler('./routes/xuetangx/course-list'));
// 正版中国
// router.get('/getitfree/category/:category?', lazyloadRouteHandler('./routes/getitfree/category.js'));
// router.get('/getitfree/search/:keyword?', lazyloadRouteHandler('./routes/getitfree/search.js'));
// 万联网
router.get('/10000link/news/:category?', lazyloadRouteHandler('./routes/10000link/news'));
@@ -803,9 +709,6 @@ router.get('/queshu/book/:bookid', lazyloadRouteHandler('./routes/queshu/book'))
// LaTeX 开源小屋
router.get('/latexstudio/home', lazyloadRouteHandler('./routes/latexstudio/home'));
// 邮箱
// router.get('/mail/imap/:email/:folder*', lazyloadRouteHandler('./routes/mail/imap'));
// 北华航天工业学院 - 新闻
router.get('/nciae/news', lazyloadRouteHandler('./routes/universities/nciae/news'));
// 北华航天工业学院 - 通知公告
@@ -836,32 +739,17 @@ router.get('/watchface/:watch_type?/:list_type?', lazyloadRouteHandler('./routes
router.get('/cnu/selected', lazyloadRouteHandler('./routes/cnu/selected'));
router.get('/cnu/discovery/:type?/:category?', lazyloadRouteHandler('./routes/cnu/discovery'));
// X-MOL化学资讯平台
// router.get('/x-mol/news/:tag?', lazyloadRouteHandler('./routes/x-mol/news.js'));
// router.get('/x-mol/paper/:type/:magazine', lazyloadRouteHandler('./routes/x-mol/paper'));
// 知识分子
router.get('/zhishifenzi/news/:type?', lazyloadRouteHandler('./routes/zhishifenzi/news'));
router.get('/zhishifenzi/depth', lazyloadRouteHandler('./routes/zhishifenzi/depth'));
router.get('/zhishifenzi/innovation/:type?', lazyloadRouteHandler('./routes/zhishifenzi/innovation'));
// 4Gamers
// router.get('/4gamers/category/:category', lazyloadRouteHandler('./routes/4gamers/category'));
// router.get('/4gamers/tag/:tag', lazyloadRouteHandler('./routes/4gamers/tag'));
// router.get('/4gamers/topic/:topic', lazyloadRouteHandler('./routes/4gamers/topic'));
// 大麦网
// router.get('/damai/activity/:city/:category/:subcategory/:keyword?', lazyloadRouteHandler('./routes/damai/activity'));
// 桂林电子科技大学新闻资讯
router.get('/guet/xwzx/:type?', lazyloadRouteHandler('./routes/guet/news'));
// はてな匿名ダイアリー
router.get('/hatena/anonymous_diary/archive', lazyloadRouteHandler('./routes/hatena/anonymous_diary/archive'));
// PNAS [Sci Journal]
// router.get('/pnas/:topic?', lazyloadRouteHandler('./routes/pnas/index'));
// cell [Sci Journal]
router.get('/cell/cell/:category', lazyloadRouteHandler('./routes/cell/cell/index'));
router.get('/cell/cover', lazyloadRouteHandler('./routes/cell/cover'));
@@ -922,9 +810,6 @@ router.get('/vulture/:tag/:excludetags?', lazyloadRouteHandler('./routes/vulture
// xinwenlianbo
router.get('/xinwenlianbo/index', lazyloadRouteHandler('./routes/xinwenlianbo/index'));
// Paul Graham - Essays
// router.get('/blogs/paulgraham', lazyloadRouteHandler('./routes/blogs/paulgraham'));
// invisionapp
router.get('/invisionapp/inside-design', lazyloadRouteHandler('./routes/invisionapp/inside-design'));
@@ -950,14 +835,6 @@ router.get('/project-zero-issues', lazyloadRouteHandler('./routes/project-zero-i
// 平安银河实验室
router.get('/galaxylab', lazyloadRouteHandler('./routes/galaxylab/index'));
// NOSEC 安全讯息平台
// router.get('/nosec/:keykind?', lazyloadRouteHandler('./routes/nosec/index'));
// discuz
// router.get('/discuz/:ver([7|x])/:cid([0-9]{2})/:link(.*)', lazyloadRouteHandler('./routes/discuz/discuz'));
// router.get('/discuz/:ver([7|x])/:link(.*)', lazyloadRouteHandler('./routes/discuz/discuz'));
// router.get('/discuz/:link(.*)', lazyloadRouteHandler('./routes/discuz/discuz'));
// 人民日报社 国际金融报
router.get('/ifnews/:cid', lazyloadRouteHandler('./routes/ifnews/column'));
@@ -1046,19 +923,12 @@ router.get('/hbut/cs/:type', lazyloadRouteHandler('./routes/universities/hbut/cs
// acwifi
router.get('/acwifi', lazyloadRouteHandler('./routes/acwifi'));
// MIT科技评论
// router.get('/mittrchina/:type', lazyloadRouteHandler('./routes/mittrchina'));
// etoland
router.get('/etoland/:bo_table', lazyloadRouteHandler('./routes/etoland/board'));
// 辽宁工程技术大学教务在线公告
router.get('/lntu/jwnews', lazyloadRouteHandler('./routes/universities/lntu/jwnews'));
// 追新番
// router.get('/fanxinzhui', lazyloadRouteHandler('./routes/fanxinzhui/latest'));
// router.get('/zhuixinfan/list', lazyloadRouteHandler('./routes/fanxinzhui/latest'));
// blur-studio
router.get('/blur-studio', lazyloadRouteHandler('./routes/blur-studio/index'));
@@ -1095,11 +965,6 @@ router.get('/ruby-china/jobs', lazyloadRouteHandler('./routes/ruby-china/jobs'))
// 广告网
router.get('/adquan/:type?', lazyloadRouteHandler('./routes/adquan/index'));
// 金色财经
// router.get('/jinse/lives', lazyloadRouteHandler('./routes/jinse/lives'));
// router.get('/jinse/timeline', lazyloadRouteHandler('./routes/jinse/timeline'));
// router.get('/jinse/catalogue/:caty', lazyloadRouteHandler('./routes/jinse/catalogue'));
// deeplearning.ai
// router.get('/deeplearningai/thebatch', lazyloadRouteHandler('./routes/deeplearningai/thebatch'));
@@ -1125,9 +990,6 @@ router.get('/199it', lazyloadRouteHandler('./routes/199it/index'));
router.get('/199it/category/:caty', lazyloadRouteHandler('./routes/199it/category'));
router.get('/199it/tag/:tag', lazyloadRouteHandler('./routes/199it/tag'));
// Grub Street
// router.get('/grubstreet', lazyloadRouteHandler('./routes/grubstreet/index'));
// Monotype
router.get('/monotype/article', lazyloadRouteHandler('./routes/monotype/article'));
@@ -1219,11 +1081,6 @@ router.get('/gov/chongqing/ljxq/zwgk/:caty', lazyloadRouteHandler('./routes/gov/
// 国家突发事件预警信息发布网
router.get('/12379', lazyloadRouteHandler('./routes/12379/index'));
// 鸟哥笔记
// router.get('/ngbj', lazyloadRouteHandler('./routes/niaogebiji/index'));
// router.get('/ngbj/today', lazyloadRouteHandler('./routes/niaogebiji/today'));
// router.get('/ngbj/cat/:cat', lazyloadRouteHandler('./routes/niaogebiji/cat'));
// 梅花网
router.get('/meihua/shots/:caty', lazyloadRouteHandler('./routes/meihua/shots'));
router.get('/meihua/article/:caty', lazyloadRouteHandler('./routes/meihua/article'));
@@ -1329,9 +1186,6 @@ router.get('/icity/:id', lazyloadRouteHandler('./routes/icity/index'));
// ABC News
// router.get('/abc/:id?', lazyloadRouteHandler('./routes/abc'));
// 台湾中央通讯社
// router.get('/cna/:id?', lazyloadRouteHandler('./routes/cna/index'));
// 妈咪帮
router.get('/mamibuy/:caty?/:age?/:sort?', lazyloadRouteHandler('./routes/mamibuy/index'));
@@ -1356,9 +1210,6 @@ router.get('/forum4399/:mtag', lazyloadRouteHandler('./routes/game4399/forum'));
// 国防科技大学
router.get('/nudt/yjszs/:id?', lazyloadRouteHandler('./routes/universities/nudt/yjszs'));
// dev.to
// router.get('/dev.to/top/:period', lazyloadRouteHandler('./routes/dev.to/top'));
// GameRes 游资网
router.get('/gameres/hot', lazyloadRouteHandler('./routes/gameres/hot'));
router.get('/gameres/list/:id', lazyloadRouteHandler('./routes/gameres/list'));
@@ -1378,9 +1229,6 @@ router.get('/sesame/release_notes', lazyloadRouteHandler('./routes/sesame/releas
// QNAP
router.get('/qnap/release-notes/:id', lazyloadRouteHandler('./routes/qnap/release-notes'));
// Liquipedia
// router.get('/liquipedia/dota2/matches/:id', lazyloadRouteHandler('./routes/liquipedia/dota2_matches.js'));
// 哈尔滨市科技局
router.get('/gov/harbin/kjj', lazyloadRouteHandler('./routes/gov/harbin/kjj'));
@@ -1510,9 +1358,6 @@ router.get('/dida365/habit/checkins', lazyloadRouteHandler('./routes/dida365/hab
// Ditto clipboard manager
router.get('/ditto/changes/:type?', lazyloadRouteHandler('./routes/ditto/changes'));
// iDaily 每日环球视野
// router.get('/idaily/today', lazyloadRouteHandler('./routes/idaily/index'));
// Oak Ridge National Laboratory
router.get('/ornl/news', lazyloadRouteHandler('./routes/ornl/news'));
@@ -1656,13 +1501,6 @@ router.get('/topbook/today', lazyloadRouteHandler('./routes/topbook/today'));
// Melon
router.get('/melon/chart/:category?', lazyloadRouteHandler('./routes/melon/chart'));
// FIX 字幕侠
// router.get('/zimuxia/portfolio/:id', lazyloadRouteHandler('./routes/zimuxia/portfolio'));
// router.get('/zimuxia/:category?', lazyloadRouteHandler('./routes/zimuxia/index'));
// 东立出版
// router.get('/tongli/news/:type', lazyloadRouteHandler('./routes/tongli/news'));
// 海南大学
router.get('/hainanu/ssszs', lazyloadRouteHandler('./routes/hainanu/ssszs'));
@@ -1672,15 +1510,6 @@ router.get('/bibgame/:category?/:type?', lazyloadRouteHandler('./routes/bibgame/
// PotPlayer
router.get('/potplayer/update/:language?', lazyloadRouteHandler('./routes/potplayer/update'));
// 加美财经
// router.get('/caus/:category?', lazyloadRouteHandler('./routes/caus'));
// 摩点
// router.get('/modian/zhongchou/:category?/:sort?/:status?', lazyloadRouteHandler('./routes/modian/zhongchou'));
// 世界计划 多彩舞台 feat.初音未来 (ProjectSekai)
// router.get('/pjsk/news', lazyloadRouteHandler('./routes/pjsk/news'));
// 人民论坛网
router.get('/rmlt/idea/:category?', lazyloadRouteHandler('./routes/rmlt/idea'));
@@ -1690,9 +1519,6 @@ router.get('/cbndata/information/:category?', lazyloadRouteHandler('./routes/cbn
// TANC 艺术新闻
router.get('/tanchinese/:category?', lazyloadRouteHandler('./routes/tanchinese'));
// Harvard
// router.get('/harvard/health/blog', lazyloadRouteHandler('./routes/universities/harvard/health/blog'));
// yuzu emulator
router.get('/yuzu-emu/entry', lazyloadRouteHandler('./routes/yuzu-emu/entry'));
@@ -1743,12 +1569,6 @@ router.get('/etherscan/transactions/:address', lazyloadRouteHandler('./routes/et
// foreverblog
router.get('/blogs/foreverblog', lazyloadRouteHandler('./routes/blogs/foreverblog'));
// Netflix
router.get('/netflix/newsroom/:category?/:region?', lazyloadRouteHandler('./routes/netflix/newsroom'));
// QuestMobile
// router.get('/questmobile/report/:category?/:label?', lazyloadRouteHandler('./routes/questmobile/report'));
// Fashion Network
router.get('/fashionnetwork/news/:sectors?/:categories?/:language?', lazyloadRouteHandler('./routes/fashionnetwork/news.js'));
-82
View File
@@ -1,82 +0,0 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const { parseDate } = require('@/utils/parse-date');
const languages = {
zh_cn: 'zh-hans',
zh_tw: 'zh-hant',
};
const categories = {
all: {
title: 'All News',
id: '0',
},
business: {
title: 'Business',
id: '1GnkLu7bxeOTxTRNCeu5qm',
},
entertainment: {
title: 'Entertainment',
id: '3SGbaxYYG5U05Z0G4piPV7',
},
innovation: {
title: 'Innovation',
id: '5TzuQELMABTu9jOPjXXlFU',
},
brazil: {
title: 'Made in Brazil',
id: '2tOmcnQB8PgkQSoQ1K4hfD',
},
impact: {
title: 'Social Impact',
id: '2bUcGjE2800LAsk3JDurGA',
},
};
module.exports = async (ctx) => {
const category = ctx.params.category ?? 'all';
const region = ctx.params.region ?? 'en';
const rootUrl = 'https://about.netflix.com';
const currentUrl = `${rootUrl}/api/data/articles?language=${Object.keys(languages).includes(region) ? languages[region] : region.replaceAll('_', '-')}&category=${categories[category].id}&limit=1000`;
const response = await got({
method: 'get',
url: currentUrl,
});
const list = response.data.entities.articles.slice(0, ctx.params.limit ? Number.parseInt(ctx.params.limit) : 15).map((item) => ({
title: item.title,
link: `${rootUrl}/${region}/news/${item.slug}`,
pubDate: parseDate(item.rawPublishedDate),
category: item.categories.map((category) => category.label),
}));
const items = await Promise.all(
list.map((item) =>
ctx.cache.tryGet(item.link, async () => {
const detailResponse = await got({
method: 'get',
url: item.link,
});
const content = cheerio.load(detailResponse.data);
if (!content('.article-contentstyles__ArticleCopy-pei0rm-6 ul li')) {
content('.article-contentstyles__ArticleCopy-pei0rm-6 p').slice(-3).remove();
}
item.description = content('.article-contentstyles__ArticleCopy-pei0rm-6').html();
return item;
})
)
);
ctx.state.data = {
title: `${categories[category].title} - Newsroom - Netflix`,
link: `${rootUrl}/${region}/newsroom`,
item: items,
};
};
-51
View File
@@ -1,51 +0,0 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const { parseRelativeDate } = require('@/utils/parse-date');
module.exports = async (ctx) => {
const response = await got({
method: 'get',
url: `http://www.zhuixinfan.com/main.php`,
});
const data = response.data;
const $ = cheerio.load(data);
const list = [];
for (let table of $('.top-list-data:not(.top-list-data-all)')) {
table = $(table);
const date = table.children('caption').first().text();
table
.find('tbody')
.children('tr')
.not((i) => i === 0)
.each((i, item) => {
item = $(item);
item.attr('date', date.slice(date.indexOf('(') + 1, date.indexOf('(') + 7));
list.push(item);
});
}
ctx.state.data = {
title: '追新番',
link: 'http://www.zhuixinfan.com/main.php',
language: 'zh-CN',
description: '追新番日剧站',
item: list.map((item) => {
const category = item.find('td.td2 a').first().text();
const title = item.find('td.td2 a').last().text();
const description = `资源大小:${item.find('td').eq(2).text()}`;
const link = item.find('td').eq(3).children('a').first().attr('href');
const pubDate = parseRelativeDate(item.attr('date'));
return {
title,
description,
category,
link,
pubDate,
};
}),
};
};
+7
View File
@@ -0,0 +1,7 @@
import type { Namespace } from '@/types';
export const namespace: Namespace = {
name: 'Netflix',
url: 'netflix.com',
lang: 'en',
};
+280
View File
@@ -0,0 +1,280 @@
import { Route } from '@/types';
import ofetch from '@/utils/ofetch';
import cache from '@/utils/cache';
import { parseDate } from '@/utils/parse-date';
export const route: Route = {
path: '/newsroom/:category?/:region?',
categories: ['new-media'],
example: '/netflix/newsroom',
parameters: {
category: {
description: 'Category',
default: 'all',
options: [
{ value: 'all', label: 'All News' },
{ value: 'business', label: 'Business' },
{ value: 'entertainment', label: 'Entertainment' },
{ value: 'product', label: 'Product' },
{ value: 'impact', label: 'Social Impact' },
],
},
region: {
description: 'Region, can be found in the region URL',
default: 'en',
options: [
{ value: 'ar', label: 'اللغة العربية' },
{ value: 'de', label: 'Deutsch' },
{ value: 'el', label: 'Ελληνικά' },
{ value: 'en', label: 'English' },
{ value: 'es', label: 'Español (LatAm)' },
{ value: 'es-es', label: 'Español (España)' },
{ value: 'fr', label: 'Français' },
{ value: 'id', label: 'Bahasa Indonesia' },
{ value: 'it', label: 'Italiano' },
{ value: 'ja', label: '日本語' },
{ value: 'ko', label: '한국어' },
{ value: 'pl', label: 'Polski' },
{ value: 'pt-br', label: 'Português (Brasil)' },
{ value: 'pt-pt', label: 'Português (Portugal)' },
{ value: 'ro', label: 'Română' },
{ value: 'ru', label: 'русский' },
{ value: 'th', label: 'ไทย' },
{ value: 'tr', label: 'Türkçe' },
{ value: 'vi', label: 'Tiếng Việt' },
{ value: 'zh-hans', label: '简体中文' },
{ value: 'zh-hant', label: '繁體中文' },
],
},
},
radar: [
{
source: ['about.netflix.com/:region/newsroom', 'netflix.com'],
},
],
name: 'Newsroom',
maintainers: ['nczitzk'],
handler,
url: 'about.netflix.com/',
};
const categories = {
all: {
title: 'All News',
id: '0',
},
business: {
title: 'Business',
id: '1GnkLu7bxeOTxTRNCeu5qm',
},
entertainment: {
title: 'Entertainment',
id: '3SGbaxYYG5U05Z0G4piPV7',
},
product: {
title: 'Product',
id: '5TzuQELMABTu9jOPjXXlFU',
},
impact: {
title: 'Social Impact',
id: '2bUcGjE2800LAsk3JDurGA',
},
};
const renderImage = ({ url, alt, caption }: { url: string; alt?: string; caption?: string }) => `<figure><img src="${url}" alt="${alt || ''}">${caption ? `<figcaption>${caption}</figcaption>` : ''}</figure>`;
const renderVideo = ({ url, poster, contentType }: { url: string; poster?: string; contentType: string }) =>
`<video controls preload="metadata"${poster ? ` poster="${poster}"` : ''}><source src="${url}" type="${contentType}"></video>`;
const renderYoutube = (youtubeId) =>
`<iframe id="ytplayer" type="text/html" width="640" height="360" src="https://www.youtube-nocookie.com/embed/${youtubeId}" frameborder="0" allowfullscreen referrerpolicy="strict-origin-when-cross-origin"></iframe>`;
const render = (node) => {
if (!node) {
return '';
}
switch (node.nodeType) {
case 'document':
return node.content?.map((c) => render(c)).join('') || '';
case 'paragraph': {
const innerHTML = node.content?.map((c) => render(c)).join('') || '';
return `<p>${innerHTML}</p>`;
}
case 'heading-2': {
const innerHTML = node.content?.map((c) => render(c)).join('') || '';
return `<h2>${innerHTML}</h2>`;
}
case 'heading-3': {
const innerHTML = node.content?.map((c) => render(c)).join('') || '';
return `<h3>${innerHTML}</h3>`;
}
case 'heading-4': {
const innerHTML = node.content?.map((c) => render(c)).join('') || '';
return `<h4>${innerHTML}</h4>`;
}
case 'heading-6': {
const innerHTML = node.content?.map((c) => render(c)).join('') || '';
return `<h6>${innerHTML}</h6>`;
}
case 'hr':
return '<hr>';
case 'text': {
let text = node.value || '';
if (!node.marks || node.marks.length === 0) {
return text;
}
for (const mark of node.marks) {
switch (mark.type) {
case 'bold':
text = `<strong>${text}</strong>`;
break;
case 'italic':
text = `<em>${text}</em>`;
break;
case 'underline':
text = `<u>${text}</u>`;
break;
case 'strikethrough':
text = `<s>${text}</s>`;
break;
default:
throw new Error(`Unhandled mark type: ${mark.type}`);
}
}
return text;
}
case 'hyperlink': {
const href = node.data?.uri || '#';
const innerHTML = node.content?.map((c) => render(c)).join('') || '';
return `<a href="${href}" target="_blank" rel="noopener noreferrer">${innerHTML}</a>`;
}
case 'embedded-asset-block': {
const file = Object.values(node.data?.file)[0];
if (!file || !file.url) {
return '';
}
const url = file.url.startsWith('//') ? 'https:' + file.url : file.url;
const contentType = file.contentType || '';
const title = Object.values(node.data?.title)[0] || '';
if (contentType.startsWith('image/')) {
return `<img src="${url}" alt="${title}">`;
} else if (contentType.startsWith('video/')) {
return renderVideo({ url, contentType });
}
return '';
}
case 'embedded-entry-block': {
let innerHTML = '';
if (node.data.display === 'carousel') {
for (const img of node.data.images) {
const file = Object.values(img.file)[0];
const url = file.url.startsWith('//') ? 'https:' + file.url : file.url;
innerHTML += renderImage({
url,
alt: Object.values(img.title)[0],
caption: img.description ? Object.values(img.description)[0] : '',
});
}
}
return innerHTML;
}
case 'embedded-entry-inline': {
const embedLink = node.data.embedLink;
if (embedLink.startsWith('https://www.youtube.com/') || embedLink.startsWith('https://youtu.be/')) {
const youtubeId = node.data.embedLink.split('youtube.com/watch?v=')[1]?.split('&')[0] || node.data.embedLink.split('youtu.be/')[1]?.split('?')[0];
return renderYoutube(youtubeId);
}
return `<a href="${embedLink}" target="_blank" rel="noopener noreferrer">${node.data.title ?? embedLink}</a>`;
}
case 'list-item': {
const innerHTML = node.content?.map((c) => render(c)).join('') || '';
return `<li>${innerHTML}</li>`;
}
case 'unordered-list': {
const itemsHTML = node.content?.map((c) => render(c)).join('') || '';
return `<ul>${itemsHTML}</ul>`;
}
case 'ordered-list': {
const itemsHTML = node.content?.map((c) => render(c)).join('') || '';
return `<ol>${itemsHTML}</ol>`;
}
default:
throw new Error(`Unhandled node type: ${node.nodeType}`);
}
};
async function handler(ctx) {
const { category = 'all', region = 'en' } = ctx.req.param();
const baseUrl = 'https://about.netflix.com';
const response = await ofetch(`${baseUrl}/api/data/articles`, {
query: {
language: region,
category: categories[category].id,
},
});
const list = [...response.entities.region.regionArticles, ...response.entities.global.globalArticles].map((i) => ({
title: i.title,
link: `${baseUrl}/${region}/news/${i.slug}`,
pubDate: parseDate(i.rawPublishedDate),
category: [...new Set([...i.categories.map((category) => category.label), ...i.locations.map((location) => location.label)])],
image: i.heroImage?.url ? `https:${i.heroImage.url.replace('?w=2560', '')}` : null,
slug: i.slug,
}));
const items = await Promise.all(
list.map((item) =>
cache.tryGet(item.link, async () => {
const response = await ofetch('https://about.netflix.com/api/data/entity', {
query: {
language: region,
entity: 'slug',
slug: item.slug,
},
});
const slug = response.entity.slug;
item.description = '';
if (slug.heroVideoUrl && !slug.heroVideoUrl.startsWith('https://www.youtube.com/')) {
item.description += renderVideo({
url: slug.heroVideoUrl,
poster: slug.heroImage?.url ? `https:${slug.heroImage.url.replace('?w=2560', '')}` : '',
contentType: 'video/mp4',
});
} else if (slug.youtubeHero) {
item.description += renderYoutube(slug.youtubeHero.videoLink.split('youtube.com/watch?v=')[1]);
} else if (slug.heroGallery?.length) {
for (const image of slug.heroGallery) {
item.description += renderImage({
url: `https:${image.url}`,
alt: image.alt,
caption: image.description || image.alt,
});
}
} else {
item.description += renderImage({
url: `https:${slug.heroImage.url.replace('?w=2560', '')}`,
alt: slug.heroImage.alt,
caption: slug.heroImage.description || slug.heroImage.alt,
});
}
item.description += render(slug.body);
return item;
})
)
);
return {
title: `${categories[category].title} - Newsroom - Netflix`,
link: `${baseUrl}/${region}/newsroom`,
image: `${baseUrl}/favicon.ico`,
item: items,
};
}
+86
View File
@@ -0,0 +1,86 @@
import { Route } from '@/types';
import ofetch from '@/utils/ofetch';
import { load } from 'cheerio';
import { parseDate } from '@/utils/parse-date';
export const route: Route = {
path: '/research',
categories: ['new-media'],
example: '/netflix/research',
radar: [
{
source: ['research.netflix.com/archive', 'research.netflix.com'],
},
],
name: 'Research',
maintainers: ['TonyRL'],
handler,
url: 'research.netflix.com/',
};
const resolveArticle = (data, store) => {
if (data === null) {
return data;
}
if (typeof data !== 'object') {
return data;
}
if (Array.isArray(data)) {
return data.map((item) => resolveArticle(item, store));
}
if (data.type === 'id') {
const id = data.id;
const target = store[id];
return target === undefined ? null : resolveArticle(target, store);
}
const out = Array.isArray(data) ? [] : {};
for (const [k, v] of Object.entries(data)) {
out[k] = resolveArticle(v, store);
}
return out;
};
async function handler() {
const baseUrl = 'https://research.netflix.com';
const link = `${baseUrl}/archive`;
const response = await ofetch(link);
const $ = load(response);
const nextData = JSON.parse($('#__NEXT_DATA__').text());
const store = nextData.props.pageProps.serverState.apollo.data;
const list = Object.values(store.ROOT_QUERY)
.map((value) => resolveArticle(value, store))
.flatMap((i) => i.items);
const seen = new Set();
const items = list
.filter((item) => {
const title = item.title.trim();
if (seen.has(title)) {
return false;
}
seen.add(title);
return true;
})
.map((item) => ({
title: item.title,
description: item.description,
link: item.link,
pubDate: (item.date ?? item.startDate) ? parseDate(item.date ?? item.startDate) : undefined,
category: item.tags?.json,
image: item.image?.url,
}));
return {
title: $('head title').text(),
link,
image: `${link}/favicon.ico`,
item: items,
};
}