├── .gitignore ├── src ├── lib │ ├── Errors.js │ ├── validateParams.js │ ├── HttpClient.js │ ├── Response.js │ └── Constants.js └── service │ ├── utilsService.js │ ├── tkVideoParserService.js │ └── dyVideoParserService.js ├── Dockerfile ├── package.json ├── process-pm2.json ├── LICENSE ├── CHANGELOG.md ├── README.md ├── app.js └── README.en.md /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | node_modules/ 3 | logs/ 4 | temp/ -------------------------------------------------------------------------------- /src/lib/Errors.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | SUCCESS: {code: 200, msg: "success"}, 3 | PARAMS_VALIDATE_FAIL: {code: 400, msg: "params validate fail", error: null}, 4 | FAIL: {code: 500, msg: "fail", error: null}, 5 | } 6 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # 使用Node.js镜像作为基础镜像 2 | FROM node:16 3 | 4 | # 设置工作目录 5 | WORKDIR /usr/src/app 6 | 7 | # 复制package.json和package-lock.json(如果有)到工作目录 8 | COPY package*.json ./ 9 | 10 | # 安装项目的依赖项 11 | RUN npm install 12 | 13 | # 将项目文件复制到工作目录 14 | COPY . . 15 | 16 | # 暴露项目运行的端口,根据项目需要调整端口号 17 | EXPOSE 3000 18 | 19 | # 启动项目 20 | CMD ["npm", "start"] 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "video-parser", 3 | "version": "1.0.2", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node app.js" 8 | }, 9 | "keywords": ["video", "parser", "douyin", "kuaishou", "tiktok"], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "axios": "^1.4.0", 14 | "express": "^4.18.2" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/lib/validateParams.js: -------------------------------------------------------------------------------- 1 | function validateParams(requiredParams) { 2 | return function (req, res, next) { 3 | const missingParams = requiredParams.filter(param => !req.query[param] && req.query[param] !== 0 && req.query[param] !== false 4 | && !req.body[param] && req.body[param] !== 0 && req.body[param] !== false); 5 | 6 | if (missingParams.length > 0) { 7 | return res.status(400).json({ code: 400, msg: `Missing required parameters: ${missingParams.join(', ')}`, error: `Missing required parameters` }); 8 | } 9 | 10 | next(); 11 | }; 12 | } 13 | 14 | module.exports = { 15 | validateParams, 16 | } 17 | -------------------------------------------------------------------------------- /src/service/utilsService.js: -------------------------------------------------------------------------------- 1 | const HttpClient = require('../lib/httpClient'); 2 | const { API } = require('../lib/Constants'); 3 | 4 | const httpClient = new HttpClient(); 5 | 6 | /** 7 | * query ip 8 | * @param host 9 | * @returns {Promise} 10 | */ 11 | async function queryIp(host) { 12 | const resp = await httpClient.get(httpClient.buildUrl(API.BASE_URL, API.UT_QUERY_IP, {host}), 'json'); 13 | if (resp.status === 200 && resp.data && resp.data.code === 200) { 14 | return resp.data.data; 15 | } 16 | console.error(`UT queryIp failed, status = ${resp.status}, errMsg = ${resp.data ? resp.data.msg : 'data is null'} requestId = ${resp.data ? resp.data.request_id : 'data is null'}`); 17 | return null; 18 | } 19 | 20 | module.exports = { 21 | queryIp, 22 | } 23 | -------------------------------------------------------------------------------- /process-pm2.json: -------------------------------------------------------------------------------- 1 | { 2 | "apps":[ 3 | { 4 | "name": "video-parser", 5 | "cwd": "/code/video-parser/", 6 | "script": "/code/video-parser/app.js", 7 | "log_date_format": "YYYY-MM-DD HH:mm Z", 8 | "error_file": "/var/log/node/video-parser/video-parser-err.log", 9 | "out_file": "/var/log/node/video-parser/video-parser-out.log", 10 | "pid_file": "/tmp/pm2-log/outlogs/video-parser.pid", 11 | "instance_var": "INSTANCE_ID", 12 | "instances": 1, 13 | "node_args": "", 14 | "min_uptime": "20s", 15 | "max_restarts": 30, 16 | "watch": false, 17 | "merge_logs": true, 18 | "exec_interpreter": "node", 19 | "exec_mode": "cluster", 20 | "env": { 21 | "NODE_ENV": "production" 22 | } 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [2023] [bxiaoj] 4 | 5 | A license is hereby granted free of charge to anyone who acquires a copy of this software or related documentation ("Software"), 6 | To manipulate the software without restriction, including but not limited to using, copying, modifying, merging, distributing, 7 | distribute, sublicense and/or sell copies of the software, and permit the person to whom the software belongs to 8 | On the property supplied, the following conditions must be met: 9 | 10 | 1. Create a new issue or private message the author in issues, explaining the usage and purpose of the project; 11 | 2. It cannot be used for any illegal and harmful behaviors that damage the health and interests of others 12 | 13 | The above copyright notice and this permission notice shall be included on all copies or most substantial portions of the Software. 14 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # update log 2 | 3 | All notable project changes will be documented here. 4 | 5 | ## [v1.0.2] - 2023-08-11 6 | 7 | ### Update type 8 | 9 | * 1. Added video parsing capability for Tiktok platform; 10 | 11 | ### Detailed description 12 | 13 | * 1. Add dy user's recent video list query; 14 | * 2. Accessing TK related video parsing interfaces; 15 | * 3. Add an interface for querying IP details; 16 | 17 | --- 18 | 19 | ## [v1.0.1] - 2023-07-24 20 | 21 | ### Update type 22 | 23 | * 1. fix the get user videos params error; 24 | * 2. fix the get user info params error; 25 | 26 | --- 27 | 28 | ## [v1.0.0] - 2023-07-23 29 | 30 | ### Update type 31 | 32 | - Added: Initial version release. 33 | 34 | ### Detailed description 35 | 36 | - Initial version release. 37 | 38 | View all versions: [View release history](https://github.com/bxiaoj/video-parser/releases) 39 | 40 | --- 41 | -------------------------------------------------------------------------------- /src/lib/HttpClient.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios'); 2 | const Constants = require('./Constants'); 3 | 4 | class HttpClient { 5 | constructor(customHeaders, axiosOptions) { 6 | 7 | this.axiosInstance = axios.create({ 8 | timeout: 30000, 9 | headers: { 10 | ...Constants.DEFAULT_HEADERS, 11 | ...customHeaders, 12 | }, 13 | ...(axiosOptions || {}), 14 | }); 15 | } 16 | 17 | get(url, responseType) { 18 | return this.axiosInstance.get(url, { responseType }); 19 | } 20 | 21 | post(url, params, data, responseType) { 22 | return this.axiosInstance.post(url, data, { params, responseType }); 23 | } 24 | 25 | buildUrl(host, path, params) { 26 | return `${host}${path}?${new URLSearchParams(params || {})}`; 27 | } 28 | } 29 | 30 | module.exports = HttpClient; 31 | -------------------------------------------------------------------------------- /src/lib/Response.js: -------------------------------------------------------------------------------- 1 | const Errors = require('./Errors'); 2 | 3 | class Response { 4 | constructor(res) { 5 | this.res = res; 6 | } 7 | 8 | success(data) { 9 | return this.res.status(Errors.SUCCESS.code).json({ 10 | code: Errors.SUCCESS.code, 11 | msg: Errors.SUCCESS.msg, 12 | data: data, 13 | }); 14 | } 15 | 16 | fail(msg, error) { 17 | return this.res.status(Errors.FAIL.code).json({ 18 | code: Errors.FAIL.code, 19 | msg: msg || Errors.FAIL.msg, 20 | error: error || Errors.FAIL.error, 21 | }); 22 | } 23 | 24 | result(errorInfo, msg, error) { 25 | return this.res.status(errorInfo.code).json({ 26 | code: errorInfo.code, 27 | msg: msg || errorInfo.msg, 28 | error: error || errorInfo.error, 29 | }); 30 | } 31 | } 32 | 33 | module.exports = Response; 34 | -------------------------------------------------------------------------------- /src/lib/Constants.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | DEFAULT_HEADERS: { 3 | 'Authorization': 'Bearer dd10ZSheAwkbML7P4Yv55tFXFVstyULL', 4 | 'Accept': 'text/html,application/json,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9', 5 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36', 6 | }, 7 | API: { 8 | // BASE_URL: 'http://vproctol.zeed.ink/api/v1', 9 | BASE_URL: 'http://vproctol.zeed.ink/api/v1', 10 | DY_ORIGINAL_URL_CONVERT: '/dy/originalUrlFetch', 11 | DY_FETCH_LIVE_ROOM_INFO: '/dy/fetchLiveRoomInfo', 12 | DY_GENERAL_SEARCH: '/dy/generalSearch', 13 | DY_VIDEO_SEARCH: '/dy/videoSearch', 14 | DY_TOPIC_SEARCH: '/dy/topicSearch', 15 | DY_USER_VIDEOS: '/dy/getUserVideos', 16 | DY_USER_INFO: '/dy/getUserInfo', 17 | DY_VIDEO_COMMENTS: '/dy/getVideoComments', 18 | DY_VIDEO_DETAIL: '/dy/getVideoDetail', 19 | DY_USER_VIDEOS_SIMPLE_RECENT: '/dy/getUserVideosSimpleRecent', 20 | TK_USER_INFO: '/tk/getUserInfo', 21 | TK_VIDEO_DETAIL: '/tk/getVideoDetail', 22 | TK_USER_VIDEOS: '/tk/getUserVideos', 23 | TK_ORIGINAL_URL_CONVERT: '/tk/originalUrlFetch', 24 | TK_FETCH_LIVE_ROOM_INFO: '/tk/fetchLiveRoomInfo', 25 | UT_QUERY_IP: '/utils/queryIp', 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/service/tkVideoParserService.js: -------------------------------------------------------------------------------- 1 | const HttpClient = require('../lib/httpClient'); 2 | const { API } = require('../lib/Constants'); 3 | 4 | const httpClient = new HttpClient(); 5 | 6 | /** 7 | * fetch original url 8 | * @param share_info 9 | * @returns {Promise} 10 | */ 11 | async function originalUrlFetch(share_info) { 12 | const resp = await httpClient.post(API.BASE_URL + API.TK_ORIGINAL_URL_CONVERT, {}, {share_info}, 'json'); 13 | if (resp.status === 200 && resp.data && resp.data.code === 200) { 14 | return resp.data.data; 15 | } 16 | console.error(`TK originalUrlFetch failed, status = ${resp.status}, errMsg = ${resp.data ? resp.data.msg : 'data is null'} requestId = ${resp.data ? resp.data.request_id : 'data is null'}`); 17 | return null; 18 | } 19 | 20 | /** 21 | * fetch live room info 22 | * @param live_url 23 | * @returns {Promise} 24 | */ 25 | async function fetchLiveRoomInfo(live_url) { 26 | const resp = await httpClient.post(API.BASE_URL + API.TK_FETCH_LIVE_ROOM_INFO, {}, {live_url}, 'json'); 27 | if (resp.status === 200 && resp.data && resp.data.code === 200) { 28 | return resp.data.data; 29 | } 30 | console.error(`TK fetchLiveRoomInfo failed, status = ${resp.status}, errMsg = ${resp.data ? resp.data.msg : 'data is null'} requestId = ${resp.data ? resp.data.request_id : 'data is null'}`); 31 | return null; 32 | } 33 | 34 | /** 35 | * get user videos 36 | * @param sec_uid 37 | * @param count 38 | * @param cursor 39 | * @returns {Promise} 40 | */ 41 | async function getUserVideos(sec_uid, count, cursor) { 42 | const resp = await httpClient.get(httpClient.buildUrl(API.BASE_URL, API.TK_USER_VIDEOS, {sec_uid, count, cursor}), 'json'); 43 | if (resp.status === 200 && resp.data && resp.data.code === 200) { 44 | return resp.data.data; 45 | } 46 | console.error(`DY getUserVideos failed, status = ${resp.status}, errMsg = ${resp.data ? resp.data.msg : 'data is null'} requestId = ${resp.data ? resp.data.request_id : 'data is null'}`); 47 | return null; 48 | } 49 | 50 | /** 51 | * get user info 52 | * @param unique_id 53 | * @returns {Promise} 54 | */ 55 | async function getUserInfo(unique_id) { 56 | const resp = await httpClient.get(httpClient.buildUrl(API.BASE_URL, API.TK_USER_INFO, {unique_id}), 'json'); 57 | if (resp.status === 200 && resp.data && resp.data.code === 200) { 58 | return resp.data.data; 59 | } 60 | console.error(`DY getUserInfo failed, status = ${resp.status}, errMsg = ${resp.data ? resp.data.msg : 'data is null'} requestId = ${resp.data ? resp.data.request_id : 'data is null'}`); 61 | return null; 62 | } 63 | 64 | /** 65 | * get video detail 66 | * @param aweme_id 67 | * @returns {Promise} 68 | */ 69 | async function getVideoDetail(aweme_id) { 70 | const resp = await httpClient.get(httpClient.buildUrl(API.BASE_URL, API.TK_VIDEO_DETAIL, {aweme_id}), 'json'); 71 | if (resp.status === 200 && resp.data && resp.data.code === 200) { 72 | return resp.data.data; 73 | } 74 | console.error(`DY getVideoDetail failed, status = ${resp.status}, errMsg = ${resp.data ? resp.data.msg : 'data is null'} requestId = ${resp.data ? resp.data.request_id : 'data is null'}`); 75 | return null; 76 | } 77 | 78 | module.exports = { 79 | originalUrlFetch, 80 | fetchLiveRoomInfo, 81 | getUserVideos, 82 | getUserInfo, 83 | getVideoDetail, 84 | } 85 | -------------------------------------------------------------------------------- /src/service/dyVideoParserService.js: -------------------------------------------------------------------------------- 1 | const HttpClient = require('../lib/httpClient'); 2 | const { API } = require('../lib/Constants'); 3 | 4 | const httpClient = new HttpClient(); 5 | 6 | /** 7 | * fetch original url 8 | * @param share_info 9 | * @returns {Promise} 10 | */ 11 | async function originalUrlFetch(share_info) { 12 | const resp = await httpClient.post(API.BASE_URL + API.DY_ORIGINAL_URL_CONVERT, {}, {share_info}, 'json'); 13 | if (resp.status === 200 && resp.data && resp.data.code === 200) { 14 | return resp.data.data; 15 | } 16 | console.error(`DY originalUrlFetch failed, status = ${resp.status}, errMsg = ${resp.data ? resp.data.msg : 'data is null'} requestId = ${resp.data ? resp.data.request_id : 'data is null'}`); 17 | return null; 18 | } 19 | 20 | /** 21 | * fetch live room info 22 | * @param live_url 23 | * @returns {Promise} 24 | */ 25 | async function fetchLiveRoomInfo(live_url) { 26 | const resp = await httpClient.post(API.BASE_URL + API.DY_FETCH_LIVE_ROOM_INFO, {}, {live_url}, 'json'); 27 | if (resp.status === 200 && resp.data && resp.data.code === 200) { 28 | return resp.data.data; 29 | } 30 | console.error(`DY fetchLiveRoomInfo failed, status = ${resp.status}, errMsg = ${resp.data ? resp.data.msg : 'data is null'} requestId = ${resp.data ? resp.data.request_id : 'data is null'}`); 31 | return null; 32 | } 33 | 34 | /** 35 | * general search 36 | * @param keyword 37 | * @param sort_type 38 | * @param publish_time 39 | * @param offset 40 | * @param count 41 | * @returns {Promise} 42 | */ 43 | async function generalSearch(keyword, sort_type, publish_time, offset, count) { 44 | const resp = await httpClient.get(httpClient.buildUrl(API.BASE_URL, API.DY_GENERAL_SEARCH, {keyword, sort_type, publish_time, offset, count}), 'json'); 45 | if (resp.status === 200 && resp.data && resp.data.code === 200) { 46 | return resp.data.data; 47 | } 48 | console.error(`DY generalSearch failed, status = ${resp.status}, errMsg = ${resp.data ? resp.data.msg : 'data is null'} requestId = ${resp.data ? resp.data.request_id : 'data is null'}`); 49 | return null; 50 | } 51 | 52 | /** 53 | * video search 54 | * @param keyword 55 | * @param sort_type 56 | * @param publish_time 57 | * @param offset 58 | * @param count 59 | * @returns {Promise} 60 | */ 61 | async function videoSearch(keyword, sort_type, publish_time, offset, count) { 62 | const resp = await httpClient.get(httpClient.buildUrl(API.BASE_URL, API.DY_VIDEO_SEARCH, {keyword, sort_type, publish_time, offset, count}), 'json'); 63 | if (resp.status === 200 && resp.data && resp.data.code === 200) { 64 | return resp.data.data; 65 | } 66 | console.error(`DY videoSearch failed, status = ${resp.status}, errMsg = ${resp.data ? resp.data.msg : 'data is null'} requestId = ${resp.data ? resp.data.request_id : 'data is null'}`); 67 | return null; 68 | } 69 | 70 | /** 71 | * topic search 72 | * @param keyword 73 | * @param sort_type 74 | * @param publish_time 75 | * @param offset 76 | * @param count 77 | * @returns {Promise} 78 | */ 79 | async function topicSearch(keyword, sort_type, publish_time, offset, count) { 80 | const resp = await httpClient.get(httpClient.buildUrl(API.BASE_URL, API.DY_TOPIC_SEARCH, {keyword, sort_type, publish_time, offset, count}), 'json'); 81 | if (resp.status === 200 && resp.data && resp.data.code === 200) { 82 | return resp.data.data; 83 | } 84 | console.error(`DY topicSearch failed, status = ${resp.status}, errMsg = ${resp.data ? resp.data.msg : 'data is null'} requestId = ${resp.data ? resp.data.request_id : 'data is null'}`); 85 | return null; 86 | } 87 | 88 | /** 89 | * get user videos 90 | * @param sec_uid 91 | * @param count 92 | * @param max_cursor 93 | * @returns {Promise} 94 | */ 95 | async function getUserVideos(sec_uid, count, max_cursor) { 96 | const resp = await httpClient.get(httpClient.buildUrl(API.BASE_URL, API.DY_USER_VIDEOS, {sec_uid, count, max_cursor}), 'json'); 97 | if (resp.status === 200 && resp.data && resp.data.code === 200) { 98 | return resp.data.data; 99 | } 100 | console.error(`DY getUserVideos failed, status = ${resp.status}, errMsg = ${resp.data ? resp.data.msg : 'data is null'} requestId = ${resp.data ? resp.data.request_id : 'data is null'}`); 101 | return null; 102 | } 103 | 104 | /** 105 | * get user info 106 | * @param sec_uid 107 | * @returns {Promise} 108 | */ 109 | async function getUserInfo(sec_uid) { 110 | const resp = await httpClient.get(httpClient.buildUrl(API.BASE_URL, API.DY_USER_INFO, {sec_uid}), 'json'); 111 | if (resp.status === 200 && resp.data && resp.data.code === 200) { 112 | return resp.data.data; 113 | } 114 | console.error(`DY getUserInfo failed, status = ${resp.status}, errMsg = ${resp.data ? resp.data.msg : 'data is null'} requestId = ${resp.data ? resp.data.request_id : 'data is null'}`); 115 | return null; 116 | } 117 | 118 | /** 119 | * get video comments 120 | * @param aweme_id 121 | * @param count 122 | * @param cursor 123 | * @returns {Promise} 124 | */ 125 | async function getVideoComments(aweme_id, count, cursor) { 126 | const resp = await httpClient.get(httpClient.buildUrl(API.BASE_URL, API.DY_VIDEO_COMMENTS, {aweme_id, count, cursor}), 'json'); 127 | if (resp.status === 200 && resp.data && resp.data.code === 200) { 128 | return resp.data.data; 129 | } 130 | console.error(`DY getVideoComments failed, status = ${resp.status}, errMsg = ${resp.data ? resp.data.msg : 'data is null'} requestId = ${resp.data ? resp.data.request_id : 'data is null'}`); 131 | return null; 132 | } 133 | 134 | /** 135 | * get video detail 136 | * @param aweme_id 137 | * @returns {Promise} 138 | */ 139 | async function getVideoDetail(aweme_id) { 140 | const resp = await httpClient.get(httpClient.buildUrl(API.BASE_URL, API.DY_VIDEO_DETAIL, {aweme_id}), 'json'); 141 | if (resp.status === 200 && resp.data && resp.data.code === 200) { 142 | return resp.data.data; 143 | } 144 | console.error(`DY getVideoDetail failed, status = ${resp.status}, errMsg = ${resp.data ? resp.data.msg : 'data is null'} requestId = ${resp.data ? resp.data.request_id : 'data is null'}`); 145 | return null; 146 | } 147 | 148 | /** 149 | * get user videos simple recent 150 | * @param sec_uid 151 | * @returns {Promise} 152 | */ 153 | async function getUserVideosSimpleRecent(sec_uid) { 154 | const resp = await httpClient.get(httpClient.buildUrl(API.BASE_URL, API.DY_USER_VIDEOS_SIMPLE_RECENT, {sec_uid}), 'json'); 155 | if (resp.status === 200 && resp.data && resp.data.code === 200) { 156 | return resp.data.data; 157 | } 158 | console.error(`DY getUserVideosSimpleRecent failed, status = ${resp.status}, errMsg = ${resp.data ? resp.data.msg : 'data is null'} requestId = ${resp.data ? resp.data.request_id : 'data is null'}`); 159 | return null; 160 | } 161 | 162 | module.exports = { 163 | originalUrlFetch, 164 | fetchLiveRoomInfo, 165 | generalSearch, 166 | videoSearch, 167 | topicSearch, 168 | getUserVideos, 169 | getUserInfo, 170 | getVideoComments, 171 | getVideoDetail, 172 | getUserVideosSimpleRecent, 173 | } 174 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Video-Parser 2 | 3 | 简体中文 | [English](README.en.md) 4 | 5 | Video-Parser 的目标是解析海内外主流视频网站的视频地址,目前支持的网站有:抖音,后续还会支持更多的网站(快手,Tiktok,YouTube,B站,斗鱼,虎牙等)。 6 | 7 | [FirRock](http://vproctol.zeed.ink/) 提供免费稳定的服务支持,特别感谢! 8 | 9 | 声明:本项目仅供学习交流使用,不得用于商业用途,如有侵权,请联系作者删除。 10 | 11 | ### Video-Parser目标 12 | * 解析目前主流的视频网站的视频地址 13 | * 提供稳定的版本 14 | * 保持最新的视频网站的解析 15 | * 第一时间更新&修复 16 | 17 | 18 | ## 接口 19 | 20 | ### 抖音 21 | * 获取原始链接 `/api/dy/originalUrlFetch` `POST` 22 | * 获取直播间信息 `/api/dy/fetchLiveRoomInfo` `POST` 23 | * 综合搜索 `/api/dy/generalSearch` `GET` 24 | * 视频搜索 `/api/dy/videoSearch` `GET` 25 | * 话题搜索 `/api/dy/topicSearch` `GET` 26 | * 获取用户视频列表 `/api/dy/getUserVideos` `GET` 27 | * 获取用户信息 `/api/dy/getUserInfo` `GET` 28 | * 获取用户评论 `/api/dy/getVideoComments` `GET` 29 | * 获取视频信息 `/api/dy/getVideoDetail` `GET` 30 | * 获取用户最近视频列表简版 `/api/dy/getUserVideosSimpleRecent` `GET` 31 | 32 | 说明:其他接口需要传的参数往往可以调用`获取原始链接`获取相应的链接,如获取视频评论需要传视频id,可以将视频链接转换原始链接获取视频id。 33 | 34 | ### Tiktok 35 | * 获取原始链接 `/api/tk/originalUrlFetch` `POST` 36 | * 获取直播间信息 `/api/tk/fetchLiveRoomInfo` `POST` 37 | * 获取用户视频列表 `/api/tk/getUserVideos` `GET` 38 | * 获取用户信息 `/api/tk/getUserInfo` `GET` 39 | * 获取视频信息 `/api/tk/getVideoDetail` `GET` 40 | 41 | 说明:其他接口需要传的参数往往可以调用`获取原始链接`获取相应的链接,如获取视频评论需要传视频id,可以将视频链接转换原始链接获取视频id。 42 | 43 | ### 工具 44 | * Ip详细信息查询 `/api/utils/queryIp` `GET` 45 | 46 | 47 | ## 例子 48 | 49 | BASE_URL: `http://localhost:3000` 50 | 51 | ### 抖音 52 | 53 | #### 获取原始链接 54 | 55 | * **请求地址**:`/api/dy/originalUrlFetch` 56 | * **请求方式**:`POST` 57 | * **请求参数**:`json` 58 | 59 | ```json 60 | { 61 | "share_info": "2.00 OxF:/ 小荷才露尖尖角~ https://v.douyin.com/iVsR2SK/ 复制此链接,打开Dou音搜索,直接观看视频!" 62 | } 63 | ``` 64 | 65 | * 响应参数:`json` 66 | 67 | ```json 68 | { 69 | "code": 200, 70 | "msg": "success", 71 | "data": { 72 | "original_url": "https://www.iesdouyin.com/share/video/7257768974631374115/?region=CN&mid=6984719806654089992&u_code=0&did=MS4wLjABAAAAbqVwCUBSDPsPpMvTx0vOuEduviBhgeXBDDMBqJYrSpkKOz8kHRuu7fVYM11smy75&iid=MS4wLjABAAAANwkJuWIRFOzg5uCpDRpMj4OX-QryoDgn-yYlXQnRwQQ&with_sec_did=1&titleType=title&share_sign=rIjKXqSq7BmP1zv22aQW8oWg.6HvSSBDPJhgiH4LmIg-&share_version=170400&ts=1689845499&from_ssr=1&from=web_code_link" 73 | } 74 | } 75 | ``` 76 | 77 | --- 78 | 79 | #### 获取直播间信息 80 | 81 | * **请求地址**:`/api/dy/fetchLiveRoomInfo` 82 | * **请求方式**:`POST` 83 | * **请求参数**:`json` 84 | 85 | ```json 86 | { 87 | "live_url": "https://v.douyin.com/kD1pKKR" 88 | } 89 | ``` 90 | 91 | * **响应参数**:`json` (内容太长,此处不展示) 92 | 93 | --- 94 | 95 | #### 综合搜索 96 | 97 | * **请求地址**:`/api/dy/generalSearch?keyword=陕西文化&sort_type=0&publish_time=0&offset=0&count=10` 98 | * **请求方式**:`GET` 99 | * **响应参数**:`json` (内容太长,此处不展示) 100 | 101 | --- 102 | 103 | #### 视频搜索 104 | 105 | * **请求地址**:`/api/dy/videoSearch?keyword=陕西文化&sort_type=0&publish_time=0&offset=0&count=10` 106 | * **请求方式**:`GET` 107 | * **响应参数**:`json` (内容太长,此处不展示) 108 | 109 | --- 110 | 111 | #### 话题搜索 112 | 113 | * **请求地址**:`/api/dy/topicSearch?keyword=陕西文化&sort_type=0&publish_time=0&offset=0&count=10` 114 | * **请求方式**:`GET` 115 | * **响应参数**:`json` (内容太长,此处不展示) 116 | 117 | --- 118 | 119 | #### 获取用户主页视频列表 120 | 121 | * **请求地址**:`/api/dy/getUserVideos?sec_uid=MS4wLjABAAAA5qMD8Gzdcgq7HXUOviKB59i0-ybJ59jJvNzyaPt5XOsVNqP6DU7WLcoAXvdxvYdp&count=15&max_cursor=0` 122 | * **请求方式**:`GET` 123 | * **响应参数**:`json` (内容太长,此处不展示) 124 | 125 | --- 126 | 127 | #### 获取用户信息 128 | 129 | * **请求地址**:`/api/dy/getUserInfo?sec_uid=MS4wLjABAAAA5qMD8Gzdcgq7HXUOviKB59i0-ybJ59jJvNzyaPt5XOsVNqP6DU7WLcoAXvdxvYdp` 130 | * **请求方式**:`GET` 131 | * **响应参数**:`json` (内容太长,此处不展示) 132 | 133 | --- 134 | 135 | #### 获取视频评论 136 | 137 | * **请求地址**:`/api/dy/getVideoComments?aweme_id=6958148148680857863&count=20&cursor=0` 138 | * **请求方式**:`GET` 139 | * **响应参数**:`json` (内容太长,此处不展示) 140 | 141 | --- 142 | 143 | #### 获取视频详情 144 | 145 | * **请求地址**:`/api/dy/getVideoDetail?aweme_id=7055666575176781069` 146 | * **请求方式**:`GET` 147 | * **响应参数**:`json` (内容太长,此处不展示) 148 | 149 | --- 150 | 151 | #### 获取用户最近视频列表简版 152 | 153 | * **请求地址**:`/api/dy/getUserVideosSimpleRecent?sec_uid=MS4wLjABAAAA5qMD8Gzdcgq7HXUOviKB59i0-ybJ59jJvNzyaPt5XOsVNqP6DU7WLcoAXvdxvYdp` 154 | * **请求方式**:`GET` 155 | * **响应参数**:`json` (内容太长,此处不展示) 156 | 157 | ### Tiktok 158 | 159 | #### 获取原始链接 160 | 161 | * **请求地址**:`/api/tk/originalUrlFetch` 162 | * **请求方式**:`POST` 163 | * **请求参数**:`json` 164 | 165 | ```json 166 | { 167 | "share_info": "https://www.tiktok.com/t/ZTRypfB5D/" 168 | } 169 | ``` 170 | 171 | * 响应参数:`json` 172 | 173 | ```json 174 | { 175 | "code": 200, 176 | "msg": "success", 177 | "data": { 178 | "original_url": "https://www.tiktok.com/video/7257768974631374115" 179 | } 180 | } 181 | ``` 182 | 183 | --- 184 | 185 | #### 获取直播间信息 186 | 187 | * **请求地址**:`/api/tk/fetchLiveRoomInfo` 188 | * **请求方式**:`POST` 189 | * **请求参数**:`json` 190 | 191 | ```json 192 | { 193 | "live_url": "https://www.tiktok.com/t/ZTRypfB5D/" 194 | } 195 | ``` 196 | 197 | * **响应参数**:`json` (内容太长,此处不展示) 198 | 199 | --- 200 | 201 | #### 获取用户主页视频列表 202 | 203 | * **请求地址**:`/api/tk/getUserVideos?sec_uid=MS4wLjABAAAAhgKK-EJ_9MmIP0LNyu6-pFEhiffelae0N0c3xdxFymHFseWJ-SsTRqm9AIiIUTtI&count=30&cursor=0` 204 | * **请求方式**:`GET` 205 | * **响应参数**:`json` (内容太长,此处不展示) 206 | 207 | --- 208 | 209 | #### 获取用户信息 210 | 211 | * **请求地址**:`/api/tk/getUserInfo?sec_uid=MS4wLjABAAAAhgKK-EJ_9MmIP0LNyu6-pFEhiffelae0N0c3xdxFymHFseWJ-SsTRqm9AIiIUTtI` 212 | * **请求方式**:`GET` 213 | * **响应参数**:`json` (内容太长,此处不展示) 214 | 215 | --- 216 | 217 | #### 获取视频详情 218 | 219 | * **请求地址**:`/api/tk/getVideoDetail?unique_id=unpai3` 220 | * **请求方式**:`GET` 221 | * **响应参数**:`json` (内容太长,此处不展示) 222 | 223 | ### 工具 224 | 225 | #### Ip或host详细信息查询 226 | 227 | * **请求地址**:`/api/utils/queryIp?host=baidu.com` 228 | * **请求方式**:`GET` 229 | * **请求参数**:`json` 230 | 231 | ## 部署 232 | 233 | 说明: 234 | * 本项目是基于`nodejs` `express`框架开发的,需要先安装`nodejs`环境,建议使用`v16`以后的稳定版本。 235 | * 其他语言或者需要自行封装调用,可直接参考[FirRock](http://vproctol.zeed.ink/) 提供的接口文档`免费`接入。 236 | 237 | ### node命令部署 238 | 239 | * clone项目到本地 240 | * 进入项目目录,执行`npm install`安装依赖 241 | * 执行`npm start`启动项目 242 | * 访问`http://localhost:3000`即可 243 | 244 | ### node pm2部署 245 | 246 | * clone项目到到目录`/code`下 247 | * 进入项目目录,执行`npm install`安装依赖 248 | * 执行`pm2 start /code/video-parser/process-pm2.json`启动项目 249 | * 访问`http://localhost:3000`即可 250 | * 执行`pm2 reload /code/video-parser/process-pm2.json`重新加载项目(有版本更新时) 251 | * 执行`pm2 stop video-parser`停止项目 252 | * 执行`pm2 restart video-parser`重启项目 253 | * 执行`pm2 delete video-parser`删除项目 254 | 255 | ### docker部署 256 | 257 | * clone项目到本地 258 | * 进入项目目录,使用以下命令在项目根目录下构建Docker镜像: 259 | ``` 260 | docker build -t video-parser . 261 | ``` 262 | 263 | * 使用以下命令在后台运行容器: 264 | ``` 265 | docker run -itd -p 3000:3000 --name video-parser video-parser 266 | ``` 267 | 268 | * 访问`http://localhost:3000`即可 269 | 270 | ## 版权和许可证 271 | 272 | ```text 273 | 274 | Copyright (c) [2023] [bxiaoj] 275 | 276 | A license is hereby granted free of charge to anyone who acquires a copy of this software or related documentation ("Software"), 277 | To manipulate the software without restriction, including but not limited to using, copying, modifying, merging, distributing, 278 | distribute, sublicense and/or sell copies of the software, and permit the person to whom the software belongs to 279 | On the property supplied, the following conditions must be met: 280 | 281 | 1. Create a new issue or private message the author in issues, explaining the usage and purpose of the project; 282 | 2. It cannot be used for any illegal and harmful behaviors that damage the health and interests of others 283 | 284 | The above copyright notice and this permission notice shall be included on all copies or most substantial portions of the Software. 285 | 286 | ``` 287 | 288 | ## 作者 289 | 290 | * [bxiaoj](https://github.com/bxiaoj) 291 | 292 | ## 链接 293 | 294 | [FirRock](http://vproctol.zeed.ink/) 提供免费稳定的服务支持,再次特别感谢! 295 | 296 | 297 | ## 备注 298 | 299 | * 本项目仅供学习交流使用,不得用于商业用途,如有侵权,请联系作者删除。 300 | * 欢迎大家提出宝贵的意见和建议,有问题可以提issue 301 | * 有能力的朋友可以提PR,一起完善项目 302 | * 欢迎大家`star` `fork`,支持一下作者,谢谢! 303 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const app = express(); 3 | const { validateParams } = require('./src/lib/validateParams'); 4 | const dyVideoParserService = require('./src/service/dyVideoParserService'); 5 | const tkVideoParserService = require('./src/service/tkVideoParserService'); 6 | const utilsService = require('./src/service/utilsService'); 7 | const Response = require('./src/lib/Response'); 8 | const Errors = require('./src/lib/Errors'); 9 | 10 | app.use(express.json()); 11 | 12 | app.post('/api/dy/originalUrlFetch', validateParams(['share_info']), async (req, res) => { 13 | const { share_info } = req.body; 14 | 15 | if (share_info.indexOf('http') === -1) { 16 | return new Response(res).result(Errors.PARAMS_VALIDATE_FAIL, 'share_info not contain url') 17 | } 18 | 19 | try { 20 | const data = await dyVideoParserService.originalUrlFetch(share_info); 21 | if (!data) { 22 | return new Response(res).fail('original url fetch Error') 23 | } 24 | new Response(res).success(data); 25 | }catch (e) { 26 | new Response(res).fail('original url fetch Error', e.message); 27 | } 28 | }); 29 | 30 | app.post('/api/dy/fetchLiveRoomInfo', validateParams(['live_url']), async (req, res) => { 31 | const { live_url } = req.body; 32 | 33 | if (live_url.indexOf('http') === -1) { 34 | return new Response(res).result(Errors.PARAMS_VALIDATE_FAIL, 'live_url not contain url') 35 | } 36 | 37 | try { 38 | const data = await dyVideoParserService.fetchLiveRoomInfo(live_url); 39 | if (!data) { 40 | return new Response(res).fail('fetch live room info Error') 41 | } 42 | new Response(res).success(data); 43 | }catch (e) { 44 | new Response(res).fail('fetch live room info Error', e.message); 45 | } 46 | }); 47 | 48 | app.get('/api/dy/generalSearch', validateParams(['keyword', 'sort_type', 'publish_time', 'offset', 'count']), async (req, res) => { 49 | const { keyword, sort_type, publish_time, offset, count } = req.query; 50 | try { 51 | const data = await dyVideoParserService.generalSearch(keyword, sort_type, publish_time, offset, count); 52 | if (!data) { 53 | return new Response(res).fail('general search Error') 54 | } 55 | new Response(res).success(data); 56 | }catch (e) { 57 | new Response(res).fail('general search Error', e.message); 58 | } 59 | }); 60 | 61 | app.get('/api/dy/videoSearch', validateParams(['keyword', 'sort_type', 'publish_time', 'offset', 'count']), async (req, res) => { 62 | const { keyword, sort_type, publish_time, offset, count } = req.query; 63 | try { 64 | const data = await dyVideoParserService.videoSearch(keyword, sort_type, publish_time, offset, count); 65 | if (!data) { 66 | return new Response(res).fail('video search Error') 67 | } 68 | new Response(res).success(data); 69 | }catch (e) { 70 | new Response(res).fail('video search Error', e.message); 71 | } 72 | }); 73 | 74 | app.get('/api/dy/topicSearch', validateParams(['keyword', 'sort_type', 'publish_time', 'offset', 'count']), async (req, res) => { 75 | const { keyword, sort_type, publish_time, offset, count } = req.query; 76 | try { 77 | const data = await dyVideoParserService.topicSearch(keyword, sort_type, publish_time, offset, count); 78 | if (!data) { 79 | return new Response(res).fail('topic search Error') 80 | } 81 | new Response(res).success(data); 82 | }catch (e) { 83 | new Response(res).fail('topic search Error', e.message); 84 | } 85 | }); 86 | 87 | app.get('/api/dy/getUserVideos', validateParams(['sec_uid', 'count', 'max_cursor']), async (req, res) => { 88 | const { sec_uid, count, max_cursor } = req.query; 89 | try { 90 | const data = await dyVideoParserService.getUserVideos(sec_uid, count, max_cursor); 91 | if (!data) { 92 | return new Response(res).fail('get user videos Error'); 93 | } 94 | new Response(res).success(data); 95 | }catch (e) { 96 | new Response(res).fail('get user videos Error', e.message); 97 | } 98 | }); 99 | 100 | app.get('/api/dy/getUserInfo', validateParams(['sec_uid']), async (req, res) => { 101 | const { sec_uid } = req.query; 102 | try { 103 | const data = await dyVideoParserService.getUserInfo(sec_uid); 104 | if (!data) { 105 | return new Response(res).fail('get user info Error'); 106 | } 107 | new Response(res).success(data); 108 | }catch (e) { 109 | new Response(res).fail('get user info Error', e.message); 110 | } 111 | }); 112 | 113 | app.get('/api/dy/getVideoComments', validateParams(['aweme_id', 'count', 'cursor']), async (req, res) => { 114 | const { aweme_id, count, cursor } = req.query; 115 | try { 116 | const data = await dyVideoParserService.getVideoComments(aweme_id, count, cursor); 117 | if (!data) { 118 | return new Response(res).fail('get video comments Error'); 119 | } 120 | new Response(res).success(data); 121 | }catch (e) { 122 | new Response(res).fail('get video comments Error', e.message); 123 | } 124 | }); 125 | 126 | app.get('/api/dy/getVideoDetail', validateParams(['aweme_id']), async (req, res) => { 127 | const { aweme_id } = req.query; 128 | try { 129 | const data = await dyVideoParserService.getVideoDetail(aweme_id); 130 | if (!data) { 131 | return new Response(res).fail('get video detail Error'); 132 | } 133 | new Response(res).success(data); 134 | }catch (e) { 135 | new Response(res).fail('get video detail Error', e.message); 136 | } 137 | }); 138 | 139 | app.get('/api/dy/getUserVideosSimpleRecent', validateParams(['sec_uid']), async (req, res) => { 140 | const { sec_uid } = req.query; 141 | try { 142 | const data = await dyVideoParserService.getUserVideosSimpleRecent(sec_uid); 143 | if (!data) { 144 | return new Response(res).fail('get user videos simple recent Error'); 145 | } 146 | new Response(res).success(data); 147 | }catch (e) { 148 | new Response(res).fail('get user videos simple recent Error', e.message); 149 | } 150 | }); 151 | 152 | app.post('/api/tk/originalUrlFetch', validateParams(['share_info']), async (req, res) => { 153 | const { share_info } = req.body; 154 | 155 | if (share_info.indexOf('http') === -1) { 156 | return new Response(res).result(Errors.PARAMS_VALIDATE_FAIL, 'share_info not contain url') 157 | } 158 | 159 | try { 160 | const data = await tkVideoParserService.originalUrlFetch(share_info); 161 | if (!data) { 162 | return new Response(res).fail('original url fetch Error') 163 | } 164 | new Response(res).success(data); 165 | }catch (e) { 166 | new Response(res).fail('original url fetch Error', e.message); 167 | } 168 | }); 169 | 170 | app.post('/api/tk/fetchLiveRoomInfo', validateParams(['live_url']), async (req, res) => { 171 | const { live_url } = req.body; 172 | 173 | if (live_url.indexOf('http') === -1) { 174 | return new Response(res).result(Errors.PARAMS_VALIDATE_FAIL, 'live_url not contain url') 175 | } 176 | 177 | try { 178 | const data = await tkVideoParserService.fetchLiveRoomInfo(live_url); 179 | if (!data) { 180 | return new Response(res).fail('fetch live room info Error') 181 | } 182 | new Response(res).success(data); 183 | }catch (e) { 184 | new Response(res).fail('fetch live room info Error', e.message); 185 | } 186 | }); 187 | 188 | app.get('/api/tk/getUserVideos', validateParams(['sec_uid', 'count', 'cursor']), async (req, res) => { 189 | const { sec_uid, count, cursor } = req.query; 190 | try { 191 | const data = await tkVideoParserService.getUserVideos(sec_uid, count, cursor); 192 | if (!data) { 193 | return new Response(res).fail('get user videos Error'); 194 | } 195 | new Response(res).success(data); 196 | }catch (e) { 197 | new Response(res).fail('get user videos Error', e.message); 198 | } 199 | }); 200 | 201 | app.get('/api/tk/getUserInfo', validateParams(['unique_id']), async (req, res) => { 202 | const {unique_id} = req.query; 203 | try { 204 | const data = await tkVideoParserService.getUserInfo(unique_id); 205 | if (!data) { 206 | return new Response(res).fail('get user info Error'); 207 | } 208 | new Response(res).success(data); 209 | } catch (e) { 210 | new Response(res).fail('get user info Error', e.message); 211 | } 212 | }); 213 | 214 | app.get('/api/tk/getVideoDetail', validateParams(['aweme_id']), async (req, res) => { 215 | const { aweme_id } = req.query; 216 | try { 217 | const data = await tkVideoParserService.getVideoDetail(aweme_id); 218 | if (!data) { 219 | return new Response(res).fail('get video detail Error'); 220 | } 221 | new Response(res).success(data); 222 | }catch (e) { 223 | new Response(res).fail('get video detail Error', e.message); 224 | } 225 | }); 226 | 227 | app.get('/api/utils/queryIp', validateParams(['host']), async (req, res) => { 228 | const { host } = req.query; 229 | try { 230 | const data = await utilsService.queryIp(host); 231 | if (!data) { 232 | return new Response(res).fail('query ip Error'); 233 | } 234 | new Response(res).success(data); 235 | }catch (e) { 236 | new Response(res).fail('query ip Error', e.message); 237 | } 238 | }); 239 | 240 | app.listen(3000, () => { 241 | console.log('API server is running on port 3000'); 242 | console.log('http://localhost:3000'); 243 | }); 244 | -------------------------------------------------------------------------------- /README.en.md: -------------------------------------------------------------------------------- 1 | # Video-Parser 2 | 3 | [简体中文](README.md) | English 4 | 5 | Video-Parser's goals to analyze the video addresses of mainstream video websites at home and abroad. The currently supported websites are: Douyin, and more websites will be supported in the future (Kuaishou, Tiktok, YouTube, Bilibili, Douyu, Huya, etc.). 6 | 7 | [FirRock](http://vproctol.zeed.ink/) Provide free and stable service support, thank you! 8 | 9 | Disclaimer: This project is only for learning and communication, not for commercial purposes. If there is any infringement, please contact the author to delete it. 10 | 11 | ### Video-Parser Goals 12 | * Parse the video address of the current mainstream video website 13 | * provide stable version 14 | * Keep up-to-date analysis of video sites 15 | * Update & fix for the first time 16 | 17 | 18 | ## api 19 | 20 | ### Douyin 21 | * Get the original URL `/api/dy/originalUrlFetch` `POST` 22 | * Get live room information `/api/dy/fetchLiveRoomInfo` `POST` 23 | * General search `/api/dy/generalSearch` `GET` 24 | * Video search `/api/dy/videoSearch` `GET` 25 | * Topic search `/api/dy/topicSearch` `GET` 26 | * Get user video list `/api/dy/getUserVideos` `GET` 27 | * Get user information `/api/dy/getUserInfo` `GET` 28 | * Get user comments `/api/dy/getVideoComments` `GET` 29 | * Get video information `/api/dy/getVideoDetail` `GET` 30 | * Get user recent video list simple `/api/dy/getUserVideosSimpleRecent` `GET` 31 | 32 | Note: For other interfaces that need to pass parameters, you can often call `Get Original Link` to get the corresponding link. For example, if you need to pass the video id to get video comments, you can convert the video link to the original link to get the video id. 33 | 34 | ### Tiktok 35 | * Get the original URL `/api/tk/originalUrlFetch` `POST` 36 | * Get live room information `/api/tk/fetchLiveRoomInfo` `POST` 37 | * Get user information `/api/tk/getUserInfo` `GET` 38 | * Get user video list `/api/tk/getUserVideos` `GET` 39 | * Get video information `/api/tk/getVideoDetail` `GET` 40 | 41 | Note: For other interfaces that need to pass parameters, you can often call `Get Original Link` to get the corresponding link. For example, if you need to pass the video id to get video comments, you can convert the video link to the original link to get the video id. 42 | 43 | ### Utils 44 | * Get IP detail information `/api/utils/queryIp` `GET` 45 | 46 | ## example 47 | 48 | BASE_URL: `http://localhost:3000` 49 | 50 | ### Douyin 51 | 52 | #### Get original link 53 | 54 | * **Request address**: `/api/dy/originalUrlFetch` 55 | * **Request method**: `POST` 56 | * **Request parameter**: `json` 57 | 58 | ```json 59 | { 60 | "share_info": "2.00 OxF:/ Xiaohe just showed her sharp corners~ https://v.douyin.com/iVsR2SK/ Copy this link, open Douyin search, and watch the video directly!" 61 | } 62 | ``` 63 | 64 | * Response parameters: `json` 65 | 66 | ```json 67 | { 68 | "code": 200, 69 | "msg": "success", 70 | "data": { 71 | "original_url": "https://www.iesdouyin.com/share/video/7257768974631374115/?region=CN&mid=6984719806654089992&u_code=0&did=MS4wLjABAAAAbqVwCUBSDPsPpMvTx0vOuEduviBhgeXBDDMB qJYrSpkKOz8kHRuu7fVYM11smy75&iid=MS4wLjABAAAANwkJuWIRFOzg5uCpDRpMj4OX-QryoDgn-yYlXQnRwQQ&with_sec_did=1&titleType=title&share_sign=rIjKXqSq7BmP1zv22aQW8o Wg.6HvSSBDPJhgiH4LmIg-&share_version=170400&ts=1689845499&from_ssr=1&from=web_code_link" 72 | } 73 | } 74 | ``` 75 | 76 | --- 77 | 78 | #### Get live room information 79 | 80 | * **Request address**: `/api/dy/fetchLiveRoomInfo` 81 | * **Request method**: `POST` 82 | * **Request parameter**: `json` 83 | 84 | ```json 85 | { 86 | "live_url": "https://v.douyin.com/kD1pKKR" 87 | } 88 | ``` 89 | 90 | * **Response parameter**: `json` (the content is too long, not shown here) 91 | 92 | --- 93 | 94 | #### Comprehensive Search 95 | 96 | * **Request Address**: `/api/dy/generalSearch?keyword=Shaanxi Culture&sort_type=0&publish_time=0&offset=0&count=10` 97 | * **Request method**: `GET` 98 | * **Response parameter**: `json` (the content is too long, not shown here) 99 | 100 | --- 101 | 102 | #### Video Search 103 | 104 | * **Request Address**: `/api/dy/videoSearch?keyword=Shaanxi Culture&sort_type=0&publish_time=0&offset=0&count=10` 105 | * **Request method**: `GET` 106 | * **Response parameter**: `json` (the content is too long, not shown here) 107 | 108 | --- 109 | 110 | #### Topic Search 111 | 112 | * **Request Address**: `/api/dy/topicSearch?keyword=Shaanxi Culture&sort_type=0&publish_time=0&offset=0&count=10` 113 | * **Request method**: `GET` 114 | * **Response parameter**: `json` (the content is too long, not shown here) 115 | 116 | --- 117 | 118 | #### Get user homepage video list 119 | 120 | * **Request address**: `/api/dy/getUserVideos?sec_uid=MS4wLjABAAAA5qMD8Gzdcgq7HXUOviKB59i0-ybJ59jJvNzyaPt5XOsVNqP6DU7WLcoAXvdxvYdp&count=15&max_cursor=0` 121 | * **Request method**: `GET` 122 | * **Response parameter**: `json` (the content is too long, not shown here) 123 | 124 | --- 125 | 126 | #### Get user information 127 | 128 | * **Request address**: `/api/dy/getUserInfo?sec_uid=MS4wLjABAAAA5qMD8Gzdcgq7HXUOviKB59i0-ybJ59jJvNzyaPt5XOsVNqP6DU7WLcoAXvdxvYdp` 129 | * **Request method**: `GET` 130 | * **Response parameter**: `json` (the content is too long, not shown here) 131 | 132 | --- 133 | 134 | #### Get Video Comments 135 | 136 | * **Request Address**: `/api/dy/getVideoComments?aweme_id=6958148148680857863&count=20&cursor=0` 137 | * **Request method**: `GET` 138 | * **Response parameter**: `json` (the content is too long, not shown here) 139 | 140 | --- 141 | 142 | #### Get video details 143 | 144 | * **Request URL**: `/api/dy/getVideoDetail?aweme_id=7055666575176781069` 145 | * **Request method**: `GET` 146 | * **Response parameter**: `json` (the content is too long, not shown here) 147 | 148 | --- 149 | 150 | #### Get user recent video list simple 151 | 152 | * **Request URL**: `/api/dy/getUserVideosSimpleRecent?sec_uid=MS4wLjABAAAA5qMD8Gzdcgq7HXUOviKB59i0-ybJ59jJvNzyaPt5XOsVNqP6DU7WLcoAXvdxvYdp` 153 | * **Request method**: `GET` 154 | * **Response parameter**: `json` (the content is too long, not shown here) 155 | 156 | ### Tiktok 157 | 158 | #### Get original link 159 | 160 | * **Request URL**:`/api/tk/originalUrlFetch` 161 | * **Request method**:`POST` 162 | * **Response parameter**:`json` 163 | 164 | ```json 165 | { 166 | "share_info": "https://www.tiktok.com/t/ZTRypfB5D/" 167 | } 168 | ``` 169 | 170 | * Response parameter:`json` 171 | 172 | ```json 173 | { 174 | "code": 200, 175 | "msg": "success", 176 | "data": { 177 | "original_url": "https://www.tiktok.com/video/7257768974631374115" 178 | } 179 | } 180 | ``` 181 | 182 | --- 183 | 184 | #### Get live room information 185 | 186 | * **Request URL**:`/api/tk/fetchLiveRoomInfo` 187 | * **Request method**:`POST` 188 | * **Response parameter**:`json` 189 | 190 | ```json 191 | { 192 | "live_url": "https://www.tiktok.com/t/ZTRypfB5D/" 193 | } 194 | ``` 195 | 196 | * **Response parameter**:`json` (the content is too long, not shown here) 197 | 198 | --- 199 | 200 | #### Get user homepage video list 201 | 202 | * **Request URL**:`/api/tk/getUserVideos?sec_uid=MS4wLjABAAAAhgKK-EJ_9MmIP0LNyu6-pFEhiffelae0N0c3xdxFymHFseWJ-SsTRqm9AIiIUTtI&count=30&cursor=0` 203 | * **Request method**:`GET` 204 | * **Response parameter**:`json` (the content is too long, not shown here) 205 | 206 | --- 207 | 208 | #### Get user information 209 | 210 | * **Request URL**:`/api/tk/getUserInfo?sec_uid=MS4wLjABAAAAhgKK-EJ_9MmIP0LNyu6-pFEhiffelae0N0c3xdxFymHFseWJ-SsTRqm9AIiIUTtI` 211 | * **Request method**:`GET` 212 | * **Response parameter**:`json` (the content is too long, not shown here) 213 | 214 | --- 215 | 216 | #### Get Video Details 217 | 218 | * **Request URL**:`/api/tk/getVideoDetail?unique_id=unpai3` 219 | * **Request method**:`GET` 220 | * **Response parameter**:`json` (the content is too long, not shown here) 221 | 222 | ### Utils 223 | 224 | #### Get IP address or Host detail information 225 | 226 | * **Request URL**:`/api/utils/queryIp?host=baidu.com` 227 | * **Request method**:`GET` 228 | * **Response parameter**:`json` 229 | 230 | ## deployment 231 | 232 | illustrate: 233 | * This project is developed based on the `nodejs` `express` framework. It is necessary to install the `nodejs` environment first. It is recommended to use a stable version after `v16`. 234 | * For other languages or need to encapsulate and call by yourself, you can directly refer to the interface document provided by [FirRock](http://vproctol.zeed.ink/) for `free` access. 235 | 236 | ### node command deployment 237 | 238 | * clone project to local 239 | * Enter the project directory, execute `npm install` to install dependencies 240 | * Execute `npm start` to start the project 241 | * Just visit `http://localhost:3000` 242 | 243 | ### node pm2 deployment 244 | 245 | * clone project to directory `/code` 246 | * Enter the project directory, execute `npm install` to install dependencies 247 | * Execute `pm2 start /code/video-parser/process-pm2.json` to start the project 248 | * Just visit `http://localhost:3000` 249 | * Execute `pm2 reload /code/video-parser/process-pm2.json` to reload the project (when there is a version update) 250 | * Execute `pm2 stop video-parser` to stop the project 251 | * Execute `pm2 restart video-parser` to restart the project 252 | * Execute `pm2 delete video-parser` to delete the project 253 | 254 | ### docker deployment 255 | 256 | * clone project to local 257 | * Enter the project directory and use the following command to build a Docker image under the project root directory: 258 | ``` 259 | docker build -t video-parser . 260 | ``` 261 | 262 | * Run the container in the background with the following command: 263 | ``` 264 | docker run -itd -p 3000:3000 --name video-parser video-parser 265 | ``` 266 | 267 | * Just visit `http://localhost:3000` 268 | 269 | ## Copyright and License 270 | 271 | ```text 272 | 273 | Copyright (c) [2023] [bxiaoj] 274 | 275 | A license is hereby granted free of charge to anyone who acquires a copy of this software or related documentation ("Software"), 276 | To manipulate the software without restriction, including but not limited to using, copying, modifying, merging, distributing, 277 | distribute, sublicense and/or sell copies of the software, and permit the person to whom the software belongs to 278 | On the property supplied, the following conditions must be met: 279 | 280 | 1. Create a new issue or private message the author in issues, explaining the usage and purpose of the project; 281 | 2. It cannot be used for any illegal and harmful behaviors that damage the health and interests of others 282 | 283 | The above copyright notice and this permission notice shall be included on all copies or most substantial portions of the Software. 284 | 285 | ``` 286 | 287 | ## Authors 288 | 289 | * [bxiaoj](https://github.com/bxiaoj) 290 | 291 | ## Links 292 | 293 | [FirRock](http://vproctol.zeed.ink/) Provide free and stable service support, thank you again! 294 | 295 | 296 | ## Remark 297 | 298 | * This project is only for learning and communication, not for commercial purposes, if there is any infringement, please contact the author to delete. 299 | * Welcome everyone to put forward valuable comments and suggestions, if you have any questions, you can raise an issue 300 | * Competent friends can submit PR to improve the project together 301 | * Welcome to `star` `fork`, support the author, thank you! 302 | --------------------------------------------------------------------------------