2016年9月30日 星期五

標籤式檔案管理


在一些多媒體網站, 像是影片, 圖片的, 常常可以看到標籤的功能
點選標籤後, 貼有相同標籤的影片或圖片就會列出來, 這是相當方便的功能
本實驗室發展一套軟體將這項功能做在 ubuntu 上, 讓個人電腦可以用這方法管理檔案
並且可以很容易的將已經庫存的檔案備份至光碟等容量較小的唯讀儲存設備
這軟體只能在 ubuntu 等 Linux 系統上運行, Windows 用戶請另尋方案
要操作這軟體, 我假設用戶已經會基本 SQL 操作並知道如何用工具操作 MySQL



這是本實驗室重要的長程計劃, 已經執行有八年以上, 經過兩次打掉重練
直到最近才進入穩定版本, 規劃時需做很多的考量, 因為這牽扯到一千多片光碟的檔案XD
如果沒有做好就會一直修改, 一千多片的資料就要重複修改, 那會死人
所以如果沒有到完全確定是不會執行導入的, 也因為如此, 我的硬碟無時無刻都是爆滿的
太多資料無法整理入庫就只能堆著, 最近軟體進入穩定版才減緩爆滿的問題
這玩具是有歷史的, 先說明一下過去的方案, 才能描述做這的動機

過去的方案: 使用Access 建立自己的資源管理系統  資料庫樣板
在前篇文 舊文件索引 中有簡短介紹:

內容簡介:
這是一份整理下載資源的教學
不過僅適用於我等糟糕眾XD
除非像我一樣整天開驢子抓一堆東西
不然應該不會需要這樣誇張的管理法XD
由於整理的對象內容極骯髒, 有 18X 資料, 不喜者請迴避XD
內容描述利用 Access 管理動漫畫,套圖,音樂的方法
並提供樣板供使用
這東西僅適用於"套裝資料"
對於零散的圖片或是文章檔案是不適合的
我曾利用課程專題自定題目時刻意選了個和整理檔案有關的題目
發展一個可以貼上多重標籤的整理工具
不過效果不好, 還在研究中
在發展出來之前只能先暫時不管小型零散檔案

2007 年的東西了, 當時做這東西是為了整理光碟, 需要整理的項目就只有動漫畫, 套圖, 音樂
這東西對於資料不多的用戶還是可以使用, 尤其用 Windows 系統的用戶, 有裝 Access 就能用
新系統只能在 ubuntu 等 Linux 系統上使用, 而且必須有資料庫概念以及會一點 SQL
舊版用了很多欄位來紀錄不同的訊息, 像是類型, 作者, 參考作品...等
不同類型的資料要用不同數量的欄位來紀錄, 像是動漫畫我們會關注關鍵詞以利日後搜尋
但音樂部份我們會比較關注演出者, 日後可以列出該演出者的作品
不同類型的資料會用不同數量的欄位來紀錄, 後來我把這方案放到某討論區
有其他用戶也導入了, 根據文件說明他們加入了不同數量的欄位來滿足需求
這一切看起來很好, 沒有什麼問題, 然而當我試圖做更多的應用時, 就會惹麻煩
如同上面的內容簡介, 這東西僅適用於 "套裝資料", 不適用零散的圖片或是文章檔案

隨著我蒐集的資料越來越多, 興趣(?)越來越雜, 需保存的資料就越來越多
不只興趣用, 工作用的也是, 我們有許多客製化的產品, 系統廠又會接觸多種硬體
有一堆各種硬體的規格書, 它們都是 PDF 的小檔案, 常常需要查找
做的案子多了, 它們也跟著越來越多, 越來越亂, 找個檔案要翻好幾個資料夾
以前我可以不管小型零散檔案, 現在我必須面對它們
面對它, 接受它, 處理它, 但絕不可以放下它, 放下就是要離職了XD
每多一種資料我就要規劃一組管理欄位, 這樣沒完沒了啊
因此需要一個通用型的工具來管理, 什麼都能丟進去, 都能分類的軟體
由於我比較相信光碟類的唯讀儲存設備, 因此這些資料丟進軟體後還要能很容易的備份與遷移
我也曾經搜尋一些軟體, 但沒看到符合的, 也有可能是我沒有認真找
這需求太特別了要找到應該不容易, NAS 機的軟體有些有接近功能的
但它們通常不會考慮備份到光碟的問題, 它們只考慮備份到另一顆硬碟
而管理光碟的軟體則是只記下內容供搜尋, 反而不考慮分類的問題
要把兩個都考量進來, 就得自己搞

以前開始規劃時並沒有所謂標籤的概念, 以前我把它當成屬性
可以觀察舊版資料庫, 它有許多共通的地方, 像是名稱, 檔案體積, DVD 編號, 註解
然後不同資料庫會增加不同的欄位, 就好像這些資料有不同的屬性
但是每筆資料不一定每個屬性都有值可以填
例如從 DVD 轉出的動畫就不會有關鍵字, 關鍵字是驢子搜尋下載時才會用的
原創的漫畫通常不會有參考作品, 參考作品只有同人本才需要
不需要的屬性仍然會佔資料庫欄位, 如果突然要紀錄一些額外訊息就只能塞在註解
讓這結構化的資料看起來一點也不結構化, 整個資料表到處有無值的空格
或是一個空格塞了一堆字串在裡面, 因為找不到合適的屬性, 或是多重屬性
例如一本同人本混和了一狗票作品在裡面大亂鬥, 全部填進參考作品這欄位就超擠
後來接觸了 nicovideo, 他們的處理方式就是標籤, 或許標籤不是他們發明的
但他們網站應該是讓我決定用標籤來規劃的地方, 下圖是 2008 年時的樣子, 現在 UI 已經大改
紅框處即是標籤列表, 點選可以列出所有貼相同標籤的影片, 從那時起還多了一種廚叫做標籤廚XD
該站標籤是大家都可以編輯的, 最多可以 10 個 (現在不知道規則有沒有變, 很久沒去了)
有些人會拿標籤來當註解用, 或是拿來罵人, 然後就會有人再把它改回去, 一直循環XD
當我們看到一個檔案具有某些特徵時, 我們會想貼個標籤作記號
這就是一開始改變的想法

不過有了想法要把它變成實體可不容易, 當時也接觸了一些論文
這類的資料會被稱作 Semi-structured data, 這裡我暫時翻作半結構化資料
意思就它是結構化的資料, 但裡面的內容不是固定的, 不像常見的資料庫裡的資料表有固定欄位
如同 wiki 上面寫, 常用的儲存方式是 XML 以及 JSON
軟體在取得 XML 以後再分析裡面的內容, 然後才找到需要的資料
第一次試做是在某個課程的專題, 當時題目印象中是自訂一個在手持裝置上運行的軟體
我做了這玩具的雛型:

用 XML 描述, 當時老師說我這篇專題他和助教討論最久
雖然這確實有符合專題要求, 但他們想很久不太知道做這個目的是什麼
當時我想, 老師除非你會讀心術不然不可能猜中的, 因為我只是要整理漫畫XDDD
專題內容是有稍微修飾一下沒有直說我想幹麻, 怕被罵所以包裝了一下XD
這一次試做就發現一些問題, 雖然 XML 可以儲存半結構化資料, 但是如同 wiki 上說的
它很難執行搜尋, 而且搜尋時得從每一筆資料去挖, 挖出來, 翻一翻看有沒有, 然後丟掉
這是很沒效率的, 尤其有些 XML library 會載入整篇 XML 後才搜尋, 那會吃光記憶體
其實 XML 搜尋也是有專門的語言, 它叫 XQuery, 不過看起來不太好懂, 而且有些限制
所以我想了一些奇怪的方法來解決, 那就是在結構化的 SQL 資料庫中放半結構化資料

雖然標籤通常是當成半結構化資料來處理, 但我們可以縮小問題範圍
wiki 上的那種半結構化資料比較像是所有資料都是標籤, 意思是所有資料都是選配
例如有的資料有名稱, 有的資料沒有名稱但是有電話號碼, 有的可能兩個都有這樣
程式讀出時依據內容再進行判斷, 所以才用 XML, 每個欄位有欄位名稱以及欄位內容
只是每筆資料不一定都有某些名稱的欄位, 而我的資料庫是要管理檔案的
目標明確, 每筆資料都一定有名稱, 檔案體積, DVD 編號, 註解
只有特徵的部份是半結構化資料, 因此我們沒有必要整個資料都半結構化
只要標記特徵的部份半結構化即可
除了名稱, 檔案體積, DVD 編號, 註解, 這些固定資訊外, 如果其他所有訊息都統一用標籤
那我們就不會有欄位的問題, 因為各項屬性都一視同仁, 都是標籤, 通通存在同一欄位
這個欄位裡字串肯定會比較長, 但至少都在一起, 不會有的欄位有, 有的欄位空
搜尋特徵時也只要在這欄位裡面撈就好, 不需要這個欄位找一下, 那個欄位找一下
而標籤的功能是建立關聯, 我們只要搜尋某個標籤, 就可以列出所有和這標籤有關的資料
這樣我們可以得到半結構化資料的好處, 同時也可以得到結構化資料的快速搜尋
而限制就是只能用在檔案整理, 所以我的資料表結構會長得像這樣:

這裡先只列出 resource 和 tag 部份表格, 其他的後面再說明
我把每筆資料當成一個資源, 也就是 resource
每筆資源有個 id (rid 欄位) 來識別, 它不可重複, 從 1 開始遞增
資源有標題 (title 欄位), 用來敘述這資源的主題, 通常是作品名稱或是文件敘述
tags 欄位用來儲存標籤, 內容是一串數字用逗號分開, 每個數字是標籤的 id
由於是用字串存所以可以是任意長度, 少於 200 個字元即可
標籤存在 tag 表格中, 每個標籤有個 id (tagid 欄位) 來識別
它不可重複, 從 1 開始遞增, 標籤名稱存在 name 欄位, 後面兩欄則是保留備用
這意思是每個標籤可以用一個數字代表, 而資源中會紀錄一串數字
可能有三個或是五個, 即代表三個或五個標籤, 搜尋時先找出標籤的 id
然後用這 id 去 resource 的 tags 欄位搜尋就可以撈出所有含這標籤的資料
用 id 是避免重複儲存時發生錯誤, 資料庫書籍會用某個 error 來描述, 名稱忘了
如果直接把標籤字串寫進 tags 欄位, 當標籤要改名字時就要全部一起改
若漏掉了沒改到, 資料就錯了, 用 id 的話就只要改標籤資料表上的名稱欄位即可

接著看 storage 資料表:

這個資料表用來描述儲存體, 也就是一片片的光碟
不過這不代表資料只能放在光碟, 在硬碟中就是資料夾而已
只是我會透過軟體限制放進資料夾的檔案量, 確保每個儲存體的檔案量都低於資料庫裡的值
意思是我們可以設定最多存 4.7G, 那麼每個資料夾一定都可以燒進 DVD
除非資料夾深度過深或檔名太長, 這部份目前交由使用者自行解決
每個儲存體都有一個 id 代表, 一樣是從 1 開始遞增且不重複
prefix_id 保留未來使用, 目前沒有功能
used_size, total_size 則是已使用空間和總空間
status, flags 保留備用, update_time 是最後更新時間
ext_id 是外部代號, 用於寫在光碟片上的代號, 尋找光碟時用, 原則上一片一個代號
如果遇到唯讀媒體更新, 例如 DVD 升級 BD 時, 原本多片 DVD 被同時放到新的 BD 上
那麼這幾片 DVD 的儲存體就會共用一個代號

最後是 res_table 資料表:

這個資料表用來存放所有的資料, 最重要的是前三個欄位, rid, sid, path
rid 對應到資源 id, sid 對應到儲存體 id, path 是路徑字串
這裡一筆資料代表一個資源在一個儲存體下的 path 中有一個檔案或目錄
一個資源可以同時擁有多個檔案, 可以分散在多個儲存體, 通通紀錄在這個資料表
size 紀錄檔案體積, 以 byte 為單位, 不計算目錄的檔案體積, 因為那個和檔案系統有關
用意是當我新增一筆資源, 同時為它新增一個檔案或目錄, 然後這個儲存體已經燒錄光碟
它已經唯讀不想再更改, 結果日後又發現這資源有續集, 或是有取得品質更好的檔案
那麼我只需要在後續的儲存體中加入即可, 已經燒錄的檔案就不再變動
不管分散到哪片光碟我們都可以把它們找出來, 品質較差想刪除的檔案可以在該筆資料註解
這功能其實可以做到 status 和 flags, 不過目前還拿不定主意, 有在想要做自動化
當更新媒體像是 DVD 升級 BD 時自動刪除標記不要的檔案並自動組合
軟體想辦法讓多個小的儲存體在精簡空間刪除不要的版本後合併入大儲存體
這需要一些複雜的機制, 目前先不做, 反正檔案體積和路徑都已經自動紀錄
有這些訊息要再重整應該都是做的到的, 舊版資料庫的人工紀錄就沒法實現, 因為路徑不明確目前的方案對於已燒錄的儲存體並不會有任何標記, 這也是還沒決定要怎麼做所以先空著

完整的資料表細節在後面發放的源碼中有文件紀錄, 還有一個資料表 vfs 目前也是預留
有想法但還沒實做, 反正寫進資料庫不儲存資料也不會佔空間就先丟著
目前實作的 SQL 並沒有 thread safe, 也就是沒有動用 lock 的 SQL
這玩具目前只能供個人使用, 無法上線讓多人去耍廚(?)XD
由於操作的細節蠻多的, 同時有資料庫和檔案要操作, 要驗收 thread safe 難度頗高
要弄一些測試程式多個 process 去測 lock 有沒有效
我沒有開發大型伺服器軟體的經驗, 這部份沒法做好, 所以還是先維持個人用
這也是本來我開發這工具的目標, 多人用的以後有需要再想辦法

以上是 SQL 部份的規劃, 接著是 UI 和軟體部份, XML 的雛型是在微軟系統上用 C# 寫
後來看到微軟系統越做越爛, 這平台看來是靠不住了, 所以改自由世界方案
一開始用 GTK+ 去寫, 然後......被坑殺了XD
雖然早就知道它很難用, 但是拿來寫比較大一點的軟體就發現真的不是普通的難用
不過最近因為一些專案開始看 GLib, 它可以在 C 上搭建物件導向系統並且容易映射到別的語言
GTK 應該要搭配這個來用會比較靠譜, 它底下就是 GLib, 以它為基礎往上疊或許會好些
當時不熟悉這些細節加上對 UI 的軟體設計沒有太多經驗所以就死了
被坑殺了以後改用 web-base, 用 php 寫, 和瀏覽器間用 Http Request 送 JSON 傳遞
透過 JQuery 包裝可以在很多的裝置上使用, 寫了一堆 java script 和 php 溝通
這樣的組合用了約三年, 它有很多的問題但勉強堪用, 常常要連進 MySQL 手動改一些資料
用 web-base 完全解決 UI 的問題, 但是帶來了更多檔案操作上的問題
因為都在伺服端, ubuntu 下會有檔案權限的問題, 從瀏覽器上傳的檔案正常
可是動畫資料不可能上傳!那都好幾 GB, 所以手動複製到伺服端的路徑, 但是 owner 是我
server 無法移動檔案入庫, 所以要改權限 777, 或是 root 權限換 owner
不管哪種都是麻煩, 但是為了驗收資料庫規劃我還是這樣用了三年, 直到 ubuntu 16 出來
php 裡的 mysql 插件更新, 語法全改, 以前的 mysql 只能對一個伺服器查詢, 這次可以多個
要多一個參數選擇連線, 這是非常好的設計, 其實本來就該這樣, 但是我一堆程式已經寫了
現在又要我修 php, 全部項目重測, 那個 JSON 一筆一筆驗很花時間啊
所以, 再打掉一次!於是就變成這次的結果, 如同 CNC 計畫的軟體, 是 Python + C
軟體內分多層, 最下面為插件, 中間是 libtdoc, 往上為對 python 的連接層:

系統核心是 libtdoc, 這是個 library, 負責操作下方的 DB 和 ST 插件
DB 即是 database, ST 則是 storage, 目前各有一個內建的
DB 內建為連到 MySQL, ST 則是 local storage, 也就是本地硬碟
libtdoc 操作這兩插件讓 ST 裡的東西能和 DB 裡的能做對應
能在 DB 裡搜尋資料然後用 ST 撈出檔案來給用戶
對 DB 操作時只用字串和數字, 不涉及任何 SQL 操作, SQL 將完全封裝在 DB 插件中
意思就是如果 DB 插件裡換成存取 XML, SQLite, 或是純文字檔的資料庫理論上應該都行
只要能依固定規則丟出資料即可, SQLite 原先想選, 但有看到文章說不建議用在大量資料上
不過如果要搬到 Android 上是可以考慮, 它跟 MySQL 最接近
而且 Android 上不太可能放太多東西......通常不會啦, 除非拿了些奇怪的開發板接硬碟(?)
對 ST 操作也類似, 只有字串數字和路徑, 理論上可替換成 HTTP 或是 FTP 進行遠端操作
不過對於取出檔案部份則需要對 ST 的插件部份界面做修改, 也就是 GetFile 這界面
這部份對於支援遠端檔案系統我認為還不可行, 不過目前也沒有這規劃所以先放著

這樣的設計是仿造硬體抽象層:HAL, Hardware Abstraction Layer, 不是人體自動化實驗室(冷)
軟體也有這樣設計, 只是大多是物件導向語言在做, 本實驗室慣 C (?)所以沒有這麼設計
除了慣 C 外, 其實還有一些對這玩具的期望, 那就是讓它在 MCU 上跑
這個就更遙遠了, 只是先放在心上, 規劃時會稍微考慮, 至於什麼時候會需要就不知了
插件層的界面宣告放在源碼中的 libtdoc/include/tdoc/plugin.h 中
大致上就是一系列的列出 / 新增 / 修改 / 刪除, 資料庫類的軟體就是不斷重複做這些事
例如以標籤來說, 只要插件可以列出標籤, 可以新增標籤, 可以修改刪除標籤
標籤部份的功能就能用, 上層不須去管到底是怎麼新增修改刪除的
而對插件來說, 插件在收到新增修改刪除的命令時就照著做就是了
它只需要專心做好這件事情, 不需要在意刪除後會不會影響檔案或是資源
像刪除標籤這功能除非刻意去引用 libtdoc/include/tdoc/interface.h
不然是不會有刪除標籤的功能, 這功能目前是測試用
因為刪除標籤是很麻煩的事情, 為了確保資料庫正確 (應該說 "維持一致性")
若真的要刪除必須連所有資源中包含該 id 的資源都要同時移除這個標籤
若有某個資源就只有這個標籤那就麻煩了, 因為移除了就沒法透過標籤連結到它
目前我的規格是不接受沒有標籤的資源, 每個資源至少要有一個標籤
沒有標籤就是沒有特徵, 沒有特徵幹麻存它!扔了吧!XD

libtdoc 的公開界面都放在 libtdoc/include/tdoc/tdoc.h
標籤和資源部份幾乎都是直通資料庫插件, libtdoc 只是個殼提供固定的界面
而檔案和儲存體相關的就要同時操作資料庫和儲存體
像新增資料就是流程最多的一個界面, 它的工作流程如下:

1. 向 DB 詢問指定的儲存體有多少空間可用
2. 檢查要加入的檔案體積, 若是資料夾則遞迴計算
3. 檔案體積有大於剩餘空間嗎? 若有, 傳回錯誤
4. 讓 ST 將檔案複製到儲存體中, 若是資料夾則遞迴複製
5. 若複製失敗要求 ST 刪除已經複製的資料後傳回錯誤
6. 將資料訊息寫入 DB
7. 查詢 DB 剩餘空間, 加上這筆資料的體積後再寫回 DB 更新使用量
8. 若更新失敗要求 ST 刪除已經複製的資料後傳回錯誤

libtdoc 界面將工作分成多個和 DB 及 ST 的操作, 兩插件各自完成自己的任務
libtdoc 只負責調度以及檢查, 開發時就是分層測試, 軟體更新時也是
如果資料庫的 API 又改了, 理論上就只會影響到插件, 上層不用更動
更新後測試時也只要調用插件界面就可以檢查有無問題, 不用在 UI 上動手腳
同樣的, 當 UI 有更動時, 也是只要專注在 UI 配置除錯, UI 只是將 libtdoc 結果列出
如果底下 libtdoc 有驗收過, 我們就可以知道問題一定只在 UI 內, 可以縮小找錯範圍

接著發放源碼:

tdoc-v1.0.tar.gz

本軟體需要 MySQL, 安裝 MySQL 請上網搜尋, 我假設用戶已完成安裝
建議可以多裝 mysql-workbench, 這個用來操作 MySQL 蠻方便的
編譯前先安裝套件

sudo apt-get install libmysqlclient18 libmysqlclient-dev libpython3-dev python3-magic

內容是 MySQL client 的 C library, Python3 C library, 以及 Python3 的 magic 組件
magic 組件可以協助我們判斷並紀錄檔案類型, 接著到 tdoc 下編譯

./build.sh

這樣可以編出 libtdoc 以及 Python3 Tdoc 組件
第一次使用需先建立資料庫以及儲存體, 要初始化這兩插件需要兩個設定檔
我有放兩個設定範例在: libtdoc/doc/sample.db libtdoc/doc/sample.st
設定檔裡用 = 分隔, 等號左邊是參數名, 右邊是參數, 所有空格都會讀入
所以不要留空格, 為了最少的依賴外部工具, 用了最簡單的方法讀取設定
參數讀法可參考 tdoc_config_parse 這函數
參數內容會設定 MySQL 就知道怎麼寫, 唯一需要說明的是 dbname 這參數
這是設定資料庫名稱, 也就是 create database 時需要的名稱
儲存體的設定就只有一行 prefix, 設定硬碟中存放檔案的目錄
建好後下這命令進行初始化:

./run init ../conf/test.db ../conf/test.st


完成後修改 pysrc/tdoc/window.py 這檔案, 在最上方:

# database config file & storage config file list
class TdocConfig():
    def __init__(self):
        self.path_cfg = [
            [
                "test", # title to display in combo menu
                "../conf/test.db", # path to database config
                "../conf/test.st", # path to storage config
            ],
            [
                "Technical Documents",
                "../conf/tech-doc.db",
                "../conf/tech-doc.st",
            ],
        ]

把存好的設定檔放進來, 本來想做 UI 去填, 但是考慮到這 UI 非常非常少用
就不做了, 直接寫死在源碼裡, 反正 python 腳本就是文字檔, 修改容易
完成後執行就像這樣

第一欄選資料庫, 第二欄選語言, 目前只有中文和英文

開啟後若正常可以看到這畫面

一開始什麼也沒有, 第一個先新增儲存體, 按下後會設定容量, 預設為 25GB, 一片 BD 容量
只燒 DVD 的用戶可自行修改為 4.7GB, 或是 CD 的 700MB


新增完成後可以點選儲存體, 跳出選單有三個功能

修改外部代號就是改光碟編號
另外兩個匯出一個是把這個儲存體關聯的資源印出, 另一個是把儲存體裡的檔案結構印出
印出時格式為 JSON, 這是備份用, 目前沒有提供工具去使用這些 JSON 檔
要備份資料庫用 MySQL 的工具就可以了, 用 mysqldump 備份資料
還原或重灌時用 mysqladmin 建資料庫, 然後 mysql 把已備份的 sql 檔填回去即可
JSON 這東西原先是打算用來做最後防線, 當 mysql 資庫不幸意外損毀
可以用這些 JSON 檔來重建資料庫, 但是標籤名稱和 ID 可能都會換, 這不容易對應
若真要謹慎建議每燒一片就存一次 sql 備份, 這樣最多就只會損失一片光碟的資料

接著切到第二個分頁, 為了示範有較多內容時的情況我拿舊的動畫資料庫來用:

第二個分頁是新增資源用, 點選開啟檔案或開啟資料夾即可選擇檔案
可以加入單一檔案也可以加入一個資料夾, 點選編輯標籤可以新增並加入標籤
可以加入多個標籤, 標籤數量上限目前為 50 個, 可參考 libtdoc/mysql/tdoc-mysql.h

#define MAX_TAGS_PER_RES 50

若要加大需同時加大 sql buffer, 不然放入資料庫可能會失敗, 尤其標籤編號越來越長時
不過 50 個已經有點扯了, 軟體機器人分類資料才需要大於這種數量XD
接著填寫標題, 填寫時會跳出下拉視窗, 這是仿 Google 的自動完成

用意是輸入時順便幫你查看看資料庫裡是否已有相同標題的資源
若有就別新增了, 到該資源中新增檔案就好, 不要創新的資源
接著填寫註解, 如果有需要的話, 然後選取想加入的儲存體, 下面有儲存體列表
就和前一分頁長得一樣, 這個列表會出現在三個地方, 最後一個在資源中, 預設選最新的一個
下面的上一頁和下一頁是用來列出的儲存體, 當儲存體越來越多時就需要換頁
點選後就完成選擇, 然後按下新增資源即可將檔案放入資料庫和儲存體中

第三個分頁是搜尋


這裡會列出最新加入的資料, 在搜尋欄位輸入字串一樣會有下拉視窗自動完成

可以注意到輸入中文在輸入欄位下半被截掉了, 這問題似乎不是我 python 腳本可以修的
我另一台機器裝 ubuntu 15.04 的就沒有這個問題, 可能和系統設定有關, 這還要查
不過這只是閱讀不好, 它並不影響功能

點選搜尋標籤會跳視窗要求輸入字串, 若有列出想搜尋的標籤, 點選該標籤後按 OK 即可搜尋標籤


或是直接點選搜尋結果列表中的標籤也可以自動查詢, 搜尋後會將標籤標示黃色

若要返回前面的列出資源頁面, 只要把搜尋標題清空然後按搜尋即可
也就是搜尋空字串

查詢結果後點選標題即可開分頁, 列出該資源細節

按編輯資源可以重填標題, 標籤, 以及註解, 和新增資源那頁相同
按加入檔案可以新增檔案給這個資源, 頁面上的按鈕功能和新增資源那頁相同
只是這裡的註解會寫到資源頁面下方檔案那裡, 而不是資源頁面上方那個註解
這註解用來說明檔案訊息, 像是品質較好, 或是後續續集之類的
對分頁按右鍵 (上圖寫 1736 那個地方) 則關閉分頁, 前三個分頁固定無法關閉
1736 是資源 ID, 原先想填標題, 但是這樣怕太長, 要裁切字串又麻煩, 就索性填 ID, 順便當除錯用

每筆檔案的操作選項有三個, 開啟檔案, 修改註解, 以及刪除檔案

開啟檔案用的是 webbrowser.open, 在 ubuntu 上會自動選系統對應的軟體
這個在不同平台會有不同回應, 我把它寫在 window.py 最下面
若在別的 linux 發現不能用可能會需要自己判斷內容, 我在那斷程式附近有留一些註解
修改註解和刪除檔案應該就不用說明了, 功能就如同字面上的意思

全部功能大概就這樣了, 最後再提一些注意事項
首先, 有個 bug ! XD
標題輸入 ' 符號, 新增資源或修改時 SQL 會失敗, 需自行改為 \' 才可加
本來想修......但是想想如果是抽象化界面我不應該修這個, 這應該由插件自己吞掉
但是插件裡要換這個有點麻煩, 要做些字串處理, 這用 C 搞有點麻煩...
是做得到但是麻煩!所以先偷懶不做XD
檔名有 ' 符號也會有問題, 這個目前在 UI 這段把它截掉, 嘗試加入這種檔案會被拒絕
只有第一層目錄會查, 因為第一層目錄會寫入資料庫, 資料夾下的就不管了

然後有個 issue !
為了講求效率, 複製檔案時是用 zero-copy, 也就是 kernel 內複製
這段程式寫在 libtdoc/local-storage/tdoc-localst.c 最上面
當檔案小於 2GB 時用 sendfile, 網路上說這個各家 linux 2.6.33 以後都能用
但是大於 2GB 的檔案就有竅門了, 以 ubuntu 的來說, 用 sendfile 它只會複製 2GB
用其他的方法像是 mmap + write 也是一樣, 不過如果是 mmap + write
你可以在發現它返回後繼續塞下一個 2GB, 它一樣會再吃完 2GB 後停下來返回, 檔案寫得進去
以 2GB 為單位持續塞, 塞到完為止, 經實驗比對 md5sum 是符合的
ubuntu 論壇說這限制似乎是相容性問題, 根據他們經驗這樣比較不會有問題
但別家 linux 發行的規則不一定相同, 這要驗過才知道
不過如果用戶沒有這種超大檔就不需要在意, 若有且不是 ubuntu, 第一次使用務必驗一下 md5sum

pysrc/tdoc/window.py 這檔案的資料庫列表有留一個額外的功能

[
    "Anime old",
    "../conf/anime-ro.db",
    "../conf/anime-ro.st",
    "read-only",
],

"read-only", 在資料庫項目的陣列中加上這值, 主視窗啟動後會把所有編輯部份功能全部停用

這功能用來封存整個資料庫用, 這是從 UI 去擋, 實際上 libtdoc 還是可讀寫
要做到資料庫插件裡的唯讀需要應用資料表 status 和 flags 欄位, 目前無迫切需求先不做

這套系統主要用於封存資料, 也就是下載來的影音檔或是 PDF 文件, 它無法被直接編輯的
如果放 doc 等文件檔進去資料庫, 操作時可能會不小心就按下存檔, 這會導致文件檔案大小改變
檔案量變了資料庫卻不知道, 這就不一致了, 解決方法是先把檔案複製出來
然後在資源中刪除這筆檔案再重新加入, 就會重新計算檔案大小
這看起來很麻煩, 但這就是本軟體的規格, 它是用來方便搜尋庫存資料同時維持檔案體積
而不是單純的方便搜尋, 如果只是做搜尋, 那我們就不會去在意檔案體積
若有這樣的應用需求建議找 NAS 主機, 它就專門做這個, 還會幫你產生縮圖, 服務超棒XD

這系統只有刪除檔案功能, 沒有刪除標籤和刪除資源, 原因就是麻煩!
標籤的問題前面說明過了, 資源基本上一樣, 刪除資源要先同時刪除該資源下的檔案
但是如果檔案已經燒錄這樣還殺的到嗎? 這就會再發生不一致的問題, 所以就乾脆不砍了
如果覺得沒用的資源礙眼可以改名拿去裝別的東西, 裡面的檔案要自行處理
看是要手動刪除還是標記, 若需要一些奇怪的操作就要自己下 SQL 指令

在 ubuntu 上可以把這工具加到啟動列, 方法是新增這檔案
路徑: ~/.local/share/applications/run_py.desktop
內容:

[Desktop Entry]
Encoding=UTF-8
Version=1.0
Type=Application
Name=Tag Documents Startup
Icon=application-default-icon
Path=/path/to/tdoc
Exec=bash ./run
StartupNotify=false
StartupWMClass=Run.py
OnlyShowIn=Unity;
X-UnityGenerated=true

這樣就會出現在啟動列, 點選就可開啟, shift+點擊則可開第二個, 第三個視窗, 同時處理多資料庫

現在我開始重整舊資料庫, 緩慢遷移中, 新的動畫資料庫片段:

新的資料庫填入資料會加上特徵, 而不是只有 720P 這類規格, 填入特徵是個既簡單又困難的事
簡單是就在 UI 上輸入, 就會寫入資料庫, 流程簡單
難的是怎麼命名標籤, 例如這影片裡主要講動物生態, 於是我們很直覺的貼了個動物的標籤
後來, 我們收了一堆報告狗班長的狗狗影片, 所以我們又貼了狗的標籤
然後, 我們又收到影片, 裡面是狗和其他動物的影片, 這下就麻煩了
我該貼上狗的標籤, 還是動物的標籤? 狗是動物, 那是不是所有含有狗的都要加上動物標籤?
這就會有一致性的問題, 而如果大多數影片都有動物的標籤, 那貼這標籤還有意義嗎?
反正怎麼按都有, 那不如不要貼, 所以下標籤時避免使用太過通用的特徵
可是如果下的太細, 例如看到哈士奇的片就貼哈士奇, 那其他的狗片呢?
難道要把所有片中狗的品種全部貼上嗎? 那會夭壽
所以下標籤時, 有用的標籤要能準確的表示特徵, 而且還要能讓這特徵能顯著的分類資料
不會切太細, 又不會涵蓋太多
不過有些例外, 像上圖的一般向標籤, 那個特徵雖然很通用, 但很重要, 這關係到檔案過濾
用來和 R18 做區分, 對於貼有 R18 標籤的檔案拿出去時要非常小心XD

這是我的音樂資料庫片段, 目前只從舊版遷移了一些過來, 許多是新的資料

我們隨便點一個演出者, 聽說這貨現在很紅 (糟糕的, 各方面XD)
這就是通用特徵的範例, 把演出者當標籤貼進去, 這樣點選演出者時, 所有關聯作品都會列出
因此用在音樂的資料庫標籤都蠻長的, 不過我們還是需要判斷一下是否加入標籤
例如:山崎はるか
當前資料庫我只有一項演出者有他, 此時我不會急著加入標籤, 先留在標題加括弧
先觀察, 如果之後有出現第二次, 我才把他加到標籤
因為有些演出者比較 "路人", 嗯, 這不太好聽, 就是可能沒出多少作品就 GG 了
這樣加入標籤它會涵蓋的資源肯定非常有限, 那就借用標題空位就好, 不要消耗標籤 ID
沒辦法, 這是很現實(?)的, 大手總是獲得比較多的資源也是很正常的
這還是和前面特徵的部份有點像, 雖然這已經是明確的屬性, 但是有沒有當成特徵看的價值
就我來說我會評估看看, 當然, 怕麻煩的用戶也是可以全加, 通通加! 這我沒意見, 只是提供一點看法

不過就算涵蓋範圍正確了, 我們還是會有難以下決定的情況
這比較常出現在動畫或漫畫, 例如:女僕 這個標籤, 這是個特徵明顯, 涵蓋範圍也不錯的標籤
有些作品配有這種角色, 毫無疑問的一定貼上這標籤
但是, 如果只是過場, 某個場景或某個畫面出現一下下而已, 這該不該貼?
沒錯, 這作品確實含有女僕, 但是成份太少, 只佔整部片的幾秒鐘, 這該屬於它的特徵嗎?
如果是軟體機器人掃到了就一定貼, 但是對人的判斷就很掙扎了
貼多了, 要查詢時會多很多不必要的資料, 貼少了, 有時想找詳細線索又資料不足
目前我是看心情!XD 覺得有必要留標籤就貼!

當我做雛型出來時老師也有跟我提類似的, 說可以分類影片
當時我沒有能力搞多媒體所以沒有和老師聊太多
現在看了一些展覽, 現代影像識別都開始商業化了, 走出實驗室
對於影像識別來說, 最重要的就是特徵擷取, 擷取後再開始做一些自動化操作
我的系統或許可以支持後端, 也就是分類特徵那裡, 前端加上特徵擷取, 說不定能搞些什麼
不過這類應用可能就不能再限制一定要能備份到光碟
那個就先放在心上, 以後在說, 也可能永遠用不到XD

4 則留言:

  1. 噫變態用久以後也會覺得以前資料夾分半天根本浪費時間,通通tag就好了ww
    不過剛才看到拿來放資料手冊、文件...嗯如果把這些資源套上噫變態的tag系統xddd,不過有些零件還是比較適合貿澤那種系統,雖然他其實是樹狀條件xd
    隨打即找看起來超方便的!不過看起來沒有多重tag處理?例如搜尋的時候用布林指定顯示((tagA|tagB)&tagC)-tagD之類的(是要寫直譯器嗎xd)。沒屋頂拍賣的系統看起來就是樹狀(資料夾)加搜尋硬上,然後缺乏競爭者的情況下就被撈寶用tag系統碾壓了(不過依然地頭蛇就是)
    另外,噫變態的tag系統還可以分類,一種找柯南可以選是找新一(作品中的角色)還是柯南道爾(作者)的概念。這樣的好處是不會所有tag通通混在一起,聲優tag就是聲優,不會和作品類型混在一起。

    回覆刪除
    回覆
    1. >雖然他其實是樹狀條件xd
      是的, 樹狀結構有些時候是有優勢在, 所以我的資料表裡 vfs 就是預留做樹
      取名自 linux 的 virtual file system, 讓資源用樹狀排而不是現在的列表
      樹狀排完加上標籤分組, 雙系統, 不過這似乎偏離標籤的目標, 還在想要怎麼加
      >不過看起來沒有多重tag處理?
      我第一個想到是 IEEE xplore 那套, 那個在 MySQL 裡是不難做 (如果只是標籤)
      但是如果要像目前的 libtdoc 那種分層封裝的架構, 要定義界面會需要動不少腦筋
      對於不同的資料庫像是 xml 或純文字, 它沒像 SQL 本身就可以 AND / OR 搜尋
      可能會需要改成上層用單一標籤界面執行多次搜尋, 然後才做 AND / OR
      若用 HAL 來解釋這就好像軟體模擬, 要不要這樣做還要再想
      直譯器部份就套 yacc 吧, 它就專門搞這種的, 只是很難學XD
      >噫變態的tag系統還可以分類,一種找柯南可以選是找新一(作品中的角色)
      這個若要我來猜應該是多個標籤, "柯南" 是一個標籤, "新一" 也是一個標籤
      然後用另一個資料表來存各個標籤的關聯, 當你詢問 "柯南" 時
      我會把它的所有子標籤全部列出, 然後你點 "新一" 時我就拿這標籤去搜尋
      而作品上面則是同時貼了 "柯南" 和 "新一" 兩個標籤, 這是對標籤建立關聯
      我規劃時是有想過, 但...這太複雜了, 不論 API 界面還是 UI, 都很難做
      要全職有營收的糟糕漫大站才有本錢做XD

      不過從你的回應我突然想到, 其實 vfs 應該可以和標籤關聯樹合體
      電子零件用樹狀的意思是例如 MCU 下面有各家的 MCU 產品, 例如 AVR, ARM
      那其實就好像 MCU 有兩個建立關聯的子標籤: AVR, ARM
      當我點 MCU 時, AVR, ARM 就會列出, 這樣可以找所有 MCU, 也可以只找 ARM 的
      就像 "柯南" 和 "新一" 的關係, 這可以再多加考量一下, 我再想想...(可能再想八年XD)

      刪除
  2. http://newtoypia.blogspot.tw/2016/08/mediainfo.html

    回覆刪除
    回覆
    1. 多謝情報!這個工具撈資料確實蠻便利的
      我目前的想法是用 gstreamer, 這個目前 python 有插件可用
      不過還沒花時間看, 不確定能不能達到目的, 若不行就用 mediainfo
      透過蒐集檔案資訊應該可以自動生成標籤供選取, 更自動, 更懶人, 感覺不錯XD

      刪除