<#
/////////////////
FFMPalm by PalmDB
/////////////////

Universal video encoder frontend for Palm OS

What's New:
* Added exit and force flags to allow for batch processes without user input prompts 
* Fixed declining file overwrite not skipping all conversion steps
#>

<#
INITIALIZATION
#>

<# Get script version #>
$version = "1.1.0"

<# Get OS version #>
if (Test-Path "$env:windir\syswow64") {
    $OS = "win64"
} else {
    $OS = "win32"
}

<# Init script behaviors #>
$exit = $false
$exitWait = $true
$force = $false

<# Show version #>
Write-Host "`n" -BackgroundColor Yellow -NoNewline
Write-Host "`n FFMPalm Version $version by PalmDB " -NoNewline -BackgroundColor Yellow -ForegroundColor Black
Write-Host "`n" -BackgroundColor Yellow


<#
PROFILES
#>

function Get-Profile($device) {

    <#
    DEVICE PROFILES
    #>

    <# Convert input to lowercase #>
    $device = $device.ToLower()

    <# Get device profile #>
    switch -regex ($device) {

        <# ACEECA #>
        "aceeca_meazura|meazura" {
            $device = "Aceeca Meazura" 
            $cpu = "DragonBallVZ"
            Break
        }

        "aceeca_pda32|pda32" {
            $device = "Aceeca PDA32" 
            $cpu = "PXA270hi"
            Break
        }


        <# ACER #>
        "acer_s10|s10" {
            $device = "Acer S10" 
            $cpu = "DragonBallVZ"
            Break
        }

        "acer_s50|s10" {
            $device = "Acer S50" 
            $cpu = "DragonBallVZ"
            Break
        }

        "acer_s60|s10" {
            $device = "Acer S60" 
            $cpu = "DragonBallVZ"
            Break
        }


        <# ALPHASMART #>
        "alphaSmart_dana|dana" {
            $device = "AlphaSmart Dana" 
            $cpu = "DragonBallVZ"
            Break
        }


        <# GARMIN #>
        "ique_3000|q3000" {
            $device = "Garmin iQue 3000" 
            <# Actually iMX, but similar performance #> 
            $cpu = "PXA250"
            Break
        }

        "ique_3200|q3200" {
            $device = "Garmin iQue 3200" 
            <# Actually iMX, but similar performance #> 
            $cpu = "PXA250"
            Break
        }

        "ique_3600|q3600" {
            $device = "Garmin iQue 3600" 
            $cpu = "DragonBallMXL"
            Break
        }


        <# FOSSIL #>
        "fossil|wristpda" {
            $device = "Fossil Wrist PDA" 
            $cpu = "DragonBallVZ"
            Break
        }


        <# GROUP SENSE PDA #>
        "xplore_g18|g18" {
            $device = "Xplore G18" 
            $cpu = "DragonBallVZ"
            Break
        }

        "xplore_g88|g88" {
            $device = "Xplore G88" 
            $cpu = "DragonBallVZ"
            Break
        }

        "xplore_m28|m28" {
            $device = "Xplore M28" 
            $cpu = "OMAP310"
            Break
        }

        "xplore_m68|m68" {
            $device = "Xplore M68" 
            $cpu = "OMAP310"
            Break
        }

        "xplore_m70|m70" {
            $device = "Xplore M70" 
            $cpu = "OMAP310"
            Break
        }

        "xplore_m68|m98" {
            $device = "Xplore M98" 
            $cpu = "OMAP310"
            Break
        }


        <# HANDERA #>
        "handera_330|330" {
            $device = "Handera 330" 
            $cpu = "DragonBallVZ"
            Break
        }


        <# HANDSPRING #>
        "treo_90|90" {
            $device = "Handspring Treo 90" 
            $cpu = "DragonBallVZ"
            Break
        }


        <# HP #>
        "hp_pre3|pre3" {
            $device = "HP Pre 3" 
            $cpu = "SnapdragonMSM"
            Break
        }

        "hp_touchpad|touchpad" {
            $device = "HP TouchPad" 
            $cpu = "SnapdragonS3"
            Break
        }

        "hp_veer|veer" {
            $device = "HP Veer" 
            $cpu = "QualcommMSM"
            Break
        }


        <# JANAM #>
        "janam_xp30|xp30" {
            $device = "Janam XP30" 
            $cpu = "DragonBallMXL"
            Break
        }


        <# LENOVO #>
        "lenovo_p300|p300" {
            $device = "Lenovo P300" 
            $cpu = "DragonBallMXL"
            Break
        }


        <# PALM #>
        "palm_i705|i705" {
            $device = "Palm i705" 
            $cpu = "DragonBallVZ"
            Break
        }

        "palm_m125|m125" {
            $device = "Palm m125" 
            $cpu = "DragonBallVZ"
            Break
        }

        "palm_m130|m130" {
            $device = "Palm m130" 
            $cpu = "DragonBallVZ"
            Break
        }

        "palm_m500|m500" {
            $device = "Palm m500" 
            $cpu = "DragonBallVZ"
            Break
        }

        "palm_m515|m515" {
            $device = "Palm m515" 
            $cpu = "DragonBallVZ"
            Break
        }

        "palm_centro|centro" {
            $device = "Palm Centro" 
            $cpu = "PXA270lo"
            Break
        }

        "palm_lifedrive|ld" {
            $device = "Palm LifeDrive" 
            $cpu = "PXA270hi"
            Break
        }

        "palm_pixi|pixi" {
            $device = "Palm Pixi" 
            $cpu = "QualcommMSM"
            Break
        }

        "palm_pre|pre" {
            $device = "Palm Pre" 
            $cpu = "OMAP3430"
            Break
        }

        "palm_tx|tx" {
            $device = "Palm TX" 
            $cpu = "PXA270hi"
            Break
        }


        <# QOOL #>
        "qool_qda700|qda700" {
            $device = "Qool QDA700" 
            $cpu = "DragonBallMXL"
            Break
        }


        <# SAMSUNG #>
        "sph_i500|i500" {
            $device = "Samsung SPH-i500" 
            $cpu = "DragonBallVZ"
            Break
        }

        "sph_i550|i550" {
            $device = "Samsung SPH-i550" 
            $cpu = "DragonBallMX1"
            Break
        }

        "sch_i539|i539" {
            $device = "Samsung SCH-i539" 
            $cpu = "DragonBallMX1"
            Break
        }


        <# SONY #>
        "clie_n610c|n610c" {
            $device = "Sony Clie N610C" 
            $cpu = "DragonBallVZ"
            Break
        }

        "clie_n760c|n760c" {
            $device = "Sony Clie N760C" 
            $cpu = "DragonBallVZ"
            Break
        }

        "clie_nr70|nr70" {
            $device = "Sony Clie NR70" 
            $cpu = "DragonBallVZ"
            Break
        }

        "clie_s320|s320" {
            $device = "Sony Clie S320" 
            $cpu = "DragonBallVZ"
            Break
        }

        "clie_s360|s360" {
            $device = "Sony Clie S360" 
            $cpu = "DragonBallVZ"
            Break
        }

        "clie_sj20|sj20" {
            $device = "Sony Clie SJ20" 
            $cpu = "DragonBallVZ"
            Break
        }

        "clie_sj30|sj30" {
            $device = "Sony Clie SJ30" 
            $cpu = "DragonBallVZ"
            Break
        }

        "clie_sl10|sl10" {
            $device = "Sony Clie SL10" 
            $cpu = "DragonBallVZ"
            Break
        }

        "clie_t400|t400" {
            $device = "Sony Clie T400" 
            $cpu = "DragonBallVZ"
            Break
        }

        "clie_t600c|t600c" {
            $device = "Sony Clie T600C" 
            $cpu = "DragonBallVZ"
            Break
        }

        "clie_t665c|t665c" {
            $device = "Sony Clie T665C" 
            $cpu = "DragonBallVZ"
            Break
        }

        "clie_nx60|nx60" {
            $device = "Sony Clie NX60"
            <# Actually PXA250, but widescreen #> 
            $cpu = "PXA260"
            Break
        }

        "clie_nx70|nx70" {
            $device = "Sony Clie NX70"
            <# Actually PXA250, but widescreen #> 
            $cpu = "PXA260"
            Break
        }

        "clie_nx80|nx80" {
            $device = "Sony Clie NX80"
            <# Actually PXA250, but widescreen #> 
            $cpu = "PXA260"
            Break
        }

        "clie_nz90|nz90" {
            $device = "Sony Clie NZ90"
            <# Actually PXA250, but widescreen #> 
            $cpu = "PXA260"
            Break
        }

        "clie_tg50|tg50" {
            $device = "Sony Clie TG50" 
            $cpu = "PXA250hi"
            Break
        }

        "clie_th55|th55" {
            $device = "Sony Clie TH55" 
            $cpu = "HHE"
            Break
        }

        "clie_tj25|tj25" {
            $device = "Sony Clie TJ25" 
            $cpu = "DragonBallMX1"
            Break
        }

        "clie_tj27|tj27" {
            $device = "Sony Clie TJ27" 
            $cpu = "DragonBallMX1"
            Break
        }

        "clie_tj35|tj35" {
            $device = "Sony Clie TJ35" 
            $cpu = "DragonBallMX1"
            Break
        }

        "clie_tj37|tj37" {
            $device = "Sony Clie TJ37" 
            $cpu = "DragonBallMX1"
            Break
        }

        "clie_ux40|ux40" {
            $device = "Sony Clie UX40" 
            $cpu = "HHE"
            Break
        }

        "clie_ux50|ux50" {
            $device = "Sony Clie UX50" 
            $cpu = "HHE"
            Break
        }

        "clie_vz90|vz90" {
            $device = "Sony Clie VZ90" 
            $cpu = "HHE"
            Break
        }


        <# SYMBOL #>
        "symbol_spt1800|spt1800" {
            $device = "Symbol SPT 1800" 
            $cpu = "DragonBallVZ"
            Break
        }


        <# TAPWAVE #>
        "tapwave_zodiac|zodiac" {
            $device = "Tapwave Zodiac" 
            $cpu = "PXA270hi"
            Break
        }


        <# TREO #>
        "treo_600|600" {
            $device = "Palm Treo 600" 
            $cpu = "OMAP1510"
            Break
        }

        "treo_650|650" {
            $device = "Palm Treo 650" 
            $cpu = "PXA270lo"
            Break
        }

        "treo_680|680" {
            $device = "Palm Treo 680" 
            $cpu = "PXA270lo"
            Break
        }

        "treo_700p|700p" {
            $device = "Palm Treo 700p" 
            $cpu = "PXA270lo"
            Break
        }

        "treo_755p|755p" {
            $device = "Palm Treo 755p" 
            $cpu = "PXA270lo"
            Break
        }


        <# TUNGSTEN #>
        "tungsten_w|tw" {
            $device = "Palm Tungsten W" 
            $cpu = "DragonBallVZ"
            Break
        }

        "tungsten_c|tc" {
            $device = "Palm Tungsten C" 
            $cpu = "PXA250hi"
            Break
        }

        "tungsten_e|e1|te" {
            $device = "Palm Tungsten E" 
            $cpu = "OMAP311"
            Break
        }

        "tungsten_e2|e2" {
            $device = "Palm Tungsten E2" 
            $cpu = "PXA250hi"
            Break
        }

        "tungsten_t|t1|tt" {
            $device = "Palm Tungsten T" 
            $cpu = "OMAP311"
            Break
        }

        "tungsten_t2|t2" {
            $device = "Palm Tungsten T2" 
            $cpu = "OMAP311"
            Break
        }

        "tungsten_t3|t3" {
            $device = "Palm Tungsten T3" 
            $cpu = "PXA260"
            Break
        }

        "tungsten_t5|t5" {
            $device = "Palm Tungsten T5" 
            $cpu = "PXA270hi"
            Break
        }


        <# ZIRE #>
        "zire_21|z21" {
            $device = "Palm Zire 21"
            <# Actually OMAP311, but grayscale requires the same players as DragonBall #> 
            $cpu = "DragonBallVZ"
            Break
        }

        "zire_22|z22" {
            $device = "Palm Zire 22" 
            $cpu = "S3C2410"
            Break
        }

        "zire_31|z31" {
            $device = "Palm Zire 31" 
            $cpu = "PXA250lo"
            Break
        }

        "zire_71|z71" {
            $device = "Palm Zire 71" 
            $cpu = "OMAP310"
            Break
        }

        "zire_72|z72" {
            $device = "Palm Zire 72" 
            $cpu = "PXA270lo"
            Break
        }

        <# Otherwise assume input is common profile #>
        Default {
            $cpu = $device
            $device = "your Palm"
        }
    }


    <#
    COMMON PROFILES
    #>

    <# Convert input to lowercase #>
    $cpu = $cpu.ToLower()

    <# Get common profile #>
    switch ($cpu) {
        <# Listed roughly in order of processing power #>

        "dragonballvz" {
            $script:deviceLegacy = $true
            $script:player = "gMovie, Kinoma, or TealMovie (*)"
            $script:width = "160"
            $script:height = "160"
            $script:fps = "20"
            $script:vcodec = "mpeg1video"
            $script:acodec = "mp2"
            $script:vbitrate = "1024K"
            $script:abitrate = "128K"
            $script:ext = "mpg"
        }
        
        "s3c2410" {
            $script:player = "CorePlayer"
            $script:width = "160"
            $script:height = "160"
            $script:fps = "20"
            $script:vcodec = "libxvid -g 120 -bf 4"
            $script:acodec = "pcm_u8"
            $script:vbitrate = "192K"
            $script:abitrate = "384K -ar 24000"
            $script:ext = "avi"
        }
        
        "omap1510" {
            $script:player = "CorePlayer"
            $script:width = "160"
            $script:height = "160"
            $script:fps = "20"
            $script:vcodec = "libxvid -g 120 -bf 4"
            $script:acodec = "pcm_u8"
            $script:vbitrate = "224K"
            $script:abitrate = "384K -ar 24000"
            $script:ext = "avi"
        }
        
        "omap310" {
            $script:player = "CorePlayer"
            $script:width = "240"
            $script:height = "176"
            $script:fps = "20"
            $script:vcodec = "libxvid -g 120 -bf 4"
            $script:acodec = "pcm_u8"
            $script:vbitrate = "224K"
            $script:abitrate = "384K -ar 24000"
            $script:ext = "avi"
        }
        
        "omap311" {
            $script:player = "CorePlayer"
            $script:width = "240"
            $script:height = "240"
            $script:fps = "20"
            $script:vcodec = "libxvid -g 120 -bf 4"
            $script:acodec = "pcm_u8"
            $script:vbitrate = "224K"
            $script:abitrate = "384K -ar 24000"
            $script:ext = "avi"
        }
        
        "dragonballmxl" {
            $script:player = "CorePlayer"
            $script:width = "304"
            $script:height = "228"
            $script:fps = "20"
            $script:vcodec = "libxvid -g 120 -bf 4"
            $script:acodec = "pcm_u8"
            $script:vbitrate = "224K"
            $script:abitrate = "384K -ar 24000"
            $script:ext = "avi"
        }
        
        "dragonballmx1" {
            $script:player = "CorePlayer"
            $script:width = "320"
            $script:height = "320"
            $script:fps = "20"
            $script:vcodec = "libxvid -g 120 -bf 4"
            $script:acodec = "pcm_u8"
            $script:vbitrate = "256K"
            $script:abitrate = "384K -ar 24000"
            $script:ext = "avi"
        }
        
        "pxa250lo" {
            $script:player = "CorePlayer"
            $script:width = "160"
            $script:height = "160"
            $script:fps = "30"
            $script:vcodec = "libxvid -g 120 -bf 4"
            $script:acodec = "pcm_u8"
            $script:vbitrate = "352K"
            $script:abitrate = "384K -ar 24000"
            $script:ext = "avi"
        }
        
        "pxa250hi" {
            $script:player = "CorePlayer"
            $script:width = "320"
            $script:height = "320"
            $script:fps = "24"
            $script:vcodec = "libxvid -g 120 -bf 4"
            $script:acodec = "pcm_u8"
            $script:vbitrate = "352K"
            $script:abitrate = "384K -ar 24000"
            $script:ext = "avi"
        }
        
        "pxa260" {
            $script:player = "CorePlayer"
            $script:width = "424"
            $script:height = "280"
            $script:fps = "24"
            $script:vcodec = "libxvid -g 120 -bf 4"
            $script:acodec = "pcm_u8"
            $script:vbitrate = "352K"
            $script:abitrate = "384K -ar 24000"
            $script:ext = "avi"
        }
        
        "hhe" {
            $script:player = "CorePlayer"
            $script:width = "456"
            $script:height = "304"
            $script:fps = "24"
            $script:vcodec = "libxvid -g 120 -bf 4"
            $script:acodec = "pcm_u8"
            $script:vbitrate = "256K"
            $script:abitrate = "384K -ar 24000"
            $script:ext = "avi"
        }
        
        "pxa270lo" {
            $script:player = "TCPMP or CorePlayer"
            $script:width = "320"
            $script:height = "320"
            $script:fps = "30"
            $script:vcodec = "libxvid -g 120 -bf 4"
            $script:acodec = "pcm_u8"
            $script:vbitrate = "640K"
            $script:abitrate = "384K -ar 24000"
            $script:ext = "avi"
        }
        
        "pxa270hi" {
            $script:player = "TCPMP or CorePlayer"
            $script:width = "480"
            $script:height = "320"
            $script:fps = "30"
            $script:vcodec = "libxvid -g 120 -bf 4"
            $script:acodec = "pcm_u8"
            $script:vbitrate = "848K"
            $script:abitrate = "384K -ar 24000"
            $script:ext = "avi"
        }
        
        "max" {
            $script:player = "TCPMP or CorePlayer overclocked to 500MHz or more"
            $script:width = "480"
            $script:height = "320"
            $script:fps = "30"
            $script:vcodec = "libxvid -g 120 -bf 4"
            $script:acodec = "pcm_u8"
            $script:vbitrate = "1920K"
            $script:abitrate = "512K -ar 32000"
            $script:ext = "avi"
        }
        
        "omap3430" {
            $script:player = "the WebOS video player app"
            $script:width = "480"
            $script:height = "320"
            $script:fps = "30"
            $script:vcodec = "libx264 -profile:v baseline"
            $script:acodec = "aac"
            $script:vbitrate = "1024K"
            $script:abitrate = "192K"
            $script:ext = "mp4"
        }
        
        "qualcommmsm" {
            $script:player = "the WebOS video player app"
            $script:width = "400"
            $script:height = "320"
            $script:fps = "30"
            $script:vcodec = "libx264 -profile:v baseline"
            $script:acodec = "aac"
            $script:vbitrate = "1024K"
            $script:abitrate = "192K"
            $script:ext = "mp4"
        }
        
        "snapdragonmsm" {
            $script:player = "the WebOS video player app"
            $script:width = "800"
            $script:height = "480"
            $script:fps = "30"
            $script:vcodec = "libx264"
            $script:acodec = "aac"
            $script:vbitrate = "1024K"
            $script:abitrate = "192K"
            $script:ext = "mp4"
        }
        
        "snapdragons3" {
            $script:player = "the WebOS video player app"
            $script:width = "1024"
            $script:height = "768"
            $script:fps = "30"
            $script:vcodec = "libx264"
            $script:acodec = "aac"
            $script:vbitrate = "1536K"
            $script:abitrate = "192K"
            $script:ext = "mp4"
        }

        <# Return empty if no device or common profile is found #>
        Default {
            $device = ""
        }
    }

    <# Return selected device string #>
    return $device
}


<#
HELP
#>

function Write-Hint {
    Write-Host "`nFor usage info, try:" -ForegroundColor Yellow
    Write-Host "`n  ffmpalm " -NoNewline -ForegroundColor Gray 
    Write-Host "-h / --help`n" -ForegroundColor Green
}

function Write-Help {
    Write-Host @"

 FFMPalm is a CLI frontend for a collection of video conversion utilities and presets designed
 to provide the best balance of quality and performance on as many Palm OS devices as possible.

 Currently, supported sources include local drives, streaming websites (YouTube et al), and DVD.
"@
    if ($exitWait) {
        Read-Host "`nPress ENTER to continue"
    }

    Write-Host "SYNTAX:" -ForegroundColor Yellow
    Write-Host "    ffmpalm " -NoNewline -ForegroundColor Gray
    Write-Host "`"input file/url`" " -NoNewline -ForegroundColor Green
    Write-Host "`"output file`" " -NoNewline -ForegroundColor Cyan
    Write-Host "device_profile " -NoNewline -ForegroundColor Magenta
    Write-Host "[--options] " -ForegroundColor DarkGreen

    Write-Host "`nOPTIONS:" -ForegroundColor Yellow
    Write-Host "    -c:x | --crop-none " -NoNewline
    Write-Host "           (Disables auto and manual crop)" -ForegroundColor Yellow
    Write-Host "    -c:r | --crop-region W:H:X:Y " -NoNewLine
    Write-Host " (Manual crop - Not recommended, will auto-crop by default!)" -ForegroundColor Yellow
    Write-Host "    -c:s | --crop-sample HH:MM:SS " -NoNewLine
    Write-Host "(Sample frame for auto-crop to find black bars)" -ForegroundColor Yellow
    Write-Host "    -t   | --dvd-title # " -NoNewLine
    Write-Host "         (Enables DVD conversion [where main feature is typically title 1 or 2])" -ForegroundColor Yellow
    Write-Host "    -s   | --smooth " -NoNewLine
    Write-Host "              (Slower conversion, smoother playback [but possibly with artifacts])" -ForegroundColor Yellow
    Write-Host "    -v   | --verbose " -NoNewLine
    Write-Host "             (Enables displaying more information during processing)" -ForegroundColor Yellow
    Write-Host "    -f   | --force " -NoNewLine
    Write-Host "               (Forces overwriting existing files without user prompts)" -ForegroundColor Yellow
    Write-Host "    -x   | --exit " -NoNewLine
    Write-Host "                (Disables user prompts when exiting failed or completed processes)" -ForegroundColor Yellow

    Write-Host "`nEXAMPLES:" -ForegroundColor Yellow
    Write-Host "    ffmpalm " -NoNewline -ForegroundColor Gray
    Write-Host "`"C:\video_in.mp4`" " -NoNewline -ForegroundColor Green
    Write-Host "`"C:\video_out`" " -NoNewline -ForegroundColor Cyan
    Write-Host "Palm_TX" -ForegroundColor Magenta
    
    Write-Host "    ffmpalm " -NoNewline -ForegroundColor Gray
    Write-Host "https://www.youtube.com/watch?v=3EjuGv9roKc " -NoNewline -ForegroundColor Green
    Write-Host "`"C:\video_out`" " -NoNewline -ForegroundColor Cyan
    Write-Host "E2 " -NoNewline -ForegroundColor Magenta
    Write-Host "--crop-sample 00:02:35 -f" -ForegroundColor DarkGreen

    Write-Host "    ffmpalm " -NoNewline -ForegroundColor Gray
    Write-Host "D:\ " -NoNewline -ForegroundColor Green
    Write-Host "`"C:\video_out`" " -NoNewline -ForegroundColor Cyan
    Write-Host "UX50 " -NoNewline -ForegroundColor Magenta
    Write-Host "--dvd-title 1 --exit" -ForegroundColor DarkGreen

    if ($exitWait) {
        Read-Host "`nPress ENTER to continue"
    }

    Write-Host "ABOUT:" -ForegroundColor Yellow
    Write-Host @"
 FFMPalm will automatically select the best conversion settings based on your input device profile.
 Device profiles can be input as either the device brand + model, or model only. For example, both 
 "T3" and "Tungsten_T3" will be recognized. (See below for a full table of supported devices. Device
 profiles are not case sensitive.)

 File extension will be selected automatically based on device profile, so there is no need to add 
 an extension to the output filename. In some cases, temporary files may also be stored at this
 location until the process is finished, so make sure there is enough free space!

 FFMPalm will attempt to automatically crop videos to remove letterboxing or pillarboxing. However,
 this requires a clear sample image to detect black bars. By default, an image will be sampled at
 1 minute. If this happens to be a black image (such as titles or transitions) or the video is less
 than one minute long, a different sample frame can be specified with the optional --crop-sample
 argument, using the time format HH:MM:SS. To disable cropping entirely, use --crop-none.

 To convert a DVD, use only the drive letter as an input path. Then, use the --dvd-title argument
 to specify which 'title' (video) to convert. A single DVD may contain multiple titles, such as
 additional trailers and bonus features. The main feature is typically title 1 or 2. The DVD will be 
 imported locally before conversion to Palm format. Further conversions can be made from the local
 version without re-importing.
"@

    if ($exitWait) {
        Read-Host "`nPress ENTER to continue"
    }

    Write-Host "PROFILES:`n" -ForegroundColor Yellow
    Write-Host @"
 |----------------------------------------------------------------------------------------------|
 | DEVICE PROFILES (OS 5+)                                                                      |
 |----------------------|--------------------|-------------------------|------------------------|
 | ACEECA               | GARMIN             | GROUP SENSE PDA         | HP                     |
 |----------------------|--------------------|-------------------------|------------------------|
 | Aceeca_PDA32 (PDA32) | iQue_3000 (Q3000)  | Xplore_M28 (M28)        | HP_Pre3     (Pre3)     |
 |                      | iQue_3200 (Q3200)  | Xplore_M68 (M68)        | HP_TouchPad (TouchPad) |
 |                      | iQue_3600 (Q3600)  | Xplore_M70 (M70)        | HP_Veer     (Veer)     |
 |                      |                    | Xplore_M98 (M98)        |                        |
 |----------------------|--------------------|-------------------------|------------------------|
 | JANAM                | LENOVO             | PALM                    | QOOL                   |
 |----------------------|--------------------|-------------------------|------------------------|
 | Janam_XP30 (XP30)    | Lenovo_P300 (P300) | Palm_Centro    (Centro) | Qool_QDA700 (QDA700)   |
 |                      |                    | Palm_LifeDrive (LD)     |                        |
 |                      |                    | Palm_Pixi      (Pixi)   |                        |
 |                      |                    | Palm_Pre       (Pre)    |                        |
 |                      |                    | Palm_TX        (TX)     |                        |
 |----------------------|--------------------|-------------------------|------------------------|
 | SAMSUNG              | SONY               | TAPWAVE                 | TREO                   |
 |----------------------|--------------------|-------------------------|------------------------|
 | SPH_i550 (i550)      | Clie_NX60 (NX60)   | Tapwave_Zodiac (Zodiac) | Treo_600  (600)        |
 | SCH_i539 (i539)      | Clie_NX70 (NX70)   |                         | Treo_650  (650)        |
 |                      | Clie_NX80 (NX80)   |                         | Treo_680  (680)        |
 |                      | Clie_NZ90 (NZ90)   |                         | Treo_700p (700p)       |
 |                      | Clie_TG50 (TG50)   |                         | Treo_755p (755p)       |
 |                      | Clie_TH55 (TH55)   |                         |                        |
 |                      | Clie_TJ25 (TJ25)   |                         |                        |
 |                      | Clie_TJ27 (TJ27)   |                         |                        |
 |                      | Clie_TJ35 (TJ35)   |                         |                        |
 |                      | Clie_TJ37 (TJ37)   |                         |                        |
 |                      | Clie_UX40 (UX40)   |                         |                        |
 |                      | Clie_UX50 (UX50)   |                         |                        |
 |                      | Clie_VZ90 (VZ90)   |                         |                        |
 |----------------------|--------------------|-------------------------|------------------------|
 | TUNGSTEN             | ZIRE               |                         |                        |
 |----------------------|--------------------|-------------------------|------------------------|
 | Tungsten_C  (TC)     | Zire_21 (Z21)      |-------------------------|------------------------|
 | Tungsten_E  (E1/TE)  | Zire_22 (Z22)      |-------------------------|------------------------|
 | Tungsten_E2 (E2)     | Zire_31 (Z31)      |-------------------------|------------------------|
 | Tungsten_T  (T1/TT)  | Zire_71 (Z71)      |-------------------------|------------------------|
 | Tungsten_T2 (T2)     | Zire_72 (Z72)      |-------------------------|------------------------|
 | Tungsten_T3 (T3)     |                    |-------------------------|------------------------|
 | Tungsten_T5 (T5)     |                    |-------------------------|------------------------|
 |----------------------|--------------------|-------------------------|------------------------|

 It is also technically possible to convert videos for playback on older/less powerful devices than 
 the list above. However, this is generally not recommended as image quality is severely limited,
 and specialized third-party desktop software is required to transfer videos generated by FFMPalm to
 the device itself as .pdb files. This software typically requires old versions of Apple QuickTime
 which may not be compatible with your PC.

 If you'd like to continue anyway, FFMPalm includes profiles for these older devices which will
 convert video to a generic format compatible with the **desktop transfer software**, not the devices
 themselves. It is up to you to install such software and select appropriate settings for transfer
 to your device.

 Visit https://palmdb.net/apps/media/video/ for more information and downloads!

 |-----------------------------------------------------------------------------------------------|
 | DEVICE PROFILES (OS 4)                                                                        |
 |--------------------------|--------------------|--------------------------|--------------------|
 | ACEECA                   | ACER               | ALPHASMART               | FOSSIL             |
 |--------------------------|--------------------|--------------------------|--------------------|
 | Aceeca_Meazura (Meazura) | Acer_S10 (S10)     | AlphaSmart_Dana (Dana)   | Fossil (WristPDA)  |
 |                          | Acer_S50 (S50)     |                          |                    |
 |                          | Acer_S60 (S60)     |                          |                    |
 |--------------------------|--------------------|--------------------------|--------------------|
 | GROUP SENSE PDA          | HANDERA            | HANDSPRING               | PALM               |
 |--------------------------|--------------------|--------------------------|--------------------|
 | Xplore_G18 (G18)         | Handera_330 (330)  | Treo_90 (90)             | Palm_i705 (i705)   |
 | Xplore_G88 (G88)         |                    |                          | Palm_m125 (m125)   |
 |                          |                    |                          | Palm_m130 (m130)   |
 |                          |                    |                          | Palm_m500 (m500)   |
 |                          |                    |                          | Palm_m515 (m515)   |
 |--------------------------|--------------------|--------------------------|--------------------|
 | SAMSUNG                  | SONY               | SYMBOL                   | TUNGSTEN           |
 |--------------------------|--------------------|--------------------------|--------------------|
 | SPH-i500 (i500)          | Clie_N610C (N610C) | Symbol_SPT1800 (SPT1800) | Tungsten_W (TW)    |
 |                          | Clie_NR70  (NR70)  |                          |                    |
 |                          | Clie_S320  (S320)  |                          |                    |
 |                          | Clie_S360  (S360)  |                          |                    |
 |                          | Clie_SJ20  (SJ20)  |                          |                    |
 |                          | Clie_SJ30  (SJ30)  |                          |                    |
 |                          | Clie_SL10  (SL10)  |                          |                    |
 |                          | Clie_T400  (T400)  |                          |                    |
 |                          | Clie_T600C (T600C) |                          |                    |
 |                          | Clie_T665C (T665C) |                          |                    |
 |--------------------------|--------------------|--------------------------|--------------------|

 There are also a number of common profiles available based on different chipsets. The above device 
 profiles will automatically select the appropriate common profile for their hardware, but if you 
 know your device's chipset, you can also select a common profile directly.

 |--------------------------------------------------------------------------------------|
 | COMMON PROFILES                                                                      |
 |-----------------|---------------|---------------|---------|------|-------------------|
 | INTEL           | MOTOROLA      | QUALCOMM      | SAMSUNG | SONY | TEXAS INSTRUMENTS |
 |-----------------|---------------|---------------|---------|------|-------------------|
 | PXA250lo        | DragonBallVZ  | QualcommMSM   | S3C2410 | HHE  | OMAP1510          |
 | PXA250hi        | DragonBallMXL | SnapdragonMSM |         |      | OMAP310           |
 | PXA260          | DragonBallMX1 | SnapdragonS3  |         |      | OMAP311           |
 | PXA270lo        |               |               |         |      | OMAP3430          |
 | PXA270hi        |               |               |         |      |                   |
 | MAX             |               |               |         |      |                   |
 |-----------------|---------------|---------------|---------|------|-------------------|

"@
}


<#
FIRST TIME SETUP
#>

<# Test whether Visual C++ redist needs to be installed #>
switch ($OS) {
    "win64" {
        $vcredist = Get-ItemProperty HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | select DisplayName | Where-Object {$_.DisplayName -like $("Microsoft Visual C++ 2010*")} | Out-String
        Break
    }

    "win32" {
        $vcredist = Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | select DisplayName | Where-Object {$_.DisplayName -like $("Microsoft Visual C++ 2010*")} | Out-String
        Break
    }

    Default {
        $vcredist = ""
    }
}

<# Install Visual C++ redestributable, if not installed #>
if ($vcredist -eq "") {
    & "$PWD\redist\vcredist_x86.exe" /q /norestart
}


<#
PARSE ARGUMENTS
#>

<# Initialize argument defaults #>
function Clear-Input {
    $script:cropEnabled = $true
    $script:cropRegion = ""
    $script:cropDefault = "crop=iw:ih:0:0"
    $script:cropSample = "00:00:59"
    $script:deviceProfile = ""
    $script:deviceLegacy = $false
    $script:dvdEnabled = $false
    $script:dvdTitle = -1
    $script:fileInput = ""
    $script:fileOutput = ""
    $script:smoothMode = "blend"
    $script:streamEnabled = $false
    $script:verbose = ""
    $script:verbosity = 0
}
Clear-Input

<# Show hint for help command if no arguments are input #>
if (($args.length) -eq 0) {
    Write-Hint
    $exit = $true
} else {
    <# Otherwise, get input arguments #>
    $dvdEnabled = ($args.Contains("--dvd-title") -or $args.Contains("-t"))
    for ($a = 0; $a -lt ($args.length); $a++) {
        <# Full help #>
        if (($args[$a] -eq "--help") -or ($args[$a] -eq "-h")) {
            Clear-Input
            Write-Help
            $exit = $true
            Break
        }

        <# Other arguments #>
        if (($args[$a] -eq "--crop-none") -or ($args[$a] -eq "-c:x")) {
            $cropEnabled = $false
            Continue
        }

        if (($args[$a] -eq "--crop-region") -or ($args[$a] -eq "-c:r")) {
            $cropRegion = "crop=" + $args[$a + 1]
            $a++
            Continue
        }

        if (($args[$a] -eq "--crop-sample") -or ($args[$a] -eq "-c:s")) {
            $cropSample = $args[$a + 1]
            $a++
            Continue
        }

        if (($args[$a] -eq  "--dvd-title") -or ($args[$a] -eq "-t")) {
            $dvdTitle = $args[$a + 1]
            $a++
            Continue
        }

        if (($args[$a] -eq "--smooth") -or ($args[$a] -eq "-s")) {
            $smoothMode = "mci"
            Continue
        }

        if (($args[$a] -eq "--verbose") -or ($args[$a] -eq "-v")) {
            $verbose = "--verbose"
            $verbosity = 40
            Continue
        }

        if (($args[$a] -eq "--force") -or ($args[$a] -eq "-f")) {
            $force = $true
            Continue
        }

        if (($args[$a] -eq "--exit") -or ($args[$a] -eq "-x")) {
            $exitWait = $false
            Continue
        }

        <# Files and profiles #>
        if ($args[$a] -is [string]) {
            <# Get input file path first #>
            if ($fileInput -eq "") {
                if ($dvdEnabled) {
                    <# Input file is DVD #>
                    if (Test-Path $args[$a]) {
                        $fileInput = $args[$a]
                    }
                } else {
                    <# Input file is URL #>
                    if (($args[$a].Substring(0, 4)) -eq "http") {
                        $streamEnabled = $true
                        $fileInput = $args[$a]
                    } else {
                        <# Input file is local path #>
                        if (Test-Path $args[$a]) {
                            $fileInput = Resolve-Path $args[$a]
                        }
                    }
                }
                Continue
            }

            <# Get output file path second#>
            if ($fileOutput -eq "") {
                <# Get target directory #>
                try { $matches.Clear() } catch { }
                $args[$a] -match ".+(\\)" | Out-Null

                <# Create target directory, if it doesn't exist #>
                if (!(Test-Path $matches[0])) {
                    New-Item -ItemType Directory -Path $matches[0] | Out-Null
                }

                <# Get fully qualified output file (without extension, if any) #>
                $fileOutput = ((Resolve-Path $matches[0]).toString()) + (($args[$a] -replace ".+(\\)") -replace "\.[^.\\/]+$")
                Continue
            }

            <# Get device profile third #>
            if ($deviceProfile -eq "") {
                $deviceProfile = $args[$a]
                Continue
            }
        }
    }

    <# Get device profile from argument #>
    $deviceProfile = Get-Profile $deviceProfile

    <# Show argument input errors #>
    while (!$exit) {
        if ($fileInput -eq "") {
            Write-Host "`nError: Missing or incorrect input file!" -ForegroundColor Red
            Write-Hint
            Clear-Input
            $exit = $true
            Break
        }
        if ($fileOutput -eq "") {
            Write-Host "`nError: Missing or incorrect output file!" -ForegroundColor Red
            Write-Hint
            Clear-Input
            $exit = $true
            Break
        }
        if ($deviceProfile -eq "") {
            Write-Host "`nError: Missing or incorrect device profile!" -ForegroundColor Red
            Write-Hint
            Clear-Input
            $exit = $true
            Break
        }
        if ($cropEnabled) {
            if ([string] $cropSample -eq "") {
                Write-Host "`nError: Crop sample declared, but missing sample time!" -ForegroundColor Red
                Write-Hint
                Clear-Input
                $exit = $true
                Break
            }
        }
        if ($dvdEnabled) {
            if ([string] $dvdTitle -eq "") {
                Write-Host "`nError: DVD title declared, but missing title number!" -ForegroundColor Red
                Write-Hint
                Clear-Input
                $exit = $true
                Break
            }
        }

        <# Show overwrite warning if output exists #>
        if (Test-Path "$fileOutput.$ext") {
            if (!$force) {
                $overwrite = Read-Host "`nFile exists. Overwrite? [Y/N]"
                Write-Host ""
            } else {
                <# Force overwrite, if enabled #>
                $overwrite = "Y"
            }

            <# Cancel if user declines to overwrite #>
            switch -regex ($overwrite) {
                "N|n" {
                    Write-Host "Operation cancelled.`n" -ForegroundColor Green
                    $exit = $true
                }
            }
        }

        <# End error checking if no errors were found #>
        Break
    }
}


<#
VIDEO PROCESSING
#>

<# Process DVD #>
if (!$exit -and $dvdEnabled) {
    Write-Host "`n[import] Importing DVD video. This will take a while, please wait...`n"

    <# Convert DVD to local file #>
    & "$PWD\bin\HandBrakeCLI.exe" --verbose=$verbosity --input "$fileInput" --title $dvdTitle --preset "Matroska/H.264 MKV 480p30" --output "$fileOutput.dvd.mkv"

    <# Use local DVD copy as input file #>
    if (Test-Path "$fileOutput.dvd.mkv") {
        $fileInput = "$fileOutput.dvd.mkv"
    } else {
        <# Otherwise show error if import failed #>
        Write-Host "`nError: Importing DVD title $dvdTitle failed!" -ForegroundColor Red
        Write-Hint
        $exit = $true
    }
}

<# Process streaming URL #>
if (!$exit -and $streamEnabled) {
    Write-Host ""

    <# Convert streaming video to local file #>
    & "$PWD\bin\yt-dlp.exe" $verbose -f "best[height<=720]" -o "$fileOutput.tmp" $fileInput

    <# Use local copy as input file #>
    if (Test-Path "$fileOutput.tmp") {
        $fileInput = "$fileOutput.tmp"
    } else {
        <# Otherwise show error if import failed #>
        Write-Host "`nError: Downloading URL `"$fileInput`" failed!" -ForegroundColor Red
        Write-Hint
        $exit = $true
    }
}

<# Process local file #>
if (!$exit) {
    Write-Host "[convert] Working, please wait..."

    <# Get crop setting, if enabled #>
    if ($cropEnabled) {
        <# Use auto-crop, if manual crop is not specified #>
        if ($cropRegion -eq "") {
            try { $matches.Clear() } catch { }
            & "$PWD\bin\ffmpeg.exe" -ss $cropSample -i "$fileInput" -vframes 5 -vf "scale=iw*min($width/iw\,$height/ih):ih*min($width/iw\,$height/ih), pad=$width`:$height`:($width-iw)/2:($height-ih)/2, cropdetect" -f null NUL 2>&1 | ForEach { $_.toString() -match 'crop=(.*)$' } | Out-Null

            <# Use autocrop setting, if found #>
            if ($matches[0].length -gt 0) {
                if (($matches[0].Substring(0, 4)) -eq "crop") {
                    $cropRegion = $matches[0]
                } else {
                    <# Otherwise use default crop #>
                    Write-Host "`nError: Detecting auto-crop region failed! Crop disabled." -ForegroundColor Red
                    $cropRegion = $cropDefault
                }
            } else {
                <# Otherwise use default crop #>
                Write-Host "`nError: Detecting auto-crop region failed! Crop disabled." -ForegroundColor Red
                $cropRegion = $cropDefault
            }
        }
    }

    <# Convert file #>
    & "$PWD\bin\ffmpeg.exe" -hide_banner -loglevel $verbosity -stats -i "$fileInput" -preset slower -c:v $vcodec.split(" ") -c:a $acodec.split(" ") -b:v $vbitrate.split(" ") -b:a $abitrate.split(" ") -r $fps.split(" ") -vf "scale=iw*min($width/iw\,$height/ih):ih*min($width/iw\,$height/ih), pad=$width`:$height`:($width-iw)/2:($height-ih)/2, $cropRegion, deblock=filter=strong:block=4, spp=4, minterpolate=fps=$fps`:mi_mode=$smoothMode" -y "$fileOutput.$ext"

    <# Cleanup temp file, if any #>
    if (Test-Path "$fileOutput.tmp") {
        Remove-Item "$fileOutput.tmp"
    }

    <# Notify process complete #>
    if (Test-Path "$fileOutput.$ext") {
        if ((Get-Item "$fileOutput.$ext").length -gt 0) {
            Write-Host "`nProcess complete!" -ForegroundColor Green
            Write-Host "`nFor $deviceProfile it is recommended to use $player for viewing converted videos."
            if ($deviceLegacy) {
                Write-Host "(*Requires companion desktop transfer software)" -ForegroundColor Yellow
            }
            if ($dvdEnabled) {
                Write-Host "`nYour DVD video has been saved for future conversions without re-importing."
            }
            Write-Host "`nVisit https://palmdb.net/apps/media/video/ for more information and downloads!`n"
        } else {
            <# Otherwise show error if conversion failed #>
            Write-Host "`nError: Converting `"$fileOutput.$ext`" failed!" -ForegroundColor Red
            Write-Hint
            $exit = $true

            <# Remove empty file #>
            Remove-Item "$fileOutput.$ext"
        }
    } else {
        <# Otherwise show error if creation failed #>
        Write-Host "`nError: Creating file `"$fileOutput.$ext`" failed!" -ForegroundColor Red
        Write-Hint
        $exit = $true
    }
}


<# 
FINALIZATION
#>

<# Prompt for exit, if enabled #>
if ($exitWait) {
    Read-Host "Press ENTER to exit"
}