【趣味連載】攻城獅上傳視頻與普通人上傳視頻:(一)生成結(jié)構(gòu)化數(shù)據(jù)

背景

當(dāng)知道要上傳的視頻資料從20條變成100條時(shí)跟衅,我就明白谤饭,絕對(duì)不能再人工處理了年枕。他們總是想當(dāng)然的認(rèn)為炫欺,錄入一條數(shù)據(jù)需要1分鐘,那錄入20條數(shù)據(jù)就是20分鐘熏兄,錄入100條數(shù)據(jù)品洛,不就是100分鐘嗎?我有時(shí)候霍弹,真的很想問問他們毫别,沒有考慮過人是會(huì)犯錯(cuò)的嗎娃弓?數(shù)據(jù)越多典格,出錯(cuò)的可能就越大;但是數(shù)據(jù)本身台丛,又是不允許出現(xiàn)紕漏的耍缴。那拿什么去保證數(shù)據(jù)的正確性?刷臉?可能嗎挽霉?

大多數(shù)時(shí)候防嗡,類似的爭論,最終幾乎總是會(huì)以他們的一句“我不懂技術(shù)侠坎,你們看著辦吧”結(jié)束蚁趁。所以,也懶得去做口舌之爭实胸。我盡力盡快做他嫡;但是你承不承認(rèn)事情本身的復(fù)雜度,并不會(huì)影響事情本身的復(fù)雜度庐完。

回到問題本身钢属,究竟如何處理新到來的100條數(shù)據(jù)以及以后更多的數(shù)據(jù),確實(shí)是一個(gè)必須想辦法徹底解決下的問題门躯。

我拿到的原始數(shù)據(jù)

此處適當(dāng)象征性的描述下我拿到的數(shù)據(jù)淆党。以下討論,單以 10 條數(shù)據(jù)為例讶凉。

一個(gè) word 文檔染乌,是一組問題。

內(nèi)容假定是:

1.【smart-transform】取自 Atom 的 babeljs&coffeescript&typescript 智能轉(zhuǎn) es5 庫
2.【YFMemoryLeakDetector】人人都能理解的 iOS 內(nèi)存泄露檢測工具類
3.【玩轉(zhuǎn)樹莓派】使用 sinopia 搭建私有 npm 服務(wù)器
4.【小技巧解決大問題】使用 frp 突破阿里云主機(jī)無彈性公網(wǎng) IP 不能用作 Web 服務(wù)器的限制
5.【樹莓派自動(dòng)化應(yīng)用實(shí)例】整點(diǎn)提醒自己休息五分鐘
6. 借助 frp 隨時(shí)隨地訪問自己的樹莓派
7.【LuaJIT版】從零開始在 macOS 上配置 Lua 開發(fā)環(huán)境
8.【最新版】從零開始在 macOS 上配置 Lua 開發(fā)環(huán)境
9. 關(guān)于混合應(yīng)用開發(fā)的未來的一些思考
10.記錄我發(fā)現(xiàn)的第一個(gè)關(guān)于 Google 的 Bug

是的懂讯,內(nèi)容中還有各種中文標(biāo)點(diǎn)荷憋。他們有相當(dāng)一部分人不理解攻城獅為什么喜歡用英文標(biāo)點(diǎn),甚至還有人以此為由說我們小學(xué)標(biāo)點(diǎn)符號(hào)沒學(xué)好域醇。懶得解釋那么多台谊,但是既然給出來了蓉媳,作為純文本,也不用管這么多锅铅,照單全收就行了酪呻。符號(hào)習(xí)慣問題本身,也是一個(gè)無傷大雅的問題盐须。

另一個(gè) word 文檔玩荠,是一組問題對(duì)應(yīng)的 Luis 語義分析結(jié)果

微軟的 Luis 語義分析服務(wù),勉強(qiáng)算是和人工智能沾點(diǎn)邊吧贼邓,感興趣的請(qǐng)自行了解下阶冈。從客戶端角度來說,你給它一個(gè)文本字符串塑径,他們分析出來和這個(gè)字符串匹配度最高的某個(gè)預(yù)錄入的答案的唯一標(biāo)記女坑。每個(gè)唯一標(biāo)記 ID,被稱作一個(gè) intent统舀。每次請(qǐng)求匆骗,最多只有一個(gè)匹配度最高的 intent。

感覺已經(jīng)有的 word 問題誉简,我們的后端小伙伴碉就,送來了另一個(gè) word 文檔:

1. smart_transform
2. memory_leakDetector
3. sinopia_npm
4. frp_ip
5. tip_rest
6. frp_anywhere
7. luajit_macos
8. lua_macos
9. app_future
10. google_bug

又是非結(jié)構(gòu)化的數(shù)據(jù)。顯而易見闷串,我們可愛的后端同學(xué)瓮钥,只是簡單完成了錄入,自己沒有做必要的單元測試烹吵。這是在等著我去發(fā)現(xiàn)問題啊碉熄。很久很久以前,我總是幻想著年叮,所有的攻城獅具被,必然都是各種自動(dòng)化測試用例,就像樹上寫的各種敏捷只损,各種快速迭代一姿。事實(shí)上,我見到的許多所謂的敏捷式開發(fā)跃惫,最終其實(shí)只是把成本后置叮叹,各種技術(shù)債。出來混爆存,真的遲早是要換的蛉顽。100個(gè)問題,逐一去驗(yàn)證先较,真的是很耗費(fèi)時(shí)間的携冤,而且最終有問題的悼粮,數(shù)量也不會(huì)太多。也就說說曾棕,如果手動(dòng)去做扣猫,很有可能尋找問題的時(shí)間,要遠(yuǎn)遠(yuǎn)大于發(fā)現(xiàn)問題的時(shí)間翘地。所以申尤,自動(dòng)化批量測試,是顯而易見的衙耕。根據(jù)不同的場景和需要昧穿,快速構(gòu)建基本夠用的批量自動(dòng)化測試工具鏈,應(yīng)該成為每個(gè)攻城獅的必修課橙喘。

一組勉強(qiáng)算是有規(guī)律的分文件夾放置的視頻

我依然是象征性的描述下时鸵,結(jié)構(gòu)類似于:

/videos/樹莓派/【smart-transform】取自 Atom 的 babeljs&coffeescript&typescript 智能轉(zhuǎn) es5 庫.mp4
/videos/樹莓派/【YFMemoryLeakDetector】人人都能理解的 iOS 內(nèi)存泄露檢測工具類.mp4
/videos/樹莓派/【玩轉(zhuǎn)樹莓派】使用 sinopia 搭建私有 npm 服務(wù)器.mp4
/videos/樹莓派/【小技巧解決大問題】使用 frp 突破阿里云主機(jī)無彈性公網(wǎng) IP 不能用作 Web 服務(wù)器的限制.mp4
/videos/frp/【樹莓派自動(dòng)化應(yīng)用實(shí)例】整點(diǎn)提醒自己休息五分鐘.mp4
/videos/frp/借助 frp 隨時(shí)隨地訪問自己的樹莓派.mp4
/videos/Lua/【LuaJIT版】從零開始在 macOS 上配置 Lua 開發(fā)環(huán)境.mp4
/videos/Lua/【最新版】從零開始在 macOS 上配置 Lua 開發(fā)環(huán)境.mp4
/videos/Lua/關(guān)于混合應(yīng)用開發(fā)的未來的一些思考.mp4
/videos/Lua/記錄我發(fā)現(xiàn)的第一個(gè)關(guān)于 Google 的 Bug.mp4

目標(biāo)數(shù)據(jù)要求

intent 必須和問題關(guān)聯(lián)起來

顯而易見,應(yīng)該使用 intent 作為數(shù)據(jù)的唯一 id渴杆。為了便于處理寥枝,索性寫成了一個(gè) JS 模塊宪塔。之所以不直接用 JSON,是因?yàn)槟K比 JSON 文件磁奖,更靈活性,后期擴(kuò)展方便某筐,如果有的話比搭。

這一步是必須手動(dòng)做的,或者說總是需要有一個(gè)人手動(dòng)去做的南誊。為了效率身诺,團(tuán)隊(duì)內(nèi)總是需要有一個(gè)人必須要充當(dāng)這個(gè)角色。

大致處理下抄囚,初版結(jié)構(gòu) intent_info.js 大概類似這樣:

module.exports = {
  /* 樹莓派 */
  "smart_transform":"【smart-transform】取自 Atom 的 babeljs&coffeescript&typescript 智能轉(zhuǎn) es5 庫",
  "memory_leakDetector":"【YFMemoryLeakDetector】人人都能理解的 iOS 內(nèi)存泄露檢測工具類",
  "sinopia_npm":"【玩轉(zhuǎn)樹莓派】使用 sinopia 搭建私有 npm 服務(wù)器",
  "frp_ip":"【小技巧解決大問題】使用 frp 突破阿里云主機(jī)無彈性公網(wǎng) IP 不能用作 Web 服務(wù)器的限制",
  /* frp */
  "tip_rest":"【樹莓派自動(dòng)化應(yīng)用實(shí)例】整點(diǎn)提醒自己休息五分鐘",
  "frp_anywhere":"借助 frp 隨時(shí)隨地訪問自己的樹莓派",
  /* Lua */
  "luajit_macos":"【LuaJIT版】從零開始在 macOS 上配置 Lua 開發(fā)環(huán)境",
  "lua_macos":"【最新版】從零開始在 macOS 上配置 Lua 開發(fā)環(huán)境",
  "app_future":"關(guān)于混合應(yīng)用開發(fā)的未來的一些思考",
  "google_bug":"記錄我發(fā)現(xiàn)的第一個(gè)關(guān)于 Google 的 Bug",
}

排序

排序霉赡,是需要增加一個(gè)新的字段 order。不過幔托,我就直接上面的類似 JSON 的結(jié)構(gòu)來排序的穴亏。因?yàn)榕判蚴怯闪硗庖粋€(gè)人做,懂技術(shù)重挑,操作很簡單些嗓化。

經(jīng)過對(duì)方排序后,intent_info.js谬哀,可能變成了這樣:

module.exports = {
  /* 樹莓派 */
  "smart_transform":"【smart-transform】取自 Atom 的 babeljs&coffeescript&typescript 智能轉(zhuǎn) es5 庫",
  "memory_leakDetector":"【YFMemoryLeakDetector】人人都能理解的 iOS 內(nèi)存泄露檢測工具類",
  "sinopia_npm":"【玩轉(zhuǎn)樹莓派】使用 sinopia 搭建私有 npm 服務(wù)器",
  "frp_ip":"【小技巧解決大問題】使用 frp 突破阿里云主機(jī)無彈性公網(wǎng) IP 不能用作 Web 服務(wù)器的限制",
  /* Lua */
  "luajit_macos":"【LuaJIT版】從零開始在 macOS 上配置 Lua 開發(fā)環(huán)境",
  "lua_macos":"【最新版】從零開始在 macOS 上配置 Lua 開發(fā)環(huán)境",
  "app_future":"關(guān)于混合應(yīng)用開發(fā)的未來的一些思考",
  "google_bug":"記錄我發(fā)現(xiàn)的第一個(gè)關(guān)于 Google 的 Bug",
  /* frp */
  "tip_rest":"【樹莓派自動(dòng)化應(yīng)用實(shí)例】整點(diǎn)提醒自己休息五分鐘",
  "frp_anywhere":"借助 frp 隨時(shí)隨地訪問自己的樹莓派",
}

在上面的優(yōu)先顯示刺覆。在真正生成 order 字段時(shí),是借助 Node 一個(gè)不太可靠的特性: 字典遍歷時(shí)史煎,會(huì)基于key的書寫順序來遍歷谦屑。這一點(diǎn)驳糯,在 Node 和 Android 瀏覽器上都是成立的,在 safari 上氢橙,無效结窘。一般開發(fā)時(shí),不應(yīng)依賴于這一點(diǎn)充蓝,不過目前隧枫,我只是需要一個(gè)夠用的東西。Node 的這個(gè)特性谓苟,在短時(shí)間內(nèi)官脓,應(yīng)該是不會(huì)有改變的。

分類

沒過幾天涝焙,果然又加了新需求卑笨,說是視頻太多了,太雜亂仑撞,想給每個(gè)視頻加個(gè)分類赤兴,然后可以按分類查看視頻。

好隧哮,那我給你加個(gè)分類:

module.exports = {
  /* 樹莓派 */
  "樹莓派":"_category",
  "smart_transform":"【smart-transform】取自 Atom 的 babeljs&coffeescript&typescript 智能轉(zhuǎn) es5 庫",
  "memory_leakDetector":"【YFMemoryLeakDetector】人人都能理解的 iOS 內(nèi)存泄露檢測工具類",
  "sinopia_npm":"【玩轉(zhuǎn)樹莓派】使用 sinopia 搭建私有 npm 服務(wù)器",
  "frp_ip":"【小技巧解決大問題】使用 frp 突破阿里云主機(jī)無彈性公網(wǎng) IP 不能用作 Web 服務(wù)器的限制",
  /* Lua */
  "Lua":"_category",
  "luajit_macos":"【LuaJIT版】從零開始在 macOS 上配置 Lua 開發(fā)環(huán)境",
  "lua_macos":"【最新版】從零開始在 macOS 上配置 Lua 開發(fā)環(huán)境",
  "app_future":"關(guān)于混合應(yīng)用開發(fā)的未來的一些思考",
  "google_bug":"記錄我發(fā)現(xiàn)的第一個(gè)關(guān)于 Google 的 Bug",
  /* frp */
  "frp":"_category",
  "tip_rest":"【樹莓派自動(dòng)化應(yīng)用實(shí)例】整點(diǎn)提醒自己休息五分鐘",
  "frp_anywhere":"借助 frp 隨時(shí)隨地訪問自己的樹莓派",
}

新加了幾個(gè)值為 _category 的字段桶良。當(dāng)檢測到值為 _category 時(shí),就自動(dòng)判定為是一個(gè)分類沮翔。我這種處理方式陨帆,免不了引來一陣唏噓。但是采蚀,許多時(shí)候疲牵,你選擇的技術(shù)策略,都必須根據(jù)項(xiàng)目所處的狀態(tài)和各種條件榆鼠,去綜合權(quán)衡纲爸。我只有幾十分鐘時(shí)間去重新規(guī)劃和整理100條數(shù)據(jù)∽惫唬可能真的沒法想太多识啦。需求總是變化的,不知道明天又會(huì)變成什么樣责静,可能再進(jìn)一步袁滥,就變成”過度設(shè)計(jì)“了。另外灾螃,項(xiàng)目本身题翻, intent 本身約定了自己特有命名規(guī)律,是可以安全認(rèn)為 intent 和 分類一定不會(huì)重復(fù)的。

問題和視頻關(guān)聯(lián)

在讀取 intent_info.js 中的足夠可信的結(jié)構(gòu)化數(shù)據(jù)后嵌赠,我會(huì)動(dòng)態(tài)建立問題和視頻的關(guān)聯(lián)塑荒。這個(gè)過程中,可能需要適當(dāng)修改問題和視頻的標(biāo)題姜挺。為了避免遺漏齿税,一個(gè)標(biāo)題,如果沒有對(duì)應(yīng)的視頻或?qū)?yīng)多個(gè)視頻炊豪,就直接crash凌箕。有些霸道,但總比后期一個(gè)一個(gè)比對(duì)排查词渤,省太多事了牵舱。結(jié)合問題和視頻標(biāo)題的特點(diǎn),我專門封裝了一個(gè)方法:

/* 獲取某個(gè)標(biāo)題對(duì)應(yīng)的本地路徑.
為了避免未知錯(cuò)誤,如果找不到或找到多個(gè),就直接 crash.

@return  本地視頻的相對(duì)路徑.
 */
function localVideoPath(title)
{
  let path = require("path")
  let fs = require ('fs-plus')
  let fse = require('fs-extra')
  let os = require("os")
  let {execSync} = require("child_process")

  let videoDir = path.resolve(__dirname,"./videos")

  let videos = fs.listTreeSync(videoDir)
                  .filter(item=>{
                    return [".mov",".mp4"].includes(path.extname(item))
                  })
                  .map(item=>{
                    return path.relative(__dirname,item)
                  })

  /* 一個(gè)標(biāo)題,能且只能對(duì)應(yīng)一個(gè)視頻,否則就拋出異常. */
  let localVideoPath = null

  for (let item of videos) {
    if (item.includes(title)) {
      if (localVideoPath) {
        const tip = `致命異常: ${title} 對(duì)應(yīng)的視頻重復(fù):
        ${localVideoPath}
        ${item}`

        throw new Error(tip)
      }

      localVideoPath = item
    }
  }

  if (!localVideoPath) {
    const tip = `致命異常!這個(gè)標(biāo)題竟然沒有對(duì)應(yīng)的視頻:\n${title}`

    throw new Error(tip)
  }

  return localVideoPath
}

見碼如唔

完整的自動(dòng)化處理成結(jié)構(gòu)數(shù)據(jù)的邏輯如下缺虐,都集中在 make_data.js 中芜壁。

/* 生成帶有排序等信息的文件. */

/* 支持自動(dòng)生成數(shù)據(jù). */
makeDataWithOrder()
function makeDataWithOrder()
{
  const fs = require('fs-extra')
  const path = require('path')

  const intentInfo = require("./intent_info.js")

  let intentInfoNew = []
  let index = 1

  /* 在node中遍歷時(shí),key的順序是和原始key的順序?qū)?yīng)的.
  這個(gè)特性,并不總是有效,比如在 ios 瀏覽器中.
  目前,僅僅是夠用. */
  let category = ""
  for (let intent in intentInfo) {
    if (intentInfo[intent] == "_category") { /* 說明是一個(gè)分類標(biāo)記. */
      category = intent
      continue
    }
    let title = intentInfo[intent]
    const local_path = localVideoPath(title)
    intentInfoNew.push({
      "type":"video",
      "content":"",
      "intent": intent,
      "title": title,
      "order": index,
      "local_video_path": local_path,
      "ext": path.extname(local_path),
      "category":category,
    })

    ++ index
  }

  localVideoLoseCheck(intentInfoNew)
  const dataPath = path.resolve(__dirname, "./data.json")
  fs.writeJsonSync(dataPath, intentInfoNew)
  console.log(`恭喜!數(shù)據(jù)已寫入 ${dataPath}`)
}

/* 確保視頻總數(shù)與intent總數(shù)是對(duì)應(yīng)的,防止有視頻遺漏.
有視頻沒有對(duì)應(yīng)問題時(shí),會(huì)直接拋出異常.
 */
function localVideoLoseCheck(intents)
{
  /* 先把視頻信息處理成 key-value. */
  let path = require("path")
  let fs = require ('fs-plus')
  let fse = require('fs-extra')
  let os = require("os")
  let {execSync} = require("child_process")

  let videoDir = path.resolve(__dirname,"./videos")
  let videoDict = fs.listTreeSync(videoDir)
                  .filter(item=>{
                    return [".mov",".mp4"].includes(path.extname(item))
                  })
                  .map(item=>{
                    return path.relative(__dirname,item)
                  })
                  .reduce((sum,item,idx)=>{
                    sum[item] = false
                    return sum
                  },{})

  for (let item of intents) {
    videoDict[item.local_video_path] = true
  }

  /* 尋找缺失的. */
  let loses = []
  for (let item in videoDict) {
    if (!videoDict[item]) {
      loses.push(item)
    }
  }

  if (loses.length) {
    const tip = `一下 ${loses.length} 個(gè)視頻沒有對(duì)應(yīng)的問題:
    ${JSON.stringify(loses)}`
    throw new Error(tip)
  }
}

/* 獲取某個(gè)標(biāo)題對(duì)應(yīng)的本地路徑.
為了避免未知錯(cuò)誤,如果找不到或找到多個(gè),就直接 crash.

@return  本地視頻的相對(duì)路徑.
 */
function localVideoPath(title)
{
  let path = require("path")
  let fs = require ('fs-plus')
  let fse = require('fs-extra')
  let os = require("os")
  let {execSync} = require("child_process")

  let videoDir = path.resolve(__dirname,"./videos")

  let videos = fs.listTreeSync(videoDir)
                  .filter(item=>{
                    return [".mov",".mp4"].includes(path.extname(item))
                  })
                  .map(item=>{
                    return path.relative(__dirname,item)
                  })

  /* 一個(gè)標(biāo)題,能且只能對(duì)應(yīng)一個(gè)視頻,否則就拋出異常. */
  let localVideoPath = null

  for (let item of videos) {
    if (item.includes(title)) {
      if (localVideoPath) {
        const tip = `致命異常: ${title} 對(duì)應(yīng)的視頻重復(fù):
        ${localVideoPath}
        ${item}`

        throw new Error(tip)
      }

      localVideoPath = item
    }
  }

  if (!localVideoPath) {
    const tip = `致命異常!這個(gè)標(biāo)題竟然沒有對(duì)應(yīng)的視頻:\n${title}`

    throw new Error(tip)
  }

  return localVideoPath
}

我們?cè)陧?xiàng)目目錄執(zhí)行

node ./make_data.js

就可以得到我們想要的結(jié)構(gòu)化的數(shù)據(jù):

[
  {
    "type": "video",
    "content": "",
    "intent": "smart_transform",
    "title": "【smart-transform】取自 Atom 的 babeljs:coffeescript:typescript 智能轉(zhuǎn) es5 庫",
    "order": 1,
    "local_video_path": "videos/樹莓派/【smart-transform】取自 Atom 的 babeljs:coffeescript:typescript 智能轉(zhuǎn) es5 庫.mp4",
    "ext": ".mp4",
    "category": "樹莓派"
  },
  {
    "type": "video",
    "content": "",
    "intent": "memory_leakDetector",
    "title": "【YFMemoryLeakDetector】人人都能理解的 iOS 內(nèi)存泄露檢測工具類",
    "order": 2,
    "local_video_path": "videos/樹莓派/【YFMemoryLeakDetector】人人都能理解的 iOS 內(nèi)存泄露檢測工具類.mp4",
    "ext": ".mp4",
    "category": "樹莓派"
  },
  {
    "type": "video",
    "content": "",
    "intent": "sinopia_npm",
    "title": "【玩轉(zhuǎn)樹莓派】使用 sinopia 搭建私有 npm 服務(wù)器",
    "order": 3,
    "local_video_path": "videos/樹莓派/【玩轉(zhuǎn)樹莓派】使用 sinopia 搭建私有 npm 服務(wù)器.mp4",
    "ext": ".mp4",
    "category": "樹莓派"
  },
  {
    "type": "video",
    "content": "",
    "intent": "frp_ip",
    "title": "【小技巧解決大問題】使用 frp 突破阿里云主機(jī)無彈性公網(wǎng) IP 不能用作 Web 服務(wù)器的限制",
    "order": 4,
    "local_video_path": "videos/樹莓派/【小技巧解決大問題】使用 frp 突破阿里云主機(jī)無彈性公網(wǎng) IP 不能用作 Web 服務(wù)器的限制.mp4",
    "ext": ".mp4",
    "category": "樹莓派"
  },
  {
    "type": "video",
    "content": "",
    "intent": "luajit_macos",
    "title": "【LuaJIT版】從零開始在 macOS 上配置 Lua 開發(fā)環(huán)境",
    "order": 5,
    "local_video_path": "videos/Lua/【LuaJIT版】從零開始在 macOS 上配置 Lua 開發(fā)環(huán)境.mp4",
    "ext": ".mp4",
    "category": "Lua"
  },
  {
    "type": "video",
    "content": "",
    "intent": "lua_macos",
    "title": "【最新版】從零開始在 macOS 上配置 Lua 開發(fā)環(huán)境",
    "order": 6,
    "local_video_path": "videos/Lua/【最新版】從零開始在 macOS 上配置 Lua 開發(fā)環(huán)境.mp4",
    "ext": ".mp4",
    "category": "Lua"
  },
  {
    "type": "video",
    "content": "",
    "intent": "app_future",
    "title": "關(guān)于混合應(yīng)用開發(fā)的未來的一些思考",
    "order": 7,
    "local_video_path": "videos/Lua/關(guān)于混合應(yīng)用開發(fā)的未來的一些思考.mp4",
    "ext": ".mp4",
    "category": "Lua"
  },
  {
    "type": "video",
    "content": "",
    "intent": "google_bug",
    "title": "記錄我發(fā)現(xiàn)的第一個(gè)關(guān)于 Google 的 Bug",
    "order": 8,
    "local_video_path": "videos/Lua/記錄我發(fā)現(xiàn)的第一個(gè)關(guān)于 Google 的 Bug.mp4",
    "ext": ".mp4",
    "category": "Lua"
  },
  {
    "type": "video",
    "content": "",
    "intent": "tip_rest",
    "title": "【樹莓派自動(dòng)化應(yīng)用實(shí)例】整點(diǎn)提醒自己休息五分鐘",
    "order": 9,
    "local_video_path": "videos/frp/【樹莓派自動(dòng)化應(yīng)用實(shí)例】整點(diǎn)提醒自己休息五分鐘.mp4",
    "ext": ".mp4",
    "category": "frp"
  },
  {
    "type": "video",
    "content": "",
    "intent": "frp_anywhere",
    "title": "借助 frp 隨時(shí)隨地訪問自己的樹莓派",
    "order": 10,
    "local_video_path": "videos/frp/借助 frp 隨時(shí)隨地訪問自己的樹莓派.mp4",
    "ext": ".mp4",
    "category": "frp"
  }
]

參考文章

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市高氮,隨后出現(xiàn)的幾起案子慧妄,更是在濱河造成了極大的恐慌,老刑警劉巖剪芍,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件塞淹,死亡現(xiàn)場離奇詭異,居然都是意外死亡紊浩,警方通過查閱死者的電腦和手機(jī)窖铡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來坊谁,“玉大人,你說我怎么就攤上這事滑臊】谏郑” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵雇卷,是天一觀的道長鬓椭。 經(jīng)常有香客問我,道長关划,這世上最難降的妖魔是什么小染? 我笑而不...
    開封第一講書人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮贮折,結(jié)果婚禮上裤翩,老公的妹妹穿的比我還像新娘。我一直安慰自己调榄,他們只是感情好踊赠,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開白布呵扛。 她就那樣靜靜地躺著,像睡著了一般筐带。 火紅的嫁衣襯著肌膚如雪今穿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,287評(píng)論 1 301
  • 那天伦籍,我揣著相機(jī)與錄音蓝晒,去河邊找鬼。 笑死帖鸦,一個(gè)胖子當(dāng)著我的面吹牛拔创,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播富蓄,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼剩燥,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了立倍?” 一聲冷哼從身側(cè)響起灭红,我...
    開封第一講書人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎口注,沒想到半個(gè)月后变擒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡寝志,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年娇斑,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片材部。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡毫缆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出乐导,到底是詐尸還是另有隱情苦丁,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布物臂,位于F島的核電站旺拉,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏棵磷。R本人自食惡果不足惜蛾狗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望仪媒。 院中可真熱鬧沉桌,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至冰抢,卻和暖如春松嘶,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背挎扰。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來泰國打工翠订, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人遵倦。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓尽超,卻偏偏與公主長得像,于是被迫代替她去往敵國和親梧躺。 傳聞我的和親對(duì)象是個(gè)殘疾皇子似谁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容