--- Title: pythonでfoobarのalternativeを作る 31 Author: yamasyuh68 Web: https://mimemo.io/m/mqLXOlJVKLlzQ19 --- 190620 # DB更新 watchDog 対応 - 画像処理の方に行ったつもりだったんだけど帰りの地下鉄でやり方が頭に浮かんできたので帰ってからやってみた - この機能が必要なのは、タグを修正するから 私の膨大な音楽ファイルはタグも不統一で文字化けしてたり全くタグをつけてなかったり このアプリで見つけた都度少しづつ直してるが、それをすぐDBに反映させたいわけです 今のDB作成ファイルだと対象フォルダの全スキャンから始まるので時間がかかる タグを書き換えた、変更したファイルだけ更新するようにすればほぼ一瞬で更新は終わります そのためのスクリプトということになる ## database_dog.py ``` import os ,mutagen import sqlite3 # update form dog_log class makeDB(): def __init__( self): self.fname=os.path.join(os.path.dirname(__file__) , 'watchdog.log') if not os.path.exists(self.fname): print('missing watchdog.log') input() quit() self.db=os.path.join(os.path.dirname(__file__) , 'database.db') if not os.path.exists(self.db): print('missing database.db') input() quit() conn = sqlite3.connect(self.db) c = conn.cursor() c.execute('create table IF NOT EXISTS musics(path PRIMARY KEY,mdate,flag,artist,album,title)') self.count={'new':0 , 'same':0,'mod':0, 'update':0 } self.first(c) # ログを開いてDBのチェック # quit() self.second(c) # フラグがNoneのものを更新 c.execute('DELETE FROM musics WHERE flag=4') # フラグが4のものを削除 c.close() conn.commit() conn.close() print(self.count) os.remove(self.fname) input('') def first(self,c): # フルパスをフラグNoneで新規挿入、成功したらそのまま # 失敗したらmdate比較して 同じならフラグ1 違ってたらフラグNone # フルパスが存在しなければFBから探してあったらフラグ4 with open(self.fname,'r') as f: flist=f.readlines() flist_u = list(set(flist)) # リストにして重複行を削除 # print(flist_u) for p in flist_u: p = p.replace('\n','') p = p.replace('\r','') # print('p',p) if os.path.exists(p): # print('f',p) mtime=os.path.getmtime(p) try: c.execute( "INSERT INTO musics (path,mdate,flag) VALUES (?,?,?)" , (p,mtime,None )) self.count['new']+=1 except: c.execute('select mdate from musics where path = ?',(p, )) res=c.fetchone() if res : if res[0]==mtime : # 同じなら flag=1 c.execute('update musics set flag = ? where path = ? ',( 1, p )) self.count['same']+=1 else : # 違ったら flag=None c.execute('update musics set mdate=?,flag = ? where path = ? ',( mtime,None, p )) self.count['mod']+=1 else : # でーた削除の場合 c.execute('select mdate from musics where path = ?',(p, )) res=c.fetchone() if res : # 存在したらフラグを4とする c.execute('update musics set flag = ? where path = ? ',( 4, p )) def second(self,c): c.execute('select path from musics where flag IS NULL') for p in c.fetchall(): # print(p) try: m = mutagen.File(p[0], easy=True) # m は辞書で要素はリスト、取り出し方が難しい tup=1, except: print('error-- ' + p[0]) c.execute('update musics set flag = ? where path = ? ',( 4, p[0] )) continue try: tup += m['albumartist'][0], except: try : tup += m['artist'][0], except: tup += '?', try : date=m['date'][0] except: date='?' try : album=m['album'][0] except: album='?' if date=='?' and album=='?' : tup += '?', else: tup += '['+ date + ']' + album , title='' sl='' try : for i in m['discnumber'][0]: if i == '/': break else: sl += i title+='{:01}.'.format(int(sl)) except: pass ti='' try: for i in m['tracknumber'][0]: if i == '/': break else: ti += i title+='{:02} '.format(int(ti)) except: pass try: title += m['title'][0] except: title='?' tup +=title, tup += p[0], c.execute('update musics set flag=?,artist=?,album=?,title=? where path=?' , tup ) self.count['update']+=1 makeDB() ``` - 基本的な設計は ①本体でwatcDogを実装、変更のあったファイルをログファイルに書き出す ②それをこのスクリプトで読み込んでDBを更新する - で、このスクリプトだが、基本はもとのDB作成ルーチンと同じ 違いは、イテレータをglobの列挙ファイルとするか、logに列挙したファイルとするかだけ ただし細かい違いもあるので、もとのスクリプトとは別にすることにした、その方が安全だから コンソールだけど最後にログも表示するようにした 本体からは別プロセスとして起動させる - 想定外だったのはwatcdogは同じファイルを何度か拾うこと 理由はよくわからないが、ログには重複したファイルが含まれることになる で、一旦リストとして読み込んだ後、set()でユニークなリストにしてからイテレータとして使った もしかしたら重複したままでも問題ないかもしれないけどそれはsqlの仕様の問題も絡むからあえて実験していない - うまく動いてくれてます、かなりfoobarライク でもfoobarはもっとリアルタイムでライブラリに変更が反映される もう少し いつも思うけど、**foobarはすごいよなあ** ### ツリーのコンテキストメニューでアルバムをリストに加えれるようにした もとはドラッグオンリーだった 新しく書くのは面倒なのでドラッグを強引に偽装した バギーかもしれない ( ̄― ̄?) ---- → [pythonでfoobarのalternativeを作る #](https://mimemo.io/m/3kyw8o3neWG6Lrg)