Repository navigation
Example Walkthrough zh TW
逐步說明 YouTube 範例 怎麼運作。提到的 API 都在 docs/lua-api.md。以下程式碼是節錄。
加入範例之後(執行範例腳本),它就在手機上了。VS Code 連線之後(第一支腳本),它會同步到本機資料夾的 youtube-rickroll/,可以像其他腳本一樣修改、按 F5 執行。
"display": { "width": 720, "height": 1280, "densityDpi": 320, "keyboard": false }腳本有自己的 720×1280 虛擬顯示器。keyboard: false 讓手機的輸入法不綁定這個顯示器上的 app,input.text 送出的按鍵才會照原樣輸入,不會被注音之類的輸入法組成中文字(Android 12 以上)。
程式裡沒有寫死任何座標:全部從 screen.width、screen.height 或比對結果推算,換成別的顯示器尺寸也能跑。
app.launch("com.google.android.youtube")
input.key(KEYCODE_SEARCH)
local _, hit = vision.wait_any({
{ text = "搜尋", roi = search_bar },
{ text = "Search", roi = search_bar },
}, 3000)-
app.launch在腳本的顯示器上啟動 YouTube。 - YouTube 可能停在上次的任何一頁,所以腳本不找搜尋按鈕,而是用
input.key送搜尋鍵,在哪一頁都會打開搜尋。冷啟動時按鍵可能被吃掉,所以最多重試五次。 -
vision.wait_any等其中任一個請求先命中。兩個都是text請求,用 OCR 找中文或英文的字。roi只辨識畫面左上角:整張辨識很慢,而右半邊可能被縮小播放器蓋住。
input.text("rick astley never gonna give you up\n")input.text 把 ASCII 字串輸入到目前有焦點的欄位,結尾的 \n 等於按 Enter。
video = vision.wait({ text = "Rick Astley - Never Gonna", roi = below_search }, 10000, 1000)
input.swipe({ W // 2, H * 3 // 4, W // 2, H // 4 }, 400)
input.tap(video.cx, video.cy)- 搜尋結果最上面常是廣告,所以腳本找官方 MV 的標題(歌手 - 歌名),而不是點第一個結果。
-
vision.wait的第三個參數是step_ms:每秒最多辨識一次,不必每張影格都跑,因為 OCR 很耗運算。 - 畫面上沒有標題時,用
input.swipe往下捲再找。 - 命中結果的
cx、cy是那段文字的中心點,直接給input.tap。
local AD_SIGNS = {
{ text = "略過", exact = true, roi = PLAYER },
{ text = "Skip ad", exact = true, roi = PLAYER },
-- …
{ text = "贊助商廣告", roi = PLAYER },
}
local idx, hit = vision.find_any(AD_SIGNS)vision.find_any 對最新的影格比對一次,回傳第一個命中的索引。略過按鈕排在前面,命中它們就點下去;命中「贊助商廣告」代表廣告還在播。exact = true 要求整行相同,倒數文字「您可以在 5 秒後略過廣告」才不會被當成按鈕。連續三秒都沒有廣告才往下走。
for _, line in ipairs(vision.read_lines({ 0, PLAYER_H // 2, W, PLAYER_H // 2 })) do
local now, total = line.text:match("(%d+:%d+)%s*/%s*(%d+:%d+)")點一下播放器叫出控制列後,vision.read_lines 回傳播放器下半部的每一行文字,再用 Lua pattern 取出 0:12 / 3:33。總長不到一分鐘代表讀到的是廣告的時間,略過不用。
input.down(1, from_x, y)
for step = 1, 10 do
sleep(30)
input.move(1, from_x + (to_x - from_x) * step // 10, y)
end
input.up(1)input.down、input.move、input.up 逐步控制一根手指(pointer 1),這是一次 swipe 做不到的。YouTube 的進度條是相對拖曳,所以手指從目前的位置按下,移動到目標的距離。
local reading = vision.read({ label.x - 8, label.y - 4, label.w + 40, label.h + 8 })
data.set("position", result)
data.set("status", "never gonna give you up")vision.read 把一個小框當成單一行直接辨識,比先偵測再辨識更快也更準。框是第 5 步找到的時間標籤,放寬一點因為數字會變長。時間與目標差 10 秒內就用 data.set 記下來,App 和 VS Code 的「腳本發佈的資料」都看得到。第 4 到第 7 步隨時可能被廣告打斷,所以整段最多重試三次。
local function fail(reason)
data.set("status", reason)
device.notify("YouTube 範例", reason)
error(reason)
end每個放棄的地方都呼叫 fail:記下原因,用 device.notify 發通知,再用 error 結束腳本,App 就會顯示「錯誤:」加上原因。
English
正體中文