unit MainScreen;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, XYoutube,
  FMX.StdCtrls, FMX.Memo, FMX.Layouts, FMX.Objects, Windows, FMX.TabControl,
  FMX.Controls.Presentation, FMX.Edit, AnonThread, FMX.TMSBitmapContainer,
  FMX.TMSBaseControl, FMX.TMSTileList;

type
  TForm3 = class(TForm)
    Button1: TButton;
    ProgressBar1: TProgressBar;
    Button2: TButton;
    Memo1: TMemo;
    Youtube1: TYoutube;
    TabControl1: TTabControl;
    TabItem1: TTabItem;
    TabItem2: TTabItem;
    Memo2: TMemo;
    Button3: TButton;
    Layout1: TLayout;
    Edit1: TEdit;
    StyleBook1: TStyleBook;
    TabItem3: TTabItem;
    TileList: TTMSFMXTileList;
    BitmapCont: TTMSFMXBitmapContainer;
    Button4: TButton;
    ProgressBar2: TProgressBar;
    ToolBar1: TToolBar;
    Label1: TLabel;
    Edit2: TEdit;
    procedure Button1Click(Sender: TObject);
    procedure Youtube1Download(Percent: Single; WorkingByte: Int64);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure TileListTileClick(Sender: TObject; ATile: TTMSFMXTile);
  private
    { Private declarations }
    Working, ThumbWorking: Integer;
    procedure CaptureConsoleOutput(const ACommand, AParameters: String; AMemo: TMemo);
    procedure ExecuteAndWait(const aCommando: string);
    procedure RunAnonymousThread;
  public
    Timer1: TTimer;
    { Public declarations }
  end;

var
  Form3: TForm3;

implementation

{$R *.fmx}
Uses System.IOUtils;

procedure TForm3.Button1Click(Sender: TObject);
var I: Integer;
begin
 if Working=0 then
  begin
    if TFile.Exists(ExtractFilePath(ParamStr(0)) + 'video.mp4') then
     begin
      TFile.Delete(ExtractFilePath(ParamStr(0)) + 'video.mp4');
     end;
    ProgressBar1.Value := 0;
    RunAnonymousThread;
  end
 else
  begin
    ShowMessage('Already Working!');
  end;
end;

procedure ClearJpegs;
var
 i: Integer;
  Path  : String;
  Files : TStringDynArray;
begin
  Path := ExtractFilePath(ParamStr(0));
// Get all project files in this folder
  Files := TDirectory.GetFiles(Path, '*.jpg');

  // Display the files - just the file names that is
  for i := Length(Files)-1 downto 0 do
   begin
     if TFile.Exists(Files[i])=True then
      begin
       TFile.Delete(Files[i]);
      end;
   end;
end;

procedure TForm3.Button2Click(Sender: TObject);
var
I: Integer;
S: String;
begin
if Working=0 then
 begin
  ClearJpegs;
  ProgressBar1.Value := 0;
  S := Edit1.Text;
  S := S.Replace('https://www.youtube.com/watch?v=','');
  S := S.Replace('http://www.youtube.com/watch?v=','');
  S := S.Replace('http://youtu.be/','');

  Youtube1.YouTubeId := S;
  Youtube1.GetInformation(Youtube1.YouTubeId);
  Memo1.Text := Memo1.Text + Youtube1.Title + #13 + #10;
  Memo1.Text := Memo1.Text + Youtube1.VideoSize + #13 + #10;
  for I := 0 to Youtube1.Count -1 do
  begin
    Memo1.Text := Memo1.Text + 'Size: ' + Youtube1.Items[I].Size + #13 + #10;
    Memo1.Text := Memo1.Text + 'Quality: ' + Youtube1.Items[I].Quality + #13 + #10;
    Memo1.Text := Memo1.Text + 'Link: ' + Youtube1.Items[I].VideoLink + #13 + #10;
    Memo1.Text := Memo1.Text + 'Type: ' + Youtube1.Items[I].MimeType + #13 + #10;
    Memo1.Text := Memo1.Text + '-------------------------------' + #13 + #10;
  end;
 end;
end;

procedure TForm3.Button3Click(Sender: TObject);
begin
if ThumbWorking=0 then
 begin
  ThumbWorking := 1;
  SetCurrentDir(ExtractFilePath(ParamStr(0)));
  //CaptureConsoleOutput('thumbs.bat','',Memo2);
  ExecuteAndWait('thumbs.bat');
  ProgressBar2.Value := 0;


  TabControl1.ActiveTab := TabItem3;
  Button4Click(Self);
  ThumbWorking := 0;
 end;
end;

procedure TForm3.Button4Click(Sender: TObject);
var
 it: TTMSFMXTile;
 i: Integer;
  Path  : String;
  Files : TStringDynArray;
begin
  Edit2.Text := '';
  Path := ExtractFilePath(ParamStr(0));
// Get all project files in this folder
  Files := TDirectory.GetFiles(Path, '*.jpg');

 TileList.BeginUpdate;
  // Display the files - just the file names that is
  for i := 0 to Length(Files)-1 do
   begin
     it := TileList.Tiles.Add;
     //it.Caption := 'Item ' + inttostr(I);
    // it.Notes := 'Hello World !';
     it.Bitmap.CreateFromFile(Files[i]);
     it.DataString := Files[i];
   end;
 TileList.EndUpdate;

end;

function CleanFileName(const InputString: string): string;
var
  i: integer;
  ResultWithSpaces: string;
begin

  ResultWithSpaces := InputString;

  for i := 1 to Length(ResultWithSpaces) do
  begin
    // These chars are invalid in file names.
    case ResultWithSpaces[i] of
      '/', '\', ':', '*', '?', '"', '|', ',', ' ', #$D, #$A, #9:
        // Use a * to indicate a duplicate space so we can remove
        // them at the end.
        {$WARNINGS OFF} // W1047 Unsafe code 'String index to var param'
        if (i > 1) and
          ((ResultWithSpaces[i - 1] = ' ') or (ResultWithSpaces[i - 1] = '*')) then
          ResultWithSpaces[i] := '*'
        else
          ResultWithSpaces[i] := ' ';

        {$WARNINGS ON}
    end;
  end;

  // A * indicates duplicate spaces.  Remove them.
  result := ResultWithSpaces.Replace('*', '');

  // Also trim any leading or trailing spaces
  result := Trim(Result);

  if result = '' then
  begin
    raise(Exception.Create('Resulting FileName was empty Input string was: '
      + InputString));
  end;
end;

procedure TForm3.TileListTileClick(Sender: TObject; ATile: TTMSFMXTile);
var
 I: Integer;
 it: TTMSFMXTile;
 S: String;
begin
 TileList.BeginUpdate;
 for I := TileList.Tiles.Count-1 downto 0 do
  begin
    it := TileList.Tiles[I];
    if it<>ATile then
     begin
      TFile.Delete(it.DataString);
     end
     else
     begin
      if Youtube1.Title<>'' then
       begin
         S := CleanFileName(Youtube1.Title.Replace(' ' ,'_'));
         TFile.Move(it.DataString,ExtractFilePath(ParamStr(0)) + S + '.jpg');
         Edit2.Text := ExtractFilePath(ParamStr(0)) + S + '.jpg';
       end
      else
       begin
         Edit2.Text := it.DataString;
       end;
     end;
     TileList.Tiles.Delete(I);
  end;
 TileList.EndUpdate;
 //TabControl1.ActiveTab := TabItem1;
end;

procedure TForm3.Timer1Timer(Sender: TObject);
begin
if Working=1 then
 begin
  //ProgressBar1.Value := ProgressBar1.Value+10;
  if ProgressBar1.Value>=ProgressBar1.Max then
   begin
    Working := 0;
    TabControl1.ActiveTab := TabItem2;
    Sleep(1000);
    Button3Click(Self);
   end;
 end;
if ThumbWorking=1 then
 begin
  ProgressBar2.Value := ProgressBar2.Value+10;
  if ProgressBar2.Value>=ProgressBar2.Max then
   begin
    ProgressBar2.Value := 0;
   end;
 end;
end;

procedure TForm3.Youtube1Download(Percent: Single; WorkingByte: Int64);
begin
  ProgressBar1.Value := Percent;
end;

procedure TForm3.CaptureConsoleOutput(const ACommand, AParameters: String; AMemo: TMemo);
 const
   CReadBuffer = 2400;
 var
   saSecurity: TSecurityAttributes;
   hRead: THandle;
   hWrite: THandle;
   suiStartup: TStartupInfo;
   piProcess: TProcessInformation;
   pBuffer: array[0..CReadBuffer] of AnsiChar;
   dRead: DWord;
   dRunning: DWord;
 begin
   saSecurity.nLength := SizeOf(TSecurityAttributes);
   saSecurity.bInheritHandle := True;
   saSecurity.lpSecurityDescriptor := nil;

   if CreatePipe(hRead, hWrite, @saSecurity, 0) then
   begin
     FillChar(suiStartup, SizeOf(TStartupInfo), #0);
     suiStartup.cb := SizeOf(TStartupInfo);
     suiStartup.hStdInput := hRead;
     suiStartup.hStdOutput := hWrite;
     suiStartup.hStdError := hWrite;
     suiStartup.dwFlags := STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW;
     suiStartup.wShowWindow := SW_HIDE;

     if CreateProcess(nil, PChar(ACommand + ' ' + AParameters), @saSecurity,
       @saSecurity, True, NORMAL_PRIORITY_CLASS, nil, nil, suiStartup, piProcess)
       then
     begin
       repeat
         dRunning  := WaitForSingleObject(piProcess.hProcess, 100);
         Application.ProcessMessages();
         repeat
           dRead := 0;
           ReadFile(hRead, pBuffer[0], CReadBuffer, dRead, nil);
           pBuffer[dRead] := #0;

           OemToAnsi(pBuffer, pBuffer);
           AMemo.BeginUpdate;
           AMemo.Lines.Add(String(pBuffer));
           AMemo.EndUpdate;
         until (dRead < CReadBuffer);
       until (dRunning <> WAIT_TIMEOUT);
       CloseHandle(piProcess.hProcess);
       CloseHandle(piProcess.hThread);
     end;

     CloseHandle(hRead);
     CloseHandle(hWrite);
   end;
end;

procedure TForm3.ExecuteAndWait(const aCommando: string);
var
  tmpStartupInfo: TStartupInfo;
  tmpProcessInformation: TProcessInformation;
  tmpProgram: String;
begin
  tmpProgram := trim(aCommando);
  FillChar(tmpStartupInfo, SizeOf(tmpStartupInfo), 0);
  with tmpStartupInfo do
  begin
    cb := SizeOf(TStartupInfo);
    wShowWindow := SW_HIDE;
  end;

  if CreateProcess(nil, pchar(tmpProgram), nil, nil, true, CREATE_NO_WINDOW,
    nil, nil, tmpStartupInfo, tmpProcessInformation) then
  begin
    // loop every 10 ms
    while WaitForSingleObject(tmpProcessInformation.hProcess, 10) > 0 do
    begin
      Application.ProcessMessages;
    end;
    CloseHandle(tmpProcessInformation.hProcess);
    CloseHandle(tmpProcessInformation.hThread);
  end
  else
  begin
    RaiseLastOSError;
  end;
end;

procedure TForm3.FormCreate(Sender: TObject);
begin
//  TileList.TileOptions := TileList.TileOptions + [loBitmap] + [loDetail];

end;

procedure TForm3.RunAnonymousThread;
var
FThread: TAnonymousThread<Boolean>;
begin
  Working := 1;

  FThread := TAnonymousThread<Boolean>.Create(
  function: Boolean
  begin
    // remember in a thread any graphical changes have to be wrapped in Synchronize()
    //Synchronize(
    //procedure
    // begin
    //    Form1.Memo1.Lines.Add(‘Begin Execution’);
    //  end);

    //Youtube1.DownloadFolder := System.IOUtils.TPath.GetDocumentsPath + PathDelim ;
    Youtube1.DownloadFolder := ExtractFilePath(ParamStr(0));
    Youtube1.Download;


    Result := True;
  end,
  procedure(AResult: Boolean)
  begin
    // Runs in main thread
    // process the result from above
  end,
  procedure(AException: Exception)
  begin
    // Runs in main thread
    // do something if there is an exception
    Working := 0;
  end,
  False);
end;

end.
