小站会根据您的关注,为您发现更多,

看到喜欢的小站就马上关注吧!

下一站,你会遇见谁的梦想?

小站头像

Machael Tips

Machael are you crazy, are you crazy machael.

RSS 归档

站长

21人关注

站长在关注

2013 / . 05 / . 28

A homemade extension for popclip to look up words through Eudic.

之前花了98元买了买了个欧路词典也已经有一段时间了,虽然取词功能略残废了一些,不过支持扩展词典上比较强,官方带词典转换工具,我自己又有一大堆现成的词典,自然这就成了不二之选。

当然,它也继承了多数国产软件的通病,开放性太弱。没办法用AppleScript直接控制欧路词典。但是,拖AppleScript足够强大的福,依然还是可以通过迂回的手段来控制的。

于是,我用AppleScript给Popclip写了一个扩展,在Popclip的弹出菜单里添加一个选项,直接调用欧路词典来查词。


tell application "System Events"
    set timeup to 3
    set timecounter to 0
    set the clipboard to "{popclip text}"
    try
        tell application id "com.eusoft.eudic" to activate
    on error
        display dialog "Can not open Eudic"
    end try
    delay 0.2
    repeat
        set eudic to first application process whose frontmost is true
        if name of eudic is "Eudic" then
            try
                get name of first window of shit
                set nowindow to false
            on error
                set nowindow to true
            end try
            if nowindow is true then
                tell application id "com.eusoft.eudic" to reopen
            end if
            keystroke "v" using command down
            key code 76
            exit repeat
        else
            set timecounter to timecounter + 0.3
            delay 0.3
        end if
        if timecounter is greater than timeup then
            exit repeat
        end if
    end repeat
end tell

这里要说的是我几乎完全不会AppleScript,也不打算违背自己原来说的不学不能跨平台的语言(但这里不用AppleScript还真的很难实现),不过好在AppleScript的流程足够标准,我能想出整体结构但不懂语法,所以几乎每想出一句要干什么都要google一下在AppleScript里语法是怎么写的。最后倒也真搞出来了。

上面贴出的是最主要的部分,剩下如何构建完整的popclip扩展,请移步观看popclip extension在github上的说明文档

A homemade extension for popclip to look up words through Eudic.

A homemade extension for popclip to look up words through Eudic.

2013 / . 05 / . 13

Shift time line in subtitle file.

外挂字幕时间跟视频对不上怎么办,写个python程序来帮您忙:

#!/usr/bin/env python2.7

from datetime import timedelta
import re, os
from contextlib import closing
from itertools import izip

def logLevel(level=0):
    loglevel = {0:logging.FATAL,
            1:logging.INFO,
            2:logging.DEBUG}
    return loglevel.get(level, logging.FATAL)

def formatTimedelta(timedeltaobj):
    secs = timedeltaobj.total_seconds()
    H, r = divmod(secs, 3600)
    M, r = divmod(r, 60)
    S = int(r)
    Ms = (r - S)*1000
    return '{0:0>2.0f}:{1:0>2.0f}:{2:0>2d},{3:0>3.0f}'.format(H, M, S, Ms)

class TimeParser(object):
    def __init__(self, delimPattern=r'(\d{1,2}):(\d{1,2}):(\d{1,2})(,(\d{1,3}))',
            fieldIndexesList=[0, 1, 2, 4],
            fieldNamesList=['hours', 'minutes', 'seconds', 'milliseconds'],
            debug = 0):
        #self.logger = logging.getLogger('TimeParser')
        self.reDelimiter = re.compile(delimPattern)
        #self.logger.debug(self.reDelimiter)
        self.timeUnitList = fieldNamesList
        #self.logger.debug(self.timeUnitList)
        self.fieldIndex = fieldIndexesList
        #self.logger.debug(self.fieldIndex)

    def __call__(self, timestr='00:00:00,000'):
        timePointGen = ( int(j) for c,j in enumerate(i for i in self.reDelimiter.search(timestr).groups()) if c in self.fieldIndex)
        timeParDict = dict(izip(self.timeUnitList, timePointGen))
        #self.logger.debug(timeParDict)
        return timeParDict


def main(fileName=None, shiftSecs=0.0, timeLinePattern=None, debug=0):
    #logger = logging.getLogger('main')
    wfileName = '{0}_{2}_{1}'.format(*os.path.splitext(fileName)+('shift',))
    shiftSecs = float(shiftSecs)
    timeParser = TimeParser()
    shiftDelta = timedelta(seconds=shiftSecs)
    #logger.debug(shiftDelta)
    if timeLinePattern is None:
        timeLineSpliter = re.compile(r'(\d{2}:\d{2}:\d{2},\d{3})\s*-->\s*(\d{2}:\d{2}:\d{2},\d{3})')
    else:
        timeLineSpliter = re.compile(timeLinePattern)
    with closing(open(fileName)) as fh, closing(open(wfileName, 'w')) as wfh:
        for line in fh:
            line = line.rstrip()
            if timeLineSpliter.search(line):
                beginTimeStr, endTimeStr = timeLineSpliter.search(line).groups()
                beginTimedelta = timedelta(**timeParser(beginTimeStr))
                endTimedelta = timedelta(**timeParser(endTimeStr))
                beginTimedelta = beginTimedelta + shiftDelta if beginTimedelta + shiftDelta > timedelta(0) else timedelta(0)
                endTimedelta = endTimedelta + shiftDelta if endTimedelta + shiftDelta > timedelta(0) else timedelta(0)
                wfh.write('{0} --> {1}\n'.format(formatTimedelta(beginTimedelta), formatTimedelta(endTimedelta)))
            else:
                wfh.write('{0}\n'.format(line))

if __name__=='__main__':
    import sys
    main(sys.argv[1], sys.argv[2])

 

####################################

用法;

timeshift.py  [字幕文件(默认srt格式)] [偏移时间(秒)]

 

例如

timeshift.py file.srt -10.9

 

相当于所有对话提前10秒900毫秒。

2013 / . 04 / . 25

Forcing Command Line Tools Network Connections via a Proxy Server.

在Linux下,对于命令行工具可以使用tsocks或proxychains来强制其使用代理服务器作网络连接。不过到了Mac下支持多种代理方式Proxychains不能用,于是只剩下了tsocks,经实验发现tsocks在mac下是可以编译通过的。

近来发现macports更新源的速度极其慢(从服务器同步ports.tar文件),下载速度只有10多kb/s。在System References里设置代理,但是速度依然很慢,怀疑是不是这个设置对命令行下不起作用。

于是乎,像到了Linux下的强制使用代理工具tsocks和proxychains(mac下不能用)

这里简单说一下tsocks的安装和使用:

首先自然是从苹果开发者网站下载UNIX命令行开发工具,(或者AppStore里下载xcode,然后在xcode里安装)

其实安装brew(方法见homebrew官网),用brew来安装autoconf。

brew install autoconf

之后下载tsocks源码:

wget 'http://ftp1.sourceforge.net/tsocks/tsocks-1.8beta5.tar.gz'

没装wget就用curl代替

解压并进入目录

tar -xzf tsocks-1.8beta5.tar.gz && cd tsocks-1.8
wget 'http://marc-abramowitz.com/download/tsocks-1.8_macosx.patch'

下载mac补丁,打补丁

patch < tsocks-1.8_macosx.patch

用autoconf重新生成configure文件,编译文件

autoconf
./configure && make

安装文件

sudo make install

到此安装完成

然后就是需要写tsock的配置文件了

在/etc下新建一个tsocks.conf文件,以我的为例:

  1 local = 192.168.0.0/255.255.0.0                                                                                       

  2 local = 210.46.0.0/255/255.0.0

  3 server = 127.0.0.1

  4 server_port = 3280

  5 server_type = 5

请忽略行号,local表示不使用代理的网络地址,server是代理服务器,server_port是端口号,server_type不出意外一定是5。

最后,你可以使用tsocks源码目录下的validateconf执行文件来检查配置文件是否有语法错误,直接运行就行:

Forcing Command Line Tools Network Connections via a Proxy Server.

没有报错,就说明一切正常。

然后怎么使用呢?仅仅是简单地把tsocks加载原来需要运行的命令前面就行了。

例如:

tsocks wget www.facebook.com

 

最最后,需要多说一点的是,如果你使用的是http代理(例如使用go马赛克ent),因为tsock只能用ssh tunnel,自然是没有办法的,但是可以有迂回的办法。

你可以通过自己“远程”连接自己,建立一个本地的监听端口,把它转发到http代理的监听端口就可以了。

例如:

ssh -TfqnN -L 3280:127.0.0.1:8087 myname@127.0.0.1

 

 

2013 / . 04 / . 04

Simple and fast way to record voice under OS X mountain lion

突然萌生了一个想要录语音的欲望,于是翻了一下系统自带的程序里发现10.8貌似已经不能录音了。 然后又打开AppStore,搜索了一下Voice Record,发现我去你妹的一个免费的工具都没有。

毕竟我在多年前还是着实研究过一段时间音频视频处理,所以即使没有现成的免费傻瓜工具,但咱还是能轻松搞定的。

这里需要用到一个强大的命令行音频处理工具sox,它的功能太繁多了,这里只用到一个录音功能。

想要方便省事的安装这个工具,最好需要事先安装macports或brew。

例如我用的是brew,终端输入:

brew install sox faac lame

这里除了sox以外还安装了faac:aac(m4a)编码器,lame:mp3编码器,因为sox直接输出的格式是wav,太大了,所以最好还是重新编码成有损压缩格式aac或mp3,毕竟对于语音来说,对音质的要求太低了。

 

1--最简单的录音方法

sox -d output.wav

-d是指使用默认音频设备(coreaudio),output.wav是输出文件

 

2--添加参数

sox -d -r 32k -b 16 --buffer 2048 output.wav

即使是输出wav格式,默认的参数也还是还是太高了(相对于无损的CD而言),所以可以考虑略降低一点,-r将采样率设为32000(语音没什么高频部分,用22050都没什么大问题),-b设置bit深度为16(跟CD音质一样),buffer设的低一点,防止可能出现报错情况。

 

2--直接输出mp3格式

sox -d -r 32k -b 16 -t wavpcm --buffer 2048 -|lame --abr 128 - output.mp3 -m joint --bitwidth 16

这样就可以直接保存成mp3格式。--abr动态平均码率128,-m设置联合立体声。

lame作为最好的mp3编码器,选项还是相当多的,这里仅仅是一个最简单的例子。更多设置需要自行参考帮助文档。

 

3--保存成aac格式

sox -d -r 32k -b 16 -t wavpcm --buffer 2048 -|faac -b 128 - -o output.aac

原理上跟前面的mp3设置相似,就不多说了。

 

无论用上面的那种方法,结束录音的时候直接按Ctrl+c就可以了。

怎么样,不管什么领域,只要懂一些皮毛就可以少当多少次冤大头。

Simple and fast way to record voice under OS X mountain lion

 

2013 / . 04 / . 03

Yet another implementation of hiding icons from launchpad.

之前给出的隐藏图标的方法虽然AppleScript实现了一个图形化的操作方式,但是其实并不方便,一是不支持批量操作,每隐藏一个图标就需要运行一遍。而是并不是直接从launchpad中选择要隐藏哪个图标,于是你得自己记住哪个图标想要隐藏但还没有被隐藏。

所以,我用Python写了一个更便捷的实现方法。

Yet another implementation of hiding icons from launchpad.

不用我多说,大家看截图就知道这个工具怎么工作了。

###################################

#!/usr/bin/env python2.7

import sqlite3 as sql
import glob
import os.path as path
import subprocess as subp

dbFile = glob.glob(path.expanduser('~')+'/Library/Application Support/Dock/*.db')[0]
print dbFile
dbCon = sql.connect(dbFile)
dbCur = dbCon.cursor()
appList = [i[0] for i in dbCur.execute('select title from apps')]
preName = None
maxWidth = 60
for i, n in enumerate(appList):
    name = '{0:>3}: {1}'.format(i+1, n.encode('gbk'))
    if preName is None:
        preName = name
        try:
            appList[i+1]
            continue
        except IndexError:
            print name.decode('gbk')
            continue
    if len(preName) + len(name) < maxWidth:
        print '{0:<{2}}{1}'.format(preName, name, maxWidth/2).decode('gbk')
        preName = None
    else:
        print preName
        preName = name
        try:
            appList[i+1]
            continue
        except IndexError:
            print name.decode('gbk')
indexString = raw_input('Input one or more apps\' indexes you want to hide:\n>> ')
indexList = indexString.split()
if indexList:
    raw_input(u'{0} "{1}" {2}'.format('You want to hide',
            '", "'.join(u'\033[91;1m{0}\033[0m'.format(appList[int(i)-1]) for i in indexList),
            'from Launchpad.'))
for i in indexList:
    for j in dbCur.execute(u'delete from apps where title="{0}"'.format(appList[int(i)-1])):
        pass
   
dbCon.commit()
dbCon.close()
subp.call('''osascript -e 'tell application "Dock" to quit' ''', shell=True)


2013 / . 04 / . 01

Hide App Icons from Launchpad

同样是把平板的一些特性带到桌面系统,Mac的Launchpad终归还是比烂B Windows8 Metro的满屏卸载程序里找程序要强的多,但是唯一让人不爽的一点是不能设置图标隐藏,你的/Applications下的所有程序都会自动出现在Launchpad里。

最近发现一个AppleScript的实现,可以隐藏图标:

on open the_items
    my Lighten_LaunchPad(the_items)
end open
on Lighten_LaunchPad(the_items)
    repeat with the_item in the_items
        set the_item to the_item as alias
        --try
        tell application "Finder"
            set nameString to name of the_item
            set sost to (my get_the_name(nameString)) as string
        end tell
        display dialog "Are you sure you want to remove \"" & sost & "\" from the Launchpad? The app itself won't be deleted."
        try
            set my_command to "sqlite3 ~/Library/Application\\ Support/Dock/" & "*.db \"DELETE from apps WHERE title=" & (quoted form of sost) & ";\";osascript -e 'tell application \"Dock\" to quit'"
            do shell script my_command
        on error the error_message number the error_number
            activate
            if the error_number is not -128 then
                if the error_number is 1 then
                    set the error_text to "Error: " & the error_number & ". " & "You probably have too many old versions of the LaunchPad database file." & return & return & " To fix that, move some old ones out of ~/Library/Application Support/Dock. You can safely move any file with a name that ends with \".db\" or \".db.backup\" except for the most recently modified one." & return & return & "Do you want me to open that folder for you?"
                    display dialog the error_text buttons {"Yes, please open it.", "Cancel"} default button 1
                    if button returned of the result is "Yes, please open it." then
                        do shell script "open" & space & quoted form of POSIX path of (path to application support folder from user domain) & "Dock"
                    end if
                    error number -128
                else
                    set the error_text to "Error: " & the error_number & ". " & the error_message
                    display dialog the error_text buttons {"Cancel"} default button 1
                end if
            else
                error number -128
            end if
        end try
    end repeat
    display dialog "All done!" buttons {"OK"} default button 1
end Lighten_LaunchPad
on get_the_name(nameString)
    tell AppleScript
        set olD to text item delimiters
        set text item delimiters to "."
        set reqItem to -1
        if last item of nameString = "." then set reqItem to -2
        set theName to text item reqItem of nameString
        --try
        set theNameNoExt to ((text items 1 through (reqItem - 1) of nameString) as string)
        set text item delimiters to olD
        return {theNameNoExt}
    end tell
end get_the_name
on run
    set the_items to ((choose file) as list)
    Lighten_LaunchPad(the_items)
end run

打开你的AppleScript Editor,把上面的内容粘进去,保存成app格式。

运行会出现一个文件选择框,到/Applications目录下选择你需要隐藏的应用就可以了。

尽管我对AppleScript只知道一点皮毛,但是大致看了一下还是能发现能够隐藏Icon的实际起作用的部分(用粗体标出来了),剩下的不过是文件名的处理。

其实就是把Sqlite数据库里相关应用的条目删掉了而已。

知道核心部分了,我用PyQt也可以弄一个一样的工具,更不需要“do shell script”来实现sqlite调用。

改用shell的更可以方便批量处理。

 

2013 / . 03 / . 29

Literature Information Aggregate Assistant

天天逼得还得看这些个害人害己的二逼文献,连提取信息都是件痛苦的事。

于是用PyQt4写了个工具助手,可以直接输出成制表符分割的单行信息,方便粘到表格软件里。

还算不上是完全版,以后发现缺什么东西再往上添

Literature Information Aggregate Assistant

 

###############################

#!/usr/bin/env python2.7
from PyQt4.QtCore import pyqtSignature, Qt
from PyQt4.QtGui import QApplication, QDialog, QButtonGroup
import sys, re, string, random
from itertools import izip
from extractArticle_ui import Ui_Dialog

class extractArticleDialog(QDialog, Ui_Dialog):
    def __init__(self, clipboard, parent=None):
        super(extractArticleDialog, self).__init__(parent)
        self.__clipboard = clipboard
        self.setupUi(self)
        self.buttonBox1 = QButtonGroup(None)
        self.buttonBox1.addButton(self.checkBoxTest, 1)
        self.buttonBox1.addButton(self.checkBoxValidation, 2)
        self.buttonBox2 = QButtonGroup(None)
        self.buttonBox2.addButton(self.checkBoxExperiment, 1)
        self.buttonBox2.addButton(self.checkBoxMethodology, 2)
        self.buttonBox2.addButton(self.checkBoxReview, 3)
        self.buttonBox3 = QButtonGroup(None)
        self.buttonBox3.addButton(self.checkBoxPositive, 1)
        self.buttonBox3.addButton(self.checkBoxNegative, 2)
   
        self.checkBoxTest.setChecked(1)
        self.checkBoxExperiment.setChecked(1)
        self.checkBoxPositive.setChecked(1)
        self.spinBoxID.setValue(1)

        self.pushButtonIdentityClear.setFocusPolicy(Qt.NoFocus)
        self.pushButtonTest.setFocusPolicy(Qt.NoFocus)

    @pyqtSignature('')
    def on_pushButtonDiseaseClear_clicked(self):
        self.lineEditDisease.clear()
        self.lineEditDisease.setFocus()

    @pyqtSignature('')
    def on_pushButtonClearAll_clicked(self):
        for lineEdit in ('lineEdit'+i for i in ('Disease', 'Effectiveness',
            'Country', 'Ethnicity', 'Factor', 'Method', 'P', 'OR', 'Title')):
            self.__getattribute__(lineEdit).clear()
        self.textEditResult.clear()
        for spinBox in ('spinBox'+i for i in ('N', 'CaseN', 'ControlN')):
            self.__getattribute__(spinBox).setValue(0)
        self.comboBoxDesign.setCurrentIndex(0)
    @pyqtSignature('')
    def on_pushButtonEffectivenessClear_clicked(self):
        self.lineEditEffectiveness.clear()
        self.lineEditEffectiveness.setFocus()
    @pyqtSignature('')
    def on_pushButtonCountryClear_clicked(self):
        self.lineEditCountry.clear()
        self.lineEditCountry.setFocus()
    @pyqtSignature('')
    def on_pushButtonEthnicityClear_clicked(self):
        self.lineEditEthnicity.clear()
        self.lineEditEthnicity.setFocus()
    @pyqtSignature('')
    def on_pushButtonFactorClear_clicked(self):
        self.lineEditFactor.clear()
        self.lineEditFactor.setFocus()
    @pyqtSignature('')
    def on_pushButtonMethodClear_clicked(self):
        self.lineEditMethod.clear()
        self.lineEditMethod.setFocus()
    @pyqtSignature('')
    def on_pushButtonResultClear_clicked(self):
        self.textEditResult.clear()
        self.textEditResult.setFocus()
    @pyqtSignature('')
    def on_pushButtonTitleClear_clicked(self):
        self.textEditTitle.clear()
        self.textEditTitle.setFocus()
    @pyqtSignature('')
    def on_pushButtonNClear_clicked(self):
        self.spinBoxCaseN.setValue(0)
        self.spinBoxControlN.setValue(0)
        self.spinBoxN.setValue(0)
    @pyqtSignature('')
    def on_pushButtonPORClear_clicked(self):
        self.lineEditP.clear()
        self.lineEditOR.clear()
        self.lineEditP.setFocus()
    @pyqtSignature('')
    def on_pushButtonIdentityClear_clicked(self):
        self.spinBoxID.setValue(0)
        self.spinBoxIndex.setValue(0)
    @pyqtSignature('')
    def on_pushButtonCopyt_clicked(self):
        self.copyButton(sep='\t')
    @pyqtSignature('int')
    def on_spinBoxCaseN_valueChanged(self):
        self.spinBoxN.setValue(self.spinBoxCaseN.value()+
                            self.spinBoxControlN.value())
    @pyqtSignature('int')
    def on_spinBoxControlN_valueChanged(self):
        self.spinBoxN.setValue(self.spinBoxCaseN.value()+
                            self.spinBoxControlN.value())
    @pyqtSignature('int')
    def on_spinBoxID_valueChanged(self):
        self.spinBoxIndex.setValue(1)
    def on_pushButtonCopyn_clicked(self):
        articleType1 = 'Test' if self.checkBoxTest.isChecked() else 'Validation'
        #articleType2 = {1:'Experiment', 2:'Methodology', 3:'Review'}[self.buttonBox2.checkedButton()]
        articleType2 = self.buttonBox2.checkedButton().text()
        #resultPoN = {1:'+', 2:'-'}[self.buttonBox3.checkedButton()]
        resultPoN = self.buttonBox3.checkedButton().text()
        text = '\n'.join((b+a for a, b in izip(
            (unicode(i) for i in (
                        articleType1,
                        articleType2,
                        self.comboBoxDesign.currentText(),
                        self.lineEditDisease.text(),
                        self.lineEditEffectiveness.text(),
                        self.lineEditFactor.text(),
                        self.lineEditMethod.text(),
                        self.lineEditP.text(),
                        self.lineEditOR.text(),
                        self.lineEditCountry.text(),
                        self.lineEditEthnicity.text(),
                        self.spinBoxN.value(),
                        self.spinBoxCaseN.value(),
                        self.spinBoxControlN.value(),
                        resultPoN,
                        self.textEditResult.toPlainText())),
            (re.sub(r'\s{1, 4}', r'\t', j.ljust(12)) for j in (
                'Type1:',
                'Type2:',
                'Design:',
                'Disease:',
                'Effect:',
                'Factor:',
                'Method:',
                'P:',
                'OR:',
                'Country:',
                'Ethnicity:',
                'Num:',
                'Case:',
                'Control:',
                'Result1:',
                'Result2:'))
            )))
        self.__clipboard.setText(text)
    def copyButton(self, sep='\t'):
        articleType1 = 'Test' if self.checkBoxTest.isChecked() else 'Validation'
        articleType2 = self.buttonBox2.checkedButton().text()
        resultPoN = self.buttonBox3.checkedButton().text()
        text = sep.join(unicode(i) for i in (
                        self.spinBoxID.value(),
                        self.spinBoxIndex.value(),
                        articleType1,
                        articleType2,
                        self.comboBoxDesign.currentText(),
                        self.lineEditDisease.text(),
                        self.lineEditEffectiveness.text(),
                        self.lineEditFactor.text(),
                        self.lineEditMethod.text(),
                        self.lineEditP.text(),
                        self.lineEditOR.text(),
                        self.lineEditCountry.text(),
                        self.lineEditEthnicity.text(),
                        self.spinBoxN.value(),
                        self.spinBoxCaseN.value(),
                        self.spinBoxControlN.value(),
                        resultPoN,
                        self.textEditResult.toPlainText()))
        self.__clipboard.setText(text)
    @pyqtSignature('')
    def on_pushButtonTest_clicked(self):
        for lineEdit in ('lineEdit'+i for i in ('Disease', 'Effectiveness',
            'Country', 'Ethnicity', 'Factor', 'Method', 'P', 'OR', 'Title')):
            self.__getattribute__(lineEdit).setText(''.join(random.sample(string.letters,random.randint(10,20))))
        self.textEditResult.setText(''.join(random.sample(string.letters,random.randint(10,20))))
#    self.connect(self.pushButtonMethodClear, SIGNAL('clicked()'), )
if __name__=='__main__':
    app = QApplication(sys.argv)
    form = extractArticleDialog(app.clipboard())
    form.show()
    app.exec_()
###############################

 

############################


#########################################

2013 / . 03 / . 29

Tool for pages cropping and reordering

以前就用Python搞了一个为了方便打印的PDF页顺序重排工具,但是自动化程度不够高,而且重排之后需要借助 texlive的pdfnup工具做裁切以及2x1 up 的landscape方向输出页面。

换到了mac下面,原来linux下几百兆的东西,竟然要2G大的安装包。实在不忍心安装这东西。

于是对原来的程序做了一些修改。直接使用PyPDF2库做裁切。n-up合并页面,可以用个同名pdfnup的python工具。但是效果还算可以,没有texlive的完美。

另外记得装PyPDF2

Tool for pages cropping and reordering

-f 提取的页数:

-f1,3,4,5,6  : 只提取1,3,4,5,6页

-f1-10,15,20-50 : 支持这种复合式的语法

-f21-   : 从21到最后一页,

-f-19   : 从1到19页。

-a 是否做对称裁切,如果不使用 -a,例如当左边裁40,右边裁50,那么所有页面都是这样。如果使用-a,那么奇数页是左40右50,而偶数页则是左50右40,这样可以空出更多的装订区域。

-t     :分别是左,下,右,上 各裁切多少,没有文档提到这个单位是什么,可以先用-f选少许几页,不断试验。

-n    :n-up输出,只有安装了texlive才有效,否则只输出portrait方向页面重排的pdf。

 

#######NewSplitPdf.py########

#!/usr/bin/env python2.7

import sys, os, copy
from itertools import izip
import subprocess as subp
from collections import OrderedDict
from contextlib import closing
import PyPDF2 as pdf
from pycut import parseFields
from NameAppend import nameAppend

class NewPdfReader(pdf.PdfFileReader):
    def getNextPage(self):
        for i in xrange(self.getNumPages()):
            yield self.getPage(i)

def cut_length(dictionary, key, factor):
    cut_factor = 1-factor
    cut = float(dictionary[key])*cut_factor
    cut = cut / 4
    return cut
       
def new_coords(dictionary, key, cut, margin, code = "tl"):
    if code == "tl":
        if key == "x":
            return abs(float(dictionary[key])+(cut+margin["l"]))
        else: return abs(float(dictionary[key])-(cut+margin["t"]))
    elif code == "tr":
        if key == "x":
            return abs(float(dictionary[key])-(cut+margin["r"]))
        else: return abs(float(dictionary[key])-(cut+margin["t"]))
    elif code == "bl":
        if key == "x":
            return abs(float(dictionary[key])+(cut+margin["l"]))
        else: return abs(float(dictionary[key])+(cut+margin["b"]))
    else:
        if key == "x":
            return abs(float(dictionary[key])-(cut+margin["r"]))
        else: return abs(float(dictionary[key])+(cut+margin["b"]))


def reorder4print(num):
    numList = range(1, num+1)
    if num%4 != 0:
        numList.extend(['NA'] * (4 - num % 4))
    num = len(numList)
    cut = num/2
    for c, x in enumerate(izip(numList[:cut],  \
            reversed(numList[cut:]))):
        if not c%2:
            yield x[0]
            yield x[1]
        else:
            yield x[1]
            yield x[0]

def main(pdfFile, fields, asymmetry=False, trim=[0, 0, 0, 0], nup=False):
    margin={'l':trim[0],
            'b':trim[1],
            'r':trim[2],
            't':trim[3]}
    factor = 1
    with closing(open(pdfFile, 'rb')) as pFH:
        pdfReader = NewPdfReader(pFH)
        if fields:
            pageNumList = tuple(parseFields(fields,
                pdfReader.getNumPages()))
        else: pageNumList = range(1, pdfReader.getNumPages()+1)
        pageNum = pdfReader.getNumPages()
        pdfWriter = pdf.PdfFileWriter()

        reordPdfFile = nameAppend(pdfFile, '_reordered_')
        marginc = margin

        for i in reorder4print(len(pageNumList)):
            try:
                currentPage = copy.copy(pdfReader.getPage(pageNumList[i-1]-1))
            except TypeError:
                currentPage = copy.copy(pdfReader.getPage(1))
                width = currentPage.mediaBox[2]-currentPage.mediaBox[0]
                height = currentPage.mediaBox[1]-currentPage.mediaBox[3]
                currentPage = currentPage.createBlankPage(width=width,height=height)
                i=1
            top_right = {'x': currentPage.mediaBox.getUpperRight_x(),
                    'y': currentPage.mediaBox.getUpperRight_y()}
            top_left = {'x': currentPage.mediaBox.getUpperLeft_x(),
                    'y': currentPage.mediaBox.getUpperLeft_y()}
            bottom_right = {'x': currentPage.mediaBox.getLowerRight_x(),
                    'y': currentPage.mediaBox.getLowerRight_y()}
            bottom_left = {'x': currentPage.mediaBox.getLowerLeft_x(),
                    'y': currentPage.mediaBox.getLowerLeft_y()}
            cut = cut_length(top_right, 'x', factor)
            if asymmetry:
                marginc = copy.copy(margin)
                if i%2==0:
                    marginc['l'], marginc['r'] = marginc['r'], marginc['l']
            new_tr = (new_coords(top_right, 'x', cut, marginc, code = "tr"),
                    new_coords(top_right, 'y', cut, marginc, code = "tr"))
            new_br = (new_coords(bottom_right, 'x', cut, marginc, code = "br"),
                    new_coords(bottom_right, 'y', cut, marginc, code = "br" ))
            new_tl = (new_coords(top_left, 'x', cut, marginc, code = "tl"),
                    new_coords(top_left, 'y', cut, marginc, code = "tl"))
            new_bl = (new_coords(bottom_left, 'x', cut, marginc, code = "bl"),
                    new_coords(bottom_left, 'y', cut, marginc, code = "bl"))
            currentPage.mediaBox.upperLeft = new_tl
            currentPage.mediaBox.upperRight = new_tr
            currentPage.mediaBox.lowerLeft = new_bl
            currentPage.mediaBox.lowerRight = new_br
            currentPage.cropBox.upperLeft = new_tl
            currentPage.cropBox.upperRight = new_tr
            currentPage.cropBox.lowerLeft = new_bl
            currentPage.cropBox.lowerRight = new_br
            pdfWriter.addPage(currentPage)
        with closing(open(reordPdfFile, 'wb')) as opwFH:
            pdfWriter.write(opwFH)
        if nup:
            landscapePdfFile = NameAppend(pdfFile, '_landscape_')
            returnState = subp.call(r'''pdfnup "{0}" --nup 2x1 --paper a4paper --landscape --frame false --delta "0 0" --offset "0 0" --scale 1.0 --openright false --turn true --noautoscale false --column false --columnstrict false --tidy --outfile "{1}"'''.format(reordPdfFile, landPdfFile, shell=True))
            if returnState == 0:
                os.remove(reordPdfFile)


if __name__ == '__main__':
    from argparse import ArgumentParser
    parser = ArgumentParser()
    parser.add_argument('-f', default=[], help='fields', dest='fields',
            action='append')
    parser.add_argument('-a', default=False, action='store_true',
            dest='asymmetry', help='asymmetry')
    parser.add_argument('-t', nargs=4, help='trim (l,b,r,t)', default=[0, 0, 0, 0],
            dest='trim', type=float, metavar='N')
    parser.add_argument('PDF', nargs=1, help='pdf file')
    parser.add_argument('-n', default=False, action='store_true',
            dest='nup', help='use n-up (need texlive and pdfjam)')
    opts = parser.parse_args()
    main(opts.PDF[0], opts.fields, opts.asymmetry, opts.trim, opts.nup)


###############################

########NameAppend.py#############

#!/usr/bin/env python2.7

import re

def nameAppend(inputName, inserString):
    try:
        fileName, fileExt = re.split(r'\.(?=[^\.]+$)', inputName)
        fileExt='.' + fileExt
    except ValueError:
        fileName = inputName
        fileExt = ""
    return fileName + inserString + fileExt

if __name__ == '__main__':
    import sys
    try:
        nameAppend(sys.argv[1], sys.argv[2])
    except:
        print '''
USAGE:
    NameOutFile INPUTNAME INSERTION_STRING
'''
###############################

##########pycut.py###############

#!/usr/bin/env python2

import re
from contextlib import closing
from operator import add

def parseMinus(fieldList,colNum):
    spliter = re.compile('-')
    for i in fieldList:
        splitedList = spliter.split(i)
        #print splitedList
        if len(splitedList) == 1:
            if int(i) <= colNum:
                yield int(i)
        else:
            if splitedList[0] == "":
                splitedList[0] = 1
                splitedList[1] = int(splitedList[1]) + 1
                for j in xrange(*splitedList):
                    if j <= colNum:
                        yield j
            elif splitedList[1] == "":
                splitedList[0] = int(splitedList[0])
                splitedList[1] = colNum + 1
                for j in xrange(*splitedList):
                    if j <= colNum:
                        yield j
            else:
                splitedList[0] = int(splitedList[0])
                splitedList[1] = int(splitedList[1]) + 1
                for j in xrange(*splitedList):
                    if j <= colNum:
                        yield j

def parseFields(fieldList,colNum):
    fieldList = [x.split(',') for x in fieldList]
    fieldList = reduce(add,fieldList)
    #print fieldList
    for col in parseMinus(fieldList, colNum):
        yield col


def pyCut(delimiter=None, fields='', regex=False, *inputfiles):
    for f in inputfiles:
        with closing(open(f,'r')) as rFH:
            if delimiter is not None and regex:
                split = re.split
            else:
                split = str.split
            for line in rFH:
                cols = split(line, delimiter)
                colNum = len(cols)
                #cuttedFields = tuple(parseFields(fields,colNum))
                #print ' '.join(cols[i-1] for i in cuttedFields)
                print ' '.join(cols[i-1]
                        for i in parseFields(fields, colNum))

if __name__ == '__main__':
    from optparse import OptionParser
    parser = OptionParser()
    parser.add_option('-d',dest='delimiter',default=None,
            help='specific delimiter')
    parser.add_option('-f',action='append',dest='field',default=[],
            help='select fields')
    parser.add_option('-r',dest='regex',action='store_true',default=False,
            help='use regular expression delimiter')
    opts, args = parser.parse_args()

    pyCut(opts.delimiter, opts.field, opts.regex, *args)
###################################

 





 

 

2013 / . 03 / . 27

Man, dont you ever get tired of slimming your system?

Nope, I just cant help it.

mac下pkg格式安装文件清理工具改良版:

###############################

Man, dont you ever get tired of slimming your system?

Man, dont you ever get tired of slimming your system?
###############################

这个版本接受DEBUG环境变量,来控制是否dry-run。

例如

DEBUG=1 delpkg com.microsoft.office.all.core.pkg.14.1.0

只会显示将会被删除的文件,而不会真的删除。

Appstore下载的app就有pkg记录,你可以这个删除。

装了一整套Office 2011,但是很多组件你用不到,也可以用这个分别删除。

P.S. 查看系统里装了那些pkg格式包用:pkgutil --pkgs

2013 / . 03 / . 23

Inspect your Mac's CPU temperature, with colors.

Tons of software do the Mac's temperature monitor job out there, but you'll probably note the word "monitor", means that they work like sort of daemons, running in background, taking a small piece of area in the menu bar displaying the current CPU temperature, and updating it over time.

Well, in my case, I dont play games on my laptop, and I'm definitely not planning to run scientific calculation works on it anymore, I just occasionally compiled some command line tools for use, so my laptop while with high CPU load is not quite often.

I just need a simple command line tool, taking one shot and gives me the information I want is all enough. Fortunately, one app does accomplish a such kind of job for me.

Temperature Monitor is an application to read out all available temperature sensors in Mac computers. The program can display and visualize measured values in a large variety of fashions. The application supports the following operations on the measured readings:

  • display in a default window
  • display in a floating window
  • tabular display in an overview window
  • display in the menu-bar
  • display of a maximum of two readings in the Dock
  • graphical display of short-term and long-term class="hot-view"class="hot-view"more..

http://www.macupdate.com/app/mac/12381/temperature-monitor

It's not yet another "monitor" app, but also provides a command line tool where a file located at TemperatureMonitor.app/Contents/MacOS/tempmonitor which do exactly what I want.

tempmonitor is an independent tool, you can extract it and put into your system PATH dir, then delete the rest of that app, and this is completely safe.

Let me give it a short tutorial for showing how using it.

tempmonitor -a -c -l

Inspect your Mac's CPU temperature, with colors.

This will give you the full list of all devices' temp.

But I just want CPUs alone, how does that?

Here's the trick:

alias cput='tempmonitor -a -c -l|awk '"'"'BEGIN{red=31;blue=34}/CPU/{color=$5<=60?blue:red;$5="\033[1;"color"m"$5"\033[0m";for(i=4;i<=NF;i++)printf("%s%s",$i,i==NF?ORS:OFS)}'"'"

then you just type: cput

Inspect your Mac's CPU temperature, with colors.

This line creates an alias of tempmonitor just gives CPU's temp. The bold part works as a threshold number. I made it 60, if the temp is more than 60C, the digits will be displayed in red, otherwise in blue, you can change it with your own consideration.

 

麻痹的,本来写了一多半,结果页面抽风没了,实在懒得再打一遍字了,就直接用英文写了。

2013 / . 03 / . 19

Trick: Read your selected text.

利用Mac内置的朗读功能,可以轻松实现对你选择的文本进行朗读:

打开Automator,新建Service,搜索run shell script,并拖拽到右侧:

Trick: Read your selected text.

如图所示,去掉原来的“cat”,改成“say”,然后保存即可,(我起名叫“Say it”)

 

Trick: Read your selected text.

选择你需要朗读的文本,在右键菜单里就可以找到建立的service了。

 

Trick: Read your selected text.

朗读属性可以在System References --> Dictation & Speech 里设置。

2013 / . 03 / . 16

Howtos: Open Multi-Instances of One App Simultaneously.

Mac很多应用默认是不让你同时打开多个实例的。

比如QQ,如果你已经开启一个登陆帐号之后,在文件管理器里再次双击QQ图标,只会显示你当前已登陆帐号的窗口,而没办法开启新的登录窗口。

但是这是有办法绕过这一限制的。

办法很简单,打开终端,输入:

open -n -a QQ

就会弹出一个新的登陆窗口,你就可以登陆新的帐号了。

Howtos: Open Multi-Instances of One App Simultaneously.

 

这里不仅仅局限于QQ,你可以改成任意想要多开的程序的名字,这个名字就是你在/Applications下应用的名字。

2013 / . 02 / . 23

Controlling the default behavior of apps when running in background in iOS

iOS上的浏览器iCabMobile可以称得上是最强,它可以去广告(关键是可以实现方便的自定义规则),可以同步firefox的书签,可以把配置备份到dropbox,以及支持大量扩展功能。

相见恨晚的我早早就掏钱买了正版,但是它唯独有一点困扰了我许久,就是浏览网页的时候一旦切出去后再切回来,所有打开的标签页就全部变成空白了。一想应该是跟应用设置的后台行为有关。

一般来说,对于iOS的多任务,app会有三种后台运行行为:

1---按HOME键,或者其他方式切换出去以后,app自动关闭。这在早期iOS不具有多任务功能时所有第三方应用都是这样,但是现在有些应用可能出于某种目的也会这样。

2---退出后,应用停止运行进入休眠状态,但是在内存中保留信息,以便快速切换回来。绝大多数应用都是这种行为

3---退出后,应用已然在后台保持运行,使用这种行为第三方应用不是没有,但苹果必然会有限制,例如只能在后台播放音频(以音乐类应用居多)、保留wifi等。

研究了一下发现这三种行为切换可以通过修改应用的.app文件夹下面的Info.plist文件来实现。

修改不需要电脑,但需要越狱,需要装有iFile。(当然,也可以连接电脑后在电脑上修改plist文件)

 

 1------强制应用在切出后自动关闭(有些应用你并不需要后台的话可以这样)-------------

 Controlling the default behavior of apps when running in background in iOS

到/var/mobile/Applications里找到你要修改的应用

 

 Controlling the default behavior of apps when running in background in iOS

再进入.app文件夹下

 

Controlling the default behavior of apps when running in background in iOS

找到Info.plist文件

 

 Controlling the default behavior of apps when running in background in iOS

使用Property List Viewer打开

 

Controlling the default behavior of apps when running in background in iOS

 

右下角,新建一个属性 

Controlling the default behavior of apps when running in background in iOS 

建立一个名为UIApplicationExitsOnSuspend,布尔类型的值。

 

 Controlling the default behavior of apps when running in background in iOS

 然后把新建立的值的开关打开就完成了。

这样,这个应用在每次切出来的时候会自动关闭。

 

至于第2种行为,犹豫本身绝大多数应用是默认行为,所以只要在Info.plist 把有关第一种或第3中行为的相关设置都删掉就可以了,不需要做特别的介绍

 至于第三种行为-----强制在后台运行,由于这一片文章的篇幅已经比较长,所以咱们下回接着说。

2013 / . 02 / . 18

How to install the last version of Vim on iOS devices

既然iOS继承自UNIX,自然也就传承了其强大的命令行。用shell script来管理iPad自然有着极大的方便(哪怕用python也行,在威锋源或178源里都有2.7.2版)。

不过cydia里提供的终端还是比较残废的,而且早已停止开发。

而我用的办法是先装个openssh,然后用appstore里的ssh远程连接工具如prompt或iSSH等自己“远程连接”自己,来当本地的终端用。这些应用的好处是它们要么提供了标准的全键盘,要么额外提供esc,shift或ctrl等键位,从而弥补了自带键盘应用到终端上的先天不足。

既然终端都有了,自然还差文本编辑器了。

Vim在类UNIX世界的“神器”地位是不可撼动的,尽管初上手比较难,但熟练之后绝对会感叹其成百上千倍的提升效率,一朝学会终生受益。

尽管appstore里有一个Vim,但是在iPad上卡的要命,简直没法正常使用。而在cydia里的Vim是7.1版的,跟现在的7.3比年代相当久远了。好在有一个cydia的第三方源,提供了最新的Vim:

打开Cydia添加新的源

apt.iwatcher.net

索引更新的速度比较慢,所以最好隔一会瞅一眼,别让屏幕自动关闭喽。

刷新源之后,在搜索里直接搜Vim就能找到,可以看到现在的版本是7.3.822,已经非常新了。

安装即可。

安装好后再把这个源删掉,省得它要求你升级一大堆莫名其妙的东西。

搞定收工。

2013 / . 02 / . 13

minor improvements to my little pathetic app deleting tool under osx

之前的那一版使用awk来parse plist文件中的CFBundleIdentifier key,但是这个key必须在root dict下并且在整个plist文件中有且只有一个才有效。但是如iPartition的Info.plist还包含了两个子CFBundleIdentifier,于是获取identity就失效了。

所以做了一点改进:

minor improvements to my little pathetic app deleting tool under osx

minor improvements to my little pathetic app deleting tool under osx

############################################################

注释掉的地方是去掉的。7-14行是新添加的地方,也就是说改用python的plistlib来parse kay/value,这样就更精确了。(尽管没法只用shell来完成处理,但是python毕竟是mac默认安装的,所以问题不大)

搞定收工。

2013 / . 02 / . 09

Using Python and plutil.pl to manipulate iOS daemon control file in order that preventing unneeded services from consuming system resources.

与Mac OS X相类似,iOS的系统服务的启动由/System/Library/LaunchDaemons目录下的一堆plist格式文件所控制(plist是苹果的property data存储格式,使用xml语法的文本文件)。例如语音、网络、游戏中心、云同步、搜索、电源管理等服务都是由这些文件来控制是否启动。而这其中有很多服务如崩溃报告相关服务,搜索索引服务,打印机之类的服务可能对于多数人来讲用不到,所以不如禁止这些服务启动,来加快系统速度了,同时也节省耗电。

如果去搜网上的教程的话,一个统一的办法就是把对应服务的plist文件删掉,不过这样一是都点不安全,而是想把服务还原回来也有点麻烦。我看了一下苹果的launchctl部分的官方文档,里面提到了一个可选属性项key:“Disabled”,使用bool值,True就表示在系统开机时不会对他进行加载。于是我想干脆写一个自动化的处理工具来给plist文件添加这个entry。

不过从mac os x 10.4开始,plist文件开始默认使用binary格式,这样的优势是加快读取速度,缺点是不能直接用文本编辑器查看了。而iOS里的plist文件也是binary格式,所以需要先将它转换为文本格式才能编辑,然后再转回binary。

如果仅仅是xml文本的话,写一个shell script也能轻松搞定。但是涉及到格式转换,还是得找工具来实现。python的plistlib库可以轻松处理plist中的键值对,不过不支持binary格式,所以还是得先用工具把bianry的plist转换为文本格式。

提供这种互相转换的工具是mac下的plutil,但是没法在别的系统下用。跨平台的工具则有libplist和plutil.pl,本来我使用前者跟python结合,但是处理了几个文件发现libplist的bug成堆,不但能把数据类型弄错,连integer值跟原始文件也能搞得不一样。遂换到plutil.pl。

这样花了半天时间,用python和plutil.pl结合,即可批量为plist文件添加Disabled项,同时以后若想把服务还原回来,只要在iOS设备上用iFile打开服务的plist文件,把Disabled项关闭即可。

######################################################

#!/usr/bin/env python2.7

import plistlib as plib
import subprocess as subp
from contextlib import closing
import os, tempfile, shutil, re
from NameAppend import nameAppend

def parsePlistToString(plistFile=None):
    '''parsePlistToString(plistFile)
    return plistDataString, isBinary'''
#    fixBugSearchRegex = re.compile(r'(?<=<array>)(.*?)(<key>.+?</key>)(.*?)(?=</array>)',flags=re.DOTALL)
#    fixBugSubRegex = re.compile(r'(?<=<array>)(.*?)<key>(.+?)</key>(.*?)(?=</array>)',flags=re.DOTALL)
    with closing(open(plistFile, 'rb')) as pfFH:
        plistString = pfFH.read()
        if plistString.find('bplist') == 0:
            isBinary = True
        else:
            isBinary = False
    if isBinary is True:
        #tempPlistFile = tempfile.mktemp()
        #subp.call('plutil -i {0} -o {1}'.format(plistFile, tempPlistFile),
        #        shell=True)
        out = subp.check_output('plutil.pl {0}'.format(plistFile), shell=True)
        try:
            plistTextFile = out.split('\n')[5].split(': ')[1]
            if not os.path.exists(plistTextFile):
                raise NameError, '{0}: no such file'.format(plistTextFile)
            #with closing(open(tempPlistFile, 'rb')) as pfFH:
            with closing(open(plistTextFile, 'rb')) as pfFH:
                plistString = pfFH.read()
        finally:
            #os.unlink(tempPlistFile)
            os.unlink(plistTextFile)
    #while fixBugSearchRegex.search(plistString):
        #plistString=fixBugSubRegex.sub(r'\1<string>\2</string>\3',plistString)
    plistData = plib.readPlistFromString(plistString)
    return plistData, isBinary

def main(plistFile=None, backup=True):
    plistData, isBinary = parsePlistToString(plistFile)
    plistData['Disabled']=True

    #tempOutFile = tempfile.NamedTemporaryFile()
    tempOutFile = tempfile.NamedTemporaryFile(suffix='.plist')
    try:
        plib.writePlist(plistData, tempOutFile)
        tempOutFile.seek(0)
        if backup is True:
            shutil.move(plistFile, plistFile+'.bak')
        if isBinary is True:
            #subp.call('plutil -i {0} -o {1}'.format(tempOutFile.name, plistFile), shell=True)
            subp.call('plutil.pl {0}'.format(tempOutFile.name), shell=True, stdout=open(os.devnull, 'w'))
            shutil.move(nameAppend(tempOutFile.name, '.binary'), plistFile)
        else:
            shutil.copy(tempOutFile.name, plistFile)
    finally:
        tempOutFile.close()

if __name__ == '__main__':
    from argparse import ArgumentParser
    import sys
    parser = ArgumentParser()
    parser.add_argument('PLISTFILE', nargs='+', help='plist file', type=str)
    parser.add_argument('-b', '--backup', action='store_true', default=False, help='backup original plist file', dest='backup')
    args = parser.parse_args()
    for plistfile in args.PLISTFILE:
        main(plistFile=plistfile, backup=args.backup)
####################################################

其中用到的plutil.pl在这下载:https://github.com/dallarosa/plist2ota/blob/master/plutil.pl

加执行权放到系统PATH下即可。

这里还用到了我另外写的一个module:NameAppend,如下

####################################################

#!/usr/bin/env python2.7

import re

def nameAppend(inputName, inserString):
    try:
        fileName, fileExt = re.split(r'\.(?=[^\.]+$)', inputName)
        fileExt='.' + fileExt
    except ValueError:
        fileName = inputName
        fileExt = ""
    return fileName + inserString + fileExt

if __name__ == '__main__':
    import sys
    try:
        nameAppend(sys.argv[1], sys.argv[2])
    except:
        print '''
USAGE:
    NameOutFile INPUTNAME INSERTION_STRING
'''

#####################################################

最后用ifuse之类的工具挂载iOS文件系统,打开终端navigate到/System/Library/LaunchDaemons下,执行例如:

add_disabled_to_plist.py com.apple.NetworkLinkConditioner.plist

如果没有任何信息,则添加成功。回头用iFile打开可以看到开关:

Using Python and plutil.pl to manipulate iOS daemon control file in order that preventing unneeded services from consuming system resources.

搞定收工。

2013 / . 02 / . 08

Howtos:Hide iOS unwanted app icons without jailbreaking

iOS自带的应用可能有些是你完全用不上的。如果你的iOS设备越狱了,在Cydia里可以找到不少可以实现隐藏图标作用的应用,甚至或者干脆用iFile,到/Applications目录下把你不想要的应用删掉。

不过,如果你得机器没有越狱的话,能不能实现隐藏图标呢?也可以。

我简要的说一下流程:

首先打开safari,进入进入该网站:http://rag3hack.no-ip.org/

Howtos:Hide iOS unwanted app icons without jailbreaking

选择“Hide Apps without jailbreaking”的链接,再选择你想要隐藏的图标的链接

Howtos:Hide iOS unwanted app icons without jailbreaking

接着会提示让你安装,点Install,紧接着会提示不能下载,然后点击Done。

Howtos:Hide iOS unwanted app icons without jailbreaking

这时候你长按图标进入抖动模式,会发现原来不能删除的系统自带应用会显示差标志,点后会跟AppStore下载的应用一样提示删除。

不过,惟一的美中不足是一旦机器重启,隐藏的图标就又回来了。

2013 / . 02 / . 06

a tiny simple applescript that automatically mount windows(samba) shared folders.

若果你的家庭局域网里,某台windows系统的电脑设置了共享文件夹,或者linux系统建立了samba服务,如何挂在这些共享目录来像本地文件系统一样访问么。

我想大家可能基本都知道,打开finder,选择Go菜单下的Connect to Server,然后输入地址,在根据提示输入账号密码,再选择需要挂载的文件夹即可。

不过这里可以有更快捷的方法:用apple script建立一个应用,实现鼠标双击自动挂载,你甚至可以在System Preferences里把它设置为Login Items,让它开机自动启动。同时,利用apple script的异常处理,即使remote server并没有启动,也不会有什么问题。

当然,apple scirpt是mac平台专有的语言,除非你专门就是在这个平台搞开发吃饭的,否则学一门平台专有的语言是浪费生命的表现。不过,对其简单的略知一二,方便使用倒也无伤大雅。

a tiny simple applescript that automatically mount windows(samba) shared folders.

打开你的AppleScript Editor,写上这么简单的几句话,不过yourname,serverip以及sharedfolder要以你的具体情况来做改变。你也可以在try block里多添几个mount,一次挂载多个目录。不过有一个问题我不知道怎么解决,就是如果用户名里面带有@符号的话是不行了,为什么账号里要有@符号?因为反人类传奇:windows 8,绑定live账号,也就是邮箱账号,所以自然有@符号了。我试了就算用反斜线转义@也不行,不知道apple script是不是有什么别的语法来解决这个问题,不过我也不想深究了,反正学一个平台专有的语言本身就是浪费时间。

然后,在File菜单里选择export,file format选择Application,这样就自动编译为.app类型的应用了。

搞定收工。

2013 / . 02 / . 05

astonishing combination apps: popclip + translate tab

尽管我说过不打算推荐应用,但是一来这货确实比较方便强大,二来这是两个应用的组合发挥的作用,也勉强不算是应用推荐而是使用技巧。

首先是popclip,这个应用是把iOS的弹出菜单特性back-port到了OS X上,例如你选中了某段文字,则会弹出菜单,并可以实现复制粘贴、拼写检查、调用系统词典查单词等等。

astonishing combination apps: popclip + translate tab

相对来讲popclip功能也不能算十分的丰富。但是一旦一个软件支持用户自行编写扩展功能时,它就已经远远超越了自身的局限,也是保持常青的动力源泉(例如vim,firefox)。不过虽然popclip确实支持用户自己编写扩展,这里倒也不需要大家真得这样做,因为官网上就已经提供了很多扩展组件。

例如这是我个人用到的功能:

astonishing combination apps: popclip + translate tab

这里另外提到的一个应用就是translate tab,它是在status bar开启google translate的mini页面的一个小工具。这样配合用popclip的translate tab扩展来调用translate tab应用,就是一个十分方便的组合。

例如,选择一段你需要翻译的话,点击translate tab按钮:

astonishing combination apps: popclip + translate tab

然后就会将这段话自动复制到google translate窗口:

astonishing combination apps: popclip + translate tab

当然,由于其本身就是调用了google translate页面,所以网页上有的功能,这里自然也有:

astonishing combination apps: popclip + translate tab

说了半天,去哪里下载呢:

popclip:http://soft.macx.cn/4739.htm

translate tab: http://soft.macx.cn/5313.htm

 

搞定收工。

 

2013 / . 02 / . 04

add multiple search engines to safari

虽然firefox犹如浩瀚宇宙般令众多其他浏览器可望而不可即,但是safari应该来讲还是有一批忠实用户的,即便safari目前所支持的扩展功能上远不如firefox,数量上也不及chrome,但是跟opera相比还是有得一拼的。

这里介绍一个扩展:popsearch,它可以为safari添加多个搜索引擎,而且还支持自行添加搜索引擎。

add multiple search engines to safari

首先自然是要下载该扩展了,下载完毕后双击根据提示安装。

add multiple search engines to safari

安装完毕后会在地址栏多了一个放大镜按钮,在这里你可以选择用哪一个搜索引擎搜索。

add multiple search engines to safari

在扩展的设置界面,你可以添加删除搜索引擎,规则其实很简单:用你想要的搜索引擎,随便搜点什么东西,然后把显示结果的地址栏复制出来,把你搜的关键字替换为%s就可以了。

话说回来,firefox上有什么类似功能的扩展呢,一句话:quick search bar + add to search bar 两个扩展将其他一切浏览器轰杀至渣,灭活活活.....

搞定收工。

 

2013 / . 02 / . 03

Howtos: Uninstall PKG format packages in mac.

在 m a c 下 安 装 卸 载 软 件 也 并 不 总 是 把 a p p 文 件 夹 拖 拽 到 A p p l i c a t i o n s 目 录 和      T r a s h   C a n 这 么 天 真 美 好 。

也 有 很 多 偏 向 于 修 改 系 统 类 的 软 件 或 扩 展 组 件 ( 例 如 输 入 法 或 者 R ) 使 用 的 是 p      k g 安 装 包 格 式 。 这 类 的 软 件 如 果 不 自 带 卸 载 工 具那 么 该 怎  么 卸 载 ?

 命 令 行 工 具 p k g u t i l 是 用 来 专 门 管 理 p k g 包 的。

例如  pkgutil --pkgs可以列出所有已安装的pkg包的PKGID,然后可以使用pkgutil --files PKGID来列出某个pkg包所有的安装文件。

Howtos: Uninstall PKG format packages in mac.

但 是 这 样 列 出 的 P K G I D 以 及 它 的 所 有 文 件 后 , 总 不 能 一 个 一 个 去 删 。 所 以 还 是 写  个 s h e l l   s c r i p t 把 p k g u t i l 做 个 封 装 , 用 起 来 会 更 方 便 些 。

    Howtos: Uninstall PKG format packages in mac.

 

            
搞定收工。

 

 

 

2013 / . 01 / . 23

Fixing iOS respring loop

在Cydia中惊喜的发现了一个牛逼功能的插件或应用,安装好之后,要让你respring一下才能生效,幸运的话1,2秒钟后,进入解锁画面,解锁后就可以探索新功能了,不幸一点的话进入的safe mode,那你只好去cydia把之前装得卸载掉了。再不幸的话会出现无限respring,只能强行关机,然后祈祷再开机不会无限respring,最不幸就是白苹果了。

不过,无限respring还是有救的:

1. 把你的iOS设备链接iFunbox

2. 选择Raw File System,找到造成问题的文件,删掉。

3. 当然,你可能对类UNIX目录结构、iOS文件系统并不熟悉,不过一般来讲,你得记着你最后安装的造成问题的东西叫什么,然后去/System/Library/LaunchDaemons/下找找看在非com.apple开头的有着类似名称的plist文件,或者去/Library/MobileSubstrate/DynamicLibraries/下找找类似名称的bylib和plist文件,把它们删掉。

4. 如果这样还是没有效果的话,那还是别再瞎折腾了,连上itunes,restore吧。

X 人人网小程序,你的青春在这里