├── .dockerignore ├── .gitignore ├── .idea ├── .gitignore ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── danmaku.iml ├── inspectionProfiles │ └── Project_Default.xml ├── jsLibraryMappings.xml ├── jsLinters │ └── eslint.xml ├── modules.xml └── vcs.xml ├── Dockerfile ├── README.md ├── app.js ├── bin └── www ├── fly.toml ├── package-lock.json ├── package.json ├── pnpm-lock.yaml ├── public ├── favicons │ └── favicon-16x16.png └── robots.txt ├── routes ├── api │ ├── base.js │ ├── bilibili.js │ ├── iqiyi.js │ ├── mgtv.js │ ├── tencentvideo.js │ ├── utils.js │ └── youku.js └── danmaku.js ├── s.yaml ├── test └── App.test.js ├── utils ├── db.js └── memory.js └── views ├── danmaku-xml.ejs ├── danmaku.ejs ├── error.ejs └── utils └── header.ejs /.dockerignore: -------------------------------------------------------------------------------- 1 | Dockerfile 2 | .dockerignore 3 | node_modules 4 | .git 5 | db -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/node,webstorm,visualstudiocode 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=node,webstorm,visualstudiocode 3 | 4 | ### Node ### 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | lerna-debug.log* 12 | .pnpm-debug.log* 13 | 14 | # Diagnostic reports (https://nodejs.org/api/report.html) 15 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 16 | 17 | # Runtime data 18 | pids 19 | *.pid 20 | *.seed 21 | *.pid.lock 22 | 23 | # Directory for instrumented libs generated by jscoverage/JSCover 24 | lib-cov 25 | 26 | # Coverage directory used by tools like istanbul 27 | coverage 28 | *.lcov 29 | 30 | # nyc test coverage 31 | .nyc_output 32 | 33 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 34 | .grunt 35 | 36 | # Bower dependency directory (https://bower.io/) 37 | bower_components 38 | 39 | # node-waf configuration 40 | .lock-wscript 41 | 42 | # Compiled binary addons (https://nodejs.org/api/addons.html) 43 | build/Release 44 | 45 | # Dependency directories 46 | node_modules/ 47 | jspm_packages/ 48 | 49 | # Snowpack dependency directory (https://snowpack.dev/) 50 | web_modules/ 51 | 52 | # TypeScript cache 53 | *.tsbuildinfo 54 | 55 | # Optional npm cache directory 56 | .npm 57 | 58 | # Optional eslint cache 59 | .eslintcache 60 | 61 | # Optional stylelint cache 62 | .stylelintcache 63 | 64 | # Microbundle cache 65 | .rpt2_cache/ 66 | .rts2_cache_cjs/ 67 | .rts2_cache_es/ 68 | .rts2_cache_umd/ 69 | 70 | # Optional REPL history 71 | .node_repl_history 72 | 73 | # Output of 'npm pack' 74 | *.tgz 75 | 76 | # Yarn Integrity file 77 | .yarn-integrity 78 | 79 | # dotenv environment variable files 80 | .env 81 | .env.development.local 82 | .env.test.local 83 | .env.production.local 84 | .env.local 85 | 86 | # parcel-bundler cache (https://parceljs.org/) 87 | .cache 88 | .parcel-cache 89 | 90 | # Next.js build output 91 | .next 92 | out 93 | 94 | # Nuxt.js build / generate output 95 | .nuxt 96 | dist 97 | 98 | # Gatsby files 99 | .cache/ 100 | # Comment in the public line in if your project uses Gatsby and not Next.js 101 | # https://nextjs.org/blog/next-9-1#public-directory-support 102 | # public 103 | 104 | # vuepress build output 105 | .vuepress/dist 106 | 107 | # vuepress v2.x temp and cache directory 108 | .temp 109 | 110 | # Docusaurus cache and generated files 111 | .docusaurus 112 | 113 | # Serverless directories 114 | .serverless/ 115 | 116 | # FuseBox cache 117 | .fusebox/ 118 | 119 | # DynamoDB Local files 120 | .dynamodb/ 121 | 122 | # TernJS port file 123 | .tern-port 124 | 125 | # Stores VSCode versions used for testing VSCode extensions 126 | .vscode-test 127 | 128 | # yarn v2 129 | .yarn/cache 130 | .yarn/unplugged 131 | .yarn/build-state.yml 132 | .yarn/install-state.gz 133 | .pnp.* 134 | 135 | ### Node Patch ### 136 | # Serverless Webpack directories 137 | .webpack/ 138 | 139 | # Optional stylelint cache 140 | 141 | # SvelteKit build / generate output 142 | .svelte-kit 143 | 144 | ### VisualStudioCode ### 145 | .vscode/* 146 | !.vscode/settings.json 147 | !.vscode/tasks.json 148 | !.vscode/launch.json 149 | !.vscode/extensions.json 150 | !.vscode/*.code-snippets 151 | 152 | # Local History for Visual Studio Code 153 | .history/ 154 | 155 | # Built Visual Studio Code Extensions 156 | *.vsix 157 | 158 | ### VisualStudioCode Patch ### 159 | # Ignore all local history of files 160 | .history 161 | .ionide 162 | 163 | ### WebStorm ### 164 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 165 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 166 | 167 | # User-specific stuff 168 | .idea/**/workspace.xml 169 | .idea/**/tasks.xml 170 | .idea/**/usage.statistics.xml 171 | .idea/**/dictionaries 172 | .idea/**/shelf 173 | 174 | # AWS User-specific 175 | .idea/**/aws.xml 176 | 177 | # Generated files 178 | .idea/**/contentModel.xml 179 | 180 | # Sensitive or high-churn files 181 | .idea/**/dataSources/ 182 | .idea/**/dataSources.ids 183 | .idea/**/dataSources.local.xml 184 | .idea/**/sqlDataSources.xml 185 | .idea/**/dynamic.xml 186 | .idea/**/uiDesigner.xml 187 | .idea/**/dbnavigator.xml 188 | 189 | # Gradle 190 | .idea/**/gradle.xml 191 | .idea/**/libraries 192 | 193 | # Gradle and Maven with auto-import 194 | # When using Gradle or Maven with auto-import, you should exclude module files, 195 | # since they will be recreated, and may cause churn. Uncomment if using 196 | # auto-import. 197 | # .idea/artifacts 198 | # .idea/compiler.xml 199 | # .idea/jarRepositories.xml 200 | # .idea/modules.xml 201 | # .idea/*.iml 202 | # .idea/modules 203 | # *.iml 204 | # *.ipr 205 | 206 | # CMake 207 | cmake-build-*/ 208 | 209 | # Mongo Explorer plugin 210 | .idea/**/mongoSettings.xml 211 | 212 | # File-based project format 213 | *.iws 214 | 215 | # IntelliJ 216 | out/ 217 | 218 | # mpeltonen/sbt-idea plugin 219 | .idea_modules/ 220 | 221 | # JIRA plugin 222 | atlassian-ide-plugin.xml 223 | 224 | # Cursive Clojure plugin 225 | .idea/replstate.xml 226 | 227 | # SonarLint plugin 228 | .idea/sonarlint/ 229 | 230 | # Crashlytics plugin (for Android Studio and IntelliJ) 231 | com_crashlytics_export_strings.xml 232 | crashlytics.properties 233 | crashlytics-build.properties 234 | fabric.properties 235 | 236 | # Editor-based Rest Client 237 | .idea/httpRequests 238 | 239 | # Android studio 3.1+ serialized cache file 240 | .idea/caches/build_file_checksums.ser 241 | 242 | ### WebStorm Patch ### 243 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 244 | 245 | # *.iml 246 | # modules.xml 247 | # .idea/misc.xml 248 | # *.ipr 249 | 250 | # Sonarlint plugin 251 | # https://plugins.jetbrains.com/plugin/7973-sonarlint 252 | .idea/**/sonarlint/ 253 | 254 | # SonarQube Plugin 255 | # https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin 256 | .idea/**/sonarIssues.xml 257 | 258 | # Markdown Navigator plugin 259 | # https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced 260 | .idea/**/markdown-navigator.xml 261 | .idea/**/markdown-navigator-enh.xml 262 | .idea/**/markdown-navigator/ 263 | 264 | # Cache file creation bug 265 | # See https://youtrack.jetbrains.com/issue/JBR-2257 266 | .idea/$CACHE_FILE$ 267 | 268 | # CodeStream plugin 269 | # https://plugins.jetbrains.com/plugin/12206-codestream 270 | .idea/codestream.xml 271 | 272 | # Azure Toolkit for IntelliJ plugin 273 | # https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij 274 | .idea/**/azureSettings.xml 275 | 276 | # End of https://www.toptal.com/developers/gitignore/api/node,webstorm,visualstudiocode 277 | upload 278 | 279 | .s 280 | db -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # 默认忽略的文件 2 | /shelf/ 3 | /workspace.xml 4 | # 基于编辑器的 HTTP 客户端请求 5 | /httpRequests/ 6 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 31 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/danmaku.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/jsLibraryMappings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/jsLinters/eslint.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:16.18.0-alpine 2 | ENV TZ Asia/Shanghai 3 | 4 | RUN apk add tzdata sqlite sqlite-dev && cp /usr/share/zoneinfo/${TZ} /etc/localtime \ 5 | && echo ${TZ} > /etc/timezone \ 6 | && apk del tzdata 7 | 8 | LABEL fly_launch_runtime="nodejs" 9 | WORKDIR /app 10 | COPY ./package.json /app 11 | RUN npm install --production && npm prune --production 12 | COPY . /app 13 | ENV NODE_ENV production 14 | 15 | CMD [ "npm", "run", "start" ] 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # danmaku 2 | 用于解析转换各大视频网站(芒果TV,腾讯视频,优酷视频,爱奇艺视频,哔哩哔哩)弹幕 3 | 4 | # 依赖 5 | - chai: 断言库 6 | - mocha: 测试框架 7 | - ejs: 模板引擎 8 | - express: web框架 9 | 10 | # 运行此项目 11 | ``` sh 12 | npm install # 安装依赖 13 | npm run dev # 本地运行 14 | npm run test # 单元测试 15 | ``` 16 | 17 | # 部署到fly.io 18 | ``` sh 19 | curl -L https://fly.io/install.sh | sh #linux 20 | iwr https://fly.io/install.ps1 -useb | iex #windows 21 | export FLYCTL_INSTALL="/home/codespace/.fly" 22 | export PATH="$FLYCTL_INSTALL/bin:$PATH" 23 | flyctl auth login 24 | flyctl deploy 25 | ``` 26 | 27 | # 性能提升 28 | 相比于旧版的Python项目,Node对于异步并发的处理能力更强。 29 | Express框架的性能也比Python的Django要好很多。 30 | 31 | # fly.io常用命令 32 | ``` sh 33 | flyctl status 34 | flyctl scale count 0 35 | flyctl regions add sea 36 | flyctl regions remove hkg 37 | flyctl config env 38 | flyctl secrets set DEBUG=true 39 | flyctl ssh console 40 | flyctl checks list 41 | flyctl ssh sftp get /app/db/danmaku.db 42 | ``` 43 | 44 | # Node常用工具 45 | ```bash 46 | npm outdated 47 | npm update 48 | ``` 49 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | const createError = require("http-errors"); 2 | const express = require("express"); 3 | const path = require("path"); 4 | const cookieParser = require("cookie-parser"); 5 | const logger = require("morgan"); 6 | const compression = require('compression'); 7 | // 引入环境变量 8 | require("dotenv") 9 | .config(); 10 | 11 | // 引入一个个路由模块 12 | const danmakuRouter = require("./routes/danmaku"); 13 | const app = express(); 14 | // 启用gzip压缩 15 | app.use(compression()); 16 | 17 | // view engine setup 18 | app.set("views", path.join(__dirname, "views")); 19 | app.set("view engine", "ejs"); 20 | app.set("trust proxy", true); 21 | 22 | app.use(logger("dev")); 23 | app.use(express.json()); 24 | app.use(express.urlencoded({ extended: false, validate: { trustProxy: false } })); 25 | app.use(cookieParser()); 26 | // 加载静态资源 27 | app.use(express.static(path.join(__dirname, "public"), {maxAge: 86400*1000 })); 28 | app.use(express.static(path.join(__dirname,"db"))) 29 | app.use("/assets", [ 30 | express.static(__dirname + "/node_modules/jquery/dist/",{maxAge: 86400*1000}), 31 | express.static(__dirname + "/node_modules/bootstrap/dist/",{maxAge: 86400*1000}), 32 | express.static(__dirname + "/node_modules/axios/dist/",{maxAge: 86400*1000}), 33 | express.static(__dirname + "/node_modules/leancloud-storage/dist",{maxAge: 86400*1000}), 34 | ]); 35 | 36 | // 加载路由 37 | app.use("/", danmakuRouter); 38 | 39 | // catch 404 and forward to error handler 40 | app.use(function (req, res, next) { 41 | next(createError(404)); 42 | }); 43 | 44 | // error handler 45 | app.use(function (err, req, res) { 46 | // set locals, only providing error in development 47 | res.locals.message = err.message; 48 | res.locals.error = req.app.get("env") === "development" ? err : {}; 49 | 50 | // render the error page 51 | res.status(err.status || 500); 52 | res.render("error"); 53 | }); 54 | 55 | module.exports = app; 56 | -------------------------------------------------------------------------------- /bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | const app = require('../app'); 7 | const debug = require('debug')('danmaku:server'); 8 | const http = require('http'); 9 | 10 | /** 11 | * Get port from environment and store in Express. 12 | */ 13 | const port = normalizePort(process.env.PORT || '3000'); 14 | app.set('port', port); 15 | 16 | /** 17 | * Create HTTP server. 18 | */ 19 | const server = http.createServer(app); 20 | 21 | /** 22 | * Listen on provided port, on all network interfaces. 23 | */ 24 | 25 | server.listen(port, () => { 26 | console.log(`Listening on port ${port}`); 27 | console.log(`visit: http://localhost:${port}`); 28 | }); 29 | server.on('error', onError); 30 | server.on('listening', onListening); 31 | 32 | /** 33 | * Normalize a port into a number, string, or false. 34 | */ 35 | 36 | function normalizePort(val) { 37 | const port = parseInt(val, 10); 38 | 39 | if (isNaN(port)) { 40 | // named pipe 41 | return val; 42 | } 43 | 44 | if (port >= 0) { 45 | // port number 46 | return port; 47 | } 48 | 49 | return false; 50 | } 51 | 52 | /** 53 | * Event listener for HTTP server "error" event. 54 | */ 55 | 56 | function onError(error) { 57 | if (error.syscall !== 'listen') { 58 | throw error; 59 | } 60 | 61 | const bind = typeof port === 'string' 62 | ? 'Pipe ' + port 63 | : 'Port ' + port; 64 | 65 | // handle specific listen errors with friendly messages 66 | switch (error.code) { 67 | case 'EACCES': 68 | console.error(bind + ' requires elevated privileges'); 69 | process.exit(1); 70 | break; 71 | case 'EADDRINUSE': 72 | console.error(bind + ' is already in use'); 73 | process.exit(1); 74 | break; 75 | default: 76 | throw error; 77 | } 78 | } 79 | 80 | /** 81 | * Event listener for HTTP server "listening" event. 82 | */ 83 | 84 | function onListening() { 85 | const addr = server.address(); 86 | const bind = typeof addr === 'string' 87 | ? 'pipe ' + addr 88 | : 'port ' + addr.port; 89 | debug('Listening on ' + bind); 90 | } 91 | -------------------------------------------------------------------------------- /fly.toml: -------------------------------------------------------------------------------- 1 | # fly.toml app configuration file generated for lyz05-danmaku on 2024-01-11T19:54:43+08:00 2 | # 3 | # See https://fly.io/docs/reference/configuration/ for information about how to use this file. 4 | # 5 | 6 | app = "lyz05-danmaku" 7 | primary_region = "sea" 8 | kill_signal = "SIGINT" 9 | kill_timeout = "5s" 10 | 11 | [experimental] 12 | auto_rollback = true 13 | 14 | [build] 15 | 16 | [env] 17 | PORT = "8080" 18 | 19 | [http_service] 20 | internal_port = 8080 21 | force_https = true 22 | auto_stop_machines = true 23 | auto_start_machines = true 24 | min_machines_running = 0 25 | processes = ["app"] 26 | 27 | [[vm]] 28 | cpu_kind = "shared" 29 | cpus = 1 30 | memory_mb = 512 31 | 32 | [mounts] 33 | source="danmaku" 34 | destination="/app/db" -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "danmaku", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "node --expose-gc --max-old-space-size=200 ./bin/www", 7 | "dev": "nodemon --expose-gc --max-old-space-size=200 ./bin/www", 8 | "test": "nyc -a mocha --recursive", 9 | "deploy": "flyctl deploy", 10 | "logs": "flyctl logs" 11 | }, 12 | "dependencies": { 13 | "ali-oss": "^6.17.1", 14 | "axios": "^1.2.1", 15 | "bootstrap": "^3.4.1", 16 | "chai": "^4.3.7", 17 | "chai-http": "^4.3.0", 18 | "compression": "^1.7.4", 19 | "cookie": "^0.5.0", 20 | "cookie-parser": "~1.4.4", 21 | "debug": "^4.3.4", 22 | "dotenv": "^16.0.3", 23 | "ejs": "^3.1.8", 24 | "express": "~4.18.2", 25 | "express-rate-limit": "^7.1.5", 26 | "filesize": "^10.0.5", 27 | "got": "^11.8.2", 28 | "http-errors": "~1.6.3", 29 | "jquery": "^3.6.1", 30 | "js-yaml": "^4.1.0", 31 | "leancloud-storage": "^4.13.4", 32 | "lib-qqwry": "^1.2.0", 33 | "moment": "^2.29.4", 34 | "morgan": "~1.9.1", 35 | "multer": "^1.4.5-lts.1", 36 | "node-cron": "^3.0.2", 37 | "node-telegram-bot-api": "^0.60.0", 38 | "openai": "^3.2.1", 39 | "pako": "^1.0.11", 40 | "querystring": "^0.2.1", 41 | "sqlite3": "^5.1.7", 42 | "whacko": "^0.19.1", 43 | "xml-js": "^1.6.11" 44 | }, 45 | "devDependencies": { 46 | "eslint-config-airbnb-base": "^15.0.0", 47 | "eslint-plugin-import": "^2.26.0", 48 | "mocha": "^10.1.0", 49 | "nodemon": "^2.0.20", 50 | "nyc": "^15.1.0" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /public/favicons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyz05/danmaku/d49fe39d79ce8b565d41f008b4286620d41b7207/public/favicons/favicon-16x16.png -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # robots.txt generated at http://www.w3cschool.cn/ 2 | User-agent: * 3 | Disallow: 4 | Crawl-delay: 120 5 | Disallow: /cgi-bin/ 6 | -------------------------------------------------------------------------------- /routes/api/base.js: -------------------------------------------------------------------------------- 1 | //引入API组件 2 | const Bilibili = require("./bilibili"); 3 | const Mgtv = require("./mgtv"); 4 | const Tencentvideo = require("./tencentvideo"); 5 | const Youku = require("./youku"); 6 | const Iqiyi = require("./iqiyi"); 7 | // 实例化API组件 8 | const bilibili = new Bilibili(); 9 | const mgtv = new Mgtv(); 10 | const tencentvideo = new Tencentvideo(); 11 | const youku = new Youku(); 12 | const iqiyi = new Iqiyi(); 13 | 14 | //TODO 优化代码 15 | module.exports = { bilibili, mgtv, tencentvideo, youku, iqiyi }; 16 | -------------------------------------------------------------------------------- /routes/api/bilibili.js: -------------------------------------------------------------------------------- 1 | const urlmodule = require("url"); 2 | const axios = require("axios"); 3 | 4 | function Bilibili() { 5 | this.name = "B站"; 6 | this.domain = "bilibili.com"; 7 | this.example_urls = [ 8 | "https://www.bilibili.com/video/av170001", 9 | "https://www.bilibili.com/video/av170001?p=2", 10 | "https://www.bilibili.com/video/BV17x411w7KC?p=3", 11 | "https://www.bilibili.com/bangumi/play/ep691614" 12 | ]; 13 | 14 | this.resolve = async (url) => { 15 | // 相关API 16 | const api_video_info = "https://api.bilibili.com/x/web-interface/view"; 17 | const api_epid_cid = "https://api.bilibili.com/pgc/view/web/season"; 18 | const q = urlmodule.parse(url, true); 19 | const path = q.pathname.split("/"); 20 | // 普通投稿视频 21 | if (url.indexOf("video/") !== -1) { 22 | // 获取视频分P信息 23 | const p = q.query.p || 1; 24 | // 判断是否为旧版av号 25 | let params; 26 | if (url.indexOf("BV") !== -1) { 27 | params = {"bvid": path[2]}; 28 | } else { 29 | params = {"aid": path[2].substring(2)}; 30 | } 31 | const response = await axios.get(api_video_info, {params}); 32 | if (response.data.code !== 0) { 33 | this.error_msg = "获取普通投稿视频信息失败!"+response.data.message; 34 | return; 35 | } 36 | this.title = response.data.data.title; 37 | const subtitle = response.data.data.pages[p - 1].part; 38 | this.title = this.title + "-" + subtitle; 39 | const cid = response.data.data.pages[p - 1].cid; 40 | return [`https://comment.bilibili.com/${cid}.xml`]; 41 | } // 番剧 42 | else if (url.indexOf("bangumi/") !== -1 && url.indexOf("ep") !== -1) { 43 | const epid = path.slice(-1)[0]; 44 | const params = {"ep_id": epid.slice(2)}; 45 | const response = await axios.get(api_epid_cid, {params}); 46 | if (response.data.code !== 0) { 47 | this.error_msg = "获取番剧视频信息失败!"; 48 | return; 49 | } 50 | for (let i = 0; i < response.data.result.episodes.length; i++) { 51 | if (response.data.result.episodes[i].id == params.ep_id) { 52 | this.title = response.data.result.episodes[i].share_copy; 53 | const cid = response.data.result.episodes[i].cid; 54 | return [`https://comment.bilibili.com/${cid}.xml`]; 55 | } 56 | } 57 | } else { 58 | this.error_msg = "不支持的B站视频网址,仅支持普通视频(av,bv)、剧集视频(ep)"; 59 | } 60 | 61 | }; 62 | 63 | this.work = async (url) => { 64 | const urls = await this.resolve(url); 65 | if (!this.error_msg) { 66 | this.url = urls[0]; 67 | } 68 | return { 69 | title: this.title, 70 | url: this.url, 71 | msg: this.error_msg? this.error_msg: "ok" 72 | }; 73 | }; 74 | } 75 | 76 | module.exports = Bilibili; 77 | 78 | if(!module.parent) { 79 | const b = new Bilibili(); 80 | b.work(b.example_urls[0]).then(() => { 81 | console.log(b.content); 82 | console.log(b.title); 83 | }); 84 | } 85 | -------------------------------------------------------------------------------- /routes/api/iqiyi.js: -------------------------------------------------------------------------------- 1 | const axios = require("axios"); 2 | const pako = require("pako"); 3 | const { 4 | time_to_second, 5 | content_template, 6 | } = require("./utils"); 7 | const memory = require("../../utils/memory"); 8 | 9 | //资源消耗大 256M内存扛不住 10 | function Iqiyi() { 11 | this.name = "爱奇艺"; 12 | this.domain = "iqiyi.com"; 13 | this.example_urls = [ 14 | "https://www.iqiyi.com/v_19rr1lm35o.html", //api lens 11 15 | "http://www.iqiyi.com/v_1qzx9b00hs4.html?vfm=m_331_dbdy", //api lens 25 16 | "https://www.iqiyi.com/v_19rr1lm35o.html", 17 | ]; 18 | 19 | this.resolve = async (url) => { 20 | const res = await axios({ 21 | url: url, 22 | method: "get", 23 | headers: { 24 | "Accept-Encoding": "gzip,deflate,compress" 25 | } 26 | }); 27 | const data = res.data; 28 | const result = data.match(/ 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | --------------------------------------------------------------------------------