's'
This commit is contained in:
@@ -142,6 +142,13 @@ type Props = {
|
|||||||
const SCRCPY_URL = "https://github.com/Genymobile/scrcpy";
|
const SCRCPY_URL = "https://github.com/Genymobile/scrcpy";
|
||||||
const ESCRCPY_URL = "https://github.com/viarotel-org/escrcpy";
|
const ESCRCPY_URL = "https://github.com/viarotel-org/escrcpy";
|
||||||
|
|
||||||
|
/** 与 LiveControlApp 一致:apiBase 为空时用根相对路径(同域 FastAPI 托管静态页)。 */
|
||||||
|
function apiUrl(apiBase: string, path: string): string {
|
||||||
|
const p = path.startsWith("/") ? path : `/${path}`;
|
||||||
|
const b = (apiBase || "").trim().replace(/\/$/, "");
|
||||||
|
return b ? `${b}${p}` : p;
|
||||||
|
}
|
||||||
|
|
||||||
export function LiveAndroidStreamConsole({
|
export function LiveAndroidStreamConsole({
|
||||||
t,
|
t,
|
||||||
apiBase,
|
apiBase,
|
||||||
@@ -188,10 +195,9 @@ export function LiveAndroidStreamConsole({
|
|||||||
const activeTransport = devices.find((d) => d.serial === serial)?.transport;
|
const activeTransport = devices.find((d) => d.serial === serial)?.transport;
|
||||||
const useFastShot = liveMs > 0;
|
const useFastShot = liveMs > 0;
|
||||||
|
|
||||||
const shotUrl =
|
const shotUrl = serial
|
||||||
apiBase && serial
|
? `${apiUrl(apiBase, "/android/screenshot")}?serial=${encodeURIComponent(serial)}&ts=${frameTs}${useFastShot ? "&fast=1" : ""}`
|
||||||
? `${apiBase}/android/screenshot?serial=${encodeURIComponent(serial)}&ts=${frameTs}${useFastShot ? "&fast=1" : ""}`
|
: "";
|
||||||
: "";
|
|
||||||
|
|
||||||
const bumpFrame = useCallback(() => {
|
const bumpFrame = useCallback(() => {
|
||||||
setFrameTs((n) => n + 1);
|
setFrameTs((n) => n + 1);
|
||||||
@@ -230,7 +236,9 @@ export function LiveAndroidStreamConsole({
|
|||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
void (async () => {
|
void (async () => {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`${apiBase}/android/display_metrics?serial=${encodeURIComponent(serial)}`);
|
const res = await fetch(
|
||||||
|
`${apiUrl(apiBase, "/android/display_metrics")}?serial=${encodeURIComponent(serial)}`,
|
||||||
|
);
|
||||||
const data = (await res.json()) as { width?: number; height?: number };
|
const data = (await res.json()) as { width?: number; height?: number };
|
||||||
if (!res.ok || cancelled) return;
|
if (!res.ok || cancelled) return;
|
||||||
if (typeof data.width === "number" && typeof data.height === "number") {
|
if (typeof data.width === "number" && typeof data.height === "number") {
|
||||||
@@ -259,7 +267,7 @@ export function LiveAndroidStreamConsole({
|
|||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
void (async () => {
|
void (async () => {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`${apiBase}/android/scrcpy/info`);
|
const res = await fetch(apiUrl(apiBase, "/android/scrcpy/info"));
|
||||||
const data = (await res.json()) as {
|
const data = (await res.json()) as {
|
||||||
server_jar?: boolean;
|
server_jar?: boolean;
|
||||||
adb_ok?: boolean;
|
adb_ok?: boolean;
|
||||||
|
|||||||
25
web.py
25
web.py
@@ -216,6 +216,28 @@ def _pro_script_head(pm2: str) -> Optional[str]:
|
|||||||
return head.lower() if head else None
|
return head.lower() if head else None
|
||||||
|
|
||||||
|
|
||||||
|
def _resolve_pro_style_script(head_l: str) -> Optional[str]:
|
||||||
|
"""多频道 / Electron 风格 PM2 名前缀(如 youtube2__、tiktok_live__)映射到仓库内脚本。
|
||||||
|
|
||||||
|
不能仅用 stem 相等判断:youtube2 != youtube.py 的 stem「youtube」。
|
||||||
|
"""
|
||||||
|
if not head_l:
|
||||||
|
return None
|
||||||
|
h = head_l.lower()
|
||||||
|
py_scripts = [p["script"] for p in PROCESS_MONITOR if str(p.get("script", "")).endswith(".py")]
|
||||||
|
matches: list[str] = []
|
||||||
|
if h.startswith("douyin_youtube"):
|
||||||
|
matches = [s for s in py_scripts if Path(s).stem.lower().startswith("douyin_youtube")]
|
||||||
|
elif h.startswith("youtube"):
|
||||||
|
matches = [s for s in py_scripts if Path(s).stem.lower().startswith("youtube")]
|
||||||
|
elif h.startswith("tiktok"):
|
||||||
|
matches = [s for s in py_scripts if Path(s).stem.lower().startswith("tiktok")]
|
||||||
|
if not matches:
|
||||||
|
return None
|
||||||
|
matches.sort(key=lambda s: (len(Path(s).stem), s))
|
||||||
|
return matches[0]
|
||||||
|
|
||||||
|
|
||||||
def script_for_pm2_or_pro(pm2: str) -> Optional[str]:
|
def script_for_pm2_or_pro(pm2: str) -> Optional[str]:
|
||||||
s = script_for_pm2(pm2)
|
s = script_for_pm2(pm2)
|
||||||
if s:
|
if s:
|
||||||
@@ -223,6 +245,9 @@ def script_for_pm2_or_pro(pm2: str) -> Optional[str]:
|
|||||||
head_l = _pro_script_head(pm2)
|
head_l = _pro_script_head(pm2)
|
||||||
if not head_l:
|
if not head_l:
|
||||||
return None
|
return None
|
||||||
|
resolved = _resolve_pro_style_script(head_l)
|
||||||
|
if resolved:
|
||||||
|
return resolved
|
||||||
for p in PROCESS_MONITOR:
|
for p in PROCESS_MONITOR:
|
||||||
if Path(p["script"]).stem.lower() == head_l:
|
if Path(p["script"]).stem.lower() == head_l:
|
||||||
return p["script"]
|
return p["script"]
|
||||||
|
|||||||
Reference in New Issue
Block a user