Skip to content

Example Walkthrough zh TW

Martin edited this page Oct 12, 2026 · 1 revision

範例解說

逐步說明 YouTube 範例 怎麼運作。提到的 API 都在 docs/lua-api.md。以下程式碼是節錄。

在 VS Code 裡打開

加入範例之後(執行範例腳本),它就在手機上了。VS Code 連線之後(第一支腳本),它會同步到本機資料夾的 youtube-rickroll/,可以像其他腳本一樣修改、按 F5 執行。

script.json:自己的顯示器

"display": { "width": 720, "height": 1280, "densityDpi": 320, "keyboard": false }

腳本有自己的 720×1280 虛擬顯示器。keyboard: false 讓手機的輸入法不綁定這個顯示器上的 app,input.text 送出的按鍵才會照原樣輸入,不會被注音之類的輸入法組成中文字(Android 12 以上)。

程式裡沒有寫死任何座標:全部從 screen.width、screen.height 或比對結果推算,換成別的顯示器尺寸也能跑。

1. 打開搜尋

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 只辨識畫面左上角:整張辨識很慢,而右半邊可能被縮小播放器蓋住。

2. 輸入關鍵字

input.text("rick astley never gonna give you up\n")

input.text 把 ASCII 字串輸入到目前有焦點的欄位,結尾的 \n 等於按 Enter。

3. 找到影片

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。

4. 略過廣告

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 秒後略過廣告」才不會被當成按鈕。連續三秒都沒有廣告才往下走。

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。總長不到一分鐘代表讀到的是廣告的時間,略過不用。

6. 拖曳進度條

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 的進度條是相對拖曳,所以手指從目前的位置按下,移動到目標的距離。

7. 確認並記錄

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 就會顯示「錯誤:」加上原因。

Clone this wiki locally