fix
This commit is contained in:
BIN
dist/hpl-toolbox-0.1.2.exe
vendored
BIN
dist/hpl-toolbox-0.1.2.exe
vendored
Binary file not shown.
BIN
dist/hpl-toolbox-0.1.2.vsix
vendored
BIN
dist/hpl-toolbox-0.1.2.vsix
vendored
Binary file not shown.
BIN
dist/hpl-toolbox-0.1.3.exe
vendored
BIN
dist/hpl-toolbox-0.1.3.exe
vendored
Binary file not shown.
BIN
dist/hpl-toolbox-0.1.3.vsix
vendored
BIN
dist/hpl-toolbox-0.1.3.vsix
vendored
Binary file not shown.
11
package.json
11
package.json
@@ -90,6 +90,17 @@
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"description": "Value of the __Host-APPLOVINID cookie for p.applov.in (log in at https://p.applov.in/playablePreview?create=1&qr=1 and copy the cookie from DevTools)."
|
||||
},
|
||||
"hplToolbox.applovin.delayMs": {
|
||||
"type": "number",
|
||||
"default": 5000,
|
||||
"minimum": 0,
|
||||
"description": "Delay (in milliseconds) between consecutive file uploads, to avoid AppLovin rate limiting / 403 responses."
|
||||
},
|
||||
"hplToolbox.applovin.randomizeUserAgent": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Randomize the User-Agent header on every request to p.applov.in to reduce bot detection."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -50,9 +50,30 @@ export function openApplovinUpload(_context: vscode.ExtensionContext) {
|
||||
});
|
||||
}
|
||||
|
||||
const USER_AGENTS = [
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36',
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 Edg/129.0.0.0',
|
||||
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
|
||||
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6 Safari/605.1.15',
|
||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0',
|
||||
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
|
||||
];
|
||||
|
||||
function pickUserAgent(randomize: boolean): string {
|
||||
if (!randomize) return USER_AGENTS[0];
|
||||
return USER_AGENTS[Math.floor(Math.random() * USER_AGENTS.length)];
|
||||
}
|
||||
|
||||
function sleep(ms: number): Promise<void> {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
async function handleUpload(panel: vscode.WebviewPanel, filePaths: string[]) {
|
||||
const cfg = vscode.workspace.getConfiguration('hplToolbox.applovin');
|
||||
const cookie = (cfg.get<string>('cookie') || '').trim();
|
||||
const delayMs = Math.max(0, cfg.get<number>('delayMs') ?? 1500);
|
||||
const randomizeUA = cfg.get<boolean>('randomizeUserAgent') ?? true;
|
||||
|
||||
const paths = Array.isArray(filePaths) ? filePaths : [filePaths];
|
||||
if (!paths.length) {
|
||||
@@ -60,14 +81,17 @@ async function handleUpload(panel: vscode.WebviewPanel, filePaths: string[]) {
|
||||
return;
|
||||
}
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
'Accept': 'application/json, text/javascript, */*; q=0.01',
|
||||
'Origin': 'https://p.applov.in',
|
||||
'Referer': 'https://p.applov.in/playablePreview?create=1&qr=1',
|
||||
'X-Requested-With': 'XMLHttpRequest',
|
||||
'User-Agent': 'Mozilla/5.0 (HPL-Toolbox-VSCode)',
|
||||
const buildHeaders = (): Record<string, string> => {
|
||||
const headers: Record<string, string> = {
|
||||
'Accept': 'application/json, text/javascript, */*; q=0.01',
|
||||
'Origin': 'https://p.applov.in',
|
||||
'Referer': 'https://p.applov.in/playablePreview?create=1&qr=1',
|
||||
'X-Requested-With': 'XMLHttpRequest',
|
||||
'User-Agent': pickUserAgent(randomizeUA),
|
||||
};
|
||||
if (cookie) headers['Cookie'] = `__Host-APPLOVINID=${cookie}`;
|
||||
return headers;
|
||||
};
|
||||
if (cookie) headers['Cookie'] = `__Host-APPLOVINID=${cookie}`;
|
||||
|
||||
const buildForm = (filePath: string): FormData => {
|
||||
const buf = fs.readFileSync(filePath);
|
||||
@@ -90,12 +114,17 @@ async function handleUpload(panel: vscode.WebviewPanel, filePaths: string[]) {
|
||||
if (!filePath || !fs.existsSync(filePath)) { reportError('File missing'); continue; }
|
||||
if (!/\.html?$/i.test(filePath)) { reportError('Must be .html'); continue; }
|
||||
|
||||
if (i > 0 && delayMs > 0) {
|
||||
panel.webview.postMessage({ type: 'status', message: `[${idx}/${paths.length}] Waiting ${delayMs}ms before ${fileName}...` });
|
||||
await sleep(delayMs);
|
||||
}
|
||||
|
||||
panel.webview.postMessage({ type: 'status', message: `[${idx}/${paths.length}] Validating ${fileName}...` });
|
||||
|
||||
let res: Response;
|
||||
try {
|
||||
res = await fetch('https://p.applov.in/validateHTMLContent', {
|
||||
method: 'POST', body: buildForm(filePath), headers,
|
||||
method: 'POST', body: buildForm(filePath), headers: buildHeaders(),
|
||||
});
|
||||
} catch (err: any) { reportError('Network error (validate): ' + (err?.message || err)); continue; }
|
||||
const validateText = await res.text();
|
||||
@@ -110,7 +139,7 @@ async function handleUpload(panel: vscode.WebviewPanel, filePaths: string[]) {
|
||||
|
||||
try {
|
||||
res = await fetch('https://p.applov.in/getCachedAdURL', {
|
||||
method: 'POST', body: buildForm(filePath), headers,
|
||||
method: 'POST', body: buildForm(filePath), headers: buildHeaders(),
|
||||
});
|
||||
} catch (err: any) { reportError('Network error (cache): ' + (err?.message || err)); continue; }
|
||||
const cacheText = await res.text();
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
urlpkg "net/url"
|
||||
@@ -12,8 +13,26 @@ import (
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var applovinUserAgents = []string{
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 Edg/129.0.0.0",
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6 Safari/605.1.15",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0",
|
||||
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
|
||||
}
|
||||
|
||||
func pickApplovinUserAgent(randomize bool) string {
|
||||
if !randomize {
|
||||
return applovinUserAgents[0]
|
||||
}
|
||||
return applovinUserAgents[rand.Intn(len(applovinUserAgents))]
|
||||
}
|
||||
|
||||
func ApplovinPage(w http.ResponseWriter, r *http.Request) {
|
||||
body := `
|
||||
<h2>AppLovin Playable Preview (QR)</h2>
|
||||
@@ -237,7 +256,16 @@ func ApplovinUpload(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
cookie := LoadConfig().Applovin.Cookie
|
||||
cfg := LoadConfig().Applovin
|
||||
cookie := cfg.Cookie
|
||||
delayMs := cfg.DelayMs
|
||||
if delayMs < 0 {
|
||||
delayMs = 0
|
||||
}
|
||||
randomizeUA := true
|
||||
if cfg.RandomizeUserAgent != nil {
|
||||
randomizeUA = *cfg.RandomizeUserAgent
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/x-ndjson")
|
||||
flusher, _ := w.(http.Flusher)
|
||||
@@ -282,7 +310,7 @@ func ApplovinUpload(w http.ResponseWriter, r *http.Request) {
|
||||
req.Header.Set("Origin", "https://p.applov.in")
|
||||
req.Header.Set("Referer", "https://p.applov.in/playablePreview?create=1&qr=1")
|
||||
req.Header.Set("X-Requested-With", "XMLHttpRequest")
|
||||
req.Header.Set("User-Agent", "Mozilla/5.0 (HPL-Toolbox-Standalone)")
|
||||
req.Header.Set("User-Agent", pickApplovinUserAgent(randomizeUA))
|
||||
if cookie != "" {
|
||||
req.Header.Set("Cookie", "__Host-APPLOVINID="+cookie)
|
||||
}
|
||||
@@ -311,6 +339,11 @@ func ApplovinUpload(w http.ResponseWriter, r *http.Request) {
|
||||
continue
|
||||
}
|
||||
|
||||
if i > 0 && delayMs > 0 {
|
||||
send(map[string]any{"type": "status", "message": fmt.Sprintf("[%d/%d] Waiting %dms before %s...", idx, len(req.Paths), delayMs, fileName)})
|
||||
time.Sleep(time.Duration(delayMs) * time.Millisecond)
|
||||
}
|
||||
|
||||
send(map[string]any{"type": "status", "message": fmt.Sprintf("[%d/%d] Validating %s...", idx, len(req.Paths), fileName)})
|
||||
|
||||
body, ct, err := buildForm(filePath)
|
||||
|
||||
Binary file not shown.
@@ -19,7 +19,7 @@ import (
|
||||
var currentHwnd atomic.Uintptr
|
||||
|
||||
func setupFileLogging() {
|
||||
logPath := filepath.Join(appDir(), "debug.log")
|
||||
logPath := filepath.Join(userDataDir(), "debug.log")
|
||||
f, err := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
|
||||
if err != nil {
|
||||
return
|
||||
@@ -57,9 +57,16 @@ func main() {
|
||||
}
|
||||
defer removeLockFile()
|
||||
|
||||
webviewTmp, err := os.MkdirTemp("", "hpltoolbox-wv2-*")
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create webview temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(webviewTmp)
|
||||
|
||||
w := webview.NewWithOptions(webview.WebViewOptions{
|
||||
Debug: false,
|
||||
AutoFocus: true,
|
||||
DataPath: webviewTmp,
|
||||
WindowOptions: webview.WindowOptions{
|
||||
Title: "HPL Toolbox",
|
||||
Width: 1100,
|
||||
|
||||
@@ -18,7 +18,9 @@ type PlecConfig struct {
|
||||
}
|
||||
|
||||
type ApplovinConfig struct {
|
||||
Cookie string `json:"cookie"`
|
||||
Cookie string `json:"cookie"`
|
||||
DelayMs int `json:"delayMs"`
|
||||
RandomizeUserAgent *bool `json:"randomizeUserAgent,omitempty"`
|
||||
}
|
||||
|
||||
type SendToMobileConfig struct {
|
||||
@@ -38,6 +40,23 @@ type AppConfig struct {
|
||||
|
||||
var configMu sync.Mutex
|
||||
|
||||
// userDataDir returns %LOCALAPPDATA%\HPLToolbox, creating it if needed.
|
||||
// All mutable app files (config, lock, logs, WebView2 cache) live here so
|
||||
// they are never placed next to the executable, which may be on a synced or
|
||||
// antivirus-watched drive and would cause message-loop stalls.
|
||||
func userDataDir() string {
|
||||
local := os.Getenv("LOCALAPPDATA")
|
||||
if local == "" {
|
||||
local = os.Getenv("APPDATA")
|
||||
}
|
||||
if local == "" {
|
||||
return appDir()
|
||||
}
|
||||
dir := filepath.Join(local, "HPLToolbox")
|
||||
_ = os.MkdirAll(dir, 0755)
|
||||
return dir
|
||||
}
|
||||
|
||||
func defaultConfig() AppConfig {
|
||||
return AppConfig{
|
||||
Plec: PlecConfig{
|
||||
@@ -46,7 +65,7 @@ func defaultConfig() AppConfig {
|
||||
PreviewBase: "https://playable.applovindemo.com/phaser/",
|
||||
SkipExistsCheck: false,
|
||||
},
|
||||
Applovin: ApplovinConfig{Cookie: ""},
|
||||
Applovin: ApplovinConfig{Cookie: "", DelayMs: 5000},
|
||||
SendToMobile: SendToMobileConfig{Port: 0},
|
||||
DailyUpdate: DailyUpdateConfig{LastProject: ""},
|
||||
}
|
||||
@@ -72,7 +91,7 @@ func appDir() string {
|
||||
}
|
||||
|
||||
func configPath() string {
|
||||
return filepath.Join(appDir(), "config.json")
|
||||
return filepath.Join(userDataDir(), "config.json")
|
||||
}
|
||||
|
||||
func LoadConfig() AppConfig {
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
)
|
||||
|
||||
func lockFilePath() string {
|
||||
return filepath.Join(appDir(), ".hpltoolbox.lock")
|
||||
return filepath.Join(userDataDir(), ".hpltoolbox.lock")
|
||||
}
|
||||
|
||||
// focusExistingInstance returns true if another instance was found and
|
||||
|
||||
Reference in New Issue
Block a user