57 lines
3.0 KiB
Python
57 lines
3.0 KiB
Python
"""Use the Windows folder picker without shipping Tcl/Tk."""
|
|
from __future__ import annotations
|
|
import base64
|
|
import json
|
|
import os
|
|
import subprocess
|
|
|
|
|
|
def pick_folder(current):
|
|
from host.bundle import installation_root
|
|
installed = installation_root()
|
|
if installed:
|
|
encoded = base64.b64encode(json.dumps(current or "").encode("utf-8")).decode("ascii")
|
|
result = subprocess.run([str(installed / "YouTubeDL-Manager.exe"), "--pick-folder", "--initial-folder", encoded],
|
|
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=600,
|
|
creationflags=subprocess.CREATE_NO_WINDOW)
|
|
if result.returncode:
|
|
raise ValueError("Не удалось открыть окно выбора папки Windows.")
|
|
return json.loads(result.stdout.strip().lstrip("\ufeff"))
|
|
if os.name != "nt":
|
|
import tkinter
|
|
from tkinter import filedialog
|
|
root = tkinter.Tk()
|
|
try:
|
|
root.withdraw(); root.attributes("-topmost", True)
|
|
return filedialog.askdirectory(initialdir=current or "", mustexist=True) or None
|
|
finally:
|
|
root.destroy()
|
|
# Only base64 data is substituted; paths are never interpolated into shell code.
|
|
encoded = base64.b64encode(json.dumps(current or "").encode("utf-8")).decode("ascii")
|
|
script = """
|
|
$ErrorActionPreference='Stop'
|
|
[Console]::OutputEncoding=[Text.UTF8Encoding]::new()
|
|
Add-Type -AssemblyName System.Windows.Forms
|
|
$taskDialog=[Windows.Forms.FolderBrowserDialog]::new()
|
|
$taskOwner=[Windows.Forms.Form]::new()
|
|
try {
|
|
$taskOwner.TopMost=$true; $taskOwner.ShowInTaskbar=$false; $taskOwner.Opacity=0
|
|
$taskDialog.Description='YouTubeDL — папка сохранения'
|
|
$taskDialog.ShowNewFolderButton=$true
|
|
$taskDialog.SelectedPath=([Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('ENCODED')) | ConvertFrom-Json)
|
|
$taskOwner.Show()
|
|
$taskChosen=$null
|
|
if($taskDialog.ShowDialog($taskOwner) -eq [Windows.Forms.DialogResult]::OK){$taskChosen=$taskDialog.SelectedPath}
|
|
ConvertTo-Json -InputObject $taskChosen -Compress
|
|
} finally {$taskDialog.Dispose();$taskOwner.Dispose()}
|
|
""".replace("ENCODED", encoded)
|
|
argument = base64.b64encode(script.encode("utf-16le")).decode("ascii")
|
|
powershell = os.path.join(os.environ.get("SystemRoot", r"C:\Windows"), "System32", "WindowsPowerShell", "v1.0", "powershell.exe")
|
|
result = subprocess.run([powershell, "-NoProfile", "-ExecutionPolicy", "Bypass", "-STA", "-EncodedCommand", argument],
|
|
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=600,
|
|
creationflags=subprocess.CREATE_NO_WINDOW,
|
|
env={**os.environ, "PSModulePath": os.path.join(os.path.dirname(powershell), "Modules")})
|
|
if result.returncode:
|
|
raise ValueError("Не удалось открыть окно выбора папки Windows.")
|
|
return json.loads(result.stdout.strip().lstrip("\ufeff"))
|