<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>jjgod / blog &#187; Python</title>
	<atom:link href="http://blog.jjgod.org/tag/python/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.jjgod.org</link>
	<description>Random notes &#38; thoughts by Jiang Jiang.</description>
	<lastBuildDate>Mon, 16 Jan 2012 11:08:59 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>最近在写的两个东西</title>
		<link>http://blog.jjgod.org/2008/07/25/apn-and-pinyinview/</link>
		<comments>http://blog.jjgod.org/2008/07/25/apn-and-pinyinview/#comments</comments>
		<pubDate>Fri, 25 Jul 2008 07:53:18 +0000</pubDate>
		<dc:creator>jjgod</dc:creator>
				<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[cocoa]]></category>
		<category><![CDATA[pinyin]]></category>

		<guid isPermaLink="false">http://blog.jjgod.org/?p=226</guid>
		<description><![CDATA[这两天写了两个简单的小程序，主要是满足朋友和个人需求的，还在修改中。 第一个叫 apn 的程序是给 Mac OS X 中 Address Book 中的联系人自动生成姓名发音 (Phonetic Name) 的脚本，所以它的名字就是 Assign Phonetic Name 的缩写。 这是一个 Python 写的程序，直接用到了 pyzh 项目提供的汉字拼音转换代码，通过 Scripting Bridge 提供的 API 来访问 Address Book，这样虽然相比直接调用 Objective-C 的 API 有点慢，但好处在于能充分利用 Python 语言的灵活性。 使用起来很简单，从 github 上把代码抓下来 (你可以 git clone git://github.com/jjgod/apn.git 或者下载一个打包的版本)，然后执行 $ python AssignPhoneticName.py 就会自动给你 Address Book 中没有分配过 Phonetic Name 的那些联系人分配一遍。注意因为汉字有多音字，这个程序做不到很智能，你最好在分配之后打开 Address [...]]]></description>
			<content:encoded><![CDATA[<p>这两天写了两个简单的小程序，主要是满足朋友和个人需求的，还在修改中。</p>

<p>第一个叫 <a href="http://github.com/jjgod/apn/tree/master">apn</a> 的程序是给 Mac OS X 中 Address Book 中的联系人自动生成姓名发音 (Phonetic Name) 的脚本，所以它的名字就是 Assign Phonetic Name 的缩写。</p>

<p>这是一个 Python 写的程序，直接用到了 <a href="http://pyzh.googlecode.com/">pyzh</a> 项目提供的汉字拼音转换代码，通过 <a href="http://www.apple.com/applescript/features/scriptingbridge.html">Scripting Bridge</a> 提供的 API 来访问 Address Book，这样虽然相比直接调用 Objective-C 的 API 有点慢，但好处在于能充分利用 Python 语言的灵活性。</p>

<p>使用起来很简单，从 github 上把代码抓下来 (你可以 <code>git clone git://github.com/jjgod/apn.git</code> 或者下载一个<a href="http://github.com/jjgod/apn/tarball/master">打包的版本</a>)，然后执行</p>

<pre><code>$ python AssignPhoneticName.py
</code></pre>

<p>就会自动给你 Address Book 中<em>没有分配过</em> Phonetic Name 的那些联系人分配一遍。注意因为汉字有多音字，这个程序做不到很智能，你最好在分配之后打开 Address Book 校对一遍。</p>

<p>第二个是给 Cocoa 程序员用的一个 <code>NSView</code> 的子类，叫 <a href="http://github.com/jjgod/pinyinview/tree/master"><code>PYView</code></a>，其作用很简单，就是在汉字上方同步的显示拼音，不过目前拼音还得自己提供。</p>

<p>调用的 API 很简单，比如这样:</p>

<pre><code>#include "PYView.h"

NSRect viewRect = NSMakeRect(50, 250, 700, 80);
view = [[PYView alloc] initWithFrame: viewRect
                            fontName: @&#8221;FZKai-Z03&#8243;
                               color: [NSColor whiteColor]];

NSArray *pinyin1 = [NSArray arrayWithObjects: @"nǐ", @"hǎo", nil];
NSArray *pinyin2 = [NSArray arrayWithObjects: @"zhōng", @"huá",
                    @"rén", @"mín", @"gòng", @"hé", @"guó", nil];


[view appendMarkerItem: [PYMarkerItem itemWithHanzi: @"你好"
                                             pinyin: pinyin1
                                               type: 1]];
[view appendMarkerItem: [PYMarkerItem itemWithHanzi: @"中华人民共和国"
                                             pinyin: pinyin2
                                               type: 1]];
</code></pre>

<p>就能得到如图所示的输出结果:</p>

<p><a href='http://blog.jjgod.org/wp-content/uploads/2008/07/pinyinview.png'><img src="http://blog.jjgod.org/wp-content/uploads/2008/07/pinyinview-300x61.png" alt="PinyinView" title="pinyinview" width="300" height="61" class="alignnone size-medium wp-image-220" /></a></p>

<p>可以从 github 上获取代码:</p>

<pre><code> git clone git://github.com/jjgod/pinyinview.git
</code></pre>

<p>然后参考提供的 <a href="http://github.com/jjgod/pinyinview/tree/master/PYViewTest">PYViewTest</a> 代码来使用。注意接口还在修改中。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.jjgod.org/2008/07/25/apn-and-pinyinview/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>用 Python 维护 iTunes Library</title>
		<link>http://blog.jjgod.org/2007/11/10/python-itunes-scripting/</link>
		<comments>http://blog.jjgod.org/2007/11/10/python-itunes-scripting/#comments</comments>
		<pubDate>Fri, 09 Nov 2007 19:48:52 +0000</pubDate>
		<dc:creator>jjgod</dc:creator>
				<category><![CDATA[DOM | Scripting]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Tools]]></category>
		<category><![CDATA[cocoa]]></category>
		<category><![CDATA[itunes]]></category>
		<category><![CDATA[scripting]]></category>

		<guid isPermaLink="false">http://blog.jjgod.org/2007/11/10/python-itunes-scripting/</guid>
		<description><![CDATA[Mac OS X 10.5 中，由于 Scripting Bridge 的引入，用 Ruby 或 Python 程序完成原来 AppleScript 才能完成的任务变得非常简单，而因为这两门语言自身的强大，无形中，可以完成的工作也多了不少。比如我们原来可能要用 ID3Mod 这样的软件进行 iTunes Music Library 的歌曲乱码转换，现在写一段不到十行的 Python 脚本就能完成 (当然，界面没有那么方便)。 一个小例子 这里先用 Python 简单的展示一点可以完成的操作: # 导入必要的模块 from Foundation import * from ScriptingBridge import * # 找到 iTunes 这个应用程序 iTunes = SBApplication.applicationWithBundleIdentifier_("com.apple.iTunes") # 打印出当前正在播放的音乐名称 print iTunes.currentTrack().name() 这段代码在 Leopard 下，既可以保存为 .py 文件，用系统自带的 python 解释器 [...]]]></description>
			<content:encoded><![CDATA[<p>Mac OS X 10.5 中，由于 <a href="http://www.apple.com/applescript/features/scriptingbridge.html">Scripting Bridge</a> 的引入，用 Ruby 或 Python 程序完成原来 AppleScript 才能完成的任务变得非常简单，而因为这两门语言自身的强大，无形中，可以完成的工作也多了不少。比如我们原来可能要用 ID3Mod 这样的软件进行 iTunes Music Library 的歌曲乱码转换，现在写一段不到十行的 Python 脚本就能完成 (当然，界面没有那么方便)。</p>

<h3>一个小例子</h3>

<p>这里先用 Python 简单的展示一点可以完成的操作:</p>

<pre><code># 导入必要的模块
from Foundation import *
from ScriptingBridge import *

# 找到 iTunes 这个应用程序
iTunes = SBApplication.applicationWithBundleIdentifier_("com.apple.iTunes")

# 打印出当前正在播放的音乐名称
print iTunes.currentTrack().name()
</code></pre>

<p>这段代码在 Leopard 下，既可以保存为 .py 文件，用系统自带的 python 解释器 (<code>/usr/bin/python</code>) 执行，也可以直接在命令行下调用 Python 解释器，查看它的输出，比如我这里是:</p>

<pre><code>$ python
Python 2.5.1 (r251:54863, Oct  5 2007, 21:08:09) 
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
&gt;&gt;&gt; from Foundation import *
&gt;&gt;&gt; from ScriptingBridge import *
&gt;&gt;&gt; iTunes = SBApplication.applicationWithBundleIdentifier_("com.apple.iTunes")
&gt;&gt;&gt; print iTunes.currentTrack().name()
Le Festin
&gt;&gt;&gt; 
</code></pre>

<p>注意，执行之前最好先在 iTunes 里开始播放一首曲目。</p>

<h3>了解更多</h3>

<p>见识了 Scripting Bridge 的威力之后，你很自然的想知道这段代码为何可以工作，应该按什么方式来调用它，除了查询当前播放的歌曲名称以外，还有什么其他的接口可以使用。这时候，我们就需要对我们希望用脚本操纵的程序所提供的 Scripting 接口有个清晰的了解。所以可以用 <code>sdef</code> 这个命令获得一个程序的脚本接口定义:</p>

<pre><code>$ sdef /Applications/iTunes.app
xml version="1.0" encoding="UTF-8"?&gt;
&lt;!DOCTYPE dictionary SYSTEM "file://localhost/System/Library/DTDs/sdef.dtd"&gt;
&lt;dictionary&gt;&lt;suite name="Standard Suite" code="****" description="Common terms for most applications"&gt;
...
</code></pre>

<p>出现了一长串的怪异信息，太混乱了，看不懂，怎么办呢？这时应该用 <code>sdp</code> 命令过滤一下，生成一个比较可读的格式，Objective-C 头文件:</p>

<pre><code>$ sdef /Applications/iTunes.app | sdp -fh --basename iTunes
$ ls
iTunes.h
$ more iTunes.h
/*
 * iTunes.h
 */

#import &lt;AppKit/AppKit.h&gt;
#import &lt;ScriptingBridge/ScriptingBridge.h&gt;
...
</code></pre>

<p>这里就是一个对 iTunes 提供的脚本编程接口的详尽描述了。从这里我们其实很容易看出，原来 <code>iTunes = SBApplication.applicationWithBundleIdentifier_("com.apple.iTunes")</code> 获得的，是一个 iTunesApplication 对象，以这个对象为出发点，我们可以做到任何 API 允许的事情。下面就是一个例子。</p>

<pre><code>#!/usr/bin/python

from Foundation import *
from ScriptingBridge import *

iTunes = SBApplication.applicationWithBundleIdentifier_("com.apple.iTunes")

for track in iTunes.sources()[0].playlists()[0].tracks():
    print track.name(), track.artist()
</code></pre>

<p>简单的观察一下，iTunes 的脚本编程 API 组织是这样的：在 <code>iTunesApplication</code> 下，可以找到多个来源 (<code>iTunesSource</code>)，来源有许多种，比如 music library，比如 CD，比如 iPod 等等，而每个来源里，又按照播放列表 (<code>iTunesPlaylist</code>) 来组织，而每个播放列表中，显而易见地有多个曲目 (<code>iTunesTrack</code>)，在上面这个例子里，我们要找的第一个来源 (<code>sources()[0]</code>) 的第一个播放列表 (<code>playlists()[0]</code>)，正是你的 iTunes Music Library。</p>

<p>值得注意的一点是，在 <code>iTunes.h</code> 中用 <code>SBElementArray *</code> 表示的数据类型，一眼可以看出它是数组，在 Python 中处理起来也很简单，直接当成 list 类型遍历即可。</p>

<h3>修改数据</h3>

<p>那么，查询我们知道了，该怎么把信息写回去，也就是说，修改原来 Music Library 的内容呢？</p>

<p>先来看看 <code>iTunes.h</code> 中的出现的一段:</p>

<pre><code>@interface iTunesTrack : iTunesItem

- (SBElementArray *) artworks;

@property (copy) NSString *album;
@property (copy) NSString *albumArtist;
@property NSInteger albumRating;
@property (readonly) iTunesERtK albumRatingKind;
</code></pre>

<p>这里描述的是一个曲目 (它继承了 <code>iTunesItem</code> 类型，所以也继承了它的 <code>name</code> 等属性)，<code>@property</code> 这种写法，是 Objective-C 2.0 中<a href="http://theocacao.com/document.page/510">新出现的</a>，也很好理解，<code>(copy)</code> 的意思是你的赋值会被复制一份保存，<code>(readonly)</code> 当然是只读的，而 <code>NSInteger</code> 这种简单的变量也是可以写的。</p>

<p>那么，查询我们知道了，比如这里有个 <code>album</code> 属性，我们就去调用 track 的 <code>album()</code> 方法，但究竟如何赋值呢？还是按照 Cocoa 的 Key-value coding 的老规矩，改成 <code>setAlbum(&lt;参数&gt;)</code>，比如:</p>

<pre><code>&gt;&gt;&gt; iTunes.sources()[0].playlists()[0].tracks()[0].name()
u'Le Festin - Performed by Camille'
&gt;&gt;&gt; iTunes.sources()[0].playlists()[0].tracks()[0].setName_(u'Le Festin')
</code></pre>

<p>这里把一首原来叫做 Le Festin &#8211; Performed by Camille 的歌曲名称修正为 <a href="">Le Festin</a>，回到 iTunes 里一看，果然改了。</p>

<h3>系统自带与 macports</h3>

<p>在 Mac OS X 10.4 中，由于系统自带的 Python 是老旧的 2.3 版本，所以对 Python 爱好者来说，都往往不得不自己编译一份或者使用 fink/macports 中提供的 Python 2.4/2.5 版本。而在 Mac OS X 10.5 中，终于把自带的 Python 升级到了最新的 2.5.1 版本，对爱好者来说无疑是省事了，可惜这个自带的版本一个令中文用户郁闷的 bug 是：在提示符模式下无法用输入法输入任何中文字符 (相信其他 CJK 字符也是如此)，比如我用输入法打一段：你好 hello 世界 world，等我一确认，Python 解释器只收到了 hello world，中文字符被自动滤掉了！然而，通过 macports 安装的 Python 此功能却是正常的。</p>

<p>这使得我们这里如果要修改中文的歌曲、作家、专辑名等等都变得很不方便，怎么办呢？</p>

<p>系统自带的 Python 的特别之处，其实在于它自带了许多 Apple 添加的模块，比如我们在代码最开始导入的 <code>Foundation</code> 和 <code>ScriptingBridge</code> 模块，这些模块有些不是开源的，有些则还没来得及把代码公开，所以我们机器上只安装有编译好的 Python 模块，然而幸好这些模块是 2.5 版本的，只要我们用 macports 也安装一个 2.5 版本，把系统自带模块的路径给加进去，就能找到并使用它们了。让我们还是用开头那个例子做个简单的示范:</p>

<pre><code>#!/opt/local/bin/python2.5

import sys

sys.path.append('/System/Library/Frameworks/Python.framework/Versions/2.5/Extras/lib/python')
sys.path.append('/System/Library/Frameworks/Python.framework/Versions/2.5/Extras/lib/python/PyObjC')

from Foundation import *
from ScriptingBridge import *

iTunes = SBApplication.applicationWithBundleIdentifier_("com.apple.iTunes")

print iTunes.currentTrack().name()
</code></pre>

<p>有了上面这些介绍，相信要把这几个工具组合在一起成为一套 iTunes Music Library 的管理利器也不是难事，各位不妨发挥想象力，我就不多说了。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.jjgod.org/2007/11/10/python-itunes-scripting/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

