2022-07-03 01:36:42 +02:00
Param (
2022-07-15 23:47:24 +02:00
[ string ] $Java = 'java' ,
2022-11-12 00:55:27 +01:00
[ switch ] $NoDeploy ,
[ switch ] $NoUpdate
2022-07-03 01:36:42 +02:00
)
Add-Type -AssemblyName System . Windows . Forms
Add-type -AssemblyName System . Drawing
$ProgressPreference = 'SilentlyContinue'
$ErrorActionPreference = 'Stop'
2022-07-19 18:33:03 +02:00
2022-07-03 01:36:42 +02:00
function execJava {
2022-07-19 18:33:03 +02:00
<#
. Description
execJava was created to additionally allow providing an array of strings to java arguments
if the first argument is a string array , it will launch with arguments in that array
otherwise it will launch with all provided arguments
#>
$SavedErrorActionPreference = $ErrorActionPreference
2022-07-03 01:36:42 +02:00
$ErrorActionPreference = 'Continue'
if ( $args [ 0 ] . getType ( ) . Name -ne " String " ) {
& $Java $args [ 0 ] 2 > & 1 | ForEach-Object { " $_ " }
}
else {
& $Java $args 2 > & 1 | ForEach-Object { " $_ " }
}
2022-07-19 18:33:03 +02:00
$ErrorActionPreference = $SavedErrorActionPreference
2022-07-03 01:36:42 +02:00
}
2022-11-12 00:32:27 +01:00
class FormItem {
$value
[ String ] $displayText
[ Bool ] $selected = $false
FormItem ( $_value , [ String ] $_displayText , [ Bool ] $_selected = $false ) {
$this . value = $_value
$this . displayText = $_displayText
$this . selected = $_selected
}
FormItem ( $_value , [ String ] $_displayText ) {
$this . value = $_value
$this . displayText = $_displayText
}
[ String ] ToString ( ) {
return $this . displayText
}
}
class FormItems : System . Collections . ArrayList <# FormItem #> {
[ System.Collections.ArrayList ] getSelectedBoolArray ( ) {
$rvalue = [ System.Collections.ArrayList ] :: new ( )
foreach ( $i in $this ) {
[ void ] $rvalue . Add ( $i . selected )
}
return $rvalue
}
[ System.Collections.ArrayList ] getDisplay ( ) {
$rvalue = [ System.Collections.ArrayList ] :: new ( )
foreach ( $i in $this ) {
[ void ] $rvalue . Add ( $i . displayText )
}
return $rvalue
}
2022-11-12 01:05:51 +01:00
FormItems ( ) { }
FormItems ( [ System.Collections.IEnumerable ] $list ) {
<#
. Description
Creates FormItems list with all items in list
where values are those items
and displaytext as string representation of them
TLDR it converts any list to FormItems
#>
foreach ( $i in $list ) {
[ void ] $this . Add ( [ FormItem ] :: new ( $i , $i . ToString ( ) ) )
}
}
2022-11-12 00:32:27 +01:00
}
function renderForm([FormItems]$items , [ String ] $label , [ String ] $title , [ System.Windows.Forms.SelectionMode ] $mode ) {
2022-07-03 01:36:42 +02:00
# https://docs.microsoft.com/en-us/powershell/scripting/samples/multiple-selection-list-boxes?view=powershell-7.2
# https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.anchorstyles
$form = New-Object System . Windows . Forms . Form
$form . Text = $title
$form . Size = New-Object System . Drawing . Size ( 300 , 200 )
$form . StartPosition = 'CenterScreen'
$OKButton = New-Object System . Windows . Forms . Button
$OKButton . Anchor = 2
$OKButton . Location = New-Object System . Drawing . Point ( 102 , 120 )
$OKButton . Size = New-Object System . Drawing . Size ( 75 , 23 )
$OKButton . Text = 'OK'
$OKButton . DialogResult = [ System.Windows.Forms.DialogResult ] :: OK
$form . AcceptButton = $OKButton
$form . Controls . Add ( $OKButton )
$_label = New-Object System . Windows . Forms . Label
$_label . Anchor = 1 + 4 + 8
$_label . Location = New-Object System . Drawing . Point ( 10 , 20 )
$_label . Size = New-Object System . Drawing . Size ( 280 , 20 )
$_label . Text = $label
$form . Controls . Add ( $_label )
$listBox = New-Object System . Windows . Forms . Listbox
$listBox . Anchor = 15
$listBox . Location = New-Object System . Drawing . Point ( 10 , 40 )
$listBox . Size = New-Object System . Drawing . Size ( 260 , 20 )
$listBox . SelectionMode = $mode
2022-11-12 00:32:27 +01:00
foreach ( $i in $items . getDisplay ( ) ) {
[ void ] $listBox . Items . Add ( $i )
2022-07-03 01:36:42 +02:00
}
2022-11-12 00:32:27 +01:00
for ( $i = 0 ; $i -lt $items . Count ; $i + + ) {
[ void ] $listBox . SetSelected ( $i , $items [ $i ] . selected )
2022-07-03 01:36:42 +02:00
}
$listBox . Height = 70
$form . Controls . Add ( $listBox )
$form . Topmost = $true
2022-11-12 00:32:27 +01:00
$dialogResult = $form . ShowDialog ( )
if ( $dialogResult -ne [ System.Windows.Forms.DialogResult ] :: OK ) {
return $false
}
$selected = [ System.Collections.ArrayList ] :: new ( )
foreach ( $i in $listbox . selectedIndices ) {
[ void ] $selected . Add ( $items [ $i ] . value )
2022-07-03 01:36:42 +02:00
}
2022-11-12 00:32:27 +01:00
$selected . TrimToSize ( )
return $selected
2022-07-03 01:36:42 +02:00
}
class config {
2022-11-12 01:59:22 +01:00
[ System.Collections.SortedList ] $version
[ System.Collections.SortedList ] $included
2022-07-03 01:36:42 +02:00
}
2022-07-20 00:52:59 +02:00
class configFile {
[ String ] $path = " .\config.json "
[ config ] $config = [ config ] :: new ( )
2022-07-03 01:36:42 +02:00
2022-07-20 00:52:59 +02:00
[ void ] load ( ) {
$fileContent = ConvertFrom-Json ( ( Get-Content $this . path ) -Join ' ' ) . ToString ( )
2022-07-03 01:36:42 +02:00
2022-11-12 01:59:22 +01:00
$version = [ System.Collections.SortedList ] :: new ( )
2022-07-20 00:52:59 +02:00
foreach ( $prop in $fileContent . version . PsObject . Properties ) {
$version . Add ( $prop . Name , $prop . Value )
}
$this . config . version = $version
2022-11-12 01:59:22 +01:00
$included = [ System.Collections.SortedList ] :: new ( )
foreach ( $prop in $fileContent . included . PsObject . Properties ) {
$included . Add ( $prop . Name , $prop . Value )
}
$this . config . included = $included
2022-07-20 00:52:59 +02:00
}
2022-07-03 01:36:42 +02:00
2022-07-20 00:52:59 +02:00
[ void ] save ( ) {
Out-File $this . path -InputObject ( ConvertTo-Json $this . config )
}
2022-11-12 01:59:22 +01:00
[ void ] setIncludesForPackage ( [ String ] $packageName , [ System.Collections.IEnumerable ] $integrationNames ) {
$this . config . included [ $packageName ] = $integrationNames . Clone ( )
}
[ System.Collections.ArrayList ] getIncludesForPackage ( [ String ] $packageName ) {
2022-11-12 04:01:55 +01:00
if ( -not $this . config . included . Keys . Contains ( $packageName ) ) { return [ System.Collections.ArrayList ] :: new ( ) }
2022-11-12 01:59:22 +01:00
return $this . config . included [ $packageName ] . Clone ( )
}
2022-07-20 00:52:59 +02:00
}
2022-07-03 01:36:42 +02:00
2022-07-20 00:52:59 +02:00
function UpdateFromGithub {
param (
[ Parameter ( Mandatory ) ] [ String ] $Repository ,
[ Parameter ( Mandatory ) ] [ configFile ] $Config ,
[ scriptblock ] $AssetsFilter = { $true } ,
[ Parameter ( Mandatory ) ] [ String ] $OutFile
)
2022-07-03 01:36:42 +02:00
2022-07-20 00:52:59 +02:00
[ String ] $InstalledTag = $Config . config . version [ $Repository ]
$LatestRelease
try {
$LatestRelease = ConvertFrom-Json ( Invoke-WebRequest " https://api.github.com/repos/ $Repository /releases/latest " ) . Content
}
catch [ System.Net.WebException ] {
Write-Host " Couldn't check for update $Repository "
return $false
}
2022-07-03 01:36:42 +02:00
2022-07-20 00:52:59 +02:00
[ String ] $UpdateTag = $LatestRelease . tag_name
2022-07-03 01:36:42 +02:00
2022-07-20 00:52:59 +02:00
if ( $InstalledTag -eq $UpdateTag ) {
Write-Host " $Repository up to date! ( $InstalledTag ) "
return $false
}
2022-07-03 01:36:42 +02:00
2022-07-20 00:52:59 +02:00
$Assets = $LatestRelease . assets | Where-Object -FilterScript $AssetsFilter
2022-07-03 01:36:42 +02:00
2022-07-20 00:52:59 +02:00
Write-Host " Downloading $Repository ( $InstalledTag -> $UpdateTag ) "
Write-Host " Changelog: https://github.com/ $Repository /compare/ $InstalledTag ... $UpdateTag "
Invoke-WebRequest $Assets [ 0 ] . browser_download_url -OutFile $OutFile
$Config . config . version [ $Repository ] = $UpdateTag
$Config . save ( )
2022-07-19 18:33:03 +02:00
2022-07-20 00:52:59 +02:00
return $true
}
2022-07-03 01:36:42 +02:00
2022-11-12 00:32:27 +01:00
class CompatiblePackage {
[ String ] $name
[ String[] ] $versions
CompatiblePackage ( [ String ] $_name , [ String[] ] $_versions ) {
$this . name = $_name
$this . versions = $_versions
}
}
class Integration {
[ String ] $name
[ String ] $description
[ String ] $version
[ Bool ] $excluded
[ Bool ] $deprecated
[ String[] ] $dependencies
<# [compatiblePackage[]] #> $compatiblePackages = [ System.Collections.ArrayList ] :: new ( )
Integration ( [ String ] $_name , [ String ] $_description ) {
$this . name = $_name
$this . description = $_description
}
Integration ( $integration ) {
$this . name = $integration . name
$this . description = $integration . description
$this . version = $integration . version
$this . excluded = $integration . excluded
$this . deprecated = $integration . deprecated
$this . dependencies = $integration . dependencies
foreach ( $i in $integration . compatiblePackages ) {
[ void ] $this . compatiblePackages . Add ( [ CompatiblePackage ] :: new ( $i . name , $i . versions ) )
}
}
[ String ] ToString ( ) {
return " $( $this . name ) - $( $this . description ) "
}
[ Bool ] Compatible ( [ String ] $name , [ String ] $version ) {
if ( $this . compatiblePackages . Count -eq 0 ) { return $true }
[ compatiblePackage[] ] $compatiblePackage = $this . compatiblePackages | Where-Object { $_ . name -eq $name }
if ( $compatiblePackage . length -eq 0 ) { return $false }
return $compatiblePackage . Contains ( $version )
}
2022-11-12 01:31:18 +01:00
[ System.Collections.ArrayList ] compatiblePackageNames ( ) {
$rvalue = [ System.Collections.ArrayList ] :: new ( $this . compatiblePackages . Count )
foreach ( $i in $this . compatiblePackages ) {
[ void ] $rvalue . Add ( $i . name )
}
return $rvalue
}
2022-11-12 00:32:27 +01:00
}
class IntegrationList : System . Collections . ArrayList <# Integration #> {
IntegrationList ( $path ) {
$integration = ConvertFrom-Json ( Get-Content $path )
foreach ( $i in $integration ) {
[ void ] $this . add ( [ Integration ] :: new ( $i ) )
}
}
[ String[] ] getDependenciesNames ( [ String ] $name ) {
foreach ( $i in $this ) {
if ( $i . name -ne $name ) { continue }
$rvalue = [ System.Collections.ArrayList ] :: new ( )
foreach ( $j in $i . dependencies ) {
if ( $rvalue . Contains ( $j ) ) { continue }
[ void ] $rvalue . Add ( $j )
}
return $rvalue
}
return $null
}
[ System.Collections.ArrayList ] getFullIntegrationList ( [ String[] ] $integrations ) {
<#
. Description
Returns Integration list with all dependencies included
#>
$rvalue = [ System.Collections.ArrayList ] :: new ( $this . Count )
foreach ( $i in $integrations ) {
if ( $rvalue . Contains ( $i ) ) { continue }
[ void ] $rvalue . Add ( $i )
$dependencies = $this . getDependenciesNames ( $i )
foreach ( $j in $this . getFullIntegrationList ( $dependencies ) ) {
if ( $rvalue . Contains ( $j ) ) { continue }
[ void ] $rvalue . Add ( $j )
}
}
return $rvalue
}
[ FormItems ] getForm ( ) {
$rvalue = [ FormItems ] :: new ( )
foreach ( $i in $this ) {
[ void ] $rvalue . Add ( [ FormItem ] :: new ( $i . name , " $( $i . name ) - for $( $i . compatiblePackages [ 0 ] . name ) - $( $i . description ) " ) )
}
return $rvalue
}
2022-11-12 01:31:18 +01:00
[ FormItems ] getForm ( [ String ] $packageName ) {
$rvalue = [ FormItems ] :: new ( )
foreach ( $i in $this ) {
if ( -not $i . compatiblePackageNames ( ) . Contains ( $packageName ) ) { continue }
[ void ] $rvalue . Add ( [ FormItem ] :: new ( $i . name , " $( $i . name ) - $( $i . description ) " ) )
}
return $rvalue
}
[ System.Collections.ArrayList ] getAllCompatiblePackagesNames ( ) {
$rvalue = [ System.Collections.ArrayList ] :: new ( )
foreach ( $i in $this ) {
foreach ( $j in $i . compatiblePackages ) {
if ( $rvalue . Contains ( $j . name ) ) { continue }
[ void ] $rvalue . Add ( $j . name )
}
}
return $rvalue
}
2022-11-12 00:32:27 +01:00
}
2022-07-20 00:52:59 +02:00
function main {
$config = [ configFile ] :: new ( )
try {
$config . load ( )
2022-07-03 01:36:42 +02:00
}
2022-07-20 00:52:59 +02:00
catch [ System.IO.FileNotFoundException ] {
Write-Host " .\config.json not found "
$config . save ( )
2022-07-03 01:36:42 +02:00
}
2022-07-20 00:52:59 +02:00
# Update
2022-11-12 00:55:27 +01:00
if ( -not $NoUpdate ) {
$updatedPatches = UpdateFromGithub -Repository " revanced/revanced-patches " -Config $config -AssetsFilter { $_ . content_type -like " application/java-archive " } -OutFile " .\app\revanced-patches.jar "
if ( $updatedPatches ) {
Invoke-WebRequest " https://raw.githubusercontent.com/revanced/revanced-patches/main/patches.json " -OutFile " .\app\revanced-patches.json "
}
2022-11-12 00:32:27 +01:00
2022-11-12 00:55:27 +01:00
UpdateFromGithub -Repository " revanced/revanced-integrations " -Config $config -AssetsFilter { $_ . content_type -like " application/* " } -OutFile " .\app\app-release-unsigned.apk " | Out-Null
UpdateFromGithub -Repository " revanced/revanced-cli " -Config $config -AssetsFilter { $_ . content_type -like " application/* " } -OutFile " .\app\revanced-cli.jar " | Out-Null
}
2022-07-20 00:52:59 +02:00
2022-07-15 23:47:24 +02:00
if ( $NoDeploy ) { return }
2022-11-12 00:32:27 +01:00
# Select apk to patch
2022-07-03 01:36:42 +02:00
$apks = ( Get-ChildItem * . apk ) . Name
[ String ] $selectedApk = ''
if ( $apks . Length -eq 0 ) { throw " No YouTube apk files found! " }
2022-07-04 02:37:55 +02:00
elseif ( $apks . getType ( ) . Name -eq 'String' ) { $selectedApk = $apks }
2022-07-03 01:36:42 +02:00
else {
2022-11-12 00:32:27 +01:00
$apkItems = [ FormItems ] :: new ( )
foreach ( $i in $apks ) {
[ void ] $apkItems . Add ( [ FormItem ] :: new ( $i , $i ) )
}
$selectedApk = renderForm -items $apkItems -label " Select apk file to patch " -title " Installer for ReVanced - apk selector " -mode One
2022-07-03 01:36:42 +02:00
}
2022-07-19 18:04:03 +02:00
if ( -not $selectedApk ) { throw " No apk selected! " }
2022-07-03 01:36:42 +02:00
# Get available integrations
2022-11-12 00:32:27 +01:00
$integrations = [ IntegrationList ] :: new ( " .\app\revanced-patches.json " )
2022-07-03 01:36:42 +02:00
2022-11-12 01:31:18 +01:00
# get package name
# FIXME: How to extract package name from its apk file?
$packageNamesForm = [ FormItems ] :: new ( $integrations . getAllCompatiblePackagesNames ( ) )
$packageName = renderForm -items $packageNamesForm -label " Which package is it? " -title " Installer for ReVanced - package name " -mode One
2022-07-03 01:36:42 +02:00
# integrations selector
2022-11-12 00:32:27 +01:00
$integrationsToInclude = [ System.Collections.ArrayList ] :: new ( )
2022-11-12 01:31:18 +01:00
$integrationsForm = $integrations . getForm ( $packageName )
2022-11-12 00:32:27 +01:00
for ( $i = 0 ; $i -lt $integrationsForm . Count ; $i + + ) {
2022-11-12 01:59:22 +01:00
if ( -not $config . getIncludesForPackage ( $packageName ) . Contains ( ( $integrationsForm [ $i ] . value ) ) ) { continue }
2022-11-12 00:32:27 +01:00
$integrationsForm [ $i ] . selected = $true
2022-07-03 01:36:42 +02:00
}
2022-07-04 02:37:55 +02:00
2022-11-12 00:32:27 +01:00
$integrationsToInclude = renderForm -items $integrationsForm -label " Select integrations to include " -title " Installer for ReVanced - integrations " -mode MultiExtended
2022-07-03 01:36:42 +02:00
2022-11-12 01:59:22 +01:00
$config . setIncludesForPackage ( $packageName , $integrationsToInclude )
2022-07-20 00:52:59 +02:00
$config . save ( )
2022-07-03 01:36:42 +02:00
2022-11-12 00:32:27 +01:00
# We save only what user selected, but we still need to include integrations that depends on selected
$integrationsToInclude = $integrations . getFullIntegrationList ( $integrationsToInclude )
2022-07-03 01:36:42 +02:00
# devices
$devices = adb devices
2022-07-20 01:01:18 +02:00
if ( $devices . Length -eq 2 ) {
throw " No devices found "
}
2022-07-03 01:36:42 +02:00
$devices = $devices [ 1 . . ( $devices . length - 2 ) ]
[ String ] $selectedDevice = ''
2022-07-20 01:01:18 +02:00
if ( $devices . Length -eq 1 ) {
2022-08-04 21:58:06 +02:00
$selectedDevice = ( $devices | ForEach-Object { $_ . split ( ) [ 0 ] } )
2022-07-19 18:01:45 +02:00
}
2022-07-03 01:36:42 +02:00
else {
2022-11-12 00:32:27 +01:00
$devicesForm = [ FormItems ] :: new ( )
foreach ( $i in $devices ) {
[ void ] $devicesForm . Add ( [ FormItem ] :: new ( $i . split ( ) [ 0 ] , $i ) )
}
$selectedDevice = ( renderForm -items $devicesForm -label " Select deployment target " -title " Installer for ReVanced - target " -mode One )
2022-07-03 01:36:42 +02:00
}
2022-07-19 18:04:03 +02:00
if ( -not $selectedDevice ) { throw " No device selected " }
2022-07-03 01:36:42 +02:00
# install to device
2022-11-12 00:32:27 +01:00
$patcherArgs = [ System.Collections.ArrayList ] :: new ( 100 )
[ void ] $patcherArgs . AddRange ( ( " -jar " , " .\app\revanced-cli.jar " , " -a " , " .\ $selectedApk " , " -c " , " -d " , " $selectedDevice " , " -o " , " $env:tmp \revanced.apk " , " -m " , " .\app\app-release-unsigned.apk " , " -b " , " .\app\revanced-patches.jar " , " --exclusive " , " --experimental " ) )
2022-07-03 01:36:42 +02:00
# is microg patch excluded?
2022-11-12 00:32:27 +01:00
if ( -not $integrationsToInclude . Contains ( " microg-support " ) ) {
[ void ] $patcherArgs . Add ( " --mount " )
2022-07-03 01:36:42 +02:00
}
2022-11-12 00:32:27 +01:00
foreach ( $i in $integrationsToInclude ) {
[ void ] $patcherArgs . AddRange ( ( " -i " , $i ) )
Write-Output " Included: $i "
2022-07-03 01:36:42 +02:00
}
2022-07-04 02:38:26 +02:00
Write-Output " Logs below are from the cli "
2022-07-03 01:36:42 +02:00
execJava $patcherArgs
}
main