all repos — fast-scripts @ 3f48e7050a4830ba23b9dcf562e3497758ed9bc9

scripts que podem ser uteis para meu dia a dia

Vídeos/criar-gif.cmd (view raw)

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
<# :
@echo off
powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -Command "Invoke-Expression ([System.IO.File]::ReadAllText('%~f0',[System.Text.Encoding]::UTF8))"
exit /b %errorlevel%
#>

# ============================================================
#  Criar GIF / Slideshow - vídeo -> GIF, ou fotos -> vídeo (FFmpeg)
#  Desenvolvido por Pablo Murad - 2026
# ============================================================

try { [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 } catch {}
try { $Host.UI.RawUI.WindowTitle = 'Criar GIF / Slideshow' } catch {}

function Pausar { Write-Host ''; Write-Host 'Pressione Enter para fechar...' -ForegroundColor DarkGray; [void][System.Console]::ReadLine() }
function Titulo($t) {
    Write-Host ''
    Write-Host '============================================================' -ForegroundColor DarkCyan
    Write-Host "  $t" -ForegroundColor Cyan
    Write-Host '============================================================' -ForegroundColor DarkCyan
}

$extVideo = @('.mp4','.mkv','.avi','.mov','.wmv','.flv','.webm','.m4v','.mpg','.mpeg','.ts','.3gp','.vob')
$extImg   = @('.jpg','.jpeg','.png','.webp','.bmp','.tif','.tiff')

Titulo 'Criar GIF / Slideshow'
Write-Host '  Desenvolvido por Pablo Murad - 2026' -ForegroundColor DarkGray
Write-Host ''
Write-Host 'Verificando o que é necessário...' -ForegroundColor Gray
$ffmpeg = Get-Command ffmpeg -ErrorAction SilentlyContinue
if (-not $ffmpeg) { Write-Host ''; Write-Host '[ERRO] FFmpeg não encontrado.' -ForegroundColor Red; Write-Host 'Instale com:  winget install Gyan.FFmpeg' -ForegroundColor White; Pausar; exit 1 }
Write-Host "[OK] FFmpeg: $($ffmpeg.Source)" -ForegroundColor Green

Titulo 'O que você quer fazer?'
Write-Host '  [1] Vídeo -> GIF' -ForegroundColor White
Write-Host '  [2] Fotos (pasta) -> vídeo (slideshow)' -ForegroundColor White
$acao = $null
while (-not $acao) { $a = Read-Host 'Opção (1-2)'; switch ($a.Trim()) { '1'{$acao='gif'} '2'{$acao='slide'} default{Write-Host '[!] Digite 1 ou 2.' -ForegroundColor Yellow} } }

if ($acao -eq 'gif') {
    # ---------------- Vídeo -> GIF ----------------
    $entrada = $null; $modoArquivo = $false; $arquivoUnico = $null
    while (-not $entrada) {
        Titulo 'Pasta ou vídeo'
        $p = (Read-Host 'Cole o caminho de um VÍDEO ou de uma PASTA').Trim().Trim('"')
        if (Test-Path -LiteralPath $p -PathType Leaf) {
            if ($extVideo -notcontains [System.IO.Path]::GetExtension($p).ToLowerInvariant()) { Write-Host '[!] Não é um vídeo suportado.' -ForegroundColor Yellow; continue }
            $entrada = (Resolve-Path -LiteralPath $p).Path; $modoArquivo = $true; $arquivoUnico = $entrada
        } elseif (Test-Path -LiteralPath $p -PathType Container) { $entrada = (Resolve-Path -LiteralPath $p).Path }
        else { Write-Host '[!] Caminho não encontrado.' -ForegroundColor Yellow }
    }
    $lEnt = Read-Host 'Largura do GIF em px (Enter = 480)'; $larg = if ($lEnt -as [int]) { [int]$lEnt } else { 480 }
    $fEnt = Read-Host 'Quadros por segundo / FPS (Enter = 12)'; $fps = if ($fEnt -as [int]) { [int]$fEnt } else { 12 }

    if ($modoArquivo) { $arquivoObj = Get-Item -LiteralPath $arquivoUnico; $origem = $arquivoObj.DirectoryName; $videos = @($arquivoObj) }
    else { $origem = $entrada; $videos = @(Get-ChildItem -LiteralPath $origem -File | Where-Object { $extVideo -contains $_.Extension.ToLowerInvariant() }) }
    $destino = Join-Path $origem 'GIF'

    Titulo 'Processando'
    Write-Host "Largura: $larg px   |   FPS: $fps   |   Destino: $destino"
    Write-Host "Vídeos: $($videos.Count)" -ForegroundColor Cyan
    if ($videos.Count -eq 0) { Write-Host 'Nenhum vídeo encontrado.' -ForegroundColor Yellow; Pausar; exit 0 }
    New-Item -ItemType Directory -Path $destino -Force | Out-Null

    $ok=0;$err=0;$i=0
    foreach ($v in $videos) {
        $i++
        $saida = Join-Path $destino ($v.BaseName + '.gif')
        Write-Host ''; Write-Host ("[{0}/{1}] {2}" -f $i,$videos.Count,$v.Name) -ForegroundColor Magenta
        if (Test-Path -LiteralPath $saida) { Write-Host '   [IGNORADO] Já existe.' -ForegroundColor Yellow; continue }
        $paleta = Join-Path $env:TEMP ("paleta_{0}.png" -f ([guid]::NewGuid().ToString('N')))
        $filtro = "fps=$fps,scale=${larg}:-1:flags=lanczos"
        & ffmpeg -hide_banner -nostdin -i $v.FullName -vf "$filtro,palettegen" -y $paleta 2>$null
        & ffmpeg -hide_banner -nostdin -i $v.FullName -i $paleta -lavfi "$filtro [x]; [x][1:v] paletteuse" -y $saida 2>$null
        Remove-Item -LiteralPath $paleta -Force -ErrorAction SilentlyContinue
        if ($LASTEXITCODE -eq 0 -and (Test-Path -LiteralPath $saida)) { Write-Host '   [OK] GIF criado.' -ForegroundColor Green; $ok++ }
        else { Write-Host '   [ERRO] Falha.' -ForegroundColor Red; if (Test-Path -LiteralPath $saida) { Remove-Item -LiteralPath $saida -Force -ErrorAction SilentlyContinue }; $err++ }
    }
    Titulo 'Concluído'
    Write-Host "GIFs criados: $ok" -ForegroundColor Green
    Write-Host "Erros: $err" -ForegroundColor $(if ($err -gt 0){'Red'}else{'Gray'})
    Write-Host "Destino: $destino"
    Pausar; exit 0
}

# ---------------- Fotos -> vídeo (slideshow) ----------------
$pasta = $null
while (-not $pasta) {
    Titulo 'Pasta com as fotos'
    $p = (Read-Host 'Cole o caminho da pasta').Trim().Trim('"')
    if (Test-Path -LiteralPath $p -PathType Container) { $pasta = (Resolve-Path -LiteralPath $p).Path } else { Write-Host '[!] Pasta não encontrada.' -ForegroundColor Yellow }
}
$fotos = @(Get-ChildItem -LiteralPath $pasta -File | Where-Object { $extImg -contains $_.Extension.ToLowerInvariant() } | Sort-Object Name)
if ($fotos.Count -eq 0) { Write-Host 'Nenhuma imagem nessa pasta.' -ForegroundColor Yellow; Pausar; exit 0 }
Write-Host ''; Write-Host "$($fotos.Count) fotos encontradas (em ordem alfabética)." -ForegroundColor Cyan

$sEnt = Read-Host 'Segundos por foto (Enter = 2)'; $seg = if ($sEnt -as [double]) { [double]$sEnt } else { 2 }
$nome = (Read-Host 'Nome do vídeo de saída (Enter = slideshow.mp4)').Trim()
if ([string]::IsNullOrWhiteSpace($nome)) { $nome = 'slideshow.mp4' }
if ($nome -notmatch '\.mp4$') { $nome += '.mp4' }
$saida = Join-Path $pasta $nome

# Monta arquivo de lista para o demuxer concat (caminhos com / e aspas)
$listaTxt = Join-Path $env:TEMP ("slide_{0}.txt" -f ([guid]::NewGuid().ToString('N')))
$sb = New-Object System.Text.StringBuilder
foreach ($f in $fotos) {
    $cam = $f.FullName -replace '\\','/'
    [void]$sb.AppendLine("file '$cam'")
    [void]$sb.AppendLine("duration $seg")
}
# repete a última foto (exigência do concat p/ respeitar a última duração)
$ultimo = $fotos[-1].FullName -replace '\\','/'
[void]$sb.AppendLine("file '$ultimo'")
[System.IO.File]::WriteAllText($listaTxt, $sb.ToString(), (New-Object System.Text.UTF8Encoding($false)))

Titulo 'Gerando slideshow'
Write-Host "Saída: $saida" -ForegroundColor Cyan
$vf = 'scale=1280:720:force_original_aspect_ratio=decrease,pad=1280:720:(ow-iw)/2:(oh-ih)/2:color=black,format=yuv420p'
& ffmpeg -hide_banner -nostdin -f concat -safe 0 -i $listaTxt -vf $vf -r 30 -c:v libx264 -preset medium -crf 20 -movflags +faststart -y $saida 2>$null
$rc = $LASTEXITCODE
Remove-Item -LiteralPath $listaTxt -Force -ErrorAction SilentlyContinue

Titulo 'Concluído'
if ($rc -eq 0 -and (Test-Path -LiteralPath $saida)) {
    Write-Host "[OK] Slideshow criado com $($fotos.Count) fotos." -ForegroundColor Green
    Write-Host "Arquivo: $saida"
} else { Write-Host '[ERRO] Falha ao gerar o slideshow.' -ForegroundColor Red }
Pausar