delphi 通过TNetHTTPClient解析抖音无水印高清视频原理及解决X-Bogus签名验证2023-5-1

这篇具有很好参考价值的文章主要介绍了delphi 通过TNetHTTPClient解析抖音无水印高清视频原理及解决X-Bogus签名验证2023-5-1。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


一、杂谈
        最近有很多热心网友反馈抖音去水印又不行了,之前是时不时被blocked,现在直接连内容都没有了,返回直接就是空了,我们今天简要给大家分析一下请求过程,附上delphi 源码,及生成签名验证,成功请求到json数据的解决方法。


二、请求过程分析
我们还是先获取一个抖音链接

https://v.douyin.com/A2VSVxc/
通过访问重定向

https://www.douyin.com/video/7065264218437717285
然后提取到其中的视频ID

7065264218437717285
如果是之前,我们会直接GET请求

https://www.douyin.com/aweme/v1/web/aweme/detail/?aweme_id=7065264218437717285
然后就能得到响应内容了。

但是这种方法已经失效了,今天我们会讲解如何在增加一些请求头参数以及X-Bogus后,可以仍然获取到JSON格式的数据。如:
{"aweme_detail":{"anchors":null,"authentication_token":"......
.........}
可以看到,获取到的aweme_detail json数据和以前一样。


三、URL参数X-Bogus
X-Bogus你可以理解为是一个根据视频ID及user-agent通过JS生成的用户信息参数,它可以用于校验。
详细的一篇分析可以参考Freebuf上的《【JS 逆向百例】某音 X-Bogus 逆向分析,JSVMP 纯算法还原》。


下面是完整的delphi 源码解析类,主要流程如下:
1.传入抖音分享链接:
https://v.douyin.com/A2VSVxc/
重定向得到:
https://www.douyin.com/video/7065264218437717285

2.提取到其中的视频ID:
7065264218437717285

3.无水印视频接口不变:
https://www.douyin.com/aweme/v1/web/aweme/detail/?aweme_id=7065264218437717285

4.(增加步骤4)根据X-Bogus 算法,传入url链接及USER_AGENT数据,生成一个形如:
https://www.douyin.com/aweme/v1/web/aweme/detail/?aweme_id=7065264218437717285&X-Bogus=DFSzswSL2MtANHxFtG3DB09WcBjv

一个携带X-Bogus签名验证字段的请求链接。使用这个链接发送GET请求,就能得到aweme_detail 的json 数据了。不信大家可以试试。不过,这个链接是不能
在浏览器直接访问的,还必须加上cookie,refer等请求头数据,详情看下面的Tdouyin解析类。

5.关于高清无水印视频链接的获取方法

从"aweme_detail"  json数据解析出视频的Uri项,带入高清视频接口:
https://aweme.snssdk.com/aweme/v1/play/?video_id=v0200fg10000c86doo3c77uai4m711qg&ratio=1080p&line=0


执行重定向getRedirectedUrl()得到高清无水印链接:
https://v95-p-cold.douyinvod.com/9f8215c6204afafffee302e612317776/64201324/video/tos/cn/tos-cn-ve-15c001-alinc2/35721d123b6243cca42398b0c5243c32/?a=1128&ch=0&cr=0&dr=0&cd=0%7C0%7C0%7C0&cv=1&br=2209&bt=2209&cs=0&ds=4&ft=bvjWJkQQqUsmfd4ZFo0OW_EklpPiXnlFZMVJEEy8kdbPD-I&mime_type=video_mp4&qs=0&rc=NDU3Omc3aDY8ZGc7OTkzOUBpajQ6N2Q6ZnJnOzMzNGkzM0BiXjE0NTQvXmExNTVeNTU2YSNuLmpmcjQwbDNgLS1kLS9zcw%3D%3D&l=20230326163724C8959375177E24BE6CEE&btag=a8000

详细步骤看以下TDouyin解析类,关键代码处都有注解:

1.解析类:

unit uDouyin;

interface
uses
  windows,classes,System.Net.URLClient, System.Net.HttpClient, System.Net.HttpClientComponent,
  System.SysUtils,strutils,uLog,System.RegularExpressions,uFuncs,system.JSON,uConfig,
  uVideoInfo,uDownVideo;
const
  wm_user=$0400;
  wm_downfile=wm_user+100+1;  //消息参数;

  //USER_AGENT标识客户端的类型,这儿是电脑浏览器端。
  USER_AGENT:string='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36';

  //USER_AGENT标识客户端的类型,这儿是手机APP端。
  USER_AGENT_PHONE:string='Mozilla/5.0 (iPhone; CPU iPhone OS 15_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.6 Mobile/15E148 Safari/604.1';
  USER_AGENT_PHONE_2:string='TikTok 26.2.0 rv:262018 (iPhone; iOS 14.4.2; en_US) Cronet';

  //无水印视频接口,跟以前一样。
  DOUYIN_API_URL:string='https://www.douyin.com/aweme/v1/web/aweme/detail/?aweme_id=' ;
  DOUYIN_API_URL_2:string='https://www.douyin.com/aweme/v1/web/aweme/detail/?aweme_id=%s&aid=1128&version_name=23.5.0&device_platform=android&os_version=2333' ;

  //高清无水印视频接口:
  DOUYIN_API_URL_1080 = 'https://aweme.snssdk.com/aweme/v1/play/?video_id=%s&ratio=1080p&line=0';
  type
  TDouyin=class(TThread)                //支持多线程下载;
   private
     FId:cardinal;   //线程标识;
     Furl:string;    //分享的链接;;
     FRedirectedUrl:string;    //重定向后的链接;
     Fvideourl:string;         //解析后得到的无水印视频链接;
     FvideoId:string;          //视频id    如:7065264218437717285
     FvideoTitle:string;       //视频标题
     Fnickname:string;         //作者昵称
     FcoverUrl:string;         //视频封面链接
     Fmsg:string;              //线程消息
     Fsavedir:string;          //保存视频文件及封面图片的目录
     Furl_1080:string;         //高清视频链接
     Furi_1080:string;         //高清视频uri参数 不懂的+v:metabycf
     Fphotos:string;
     class var Fcookie: string;   //cookie参数 ,可从浏览器获取  静态类成员
     class var Fform: HWND;       //接收消息的窗体句柄  类成员
     procedure SetId(id:cardinal);       //设置线程id
     procedure SetSaveDir(dir:string);    //设置保存目录
     class procedure SetForm(const hForm: HWND); static;    //设置窗体句柄 静态方法
     class procedure SetCookie(const cookie: string); static; //设置cookie 静态方法

   protected
     procedure Execute; override;
   public
     constructor Create(id:cardinal;url:string);
     destructor Destroy;
     property id:cardinal read FId write SetId;      //id属性
     property url:string read Furl;                  //分享链接 属性
     property msg:string read Fmsg;                  //线程消息 属性
     property videourl:string read Fvideourl;         //无水印视频链接 属性
     property videoTitle:string read FvideoTitle;     //视频标题  属性
     property nickname:string read Fnickname;         //用户昵称
     property RedirectedUrl:string read FRedirectedUrl;  //重定向链接  属性
     property videoId:string read FvideoId;              //视频id   属性  如:7065264218437717285
     property coverUrl:string read FcoverUrl;            //封面链接  属性
     property url_1080:string read Furl_1080;            //高清视频链接   属性
     property photos:string read Fphotos;
     property savedir:string read Fsavedir write setSaveDir;  //保存目录 属性
     function getRedirectedUrl(url:string):string;overload;   //获取重定向链接
     function getRedirectedUrl(url,refer,user_agent:string):string;overload;  //获取重定向链接
     function getVideoId(txt:string):string; //解析出视频id  如:7065264218437717285
     function getVideoUrl():string;          //解析无水印视频地址,封面链接,视频标题    工作流程方法在这儿:
     function parseJson(jo:string):string;   //解析aweme_detail json数据
     class property form: HWND read Fform write SetForm;  //窗体句柄 类属性
     class property cookie: string read Fcookie write SetCookie; //cookie 类属性
     function getPostResult(data:string):string;  //post 请求
     function getRequestResult2(apiurl:string;Cookie:string):string; //GET 请求
     function getBogusUrl(url:string):string; X-Bogus 算法 不明白的+v:metabycf
  end;
implementation

//解析无水印视频地址,封面链接,视频标题    工作流程方法在这儿:
function TDouyin.getVideoUrl():string;
var
  apiurl,apiurl2,jo:string;
  i:integer;
  video:TvideoInfo;
  down:TdownVideo;
begin
  result:='';
  FcoverUrl:='';
  FvideoUrl:='';
  Fphotos:='';
try
  //第一步:执行重定向,从而获取到视频id
  //如:https://www.douyin.com/video/7065264218437717285
  FRedirectedUrl:=getRedirectedUrl(Furl,Furl,USER_AGENT);
  log('FRedirectedUrl='+FRedirectedUrl);  //日志记录
  if(FRedirectedUrl)='' then exit;

  //第二步:分析出视频id,如:7065264218437717285
  FvideoId:=getVideoId(FRedirectedUrl);
  log('FvideoId='+FvideoId);     //日志记录
  if(FvideoId)='' then exit;

  //apiurl:=DOUYIN_API_URL+FvideoId; //视频接口
  apiurl:=format(DOUYIN_API_URL_2,[FvideoId]); //视频接口

  //第三步:计算X-Bogus验证,加到视频接口上。得到新的请求链接  多了这一步骤。
  //如:https://www.douyin.com/aweme/v1/web/aweme/detail/?aweme_id=7065264218437717285&X-Bogus=DFSzswSL2MtANHxFtG3DB09WcBjv
  //不明白的+v:metabycf
  apiurl2:=getBogusUrl(apiurl);    //具有X-Bogus验证的视频接口  多了这一步骤。
  log(apiurl2);                    //日志记录
  if(apiurl2='')then begin log('apiurl2=k');exit;end;

  //第四步:发送GET请求,带上cookie,refer参数;到这一步,已经能拿到"aweme_detail"  json数据了。
  jo:=getRequestResult2(apiurl2,Fcookie);
  Fmsg:=jo;
  log(jo);  //日志记录
  if(pos('aweme_detail',jo)<=0)then begin
    log('aweme_detail=k');
    exit;
  end;
  if(pos('"aweme_detail":null',jo)>0)then exit;

  //第五步: 解析 "aweme_detail"  json数据
  parseJson(jo);

  //第六步: 1解析 图文
  if(Fphotos<>'')then
  begin
    video:=TvideoInfo.Create(Fvideotitle,coverUrl,'',Fphotos);
    down:=TdownVideo.Create(Fid,video,Fsavedir,false);
    //down.form:=Fform;
    //down.cookie:=Fcookie;
    //if(DEBUG=true)then downvideo.process else
    down.Start;
    exit;
  end;

  //第六步: 2解析 高清视频地址
  if(Furi_1080<>'')then  //Furi_1080为视频 uri
  begin
    Furl_1080:=format(DOUYIN_API_URL_1080,[Furi_1080]);
    log(Furl_1080); //日志记录
    Furl_1080:=getRedirectedUrl(Furl_1080,FRedirectedUrl, USER_AGENT_PHONE); //重定向
    log('Furl_1080='+Furl_1080);    //日志记录
  end;

  //第七步: 启动下载线程,下载视频文件和封面图片。
  if(Fvideotitle<>'')and(Furl_1080<>'')and(FcoverUrl<>'')then
  begin
    video:=TvideoInfo.Create(Fvideotitle,coverUrl,Furl_1080,'');
    down:=TdownVideo.Create(Fid,video,Fsavedir,false);
    //down.form:=Fform;
    //down.cookie:=Fcookie;
    down.Start;
  end;
finally
  //第八步: 发送解析完成消息。
  Fmsg:='complete';
  SendMessage(Fform,wm_downfile,2,integer(self));
end;

end;

//第四步:发送GET请求,带上cookie,refer参数;到这一步,已经能拿到"aweme_detail"  json数据了。
function TDouyin.getRequestResult2(apiurl:string;Cookie:string):string;
var
  client: TNetHTTPClient;
  ss: TStringStream;
  s,id:string;
  AResponse:IHTTPResponse;
  i:integer;
begin
try
  client := TNetHTTPClient.Create(nil);
  SS := TStringStream.Create('', TEncoding.UTF8);
  ss.Clear;
  with client do
  begin
    ConnectionTimeout := 10000; // 10秒
    ResponseTimeout := 10000; // 10秒
    AcceptCharSet := 'utf-8';
    UserAgent := USER_AGENT; //1   USER_AGENT      USER_AGENT_PHONE_2
    client.AllowCookies:=true;
    client.HandleRedirects:=true;
    Accept:='application/json'; //'*/*'
    client.ContentType:='application/json'; //2
    client.AcceptLanguage:='zh-CN';

    client.CustomHeaders['Cookie'] := cookie;
    client.CustomHeaders['Referer'] := Furl;
    try
        AResponse:=Get(apiurl, ss);
        result:=ss.DataString;
    except
      on E: Exception do
        Log(e.Message);

    end;
  end;
finally
  ss.Free;
  client.Free;
end;

end;

//第五步: 解析 "aweme_detail"  json数据  :分为视频和图文两类
function TDouyin.parseJson(jo:string):string;
var
  json,jroot,jvideo,j1,j2: TJSONObject;
  arr,arr1:TJSONARRAY;
  uri,aweme_type,photo:string;
  i:integer;
begin
  result:='';
try
  json := TJSONObject.ParseJSONValue(jo) as TJSONObject;
  if json = nil then exit;
  jroot:=json.GetValue('aweme_detail') as TJSONObject;
  FvideoTitle:=trim(jroot.GetValue('desc').Value);

  aweme_type:=jroot.GetValue('aweme_type').Value;

  if(aweme_type='68')then       //图文
  begin
    arr:=jroot.GetValue('images') as TJSONARRAY;
    for I := 0 to arr.Size-1 do
    begin
      j1:=arr.Get(i) as TJSONObject;
      arr1:=j1.GetValue('url_list')  as TJSONARRAY;

      photo:=arr1.Items[0].Value;
      Fphotos:=Fphotos+photo+#13#10;
    end;
    result:='#100#'+Fphotos+'#'+FcoverUrl+'#'+FvideoTitle;
    exit;
  end;

  jvideo:=jroot.GetValue('video') as TJSONObject;
  j1:=jvideo.GetValue('cover') as TJSONObject;  //cover origin_cover
  arr:=j1.GetValue('url_list') as TJSONARRAY;
  FcoverUrl:=arr[0].Value;

  j1:=jvideo.GetValue('play_addr') as TJSONObject;
  arr:=j1.GetValue('url_list') as TJSONARRAY;
  FvideoUrl:=arr[0].Value;
  FvideoUrl:=stringreplace(FvideoUrl,'playwm','play',[rfReplaceAll]);

  Furi_1080:=j1.GetValue('uri').Value;

  result:='#100#'+FvideoUrl+'#'+FcoverUrl+'#'+FvideoTitle;

finally
  if json <> nil then json.Free;
end;
end;

//第二步:分析出视频id,如:7065264218437717285
function TDouyin.getVideoId(txt:string):string;
var
 m:TMatch;
  i:integer;
begin
  result:='';
  m := TRegEx.Match(txt,'/video/([^/?]+)/');
  if(m.Groups[1].Success=false) or (length(m.Groups[1].Value)<>19)then exit;
  result:=m.Groups[1].Value;

end;
  //X-Bogus 算法 不明白的+v:metabycf
function TDouyin.getBogusUrl(url:string):string;
var
  json:TJSONObject;
  data:string;
begin
  result:='';
try
  json:=TJSONObject.Create;
  json.AddPair('url',url);
  json.AddPair('user_agent',USER_AGENT);
  data:=json.ToString;
  log(data);
  data:=getPostResult(data);
  log(data);
  if(data='')then exit;
  json:=TJSONObject.ParseJSONValue(data) as TJSONObject;
  result:=json.GetValue('param').Value;
finally
  json.Free;
end;
end;

//第一步:执行重定向,从而获取到视频id
function TDouyin.getRedirectedUrl(url,refer,user_agent:string):string;
var
  client: TNetHTTPClient;
  ss: TStringStream;
  s,id:string;
  AResponse:IHTTPResponse;
  i:integer;
begin
try
  client := TNetHTTPClient.Create(nil);
  SS := TStringStream.Create('', TEncoding.UTF8);
  ss.Clear;
  with client do
  begin
    ConnectionTimeout := 2000; // 2秒
    ResponseTimeout := 2000; // 10秒
    AcceptCharSet := 'utf-8';
    UserAgent := user_agent;
    client.AllowCookies:=true;
    client.HandleRedirects:=false;
    Accept:='*/*';
    client.CustomHeaders['Referer'] := refer;
    try
        AResponse:=Get(url, ss);
        Log('getRedirectedUrl AResponse='+ss.DataString);
        s:=AResponse.HeaderValue['Location'];
        if(s='')then exit;
        result:=s;
    except
      on E: Exception do
        Log(e.Message);

    end;
  end;
finally
  ss.Free;
  client.Free;
end;
end;

constructor TDouyin.Create(id:cardinal;url:string);
begin
  //inherited;
  //FreeOnTerminate := True;
  inherited Create(True);
  FId:=id;
  Furl:=url;     //分享链接
  Furi_1080:='';   //视频uri
  Fphotos:='';
end;
destructor TDouyin.Destroy;
begin
  inherited Destroy;
end;

//工作线程
procedure TDouyin.Execute;
begin
try
  getVideoUrl();
finally

end;
end;


//------------------------------------------属性方法-------------------------------------
 procedure TDouyin.SetId(Id:cardinal);
 begin
   FId:=Id;
 end;
 class procedure TDouyin.SetForm(const hForm: HWND);
 begin
   Fform:=hForm;
 end;

 procedure TDouyin.SetSaveDir(dir:string);
 begin
   Fsavedir:=dir;
 end;
 class procedure TDouyin.SetCookie(const cookie: string);
 begin
   Fcookie:=cookie;
 end;


end.

2、视频信息

unit uVideoInfo;

interface
type
  TVideoInfo=class
    private
      Ftitle:string;       //标题
      FcoverUrl:string;   //封面地址
      FvideoUrl:string;   //视频地址
      Fphotos:string;     //图片地址
      procedure SetTitle(title:string);
    public
      property title:string read Ftitle write Settitle;
      property coverUrl:string read FcoverUrl;
      property videoUrl:string read FvideoUrl;
      property photos:string read Fphotos;
      constructor Create(title,coverUrl,videoUrl,photos:string);
  end;
implementation
constructor TVideoInfo.Create(title,coverUrl,videoUrl,photos:string);
begin
  Ftitle:=title;
  FcoverUrl:=coverUrl;
  FvideoUrl:=videoUrl;
  Fphotos:=photos;
end;
procedure TVideoInfo.Settitle(title:string);
begin
  Ftitle:=title;
end;
end.

3、下载


unit uDownVideo;

interface
uses
  windows,classes,System.Net.URLClient, System.Net.HttpClient, System.Net.HttpClientComponent,
  System.SysUtils,strutils,uLog,System.RegularExpressions,uFuncs,system.JSON,uConfig,
  uVideoInfo,WinInet,urlmon,shlobj,ioutils;
const
  wm_user=$0400;
  wm_downfile=wm_user+100+1;
  USER_AGENT:string='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36';
type
  TDownVideo=class(TThread)
   private
     FId:cardinal;
     Fvideo:TvideoInfo;
     Fsavedir:string;
     FvideoFilename:string;
     FcoverFilename:string;
     FphotoFilename:string;    //图片文件名
     Fmsg:string;
     FSerial:boolean;         //是否在文件名前面加入序号;
     Fsuccess:boolean;
     Frefer:string;
     class var Fcookie: string;

     procedure SetId(id:cardinal);
     procedure SetSavedir(dir:string);
     procedure SetRefer(refer:string);
     class var Fform: HWND;
     class procedure SetForm(const hForm: HWND); static;
     class procedure SetCookie(const cookie: string); static;
     function DownloadFile(SourceFile, DestFile: string): Boolean;

   protected
     procedure Execute; override;
   public
     constructor Create(id:cardinal;video:TvideoInfo;savedir:string;bSerial:boolean);
     destructor Destroy;
     property id:cardinal read FId write SetId;
     property savedir:string read Fsavedir write SetSavedir;
     property video:TvideoInfo read Fvideo;
     property msg:string read Fmsg;
     property videoFilename:string read FvideoFilename;
     property coverFilename:string read FcoverFilename;
     property photoFilename:string read FphotoFilename;
     property serial:boolean read Fserial;
     property success:boolean read Fsuccess;
     property refer:string read Frefer write SetRefer;
     class property cookie: string read Fcookie write SetCookie;
     class property form: HWND read Fform write SetForm;
     function formatFilename(caption:string):string;
     function formatDir(dir:string):string;
     function GetValidName(s:string):string;

     procedure downloadFileLog(SourceFile, DestFile: string);
     procedure process();
  end;
implementation
//bSerial为是否给文件名加上序号
constructor TDownVideo.Create(id:cardinal;video:TvideoInfo;savedir:string;bSerial:boolean);
begin
  //inherited;
  //FreeOnTerminate := True;
  inherited Create(True);
  FId:=id;
  Fvideo:=video;
  Fsavedir:=formatdir(savedir);
  Fmsg:='';
  FvideoFilename:='';
  FcoverFilename:='';
  FphotoFilename:='';
  Fsuccess:=false;
  Fserial:=bSerial;
  if(not directoryexists(Fsavedir))then
    forcedirectories(Fsavedir);
end;
destructor TDownVideo.Destroy;
begin
  inherited Destroy;
end;
//下载流程
procedure TDownVideo.process();
var
  dir,title,photoUrl,photoname:string;
  b:boolean;
  photolist:tstrings;
  i:integer;
begin
  photolist:=nil;
try
  title:=formatfilename(trim(video.title));
  if(Fvideo.photos='')then  //下载视频
  begin
    if(Fserial=true)then
    begin
      FcoverFilename:=Fsavedir+'\'+inttostr(Fid)+'.'+title+'.webp';
      FvideoFilename:=Fsavedir+'\'+inttostr(Fid)+'.'+title+'.mp4';
    end else begin
      FcoverFilename:=Fsavedir+'\'+title+'.webp';
      FvideoFilename:=Fsavedir+'\'+title+'.mp4';
    end;
    if(video.coverUrl<>'')then downloadFileLog(Fvideo.coverUrl,FcoverFilename);
    if(video.videoUrl<>'')then downloadFileLog(Fvideo.videoUrl,FvideoFilename);
  end else begin      //下载图片
    photolist:=tstringlist.Create;
    photolist.Text:=video.photos;

    if(Fserial=true)then
      dir:=Fsavedir+'\'+inttostr(Fid)+'.'+title
    else
      dir:=Fsavedir+'\'+title;
    forcedirectories(dir);
    if(Fvideo.coverUrl<>'')then
    begin
      FcoverFilename:=dir+'\0.封面 '+title+'.webp';
      downloadFileLog(Fvideo.coverUrl,FcoverFilename);
    end;
    for I := 0 to photolist.Count-1 do
    begin
      photoUrl:=photolist[i];
      if(trim(photoUrl)='')then continue;
      photoname:=dir+'\'+inttostr(i+1)+'.'+title+'.webp';
      downloadFileLog(photoUrl,photoname);
      FphotoFilename:=FphotoFilename+photoname+#13#10;
    end;
  end;

finally
  Fmsg:='complete';
  if(photolist<>nil)then photolist.Free;
  SendMessage(Fform,wm_downfile,1,integer(self));
end;
end;
//线程中执行下载
procedure TDownVideo.Execute;
begin
  process();
end;
function TDownVideo.GetValidName(s:string):string;
var
  c:char;
  txt:string;
begin
  txt:=s;
  for c in TPath.GetInvalidFileNameChars() do
  begin
    txt:=stringreplace(txt,c,'',[rfReplaceAll]);
  end;
  result:=txt;
end;
//去除文件名中的非法字符
function TDownVideo.formatFilename(caption:string):string;
var
  s:string;
begin
  s:=caption;
  if(length(s)>72)then s:=leftstr(s,72);
  result:=GetValidName(s);
end;
//去除路径中的非法字符
function TDownVideo.formatDir(dir:string):string;
var
  caption:string;
begin
  caption:=trim(extractfilename(dir));
  if(length(caption)>72)then caption:=leftstr(caption,72);
  caption:=GetValidName(caption);
  result:=extractfilepath(dir)+caption;
end;
//下载文件
procedure TDownVideo.downloadFileLog(SourceFile, DestFile: string);
begin
  if(fileexists(DestFile))then deletefile(DestFile);
  if(Downloadfile(SourceFile,DestFile))then
  begin
    log('成功:'+DestFile);
    Fsuccess:=true;
  end else begin
    log('失败:'+DestFile+'  '+SourceFile);
    Fsuccess:=false;
  end;
end;
//下载文件
function TDownVideo.DownloadFile(SourceFile, DestFile: string): Boolean;
begin
try
  DeleteUrlCacheEntry(pchar(SourceFile));
  Result := UrlDownloadToFile(nil, PChar(SourceFile), PChar(DestFile), 0, nil) = 0;
except
  Result := False;
end;
end;


//------------------------------------------属性方法-------------------------------------
 procedure TDownVideo.SetSavedir(dir:string);
 begin
   Fsavedir:=dir;
 end;
 procedure TDownVideo.SetRefer(refer:string);
 begin
   Frefer:=refer;
 end;
 class procedure TDownVideo.SetCookie(const cookie: string);
 begin
   Fcookie:=cookie;
 end;
  procedure TDownVideo.SetId(Id:cardinal);
 begin
   FId:=Id;
 end;
 class procedure TDownVideo.SetForm(const hForm: HWND);
 begin
   Fform:=hForm;
 end;

end.

需要技术支持及成品的+v:metabycf

delphi 通过TNetHTTPClient解析抖音无水印高清视频原理及解决X-Bogus签名验证2023-5-1,音视频,开发语言文章来源地址https://www.toymoban.com/news/detail-685448.html

到了这里,关于delphi 通过TNetHTTPClient解析抖音无水印高清视频原理及解决X-Bogus签名验证2023-5-1的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 视频解析网站让你轻松获取高清无水印视频!

    相信各位好多学习视频剪辑或者下载视频的小伙伴们来说,每次视频解析都是一件特别困难的事情吧,要么画质不会就是水印挡着了关键的地方让大家非常不适,今天就推荐几个视频解析网站给大家把。 ​ 第一款的话就是我们的水印云视频解析网站它可以一键智能去除水印

    2024年03月14日
    浏览(69)
  • 如何获得高清、4K无水印视频素材?教你轻松拥有高清视频

    随着短视频越来越火爆,大家也都加入到了视频创作的行业中,平时也会喜欢剪辑一些视频发布到平台上,那高清的短视频肯定是最受欢迎的,我们自己又如何获得高清的视频呢? 1. 视觉质量:高清视频素材可以提供更清晰、更精细的图像细节和更高的分辨率。这可以使观看

    2024年02月06日
    浏览(73)
  • 找高清无水印视频素材,就上这9个网站。

    推荐几个我的视频素材库,有免费、收费、商用,希望对大家有帮助! 1、菜鸟图库 https://www.sucai999.com/video.html?v=NTYwNDUx 菜鸟图库可以找到设计、办公、图片、视频、音频等各种素材。视频素材就有上千个,全部都很高清,站内可以按标签分类查找,还可以搜索,找素

    2024年02月08日
    浏览(50)
  • Python实现超简单【抖音】无水印视频批量下载

    python免费学习资料以及群交流解答点击即可加入 01 获取你喜欢的拍客的视频url 即抖音用户主页的url,我将以罗永浩的主页连接为例(本人第一次下载抖音就是冲着罗永浩去的,所以也只关注了他一个人) 1. 获取主页链接 打开抖音,点进用户的主页面,点击右上角的三个点:

    2024年04月24日
    浏览(57)
  • 安卓OpenGL添加水印并录制(二)---抖音录制原理

    本文首发地址 https://h89.cn/archives/146.html 最新更新地址 https://gitee.com/chenjim/chenjimblog 源码地址: Gitee: OpenGLRecorder 通过 前文 我们知道了如何采集 Camera 视频,叠加水印、贴纸保存为MP4,但是录制视频并没有音频,本文进一步介绍添加音频录制实现。 前文介绍的视频处理流程及主

    2024年02月21日
    浏览(33)
  • c# 通过webView2模拟登陆小红书网页版,解析无水印视频图片,以及解决X-s,X-t签名验证【2023年4月29日】

    一、c# WebView2简介   1.一开始使用WebBrowser,因为WebBrowser控件使用的是ie内核,经过修改注册表切换为Edge内核后, 发现Edge内核版本较低,加载一些视频网站提示“浏览器版本过低“,”视频无法加载“。 2.WebBrowser内核版本与WebView2比较 WebBrowser内核版本: 内核版本 (Version) E

    2024年02月05日
    浏览(63)
  • 情感视频素材免费下载无水印,分享几个抖音热门情感视频素材网站

             在当今这个短视频内容为王的时代,情感短视频无疑成为了最直接、最有效的情感传达方式之一。无论是用来表达生活点滴,还是用于品牌故事的讲述,一段精心制作的视频能够让人触动心弦,留下深刻印象。但是,优秀的情感视频素材并且免费下载无水印离不开

    2024年04月12日
    浏览(162)
  • delphi 通过注册表 取桌面目录路径

    直接上代码: 调用方式很简单, vDesktopFilePath := GetShellFolders(\\\'Desktop\\\'); 直接调用这个函数,参数为Desktop,就可以取到当前用户桌面目录的路径。 可以看到,我们还能取到的其他目录路径,只要我们将参数设置为红框里的键值就可以取到了。 

    2024年02月16日
    浏览(32)
  • FreeBASIC通过Delphi7 DLL调用MS SOAP使用VB6 Webservice

    前几篇笔记习练了IIS soapis30配置、VB6 webservice创建、Delphi7和VB6 webservice访问: VB6 COM webservice发布,VB.NET和Delphi 7 对webservice访问,及MS Soap Toolkit 3.0在IIS上的ISAPI配置_Mongnewer的博客-CSDN博客 本篇笔记重点编写 Delphi7 DLL 对MS soap3 进行封装,让FreeBASIC通过Delphi7的DLL封装,访问IIS上的

    2024年02月09日
    浏览(59)
  • 一键AI高清换脸——基于InsightFace、CodeFormer实现高清换脸与验证换脸后效果能否通过人脸比对、人脸识别算法

    1、项目简介 AI换脸是指利用基于深度学习和计算机视觉来替换或合成图像或视频中的人脸。可以将一个人的脸替换为另一个人的脸,或者将一个人的表情合成到另一个人的照片或视频中。算法常常被用在娱乐目上,例如在社交媒体上创建有趣的照片或视频,也有用于电影制作

    2024年02月08日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包