
Douyin Video
Download Douyin share links as watermark-free video and optional Mandarin transcripts for solo builders repurposing short-form research or clips.
Install
npx skills add https://github.com/yzfly/douyin-mcp-server --skill douyin-videoWhat is this skill?
- Resolves Douyin share links to direct no-watermark download URLs via mobile-style HTTP fetch
- Three CLI actions: info (links only), download (video to disk), extract (audio + SiliconFlow transcription)
- Per-video output directory with saved transcript text when API_KEY is set
- Depends on requests and ffmpeg-python; API_KEY uses SiliconFlow FunAudioLLM/SenseVoiceSmall
- Agent skill wrapping the Python downloader workflow for Douyin-specific ingestion
Adoption & trust: 1.5k installs on skills.sh; 1.1k GitHub stars; 2/3 security scanners passed (skills.sh audits).
Recommended Skills
Journey fit
Canonical shelf is Grow because the payoff is content assets and copy you can reuse in newsletters, SEO, and distribution—not wiring product code. Content subphase fits transcript extraction, per-video output folders, and turning platform-native video into editable text.
Common Questions / FAQ
Is Douyin Video safe to install?
skills.sh reports 2 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.
SKILL.md
READMESKILL.md - Douyin Video
#!/usr/bin/env python3 """ 抖音无水印视频下载和文案提取工具 功能: 1. 从抖音分享链接获取无水印视频下载链接 2. 下载视频并提取音频 3. 使用硅基流动 API 从音频中提取文本 4. 自动保存文案到文件 (一个视频一个文件夹) 环境变量: - API_KEY: 硅基流动 API 密钥 (用于文案提取功能) 使用示例: # 获取下载链接 (无需 API 密钥) python douyin_downloader.py --link "抖音分享链接" --action info # 下载视频 python douyin_downloader.py --link "抖音分享链接" --action download --output ./videos # 提取文案并保存到文件 (需要 API_KEY 环境变量) python douyin_downloader.py --link "抖音分享链接" --action extract --output ./output """ import os import re import sys import json import argparse import tempfile import shutil from pathlib import Path from typing import Optional from datetime import datetime def check_dependencies(): """检查必要的依赖是否已安装""" missing = [] try: import requests except ImportError: missing.append("requests") try: import ffmpeg except ImportError: missing.append("ffmpeg-python") if missing: print(f"缺少依赖: {', '.join(missing)}") print(f"请运行: pip install {' '.join(missing)}") sys.exit(1) check_dependencies() import requests import ffmpeg # 请求头,模拟移动端访问 HEADERS = { 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) EdgiOS/121.0.2277.107 Version/17.0 Mobile/15E148 Safari/604.1' } # 硅基流动 API 配置 DEFAULT_API_BASE_URL = "https://api.siliconflow.cn/v1/audio/transcriptions" DEFAULT_MODEL = "FunAudioLLM/SenseVoiceSmall" class DouyinProcessor: """抖音视频处理器""" def __init__(self, api_key: str = "", api_base_url: Optional[str] = None, model: Optional[str] = None): self.api_key = api_key self.api_base_url = api_base_url or DEFAULT_API_BASE_URL self.model = model or DEFAULT_MODEL self.temp_dir = Path(tempfile.mkdtemp()) def __del__(self): """清理临时目录""" if hasattr(self, 'temp_dir') and self.temp_dir.exists(): shutil.rmtree(self.temp_dir, ignore_errors=True) def parse_share_url(self, share_text: str) -> dict: """从分享文本中提取无水印视频链接""" # 提取分享链接 urls = re.findall(r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', share_text) if not urls: raise ValueError("未找到有效的分享链接") share_url = urls[0] share_response = requests.get(share_url, headers=HEADERS) video_id = share_response.url.split("?")[0].strip("/").split("/")[-1] share_url = f'https://www.iesdouyin.com/share/video/{video_id}' # 获取视频页面内容 response = requests.get(share_url, headers=HEADERS) response.raise_for_status() pattern = re.compile( pattern=r"window\._ROUTER_DATA\s*=\s*(.*?)</script>", flags=re.DOTALL, ) find_res = pattern.search(response.text) if not find_res or not find_res.group(1): raise ValueError("从HTML中解析视频信息失败") # 解析JSON数据 json_data = json.loads(find_res.group(1).strip()) VIDEO_ID_PAGE_KEY = "video_(id)/page" NOTE_ID_PAGE_KEY = "note_(id)/page" if VIDEO_ID_PAGE_KEY in json_data["loaderData"]: original_video_info = json_data["loaderData"][VIDEO_ID_PAGE_KEY]["videoInfoRes"] elif NOTE_ID_PAGE_KEY in json_data["loaderData"]: original_video_info = json_data["loaderData"][NOTE_ID_PAGE_KEY]["videoInfoRes"] else: raise Exception("无法从JSON中解析视频或图集信息") data = original_video_info["item_list"][0] # 获取视频信息 video_url = data["video"]["play_addr"]["url_list"][0].replace("playwm", "play") desc = data.get("desc", "").strip() or f"douyin_{video_id}" # 替换文件名中的非法字符 desc = re.sub(r'[\\/:*?"<>|]', '_', desc) return { "url": video_url, "title": desc, "video_id": video_id } def download_video(self, video_info: dict, output_dir: Optional[Path] = None, show_progress: bool = True) -> Path: """下载视频""" if output_dir is None: