delphi 调用youtube-dl命令,下载youtube视频,原理及源代码

news2025/1/11 21:58:05

一、概要


1、Youtube-dl工具

  强大的视频下载命令行工具Youtube-dl项目由Ricardo Garcia创建于2008年,源代码由Python编写,托管在GitHub上,
最初仅支持YouTube,但随着项目的发展,也开始支持其他视频网站,优势在于使用简单、功能齐全、体积小巧,
但唯一遗憾的是国内使用需要开启代理。 可以从YouTube、Dailymotion、Google Video、Photobucket、Facebook、Yahoo、Metacafe、Depositfiles、Bilibili 和类似网站下载视频。
目前已知 youtube-dl 所支持的国内、外音、视频平台共有 1226 个之多,详情请参考:
http://ytdl-org.github.io/youtube-dl/supportedsites.html 
它不受平台限制,可以在任何 GNU/Linux、Windows 或 macOS 系统上运行。
  下载地址:

https://github.com/ytdl-org/youtube-dl

该脚本源代码基于Python 编写,需要安装 Python 3.2以上版本,Python 下安装命令:

#直接安装 youtube-dl

pip install youtube-dl

#更新安装 youtube-dl

pip install --upgrade youtube-dl

2、FFmpeg组件


​ FFmpeg是处理多媒体内容(例如音频、视频、字幕和相关元数据)的库和工具的集合。FFmpeg是处理多媒体内容(例如音频、视频、字幕和相关元数据)的库和工具的集合。从组件下载地址下载完成后,解压到想要的位置即可。
下载地址:(我下载的是gpl-shared版)
https://github.com/BtbN/FFmpeg-Builds/releases
​ 在这里使用FFmpeg的原因是:Youtube-dl下载的内容可能是音视频分开下载的(某些分辨率或者某些站点),用视频剪辑软件合并又要浪费一定的时间,而安装FFmpeg之后,则可以自动合并(merge)。
​ FFmpeg分为3个版本:Static,Shared,Dev。前两个版本可以直接在命令行中使用,他们的区别在于:

Static里面只有3个应用程序:ffmpeg.exe,ffplay.exe,ffprobe.exe,每个exe的体积都很大,相关的Dll已经被编译到exe里面去了。
Shared里面除了3个应用程序:ffmpeg.exe,ffplay.exe,ffprobe.exe之外,还有一些Dll,比如说avcodec-54.dll之类的。Shared里面的exe体积很小,他们在运行的时候,到相应的Dll中调用功能。
Dev版本是用于开发的,里面包含了include(头文件xxx.h)和lib(库文件xxx.lib),这个版本不包含exe文件。
​ 最后,确保已经在PATH中已经配置环境,我的配置如下:
​ 按Win+R或直接在任务栏搜索框,输入“cmd”,再输入以下命令,检测是否安装成功,

ffmpeg -version

二、Delphi调用Cmd命令行并能过管道取得返回结果


使用CreateProcess创建cmd进程。

 zeromemory(@sa,sizeof(sa));
  sa.nLength := Sizeof(sa);
  设置允许继承,否则在NT和2000下无法取得输出结果
  sa.bInheritHandle := True;
  sa.lpSecurityDescriptor := nil;
  hReadPipe:=0;
  hWritePipe:=0;
try
  //创建管道
  ret := CreatePipe(hReadPipe, hWritePipe, @sa, 0);
  if not ret then
  begin
    uLog.Log('CreatePipe false.');
    exit;
  end;
  //FillChar(StartupInfo, SizeOf(StartupInfo), 0);
  zeromemory(@StartupInfo, SizeOf(StartupInfo));
  StartupInfo.cb := sizeof(StartupInfo);
  GetStartupInfo(StartupInfo);
   //使用指定的句柄作为标准输入输出的文件句柄,使用指定的显示方式
  StartupInfo.dwFlags:=STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
  StartupInfo.wShowWindow:=SW_HIDE; //SW_HIDE

  StartupInfo.hStdOutput:=hWritePipe;
  StartupInfo.hStdError:=hWritePipe;

  zeromemory(@ProcessInfo, SizeOf(ProcessInfo));
  ret:=CreateProcess(nil,pchar(cmdline), @sa, @sa, true, 0, nil, pchar(uConfig.workdir), StartupInfo, ProcessInfo);

//从管道读取cmd返回的信息
function TTubeDown.getPipeInfo2(hReadPipe:THandle):string;
var
  //buf:array[0..1023] of ansichar;
  buf:array[0..1023] of byte;
  lngBytesread:cardinal;
  ret:BOOL;
  dwRead,dwAvail:DWORD;
begin
  result:='';
  ret:=true;
  while ret do
  begin
    if(not PeekNamedPipe(hReadPipe, nil, 0, @dwRead, @dwAvail, nil))then break;
    if(dwAvail<=0)then break;
    FillChar(buf,Sizeof(buf),#0);
    ret := ReadFile(hReadPipe, buf, 1024, lngBytesread, nil);
    if(lngBytesread<=0)then break;
    //result:=result+string(buf);
    result:=getStringFrombuf(buf,lngBytesRead);
  end;
end;

三、完整代码:

unit uTubeDown;

interface
uses
  windows,classes,strutils,sysutils,uLog,uConfig,uAuth;
const
  wm_user=$0400;
  wm_downfile=wm_user+100+1;
  //cmd命令类别
  CMD_DOWN=1;                  //下载
  CMD_FIND=2;                    //查询
  CMD_FIND_DOWN=3;       //查询下载
  CMD_UPGRADE=4;           //升级 
  //cmd参数
  PARAM_FIND='-F';              //查询
  PARAM_FIND_DOWN='-f';    //查询下载
  PARAM_FIND_BEST='-f best';     //以最高分辨率下载
type


  TTubeDown=class(TThread)
   private
     FId:cardinal;
     Furl:string;                        //视频地址
     Ffilename:string;          //保存的文件名
     FsaveDir:string;           //保存目录 
     Fmsg:string;               //消息
     Fcmd:integer;            //cmd命令类别
     Fparam:string;              //视频地址
     class var Fform: HWND;       //视频地址
     procedure SetId(id:cardinal);
     procedure SetCmd(cmd:integer);
     procedure SetParam(param:string);
     procedure SetSaveDir(dir:string);
     class procedure SetForm(const hForm: HWND); static;

     function getPipeInfo(hReadPipe:THandle):string;
     function getPipeInfo2(hReadPipe:THandle):string;
     function getStringFromBuf(buf:array of byte;length:integer):string;
   protected
     procedure Execute; override;
   public
     constructor Create(id:cardinal;url:string);
     destructor Destroy;
     function WaitExe(): integer;
     property id:cardinal read FId write SetId;
     property url:string read Furl;
     property msg:string read Fmsg;
     property filename:string read Ffilename;
     property cmd:integer read Fcmd write SetCmd;
     property param:string read Fparam write SetParam;
     property savedir:string read FsaveDir write SetSaveDir;
     class property form: HWND read Fform write SetForm;

  end;


implementation
constructor TTubeDown.Create(id:cardinal;url:string);
begin
  //inherited;
  //FreeOnTerminate := True;
  inherited Create(True);
  FId:=id;
  Furl:=url;
  //FComplete:=false;
end;
destructor TTubeDown.Destroy;
begin
  inherited Destroy;
end;
procedure TTubeDown.Execute;
begin
  WaitExe();
end;

//-----------------------------------------------------------------------------------
//****************************************************
//* 函数功能:执行程序至完成
//* 函数名称: WaitExe
技术支持:QQ:39848872;V:byc6352
//****************************************************
function TTubeDown.WaitExe(): integer;
var
  sa:TSecurityAttributes;
  hReadPipe,hWritePipe:THandle;
  ret:BOOL;
  info:string;
  StartupInfo: TStartupInfo;
  ProcessInfo: TProcessInformation;
  lngBytesread,i:DWORD;
  cmdline:string;
  downcount:integer;
  dwRead:DWORD;
  buf:array[0..1023] of byte;
begin
  Result:=0;
  if(Fcmd=CMD_UPGRADE)then
  begin
    cmdline:=Furl;
  end else begin
  if(pos('bilibili',Furl)>0)then
  begin
    cmdline:='bbdown -tv --work-dir '+Fsavedir+' '+Furl;
  end else if (pos('youtube.com/shorts',Furl)>0)then
  begin
    //cmdline:='you-get.exe --debug -o '+Fsavedir+' '+Furl;
    cmdline:='yt-dlp.exe -o '+Fsavedir+'/%(title)s.%(ext)s '+Fparam+' '+Furl;
 end else if (pos('twitter.com',Furl)>0)then
  begin
    cmdline:='youtube-dl.exe -o '+Fsavedir+'/%(title)s.%(ext)s '+Fparam+' '+Furl;
  end else begin
    //yt-dlp.exe为youtube-dl的一个分支
    cmdline:='yt-dlp.exe -o '+Fsavedir+'/%(title)s.%(ext)s '+Fparam+' '+Furl;
  end;
  end;
  Log(cmdLine);

  zeromemory(@sa,sizeof(sa));
  sa.nLength := Sizeof(sa);
  sa.bInheritHandle := True;
  sa.lpSecurityDescriptor := nil;
  hReadPipe:=0;
  hWritePipe:=0;
try
  ret := CreatePipe(hReadPipe, hWritePipe, @sa, 0);  //创建管道
  if not ret then
  begin
    uLog.Log('CreatePipe false.');
    exit;
  end;
  //FillChar(StartupInfo, SizeOf(StartupInfo), 0);
  zeromemory(@StartupInfo, SizeOf(StartupInfo));
  StartupInfo.cb := sizeof(StartupInfo);
  GetStartupInfo(StartupInfo);
  StartupInfo.dwFlags:=STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
  StartupInfo.wShowWindow:=SW_HIDE; //SW_HIDE

  StartupInfo.hStdOutput:=hWritePipe;
  StartupInfo.hStdError:=hWritePipe;

  zeromemory(@ProcessInfo, SizeOf(ProcessInfo));

  ret:=CreateProcess(nil,pchar(cmdline), @sa, @sa, true, 0, nil, pchar(uConfig.workdir), StartupInfo, ProcessInfo);
  if not ret then
  begin
    uLog.Log('CreateProcess false.');
    Exit;
  end;
  while true do
  begin
    lngBytesread:=WaitForSingleObject(ProcessInfo.hProcess, 1000);//1秒钟输出一次信息;
    if(lngBytesRead=WAIT_FAILED)then
    begin
      uLog.Log('WaitForSingleObject false.');
      Exit;
    end;
    if(lngBytesRead= WAIT_OBJECT_0)then         //1秒获取信息一次
    begin

      if(Fcmd=CMD_FIND)then
        info:=getPipeInfo2(hReadPipe)         //取cmd输出信息
      else
        info:=getPipeInfo(hReadPipe);
      Log(info);
      Fmsg:=info;
      SendMessage(Fform,wm_downfile,0,integer(self));  //信息发送至窗体
      info:='complete';
      Log(info);
      result:=1;
      Fmsg:=info;
      SendMessage(Fform,wm_downfile,0,integer(self));
      exit;

    end;
    if(lngBytesRead=WAIT_TIMEOUT)then             //cmd进程结束
    begin
      if(Fcmd=CMD_FIND)then continue;
      info:=getPipeInfo(hReadPipe);                    //取cmd输出信息
      Log(info);
      Fmsg:=info;
      SendMessage(Fform,wm_downfile,0,integer(self));
    end;
  end;
  result:=1;
  info:='complete over.';
  Log(info);
  Fmsg:=info;
  SendMessage(Fform,wm_downfile,0,integer(self));
  //------------------------------------------------------------
finally
  if(hReadPipe<>0)then CloseHandle(hReadPipe);
  if(hWritePipe<>0)then CloseHandle(hWritePipe);
  if(ProcessInfo.hThread<>0)then  CloseHandle(ProcessInfo.hThread);
  if(ProcessInfo.hProcess<>0)then CloseHandle(ProcessInfo.hProcess);
end;
end;
//字节转换成字符串
function TTubeDown.getStringFromBuf(buf:array of byte;length:integer):string;
var
  tmp:array of byte;
  str:ansistring;
begin
  result:='';
  if(length<=0)then exit;
try
  setlength(tmp,length);
  copymemory(tmp,@buf[0],length);
  result:=Tencoding.UTF8.GetString(tmp);              //youtube等外网视频站点是utf8编码
except
  setlength(str,length);
  copymemory(@str[1],@buf[0],length);
  result:=str;

end;
end;
//非阻塞方式读取管道信息
function TTubeDown.getPipeInfo2(hReadPipe:THandle):string;
var
  //buf:array[0..1023] of ansichar;
  buf:array[0..1023] of byte;
  lngBytesread:cardinal;
  ret:BOOL;
  dwRead,dwAvail:DWORD;
begin
  result:='';
  ret:=true;
  while ret do
  begin
    if(not PeekNamedPipe(hReadPipe, nil, 0, @dwRead, @dwAvail, nil))then break;
    if(dwAvail<=0)then break;
    FillChar(buf,Sizeof(buf),#0);
    ret := ReadFile(hReadPipe, buf, 1024, lngBytesread, nil);
    if(lngBytesread<=0)then break;
    //result:=result+string(buf);
    result:=getStringFrombuf(buf,lngBytesRead);
  end;
end;
//阻塞方式读取管道信息
function TTubeDown.getPipeInfo(hReadPipe:THandle):string;
var
  //buf:array[0..1023] of ansichar;
  buf:array[0..1023] of byte;
  lngBytesread:cardinal;
  ret:BOOL;
begin
  result:='';
  FillChar(buf,Sizeof(buf),#0);
  ret := ReadFile(hReadPipe, buf, 1024, lngBytesread, nil);
  if(ret=true)then
  begin
    //result:=buf;
    result:=getStringFrombuf(buf,lngBytesRead);
  end;
end;
{
procedure TTubeDown.start();
begin
  Execute;
end;
}
//------------------------------------------属性方法-------------------------------------
 procedure TTubeDown.SetId(Id:cardinal);
 begin
   FId:=Id;
 end;
 class procedure TTubeDown.SetForm(const hForm: HWND);
 begin
   Fform:=hForm;
 end;
 procedure TTubeDown.SetCmd(cmd:integer);
 begin
   Fcmd:=cmd;
 end;
 procedure TTubeDown.SetParam(param:string);
 begin
   Fparam:=param;
 end;
 procedure TTubeDown.SetSaveDir(dir:string);
  begin
   FSaveDir:=dir;
 end;
end.

四、使用方法:

var
  tube:TTubeDown;
begin
     tube:=TTubeDown.Create(i,url);
      tube.cmd:=CMD_DOWN;
      tube.param:='';
      tube.savedir:=uConfig.saveDir;
      tube.start();
end;

五、成品

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/634826.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何优化selenium webdriver的执行速度

目录 前言 在page_source中断言text比直接使用text属性断言要快 元素越具体&#xff0c;获取text的速度越快 使用变量去缓存没有变化的元素 快速在文本框中输入大文本 使用动态等待进行动态/AJAX 操作而不是固定睡眠 最后 前言 让自动化测试脚本正常工作只是自动化测试的…

微信小程序的自动化测试框架Minium详解,10分钟掌握

目录 前言 minium 是为小程序专门开发的自动化框架 文档使用 框架依赖运行环境部署 使用 打开工具 特别说明&#xff1a; 总结&#xff1a; 前言 微信发布了小程序的自动化测试框架Minium&#xff0c;提供了多种运行验证方式&#xff0c;其特点&#xff1a; 支持一套脚…

Alloy Tutorial(2)LastPass; cacheMemory

文章目录 LastPass整体 solution 代码&#xff1a; cacheMemory LastPass module LastPass/** LastPass password map** A simple example to explain basics of Alloy. ** The PassBook keeps track of a set of users passwords for a set of URLs. * For each User/URL pai…

【阿里云】第一次进行域名注册、备案以及使用全过程

前言 随着ChatGPT的爆火&#xff0c;让我直面感受到了一项技术的突破可以产生堪比原子弹爆炸的威力&#xff0c;因而在品尝过ChatGPT带来的便利与甜头后&#xff0c;就一直在跟进&#xff0c;同时也在能力范围内&#xff0c;让数十位朋友使用上了ChatGPT 前段时间&#xff0c…

ftrace学习 —— user_events的用法

参考 https://docs.kernel.org/trace/user_events.html 测试程序 samples/user_events/example.c tools/testing/selftests/user_events/ftrace_test.c 正文 通过user_event可以实现对应用程序的跟踪&#xff0c;类似linux内核中的tracepoint那样。相似的方法还有借助/sys…

走进docker

一、Docker 概述 1、Docker的概念 • Docker是一个开源的应用容器引擎&#xff0c;基于go语言开发并遵循了apache2.0协议开源 • Docker是在Linux容器里运行应用的开源工具&#xff0c;是一种轻量级的“虚拟机” • Docker 的容器技术可以在一台主机上轻松为任何应用创建一…

异常数据检测 | Python实现基于高斯概率分布的异常数据检测

文章目录 文章概述模型描述源码分享学习小结参考资料文章概述 高斯分布也称为正态分布。它可以被用来进行异常值检测,不过我们首先要假设我们的数据是正态分布的。不过这个假设不能适应于所有数据集。但如果我们做了这种假设那么它将会有一种有效的方法来发现异常值。 模型描述…

asp.net审计项目管理系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio

一、源码特点 asp.net审计项目管理系统 是一套完善的web设计管理系统&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为vs2010&#xff0c;数据库为sqlserver2008&#xff0c;使用c#语言 开发 二、功能介绍 (1)科室管理&…

GIT远程仓库(随笔)

目录 前言 一、GIt常见命令 二、概念原理 三、常见的代码托管平台 四、配置SSH公钥 五、操作 1、注册账号 2、在gitee中&#xff0c;创建远程仓库 3、Git命令创建本地仓库 4、Git命令创建第一个版本提交 5、Git命令添加远程仓库 6、推送 7、修改开源项目 ​编辑 8、…

浅谈数据库系统:MySQL的简介与安装配置

前言 ✨文末送书&#xff0c;小K赠书活动第一期 目录 前言一、数据库系统概述数据(Data)数据库(Database)数据库管理系统(Database Management System,DBMS)数据库系统(Database System,DBS)什么是SQL 二、MySQL的简介与安装MySQL简介MySQL下载与安装下载解压版安装配置安装版安…

前端 vue 自定义导航栏组件高度及返回箭头 自定义 tabbar 图标

前端vue自定义导航栏组件高度及返回箭头 自定义tabbar图标, 下载完整代码请访问uni-app插件市场地址:https://ext.dcloud.net.cn/plugin?id12986 效果图如下: # #### 使用方法 使用方法 // page.json 采用矢量图标设置返回箭头 ,{ "path" : "pages/Home/Ho…

2023.06.11 学习周报

文章目录 摘要文献阅读1.题目2.问题3.介绍4.Problem definition5.Method5.1 Feature Extractor5.2 Synthetic Node Generation5.3 Edge Generator5.4 GNN Classifier5.5 Optimization Objective5.6 算法 6.实验6.1 数据集6.2 基线6.3 实验结果 7.结论 数学建模1.欧式距离2.切比…

leetcode174. 地下城游戏(java)

地下城游戏 leetcode174. 地下城游戏题目描述 动态规划解题思路代码 动态规划专题 leetcode174. 地下城游戏 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;https://leetcode.cn/problems/dungeon-game 题目描述 恶魔们抓住了公主并将她关在了地下城 …

python基础知识(十一):matplotlib的基本用法一

目录 1. matplotlib库和numpy库2. matplotlib绘图的简单示例3. 设置窗口的尺寸比例&#xff0c;线宽和颜色4. 坐标轴设置5. 去除坐标轴边框和坐标轴原点化6. 图例7. 文本标注 1. matplotlib库和numpy库 matplotlib库是python的绘图库&#xff0c;numpy库是numpy是python中基于…

如何使用Docker实现分布式Web自动化!

1、前言 顺着docker的发展&#xff0c;很多测试的同学也已经在测试工作上使用docker作为环境基础去进行一些自动化测试&#xff0c;这篇文章主要讲述在docker中使用浏览器进行自动化测试如果可以实现可视化&#xff0c;同时可以对浏览器进行相关的操作。 如果你想学习自动化测…

【动态规划专栏】-- 回文串问题 -- 动态规划经典题型

目录 动态规划 动态规划思维&#xff08;基础&#xff09; 状态表示&#xff08;最重要&#xff09; 状态转移方程&#xff08;最难&#xff09; 初始化&#xff08;细节&#xff09; 填表顺序&#xff08;细节&#xff09; 返回值&#xff08;结果&#xff09; 回文子串…

浮点型进制转换 和 与或非(逻辑短路)

正数的反码是其本身 负数的补码是其反码1 原码 十进制数据的二进制表现形式 byte b 13 1101&#xff08;13的十进制&#xff09;byte代表占存储的一个字节&#xff08;1字节等于8位&#xff09; 此时13的在存储里的形式 0000 1101 &#xff08;原码最左边0为正&#…

物联网Lora模块从入门到精通(六)OLED显示屏

一、前言 获取到数据后我们常需要在OLED显示屏上显示&#xff0c;本文中我们需要使用上一篇文章(光照与温湿度数据获取)的代码&#xff0c;在其基础上继续完成本文内容。 基础代码&#xff1a; #include <string.h> #include "board.h" #include "hal_ke…

Spring boot之WEB 开发-静态资源访问--自定义转换器--处理JSON--内容协商

Spring boot之WEB 开发-静态资源访问 官方文档 在线文档: https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.develo\ping-web-applications 基本介绍 1. 只要静态资源放在类路径下&#xff1a; /static 、/public 、/resources 、/M…

2023-06-11:redis中,如何在100个亿URL中快速判断某URL是否存在?

2023-06-11&#xff1a;redis中&#xff0c;如何在100个亿URL中快速判断某URL是否存在&#xff1f; 答案2023-06-11&#xff1a; 传统数据结构的不足 当然有人会想&#xff0c;我直接将网页URL存入数据库进行查找不就好了&#xff0c;或者建立一个哈希表进行查找不就OK了。 …