1. Add-Type -AssemblyName PresentationFramework
  2. Add-Type -AssemblyName System.Windows.Forms
  3.  
  4. # Déterminer le dossier du script et localiser ffmpeg/ffprobe
  5. try {
  6. $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
  7. } catch {
  8. $scriptDir = Get-Location
  9. }
  10. $ffmpegCmd = Join-Path $scriptDir "ffmpeg.exe"
  11. $ffprobeCmd = Join-Path $scriptDir "ffprobe.exe"
  12.  
  13. # Vérifier la présence de ffmpeg/ffprobe
  14. if (-not (Test-Path $ffmpegCmd)) {
  15. [System.Windows.MessageBox]::Show("ffmpeg.exe est introuvable dans le dossier du script.")
  16. exit
  17. }
  18. if (-not (Test-Path $ffprobeCmd)) {
  19. [System.Windows.MessageBox]::Show("ffprobe.exe est introuvable dans le dossier du script.")
  20. exit
  21. }
  22.  
  23. # Créer la fenêtre WPF
  24. [xml]$xaml = @"
  25. Title="Convertisseur vidéo (H.264 + AAC)" Height="500" Width="650"
  26. WindowStartupLocation="CenterScreen" ResizeMode="NoResize" Background="#202020">
  27. <Grid Margin="15">
  28. <Grid.RowDefinitions>
  29. <RowDefinition Height="Auto"/>
  30. <RowDefinition Height="Auto"/>
  31. <RowDefinition Height="Auto"/>
  32. <RowDefinition Height="Auto"/>
  33. <RowDefinition Height="*"/>
  34. <RowDefinition Height="Auto"/>
  35. </Grid.RowDefinitions>
  36. <TextBlock Grid.Row="0" Text="Fichier vidéo :" Foreground="White" Margin="0,0,0,5"/>
  37. <StackPanel Grid.Row="1" Orientation="Horizontal">
  38. <TextBox x:Name="InputFile" Width="450" Margin="0,0,5,0"/>
  39. <Button x:Name="BrowseButton" Content="Parcourir..." Width="120"/>
  40. </StackPanel>
  41. <StackPanel Grid.Row="2" Orientation="Horizontal" Margin="0,10,0,0">
  42. <TextBlock Text="Redimensionnement (%) :" Foreground="White" VerticalAlignment="Center"/>
  43. <TextBox x:Name="ResizePercent" Width="60" Margin="10,0,0,0" Text="100"/>
  44. </StackPanel>
  45. <StackPanel Grid.Row="3" Orientation="Horizontal" Margin="0,10,0,0">
  46. <CheckBox x:Name="OverwriteCheckbox" Content="Écraser le fichier existant" Foreground="White"/>
  47. </StackPanel>
  48. <TextBox x:Name="OutputLog" Grid.Row="4" Margin="0,10,0,10" AcceptsReturn="True"
  49. VerticalScrollBarVisibility="Auto" Background="#101010" Foreground="#00FF00" FontFamily="Consolas"/>
  50. <Button x:Name="ConvertButton" Grid.Row="5" Content="Convertir" Width="120" Height="30"
  51. HorizontalAlignment="Right" Margin="0,10,0,0"/>
  52. </Grid>
  53. </Window>
  54. "@
  55.  
  56. # Charger le XAML
  57. $reader = New-Object System.Xml.XmlNodeReader $xaml
  58. $window = [Windows.Markup.XamlReader]::Load($reader)
  59.  
  60. # Associer les contrôles
  61. $BrowseButton = $window.FindName("BrowseButton")
  62. $InputFile = $window.FindName("InputFile")
  63. $ResizePercent = $window.FindName("ResizePercent")
  64. $OutputLog = $window.FindName("OutputLog")
  65. $ConvertButton = $window.FindName("ConvertButton")
  66. $OverwriteCheckbox = $window.FindName("OverwriteCheckbox")
  67.  
  68. # Fonction pour journaliser dans la zone de texte
  69. function Add-LogLine {
  70. param($text)
  71. $OutputLog.AppendText("$text`r`n")
  72. $OutputLog.ScrollToEnd()
  73. }
  74.  
  75. # Parcourir un fichier
  76. $BrowseButton.Add_Click({
  77. $ofd = New-Object System.Windows.Forms.OpenFileDialog
  78. $ofd.Filter = "Fichiers vidéo|*.mp4;*.mkv;*.avi;*.mov;*.flv;*.wmv;*.webm|Tous les fichiers|*.*"
  79. if ($ofd.ShowDialog() -eq "OK") {
  80. $InputFile.Text = $ofd.FileName
  81. }
  82. })
  83.  
  84. # Conversion
  85. $ConvertButton.Add_Click({
  86. $file = $InputFile.Text
  87. if (-not (Test-Path $file)) {
  88. [System.Windows.MessageBox]::Show("Veuillez sélectionner un fichier vidéo valide.")
  89. return
  90. }
  91.  
  92. $percent = [int]$ResizePercent.Text
  93. if ($percent -le 0) { $percent = 100 }
  94.  
  95. Add-LogLine "Lecture des dimensions de la vidéo..."
  96.  
  97. # Lire les dimensions avec ffprobe
  98. $psi = New-Object System.Diagnostics.ProcessStartInfo
  99. $psi.FileName = $ffprobeCmd
  100. $psi.Arguments = "-v error -select_streams v:0 -show_entries stream=width,height -of csv=p=0 `"$file`""
  101. $psi.UseShellExecute = $false
  102. $psi.RedirectStandardOutput = $true
  103. $psi.RedirectStandardError = $true
  104. $psi.CreateNoWindow = $true
  105.  
  106. $process = New-Object System.Diagnostics.Process
  107. $process.StartInfo = $psi
  108. $process.Start() | Out-Null
  109. $dimensions = $process.StandardOutput.ReadToEnd().Trim()
  110. $process.WaitForExit()
  111.  
  112. if (-not $dimensions -or $dimensions -eq "") {
  113. Add-LogLine "Erreur : impossible de lire les dimensions."
  114. return
  115. }
  116.  
  117. $dims = $dimensions -split ","
  118. $width = [int]$dims[0]
  119. $height = [int]$dims[1]
  120.  
  121. $newWidth = [int]($width * $percent / 100)
  122. $newHeight = [int]($height * $percent / 100)
  123.  
  124. # Arrondir à un nombre pair pour éviter les problèmes d'encodage
  125. if ($newWidth % 2 -ne 0) { $newWidth-- }
  126. if ($newHeight % 2 -ne 0) { $newHeight-- }
  127.  
  128. $dir = Split-Path $file -Parent
  129. $base = [System.IO.Path]::GetFileNameWithoutExtension($file)
  130. $outFile = Join-Path $dir "$base`_resize.mp4"
  131.  
  132. if ($OverwriteCheckbox.IsChecked) {
  133. $outFile = Join-Path $dir "$base.mp4"
  134. if (Test-Path $outFile) {
  135. $result = [System.Windows.MessageBox]::Show("Le fichier existe déjà. Écraser ?", "Confirmation", "YesNo")
  136. if ($result -ne "Yes") { return }
  137. }
  138. }
  139.  
  140. Add-LogLine "Conversion de : $file"
  141. Add-LogLine "Dimensions : $width x $height -> $newWidth x $newHeight"
  142. Add-LogLine "Sortie : $outFile"
  143. Add-LogLine "=== Démarrage de ffmpeg... ==="
  144.  
  145. # Désactiver le bouton pendant la conversion
  146. $ConvertButton.IsEnabled = $false
  147.  
  148. # Lancer ffmpeg
  149. $psi2 = New-Object System.Diagnostics.ProcessStartInfo
  150. $psi2.FileName = $ffmpegCmd
  151. $psi2.Arguments = "-i `"$file`" -vf `"scale=${newWidth}:${newHeight}:force_original_aspect_ratio=decrease`" -c:v libx264 -preset slow -crf 23 -c:a aac -b:a 192k -movflags +faststart -y `"$outFile`""
  152. $psi2.UseShellExecute = $false
  153. $psi2.RedirectStandardOutput = $true
  154. $psi2.RedirectStandardError = $true
  155. $psi2.CreateNoWindow = $true
  156.  
  157. $process2 = New-Object System.Diagnostics.Process
  158. $process2.StartInfo = $psi2
  159.  
  160. # Utiliser un runspace pour exécuter en arrière-plan sans bloquer l'UI
  161. $rs = [runspacefactory]::CreateRunspace()
  162. $rs.Open()
  163. $rs.SessionStateProxy.SetVariable("process2", $process2)
  164. $rs.SessionStateProxy.SetVariable("OutputLog", $OutputLog)
  165. $rs.SessionStateProxy.SetVariable("ConvertButton", $ConvertButton)
  166. $rs.SessionStateProxy.SetVariable("window", $window)
  167.  
  168. $ps = [powershell]::Create()
  169. $ps.Runspace = $rs
  170.  
  171. $ps.AddScript({
  172. $process2.Start() | Out-Null
  173.  
  174. while (-not $process2.StandardError.EndOfStream) {
  175. $line = $process2.StandardError.ReadLine()
  176. if ($line) {
  177. $window.Dispatcher.Invoke([action]{
  178. $OutputLog.AppendText("$line`r`n")
  179. $OutputLog.ScrollToEnd()
  180. })
  181. }
  182. }
  183.  
  184. $process2.WaitForExit()
  185.  
  186. $window.Dispatcher.Invoke([action]{
  187. $OutputLog.AppendText("`r`n=== Conversion terminée ===`r`n")
  188. $OutputLog.ScrollToEnd()
  189. $ConvertButton.IsEnabled = $true
  190. })
  191. }) | Out-Null
  192.  
  193. $ps.BeginInvoke() | Out-Null
  194. })
  195.  
  196. # Afficher la fenêtre
  197. $window.ShowDialog() | Out-Null