delphi M3U8列表下载视频  
官方Delphi 学习QQ群: 682628230(三千人)
频道

delphi M3U8列表下载视频


需要uAES这里下载:https://sourceforge.net/projects/eucoin/


unit FM_Main;


interface


uses

  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,

  System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,

  Vcl.StdCtrls, Vcl.ExtCtrls, Vcl.ComCtrls, IdIOHandler, IdIOHandlerSocket,

  IdIOHandlerStack, IdSSL, IdSSLOpenSSL, IdBaseComponent, IdComponent,

  IdTCPConnection, IdTCPClient, IdHTTP, IdGlobal, uAES;


type

  TDownloadEven = procedure(Sender: TObject; ATotal, AIndex: Integer) of object;


  TM3U8 = class

  private

    mHTTP: TIdHTTP;

    mSSL: TIdSSLIOHandlerSocketOpenSSL;

    mURL_Head: string;

    mKey: TAESKey128;

    mIV: TAESBuffer;

    mList: TStringList;

    FOnDownload: TDownloadEven;

    ///

    procedure GetURLHead(AURL: string);

    ///

    procedure ParseKey(AText: string);

    ///

    procedure GetAESKey(AURL: string);

    ///

    procedure GetIV(AText: string);

    ///

    procedure GetList(AURL: string);

    ///

    procedure GetTS(AURL: string; out Ams: TMemoryStream);

    ///

    procedure SaveTS(AFileName: string);

    procedure SetOnDownload(const Value: TDownloadEven);

  public

    constructor Create;

    destructor Destroy; override;

    ///

    ///链接地址

    ///保存文件名,含完整路径

    procedure Download(AURL, AFileName: string);

    property OnDownload: TDownloadEven read FOnDownload write SetOnDownload;

  end;


  TfrmMain = class(TForm)

    edtURL: TLabeledEdit;

    btnRun: TButton;

    mmoLog: TMemo;

    edtFile: TLabeledEdit;

    btnSelectFile: TButton;

    pb1: TProgressBar;

    dlgSave1: TSaveDialog;

    lblTProgress: TLabel;

    lbl1: TLabel;

    procedure FormCreate(Sender: TObject);

    procedure FormDestroy(Sender: TObject);

    procedure btnRunClick(Sender: TObject);

    procedure btnSelectFileClick(Sender: TObject);

  private

    m3u8: TM3U8;

    procedure ProcDownload(Sender: TObject; ATotal, AIndex: Integer);

  public

  end;


var

  frmMain: TfrmMain;


implementation


{$R *.dfm}


const //使用说明

  Tips = '【使用说明】' + #13#10 //

    + '1. 用【火狐】打开网页,找到想要下载的视频,并播放' + #13#10 //

    + '2. 按【F12】进入到调试模式' + #13#10 //

    + '3. 从出来的界面中点【网络】' + #13#10 //

    + '4. 在下方选择【XHR】' + #13#10 //

    + '5. 按【F5】刷新,或者点界面中的【重新载入】' + #13#10 //

    + '6. 选择第一条【方法】列为【GET】,且【类型】列为【vnd.apple.mpegurl】' + #13#10 //

    +

    '7. 复制【GET】后面的网址,例如:【https://cd11-ccd1-1.play.bokecc.com/flvs/4800438B48685E7E/2018-08-23/6D06EE8E082C7D789C33DC5901307461-10.m3u8?t=1600635731&key=0AA94E693F6E5786ADD5E7009BFBF5C9&tpl=10&tpt=112】' +

    #13#10 //

    + '8. 把网址粘贴到本工具的【下载地址】里' + #13#10 //

    + '9. 点【选择位置】,选择一个要保存的文件夹,并给要下载的视频起个名字' + #13#10 //

    + '10.点【开始下载】等待视频下载完成' + #13#10 //

    + '11.重复以上操作下载其它视频' + #13#10 //

    + '================================================================================';


{ TM3U8 }


constructor TM3U8.Create;

begin

  mHTTP := TIdHTTP.Create(nil);

  mSSL := TIdSSLIOHandlerSocketOpenSSL.Create(nil);

  mSSL.SSLOptions.Method := sslvSSLv23;

  mSSL.SSLOptions.Mode := sslmBoth;

  mHTTP.IOHandler := mSSL;

  mList := TStringList.Create;

  mHTTP.Request.Accept := '*/*';

  mHTTP.Request.AcceptEncoding := 'gzip, deflate, br';

  mHTTP.Request.AcceptLanguage :=

    'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2';

  mHTTP.Request.Connection := 'keep-alive';

  mHTTP.Request.UserAgent :=

    'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0';

end;


destructor TM3U8.Destroy;

begin

  mList.Free;

  mSSL.Free;

  mHTTP.Free;

  inherited Destroy;

end;


procedure TM3U8.Download(AURL, AFileName: string);

begin

  //提取链接头

  GetURLHead(AURL);

  //提取分片列表

  GetList(AURL);

  //下载分片

  SaveTS(AFileName);

end;


procedure TM3U8.GetAESKey(AURL: string);

var

  ms: TMemoryStream;

begin

  ms := TMemoryStream.Create;

  try

    mHTTP.Get(AURL, ms);

    ms.Position := 0;

    ms.Read(mKey, 16);

  finally

    ms.Free;

  end;

end;


procedure TM3U8.GetIV(AText: string);

var

  i: Integer;

begin

  for i := 0 to 15 do

  begin

    mIV[i] := StrToUInt('$' + Copy(AText, i * 2 + 1, 2)) and $FF;

  end;

end;


procedure TM3U8.GetList(AURL: string);

var

  sl: TStringList;

  i: Integer;

begin

  sl := TStringList.Create;

  try

    sl.Text := mHTTP.Get(AURL);

    mList.Clear;

    for i := 0 to sl.Count - 1 do

    begin

      //密钥

      if Pos('#EXT-X-KEY', UpperCase(sl[i])) > 0 then

      begin

        ParseKey(sl[i]);

        Continue;

      end;

      //分片列表

      if Pos('#EXTINF', UpperCase(sl[i])) > 0 then

      begin

        mList.Add(mURL_Head + sl[i + 1]);

        Continue;

      end;

    end;

  finally

    sl.Free;

  end;

end;


procedure TM3U8.GetTS(AURL: string; out Ams: TMemoryStream);

var

  ms: TMemoryStream;

begin

  ms := TMemoryStream.Create;

  try

    mHTTP.Get(AURL, ms);

    ms.Position := 0;

    Ams.Clear;

    DecryptAESStreamCBC(ms, ms.Size, mKey, mIV, Ams);

  finally

    ms.Free;

  end;

end;


procedure TM3U8.GetURLHead(AURL: string);

var

  sl: TStringList;

  i: Integer;

begin

  mURL_Head := '';

  sl := TStringList.Create;

  try

    ExtractStrings(['/'], [], PChar(AURL), sl);

    for i := 0 to sl.Count - 2 do

      mURL_Head := mURL_Head + sl[i] + '/';

    mURL_Head := StringReplace(mURL_Head, 'https:/', 'https://', [rfIgnoreCase]);

  finally

    sl.Free;

  end;

end;


procedure TM3U8.ParseKey(AText: string);

var

  sl: TStringList;

  i: Integer;

  url, iv: string;

begin

  url := '';

  sl := TStringList.Create;

  try

    ExtractStrings([','], [], PChar(AText), sl);

    for i := 0 to sl.Count - 1 do

    begin

      if UpperCase(sl.KeyNames[i]) = 'URI' then

      begin

        url := sl.ValueFromIndex[i];

        url := StringReplace(url, '"', '', [rfReplaceAll, rfIgnoreCase]);

        GetAESKey(url);

        Continue;

      end;

      if UpperCase(sl.KeyNames[i]) = 'IV' then

      begin

        iv := sl.ValueFromIndex[i];

        iv := StringReplace(iv, '0x', '', [rfReplaceAll, rfIgnoreCase]);

        GetIV(iv);

        Continue;

      end;

    end;

  finally

    sl.Free;

  end;

end;


procedure TM3U8.SaveTS(AFileName: string);

var

  fs: TFileStream;

  ms: TMemoryStream;

  i: Integer;

begin

  fs := TFileStream.Create(AFileName, fmCreate);

  ms := TMemoryStream.Create;

  try

    fs.Position := 0;

    for i := 0 to mList.Count - 1 do

    begin

      if Assigned(FOnDownload) then

        FOnDownload(Self, mList.Count, i);

      GetTS(mList[i], ms);

      fs.CopyFrom(ms, 0);

      Application.ProcessMessages;

    end;

  finally

    if Assigned(FOnDownload) then

      FOnDownload(Self, mList.Count, i);

    ms.Free;

    fs.Free;

  end;

end;


procedure TM3U8.SetOnDownload(const Value: TDownloadEven);

begin

  FOnDownload := Value;

end;


procedure TfrmMain.btnRunClick(Sender: TObject);

begin

  if Trim(edtURL.Text) = '' then

  begin

    ShowMessage('下载地址不能为空!');

    Exit;

  end;

  if Trim(edtFile.Text) = '' then

  begin

    ShowMessage('保存位置不能为空!');

    Exit;

  end;

  mmoLog.Lines.Add(Format('[%s]从【%s】下载到【%s】', [FormatDateTime('HH:NN:SS', Now),

    edtURL.Text, edtFile.Text]));

  m3u8.Download(edtURL.Text, edtFile.Text);

  mmoLog.Lines.Add(Format('[%s]%s', [FormatDateTime('HH:NN:SS', Now), 'OK!']));

end;


procedure TfrmMain.btnSelectFileClick(Sender: TObject);

begin

  dlgSave1.Filter := 'mp4|*.mp4';

  dlgSave1.DefaultExt := 'mp4';

  if dlgSave1.Execute then

    edtFile.Text := dlgSave1.FileName;

end;


procedure TfrmMain.FormCreate(Sender: TObject);

begin

  m3u8 := TM3U8.Create;

  m3u8.OnDownload := ProcDownload;

  mmoLog.Lines.Add(Tips);

end;


procedure TfrmMain.FormDestroy(Sender: TObject);

begin

  m3u8.Free;

end;


procedure TfrmMain.ProcDownload(Sender: TObject; ATotal, AIndex: Integer);

begin

  pb1.Max := ATotal;

  pb1.Position := AIndex;

  lblTProgress.Caption := Format('%d/%d', [AIndex, ATotal]);

end;


end.



推荐分享
图文皆来源于网络,内容仅做公益性分享,版权归原作者所有,如有侵权请告知删除!
 

Copyright © 2014 DelphiW.com 开发 源码 文档 技巧 All Rights Reserved
晋ICP备14006235号-8 晋公网安备 14108102000087号

执行时间: 0.042407989501953 seconds