1、首先是插件篇:
1.1 manifest.json
{
"manifest_version": 3,
"name": "My Douyin Downloader",
"version": "1.1",
"description": "My Douyin Downloader",
"content_scripts": [
{
"matches": ["https://*.douyin.com/*"],
"js": ["content.js"]
}
],
"permissions": ["activeTab", "webRequest", "downloads"],
"host_permissions": ["https://*.douyin.com/*", "https://*.zjcdn.com/*","https://*.douyinvod.com/*"],
"web_accessible_resources": [
{
"resources": ["assets/*", "popup.js", "popup.css"],
"matches": ["https://douyin.com/*", "https://www.douyin.com/*","https://*.douyinvod.com/*"]
}
],
"background": {
"service_worker": "background.js"
},
"action": {
"default_icon": {
"16": "assets/images/icon.png",
"48": "assets/images/icon.png",
"128": "assets/images/icon.png"
}
}
}1.2 content.js
(function() {
'use strict';
document.addEventListener("keyup", function (event) {
// 79 是 o 键的键码
if (event.keyCode === 79 || event.keyCode === 111) {
//let videoInfoDetailElement = document.querySelector('.video-info-detail');
//let videoId = videoInfoDetailElement.getAttribute('data-e2e-aweme-id');
let targetDivDom = document.querySelector('[data-e2e="feed-active-video"]');
let videoId = targetDivDom.getAttribute("data-e2e-vid");
console.log(videoId);
alert("你好!"+videoId);
let p = {};
p.videoId = videoId;
chrome.runtime.sendMessage(p, function (response) {
if (chrome.runtime.lastError) {
alert("chrome.runtime.lastError")
console.log(chrome.runtime.lastError.message);
} else {
if (response.status === "ok") {
console.log(response.videoLink)
let data ={};
data.videoId = videoId;
data.videoUrl =response.videoLink;
console.log("抖音下载小助手,下载前的payload构造打印:");
console.log(data);
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://localhost:8000/videos", true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
var response = xhr.responseText;
console.log(response);
}
};
var payload = JSON.stringify(data);
xhr.send(payload);
} else {
alert("failed from background")
}
}
});
}
});
})();1.3 background.js
//background.js
let urlList = [];
chrome.webRequest.onBeforeRequest.addListener(
(details) => {
const link = details.url;
//if (link.includes("zjcdn") && urlList.at(-1) !== link) {
// if (urlList.length > 50) {
// urlList.shift();
// }
urlList.push(link);
//}
},
{ urls: ["https://*.douyinvod.com/*"] }
);
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
console.log(request);
const videoLink = urlList.find((link) => link.includes(request.videoId));
sendResponse({ status: "ok", videoLink:videoLink});
// Return true to keep the message channel open
return true;
});========================================================
2、插件这边就算完成了,接着是python这边
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
import requests
app = FastAPI()
def downloadVideo(url,filename):
response =requests.get(url,stream=True)
response.raise_for_status()
with open(filename,"wb") as file:
for chunk in response.iter_content(chunk_size=8192):
if chunk:
file.write(chunk)
class Video(BaseModel):
videoId: str
videoUrl: str
# 因为是xxxx发起的,所以需要要把抖音的这个地址加进去
origins = [
"http://localhost.tiangolo.com",
"https://localhost.tiangolo.com",
"http://www.douyin.com",
"https://www.douyin.com",
"http://localhost",
"http://localhost:8080",
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.post("/videos")
async def main(video: Video):
downloadVideo(video.videoUrl,video.videoId+".mp4")
return video
#用这个去启动
#source .venv/bin/activate
#uvicorn postserver:app --reload
#pip install fastapi-cors3、使用
先加载插件,然后激活,这样x的web版本就可以加载这个插件了,background监听到具体的url后,建立一个list
然后,在content.js里,按下o键,就会激发过程
查到url后,将
data.videoId = videoId;
data.videoUrl =response.videoLink;发给python这边来负责下载
之所以要这么写也是因为,这样可以前后端分离,稍后可以把python部署到nas那边去
其外是,我不太相信js的下载能力
我也不想下载到本机
python这边需要注意的技巧就是:
from fastapi.middleware.cors import CORSMiddleware
# 因为是xxx发起的,所以需要要把抖音的这个地址加进去
origins = [
"http://localhost.tiangolo.com",
"https://localhost.tiangolo.com",
"http://www.douyin.com",
"https://www.douyin.com",
"http://localhost",
"http://localhost:8080",
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)反正fastapi也有不少坑就是了,以上是摸索了好久搞定的CORS这块
from pydantic import BaseModel
class Video(BaseModel):
videoId: str
videoUrl: str
@app.post("/videos")
async def main(video: Video):
算是比较优雅的接受参数的方式了,还可以声明None什么的