顯示具有 Python 標籤的文章。 顯示所有文章
顯示具有 Python 標籤的文章。 顯示所有文章

2011年11月17日 星期四

系統備份 script

紀錄一下半年前的筆記(快沒時間了...Orz)。

之前備份策略是每個禮拜將 /home , /etc , /var 備份到另一顆硬碟上,過兩個禮拜再存到外接硬碟,但有時候會忘記整理,就會碰到備份檔把整顆硬碟空間吃光的情形;現在改成先檢查硬碟空間再備份,如果空間不夠會在 terminal 上顯示訊息,等待十分鐘後再次檢查硬碟空間,如果要在 cron job 啟動 GUI 程式,只要在 cmd 前面加上 export DISPLAY=:0 就行了。

原本想說用 `wall` 或 `talk` 來送訊息,卻發現 rxvt-unicode 收不到廣播訊息,不信邪想翻翻 `walk` 的原始碼看看到底是怎麼寫的,結果發現原始碼內的輸出訊息不大一樣,才發現 Arch Linux 是用 sysinitv 裡面的 `wall` 而不是 util-linux 內的 `wall`,也因此發現有 pkgtools 這個好用的 package,只要下 pkgfile -s CMD 就可以知道是哪個 package 提供的程式。

看了 sysinitv 內的 dowall.c 發現是用 getutent() 來抓目前登入的使用者,但是抓不到 rxvt-unicode 登入的紀錄,還有 xterm +ut 也是抓不到,後來乾脆就直接去掃 /dev/pts/ ,用檔案擁有者來判斷登入者,也很方便, getutent() 測試原始碼如下,編譯完成後只要執行就會列出有抓到登入的使用者。

#include <sys/types.h>
#include <stdio.h>
#include <utmp.h>
#include <unistd.h>

int main(){

int type ,pid;
char *tty,*id, *user, *host;
struct utmp *utmp;
while ((utmp = getutent()) != NULL) {
type = utmp->ut_type;
pid = utmp->ut_pid;
tty = utmp->ut_line;
id = utmp->ut_id;
user = utmp->ut_user;
host = utmp->ut_host;

printf("%d - %d - %s - %s - %s - %s\n",type , pid, tty, id, user, host);
}
}


因為 dcron 有類似 anacron 的功能,所以只要把 script 丟進 /etc/cron.weekly 就會自動執行,這次還用到 logging 這個 module ,非常方便,有了這個 module 就不必自己辛苦刻 log 了 :)


Reference:

2011年5月26日 星期四

sha1 hash encoded in base64

到了報稅的季節,幫家人安裝報稅軟體的時候發現有提供 SHA1 驗證檔,點進去一看,應該是以 base64 編碼,在 Windows 下有安裝 Python 2.7 ,就直接解碼看看( 沒想到 Python 內建的 IDLE 那麼難用,已經習慣 shell 裡按上下鍵叫出之前的指令了... ),解開一看發現真的是 hash (註一),沒有轉成一般可見的文字,跟以前看過的驗證碼(註二)不一樣 ,還以為是我下錯指令或編碼不是 base64 ,翻了說明文件才發現是我見識淺薄,用 hashlib 的 hash.digest() 就可以得到相同結果,使用 hash.hexdigest() 才會得到一般的驗證碼,但是這串文字又不能直接 decode("hex"),在 Python 裡面 decode("hex") 或 encode("hex") 都是已經轉碼好了(註三),身為一個懶得思考的傢伙,就直接跑去看人家 hashlib 原始碼是怎麼寫的,結果人家是用 C 寫的,後來又發現 binascii 這個 module 可以直接用 hexlify 這個 function 轉換字串,又跑去看原始碼,看到註解還真有點囧
/* make hex version of string, taken from shamodule.c */

for(i=j=0; i<sizeof(digest); i++) {
char c;
c = (digest[i] >> 4) & 0xf;
c = (c>9) ? c+'a'-10 : c + '0';
hex_digest[j++] = c;
c = (digest[i] & 0xf);
c = (c>9) ? c+'a'-10 : c + '0';
hex_digest[j++] = c;
}

沒想到我連這麼簡單的字元轉換都記不起來,還用
bin( ord("a") >> 4 & 0xf )
配合 ascii 表查了一下才瞭解這段程式
算 hash 的時候還忘記要用 binary mode 讀檔...Orz

後來寫了一小段 script 來比對驗證碼是否符合,如果明年幫忙安裝報稅軟體的時候可以拿來用 ( 感覺機會不大 XD ),最後要抱怨一下,這 "個人綜合所得稅電子結算申報程式" 真是他媽的難用,難用到我只是幫家人操作讀取檔案和列印單據就想摔滑鼠的程度。


註一\xe6@\x0e\x86\xdeD\xdeW\x87\xf8\t\x9c=o\xee\xd3\xdcw\xdc
註二
60e6400e86de44de5787f8099c3d6feed3dc77dc
註三"abc".encode("hex") == "616263"

2010年4月18日 星期日

[Script] Split audio files by cue

自從去年那篇 Split(Rename) audio files by cue files 後,覺得還要一個一個打指令實在太麻煩了,就自己寫個 script 來完成全部步驟,所需 package 相同, 只是要多加一個 ffmpeg 來幫 ape 轉檔,shnsplit 內建是 mac ,但是原作者網站都掛了,AUR 上又連到 gentoo 的軟體包去抓,實在很怪,就用 ffmpeg 來轉,如果 cue 是 UTF-8 的話會移除 BOM 再餵給 cuebreakpoint 才不會出錯,分割完後使用 cuetag.sh 設定 tag 資訊,但只支援 id3 和 vorbis,最後再改檔名。

下載

內容:

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# require: ffmpeg, cuebreakpoint, cueprint, cuetag.sh , shnsplit
# use ffmpeg to convert musics

import sys
import os
import glob
import getopt
import subprocess as sp

###### usage ######
usage = """ \
Usage :
-c cuefile: the cue files to be used
-i file : the music file to be split
-o format : specify the format to be converted
"""

###### main ######

def parse_opt():
c_file = m_file = format = ""
try:
opts, args = getopt.getopt( sys.argv[1:],"c:i:o:" )
for o in opts:
if o[0] == "-c":
c_file = o[1]
elif o[0] == "-i":
m_file = o[1]
elif o[0] == "-o":
format = o[1]

# raise Error if not correct args
for f in [ c_file, m_file, format]:
if f == "": raise ValueError

return c_file ,m_file ,format

except ( getopt.GetoptError, ValueError ):
print usage
sys.exit()

def try_cmd( cmd_arg ):
# error strings
error = ["error", "Error", "ERROR"]
try:
ret = sp.Popen([ cmd_arg ],stdout=sp.PIPE,stderr=sp.PIPE,\
shell=True).communicate()
# if error strings passed to stdout or stderror
# raise error and stop the script
for es in error:
if ( es in ret[0] ) or ( es in ret[1]):
raise OSError( "\n\nExecution failed !!!\n" +\
"error messages :\n\n" +\
ret[0] + ret [1] )
return ret[0]
except OSError, e:
raise

def track_rename( c_file ):
track_names = try_cmd("cueprint -t '%02n. %t\n' " + c_file)
track_names = track_names.split('\n')
tracks = glob.glob("./split_cue_tmp_*")
tracks = sorted( tracks )
file_type = tracks[0].rpartition('.')[2]
zf = zip(tracks, track_names)
for t_name in zf:
print t_name[0], t_name[1]
os.rename( t_name[0], t_name[1] + '.' + file_type)

def remove_BOM( utf8_file ):
with open(utf8_file,'r') as f:
content = f.readlines()

check_c = map( ord, [ c for c in content[0][0:3] ] )

if check_c == [239, 187, 191] :
print "There are BOM inside!"
content[0] = content[0][3:]
with open(utf8_file + ".tmp.cue" , 'w') as f:
f.writelines(content)
return utf8_file + ".tmp.cue"
else:
print "File with no BOM"
return utf8_file

def check_format( m_file, format ):
if format == "":
return False
f_string = [format.lower(), format.upper(), format.capitalize()]
f_info = try_cmd("file " + m_file)
print f_info
for s in f_string:
if s in f_info:
print "Orginal file format is the same as specified !!"
return True
# different file format, need conversion
return False

def split_tracks(c_file, m_file, format):
# mac not installed , use ffmpeg to convert ape
if check_format( m_file, "ape"):
new_m_file = m_file.rpartition('.')[0] + '.' + format.lower()
try_cmd("ffmpeg -i " + m_file + " " + new_m_file)
m_file = new_m_file

# cuebreakpoints |shnsplit
s_args = " -a split_cue_tmp_ -o " + format + " "
try_cmd("cuebreakpoints " + c_file + "|shnsplit " + s_args + m_file)
# use cuetag.sh to add tags (only for vorbis and id3)
try_cmd("cuetag.sh " + c_file + " split_cue_tmp_*")

def main():
c_file, m_file, format = parse_opt()
c_file = remove_BOM( c_file )
split_tracks(c_file, m_file, format)
track_rename(c_file)


if __name__ == "__main__":
main()


2009年12月17日 星期四

利用 cron 與 rsync 備份資料

Reference:
鳥哥的私房菜 - 例行性工作排程rsync manualA turial on using rsyncrsync exampletar - exclude files

上次電腦當機後,決心要幫電腦資料做定期備份,才不會一次打破整籃雞蛋,我的構想是每天晚上利用 rsync 備份更動最頻繁的 home 到另一顆硬碟上,每周五利用 tar 將不見時會搥心肝的重要資料打包成 gz 存到另一顆硬碟,再燒到光碟上,並存入隨身碟,總共存放在三處,如此一來,資料消失在世界上的風險性相信可以大大降低。

不過存放備份的硬碟是 fat 格式,造成 rsync 時沒辦法複製權限和一堆有的沒的東東而錯誤,卡在那邊花了不少時間,後來就隨它去了,不能設權限也沒差,反正資料在就好,而且用 tar 打包時就可以保留檔案權限了,而 tar 時原本想用 bzip2 或 lzma 壓縮,但是所花的時間多到讓我受不了,乾脆用簡單的 gzip ,有壓總比沒壓好,下一步要把 anacron 搞懂,才不會因為有時電腦沒開而少了一次備份。

備份的 script 都是用 python 寫的,rsync 的 exclude 跟 tar 有點不太一樣,為了研究這個還花了不少時間, 不過有了範本後,下次要寫其他 script 應該可以更快上手。
rsync script:

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# use 'rsync' to backup files to a fat partition
# write logs into log_file

import time
import sys
import subprocess as sp

# not configure ACL, xattrs currently(can use -AX to sync)
# the same as -va --compress -stats --delete
# args = " --verbose --archive --compress --stats --delete "

# because sync file from ext3 to vfat lead to errors (vfat don't have
# some file attributes), need to remove some args
args = " --verbose --recursive --times --compress --delete "

# need to sync some windows program, so use exclude
# instead of --cvs-exclude
ex_PATTERN = [ "*~", "*.pyc",\
"**cache**","**Cache**","**CACHE**", "**.macromedia/",\
"**.opera/icons/", "**.thumbnails/"]

exclude = ''.join( map( lambda p: " --exclude=" + p, ex_PATTERN))

SRC = " /home/myHome"
DEST = " /mnt/HardDisk/back/sync"
# there is also --log-file=FILE option
log_file = "/home/mylog.log"

def write_log( messages ):
with open(log_file, 'a') as f:
f.writelines("\n***************************************\n")
f.writelines( time.ctime() )
f.writelines("\n***************************************\n")
f.writelines( messages )

try:
ret = sp.Popen(["rsync" + args + exclude + SRC + DEST],\
stdout=sp.PIPE,shell=True).communicate()[0]
write_log(ret)
except OSError, e:
write_log("Execution failed:" + e )





tar script:

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# use 'tar' to backup files, save them as my_tar_Year_Month_Day.tar.gz
# write logs into log_file

import time
import sys
import subprocess as sp

# use -f in front of DEST to prevent args mix up
args = " -czv --exclude-caches-all"

SRC = " /mnt/HardDisk/my_precious \
/mnt/HardDisk/rotl "

TIME_STRING = time.strftime( "%Y_%m_%d", time.localtime() )

DEST = " /mnt/HardDisk/bak/mytar_" + TIME_STRING + ".tar.gz"

log_file = "/home/mytargz.log"

ex_PATTERN = [ "*~", "*.pyc",\
"**cache**", "**Cache**","**CACHE**",\
"**.macromedia/", "**.opera/icons/", "**.thumbnails/"]

exclude = ''.join( map( lambda p: " --exclude=" + p, ex_PATTERN))


def write_log( messages ):
with open(log_file, 'a') as f:
f.writelines("\n***************************************\n")
f.writelines( time.ctime() )
f.writelines("\n***************************************\n")
f.writelines( messages )

try:
# use -f in front of DEST to prevent args mix up
ret = sp.Popen(["tar" + args + exclude + " -f " + DEST + SRC ],\
stdout=sp.PIPE,shell=True).communicate()[0]
write_log(ret)
except OSError, e:
write_log("Execution failed:" + e )

2009年12月8日 星期二

Easy iptables log analyzer

之前寫 iptables rule 的時候,偶爾會翻一下 log 來看有沒有哪些設定出問題,可是蠢人如我只會用簡單的 grep ,主要還是靠肉眼檢視,網路上找到的 analyzer 還要架 http 伺服器和 database,想說只是自己單機要用,不必那麼麻煩,也順便練習寫 python ,就寫了這個小程式做篩選,但先天規劃不良,後來反覆改寫花了不少時間,改到現在也沒那個熱血去翻 iptables log 了 XDD~

這程式主要是利用 sqlite3 這個 module 來把分析過後的 log 存在記憶體內,所以每次使用都要分析一遍,並沒有存實體檔案,因為我當初只想說偶爾看一下而已,沒想太多 :)

分析跑完後會出現一個 CLI ,輸入?就會列出可使用的 command list,主要就是送 query 查詢,可以選擇要顯示哪些欄位,也有些暫存的字串可以紀錄,不用每次打一大串指令,查詢完會先顯示有多少符合的 log,然後就可決定要將結果輸出或存成檔案。

分析的欄位有點簡陋,只有 Interface, IP , Port, Protocol, TCP flags ,其他的全包成同一個字串,有很大的改善空間,但是我很懶惰,所以... XD

檔案下載:eila.tar.gz

2009年12月3日 星期四

[Link] Python Speed

Python Speed
PerformanceTips
Python Patterns - An Optimization Anecdote

可以用 profile 來檢視執行效率

看了以上幾篇,讓我想法改變不少,���過如果完全照裡面的作法來寫,程式碼會變得不怎麼好看而且不好維護,感覺跟 zen of python 有相抵觸

另外還翻到在 lambda 裡面用 if / else 的方法:
  1. Boolean Operations:利用 and, or
  2. x if C else y:會先判斷 C ,再決定要執行 x 或 y
感覺上第一個比較不直覺,但是第二個似乎也不怎麼好看...

2009年10月19日 星期一

[Python] Slicing on sequences

今天在 comp.lang.python 的討論裡看到一篇 Reverse Iteration Through Integers
,提到 list[::-1] 的用法,就找了一下 python docs

Sequences also support slicing: a[i:j] selects all items with index k such that i <= k < j.

When used as an expression, a slice is a sequence of the same type.

This implies that the index set is renumbered so that it starts at 0.

Some sequences also support “extended slicing” with a third “step” parameter: a[i:j:k] selects all items of a with index x where x = i + n*k, n >= 0 and i <= x < j.



所以 a[::-1]  的 index X 會由 X = 0+1*(-1) = -1,X = 0+2*(-1) = -2 這樣慢慢往回跑

Test code:
#! /usr/bin/env python
# -*- coding: utf-8 -*-
a = 123450
print "a=",a,"\t type = ",type(a)
b = str(a)
print "b=",b,"\t type = ",type(b)
c = b[::-1]
print "c=",c,"\t type = ",type(c)
d = int(c)
print "d=",d,"\t type = ",type(d)

[小程式]hipls

有時候無聊會想聽聽廣播,又懶得多開一個網頁, hinedo 似乎可以直接播放,但之前用 openSUSE 時編不起來,就乾脆自己寫一個,這程式會直接到 hiChannel 抓所有的廣播電台清單,讓使用者選擇想聽那幾個電台,然後再將這幾個電台網址存成一份 playlist ,只要使用支援 mms 協定的播放器播放就可以聽了,目前遇到的問題是用 mpayer 播放會顯示亂碼...

用 python 內建函式庫寫的,照理說 windows 也可以使用,不過我只在 linux 上試過,有問題歡迎回報 :)

Updated 11/05:修改顯示電台清單時,因為中文字元長度問題而無法對齊的狀況

Usage:
1. save as hipls.py
2. python hipls.py

Download:hipls.py

Source Code:

#! /usr/bin/env python
# -*- coding: utf-8 -*-
#
# Author : lefthaha (at) gmail{dot}com
# License :http://creativecommons.org/licenses/by-nc-sa/2.5/tw
# Last Modify : 2009/11/05
#

import sys
import urllib2
import re
import string

def get_html(url):
# must add header to connect hichannel
# http://www.voidspace.org.uk/python/articles/urllib2.shtml
headers = {"User-Agent":" Mozilla/5.0 "}
req = urllib2.Request(url, None, headers)
response = urllib2.urlopen(req)
return response.readlines()

def get_match(pattern, target):
result = []
for line in target:
result.append( pattern.findall(line) )
# strip empty result , able to handle multiple matches
result = filter(lambda x: x is not None, result)
result = [ x[i] for x in result for i in range( len(x) ) ]
return result

def show_all(rlist):
# Updated 2009/11/05
print "目前搜尋到的電台有:"
for num in range(0, len(rlist)-1, 2):
name1 = rlist[num].name.decode("UTF8")
mytab = len(name1.encode("BIG5")) - len(name1)
print "({0:02}) {1:{4}} ({2:02}) {3}".format(num+1,\
rlist[num].name, num+2, rlist[num+1].name, 30+mytab)
print "請輸入你喜歡的電台編號,並且以逗號區別 (ex : 5,4,3,2,1):"

def edit_list(rlist):
show_all(rlist)
inl = re.split(r",|," ,sys.stdin.readline() )
print "你所輸入的電台順序是:"
for num in range( len(inl) ):
inl[num] = string.atoi(inl[num])-1
print "({0}) {1}".format(num+1,rlist[inl[num]].name)
print "以上是否正確?(Y/n)"
if re.match(r"[y|Y]", sys.stdin.readline() ) is not None:
return inl
else:
print "請重新選擇電台順序"
return None

def create_list(all_list, to_save):
entries = len(to_save)
content = "[playlist]\nNumberOfEntries={0}\n\n".format(entries)
for num in range(entries):
content = content + \
"File{0}={1}\nTitle{0}={2}\nLength{0}=-1\n\n".format(num+1,\
all_list[ to_save[num]].get_mms(),all_list[ to_save[num]].name )
content = content + "Version=2"
plsf = open("MyHipls.pls",'w')
plsf.write(content)
plsf.close()

class Radio:
def __init__(self, rid_url):
# strip useless strings
rid_url = re.sub( r".*id=|&lt;", "", rid_url)
rid_url = re.sub( r"\">", ",", rid_url)
# split and assign radio id and name
self.rid, self.name = re.split(",", rid_url)
self.player_url="http://hichannel.hinet.net/player/radio/\
index.jsp?radio_id=" + self.rid
def get_mms(self):
page = get_html(self.player_url)
#?data=mms://bcr.media.hinet.net/RA000007&id=RADIO:206&group="+g);
line = get_match(re.compile(r".*=mms:.*"), page)
line = re.sub(r".*mms", "mms", line[0])
self.mms_url = re.sub(r"&id.*", '', line)
return self.mms_url

def main():
list_url = "http://hichannel.hinet.net/radioRank.do?typeId=99"
list_page = get_html(list_url)
# example : &lt;a href="/radio.do?id=177">ICRT&lt;/a>
rids = get_match( re.compile(r"&lt;a.*\"/radio.+\d\">[^&lt;]+?&lt;"), list_page)
radio_list=[]
for line in rids:
# initialize class Radio
radio_list.append( Radio(line) )
list_to_save = None
while( list_to_save is None):
list_to_save = edit_list(radio_list)
create_list(radio_list, list_to_save)
print "已將所選擇的電台清單儲存至 MyHipls.pls !"

if __name__ == "__main__":
main()

2009年9月27日 星期日

Upgrade Comix Bookmarks from 3.x to 4.x

!! Updated 2009/10/07 for comix 4.0.4 have changed the bookmark path

Comix 由 3.x 升級到 4.0時,會自動偵測之前的書籤,但只能選擇刪除,所以就自己寫程式將舊的書籤更新到新格式,順便學一下 Python 。
怠惰的天性使然,這個小程式花了好幾個月才完成(別打我,當兵的時候每次放假只想玩,沒什麼動力寫程式啊...),所以裡面的縮排和註解很亂,請多包涵,有空我會再花時間去看看 Style Guide for Python Code

使用方法:
1. Save as upbmk.py
2. chmod +x upbmk.py
3. ./upbmk.py OLD_BOOKMARK_FILE


#! /usr/bin/env python
# -*- coding: utf-8 -*-
# upbmk.py - Upgrade Comix bookmarks form 3.x to 4.x
# Usage : upbmk.py [ OLD_BOOKMARK_FILE ]

import os, sys, shutil, re
import cPickle
import subprocess

import zipfile, tarfile

if len(sys.argv)==2 :
ob_path=sys.argv[1]
else:
ob_path="./bookmarks_data"

# open current / old book mark file , make backups
# updated 2009/10/07 , for comix 4.0.4 changed bookmark path
# tStr = os.path.expanduser("~/.comix/bookmarks.pickle")
data_path = os.getenv("XDG_DATA_HOME", os.path.expanduser("~/.local/share") )
tStr = os.path.join(data_path,"comix","bookmarks.pickle")
shutil.copyfile( ob_path, "./backup_old_bookmarks_data")
shutil.copyfile( tStr, "./backup_current_bookmarks.pickle")
cbf = open(tStr,'r')
obf = open(ob_path,'r')

#load current and old bookmarks
cbk = []
cbk.append(cPickle.load(cbf))
cbk.append(cPickle.load(cbf))
odata = cPickle.load(obf)
odata2 = cPickle.load(obf)
obk = []
cbf.close()
obf.close()

for num in range(len(odata)):
temp = odata[num],odata2[num]
obk.append( temp )

del cbf,obf,odata,odata2

# distinguish file types
ZIP, RAR, TAR, GZIP, BZIP2 = range(5)
def what_type( filepath ):
try:
if not os.access( filepath , os.R_OK ):
print " You don't have the permission to read ",filepath,\
" ,you better check it out !! "
sys.exit()
if zipfile.is_zipfile( filepath ):
return ZIP
# use magic numbers to distinguish type
opf = open( filepath , 'r' )
magic = opf.read(8)
opf.close
if magic.startswith('\x52\x61\x72\x21\x1a\x07\x00'):
return RAR
if magic.startswith('\x1f\x8b\x08'):
return GZIP
if magic.startswith('\x42\x5a\x68'):
return BZIP2
# this can also read tar.gz , tar.bz2 ,so put it to the last one
if tarfile.is_tarfile( filepath ):
return TAR
# No of above , check it later
else:
return None
except Exception:
print " Error when reading ",filepath
return None

# test if command "rar" ,"unrar" exist or not
rcmd = None
for testcmd in ["rar","unrar"]:
try:
subprocess.Popen( [testcmd], stdout=subprocess.PIPE)
rcmd = testcmd
except Exception:
pass

# count how many image files in the archive
def get_pages( filepath , archive_type ):
all_files=[]
if archive_type == ZIP :
zfile = zipfile.ZipFile( filepath , 'r' )
all_files = zfile.namelist()
elif archive_type in ( TAR , GZIP , BZIP2 ) :
tfile = tarfile.open( filepath , 'r')
all_files = tfile.getnames()
elif archive_type == RAR :
if rcmd != None:
rout=subprocess.Popen([ rcmd,"vb",filepath],stdout=subprocess.PIPE)
# may contain one newline character
all_files = rout.stdout.readlines()
#print all_files
else:
print ' Unable to extract '+ filepath +' with "rar" or "unrar" '
# not an archive , just a image , scan the directory
elif re.search(r"\.(jpg|jpeg|png|gif|tif|tiff)\s?$", filepath, re.I):
all_files = os.listdir( os.path.dirname(filepath) )
# Error on reading files
else:
print ' Unable to handle" '+ filepath +'" , sorry'
return 0
imgs = 0
#count image files
for name in all_files:
if re.search(r"\.(jpg|jpeg|png|gif|tif|tiff)\s?$",name,re.I):
imgs = imgs + 1
# return number of total image files
return imgs

# convert tuple to list for manipulation
# insert filename,total pages,aechive type
obklist = []
for num in range(len(obk)):
obklist.append( list(obk[num]) )
obklist[num].insert( 0 , os.path.basename( obklist[num][0] ) )
file_type = what_type( obklist[num][1] )
obklist[num].append( get_pages( obklist[num][1], file_type) )
obklist[num].append( file_type )

for bmk in obklist:
cbk[1].append( tuple( bmk))

cbf = open(tStr,'wb')
cPickle.dump( cbk[0], cbf, cPickle.HIGHEST_PROTOCOL)
cPickle.dump( cbk[1], cbf, cPickle.HIGHEST_PROTOCOL)
cbf.close()

print " Upgrade Complete !! After Checking the new bookmarks,\n\
remember to delete backup files "

####### print out data inside bookmarks #########

#print len (cbk[1][0]) // 5
#for num in range(len(cbk[1][1])):
# print cbk[1][1][num-1]
#print cbk[1]
#print len(obk)
#print obk

######### bookmark file format ###########

# cbk = [ 'version',('cbookmarks') ]
# cbookmarks = [ (cbmk1),(cbmk2),....]
# cbmk = [ filename , path , bmk_page , total_pages , archive type]
# obk = [ oldbmk1 , oldbmk2 ...]
# oldbmk = [ path , bmk_page ]

2009年9月21日 星期一

Split(Rename) audio files by cue files

Reference:Split lossless audio (ape, flac, wv, wav) by cue file in Ubuntu
Tools: cuetools, shntools,audio file decoder

起因:
有塊 CD 整個壓成一個 *.tta 加 *.cue ,在 Windows 下要播放時,可用 foobar2000 直接讀取 *.cue ,但是在 linux 下似乎沒這麼方便,所以就乾脆把它每首都拆開

過程:
1. *.cue 用 more 下去看是亂碼, 用 gedit 一個個測才查出編碼是CP932
2. 怕命名以後也是亂碼,就用比較笨的方法, tta 先解成 wav,再下 cuebreakpoints *.cue | shnsplit *.tta, 分割成一個個的 split-track*.wav
3. 用 Python 讀 *.cue 進來, str.decode("CP932"), 確定可以正常顯示日文,再找每一首的檔名, os.rename() 重新命名

因為只有一塊要轉,就直接用 Python Interpreter 作業,一首首命名,沒寫什麼程式,單純紀錄一下所用的工具。

自去年入伍服役以後第一次更新 blog, 11 個月的時間總算熬過去了,外面的空氣真好 :)