DanGough / Nevergreen

This module is an alternative to Evergreen, and allows you to find the latest version and download URL for various Windows apps. Evergreen uses API queries to obtain its data whereas this module is more focussed on web scraping. This is more prone to breaking when websites are changed, hence the name.
The Unlicense
71 stars 16 forks source link

TikTok Effect House [New App Request] #54

Closed AScott-WWF closed 3 months ago

AScott-WWF commented 8 months ago

I would like to be able to screen scrape the Tiktok Effects House downloads page to obtain the URL for the latest version download

Download URL : "https://effecthouse.tiktok.com/download" Release Notes : "https://effecthouse.tiktok.com/latest/release-notes-latest/"

I have managed to read the latest version number (from the Release Notes page), but have so far been unable to find the installer URL from the downloads page - this is what I have acheived so far with the following Powershell:

[cmdletbinding()]
Param()

Clear-Host
Write-Verbose "Setting Arguments" -Verbose

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

$DetectionMethod = "Webscrape"
$AppName = "TikTokEffectHouse"
$Application = "TikTok Effect House"
#$Arch = "x64"
$AppType = "EXE"
$AppInstaller = "Effect_House_Setup.exe"
$InstallPath = "$($env:LOCALAPPDATA)\Effect House\Effect House.exe"
$DownloadsURL = "https://effecthouse.tiktok.com/download"
$ReleaseNotes = "https://effecthouse.tiktok.com/latest/release-notes-latest/"

# $PSScriptRoot should always be something like C:\Users\FSmith\gitrepos\Intune\Admin\Scripts.
# Our Base folder should be 'Intune', or 2 levels up.
$BaseFolder = "$PSScriptRoot\..\.."
$AllAppsFolder = ".\Apps"
$PrepToolExe = ".\Microsoft-Win32-Content-Prep-Tool-1.8.4\IntuneWinAppUtil.exe"

$StartTime = Get-Date

Write-Verbose "Finding installed version" -Verbose
# Check if App is installed and if it is get version
if (Test-Path -Path $InstallPath) {
    [version]$InstalledVersion = (Get-ItemProperty $InstallPath).VersionInfo.FileVersion
    Write-Host "Installed version of $($Application) is: $($InstalledVersion)"
} else {
    Write-Host "WARNING :: $($Application) is not installed" -ForegroundColor Red
}

Write-Verbose "Using $($DetectionMethod) to check for latest version from: $($ReleaseNotes)..." -Verbose
try {
    # $Web = Invoke-WebRequest -UseBasicParsing -Uri $DownloadsUrl -ErrorAction SilentlyContinue
    $Web = Invoke-WebRequest -UseBasicParsing -Uri $ReleaseNotes -ErrorAction SilentlyContinue
}
catch {
    Throw "Failed to connect to URL: $ReleaseNotes with error $_."
    Break
}
finally {
# Luckily, although this web page covers a major release it only seems to have active links to the very latest update.
# So we can determine the latest version by searching for specific text in the page...
    $PageContent = ($Web.Content)
    $SearchString = "</style><h2 class=`"css-ov5iey e15xsn0a4`">v"
    $CaptureStart = $PageContent.IndexOf($SearchString) + $SearchString.Length
    $EndIndex = $PageContent.IndexOf(" (", $CaptureStart) - $CaptureStart
    $Version = ($PageContent.Substring($CaptureStart, $EndIndex).Trim()) -replace "\.","-"
    [version]$LatestVersion = ($PageContent.Substring($CaptureStart, $EndIndex).Trim()) -replace "-","."
}

Write-Output "Latest version of $($Application) is:          $($LatestVersion)"

Write-Verbose "Using $($DetectionMethod) to find latest version download from: $($DownloadsURL)..." -Verbose
try {
    # $Web = Invoke-WebRequest -UseBasicParsing -Uri $DownloadsUrl -ErrorAction SilentlyContinue
    $Download = Invoke-WebRequest -UseBasicParsing -Uri $DownloadsURL -ErrorAction SilentlyContinue
}
catch {
    Throw "Failed to connect to URL: $DownloadsURL with error $_."
    Break
}
finally {
# This web page only seems to have an active link to the very latest update - obscured by CSS.
# So we need to determine the latest version download by searching within the links on the page...
    $DownloadContent = (($Download.Links | Where-Object {$_.href -eq "/download"}).outerHTML)
    <#
    $SourceUrl = "" # To be read from page ?
    #>
    # Current Download URL for v3.3.2.87 has been obtained in a browser:
    $SourceUrl = "https://sf16-va.tiktokcdn.com/obj/eden-va2/olaa_ajlmml_zlp/ljhwZthlaukjlkulzlp/V332_External_Release_0927/Effect_House_v3.3.2.87_101_Setup.exe"
}

<#
Other code...
N.B. Includes setting path to $Outfile
#>

# New Version available, so open Release Notes
$ReleaseNotesURL = "https://effecthouse.tiktok.com/effect-platform/latest/release-notes-latest/v$($version)/?enter_method=category_card"
Write-Output ""
Write-Host "New version $($LatestVersion) has been released, Opening release notes in default browser..." -ForegroundColor DarkGreen
Start-Process $ReleaseNotesURL
Write-Output ""

# Download the latest Installer
Write-Output ""
Write-Output "Downloading $($Application) $($LatestVersion) from $($SourceUrl)..."
$ProgressPreference = 'SilentlyContinue'
Invoke-WebRequest -Uri $SourceUrl -OutFile $Outfile
ThatDraggyCodes commented 3 months ago

Did some digging. My conclusion: There is no simple download link that's reconstructable just from the website.

One can get the File-Data using the same POST request as the downloadbutton does:

$uri = 'https://effecthouse.tiktok.com/api/web/download'
$blob = Invoke-RestMethod -Method Post -Uri $uri -Body @{osType='windows';}
$blob | Out-File 'Installer.exe'  # Not sure what file ending...

(Note: I left out the entryPoint="101" parameter that the website also sends additionally to the osType)

This will give you a blob containing the installer for Windows, but not the download link.

Using Invoke-WebRequest one could get the binary data plus extra data and applying some lines of the Resolve-Uri CMDLet from Nevergreen will give you the download link, but at this point the setup has already been downloaded.

$a = Invoke-WebRequest -Method Post -Uri $uri -Body @{osType='windows';}
$a.BaseResponse.RequestMessage.RequestUri.AbsoluteUri

would result in something like

https://sf16-va.tiktokcdn.com/obj/eden-va2/olaa_ajlmml_zlp/ljhwZthlaukjlkulzlp/V383_ExternalRelease_0306/Effect_House_v3.8.3.30_101_Setup.exe

I don't think this approach is feasable for this project, unless one could send that post request without getting the contents and just analyze the BaseResponse to get the Download-URL. I wnated to share my findings anyway.

Extra Infos Here's the form-Element I got via my Browsers debug tool. Wasn't able to find it in the sourcecode view of the website though. Maybe it got added to the DOM via JS? But that's where I got the POST-request data from. ```html
ttep_download_banner_btn_mac
``` Please ignore the darkreader stuff, that's from a browser addon. Also I blocked some scripts, therefore the website couldn't apply it's localization. Meaning that `ttep_download_page_download_pc_btn` my not be available for search.
AScott-WWF commented 3 months ago

Thanks, I'd forgotten I'd raised this. We abandoned this software as it does not have any silent / unattended command line switches which made it impossible to deploy to users in an automated manner. If TikTok ever fix that we may revisit.

DanGough commented 3 months ago

Sorry I didn't respond to this earlier, but looks like I can close it now anyway!