脚本下载谷歌高质量的音乐

Program — Tags: — ronnie @ 1:49 am

谷歌的音乐一上线,就有人搞出来脚本下载,不过他这个脚本是Python3.0的,我不太喜欢Python3.0,就将其改成了2.5的了,且我喜欢下载整张专辑,也就改成了给脚本专辑地址了,避免搜索。

#!/usr/bin/python
import sys, os, re, urllib
from HTMLParser import HTMLParser
import httplib
from subprocess import Popen
import time
 
def decode(string):
	return re.sub('&#[0-9]{5};', lambda x: unichr(int(x.group(0)[2:-1])),re.sub(' ', ' ', string))
 
def get_attr(attrs, attr):
	for key, value in attrs:
		if key == attr:
			return value
	return None
 
class SongParser(HTMLParser):
	song_list = []
	def parse(self, htm):
		self.feed(htm.read().decode("utf-8"))
		return self.song_list
 
	def handle_starttag(self, tag, attrs):
		if get_attr(attrs, "class") == "SongItem BottomBorder":
			self.song_list.append( get_attr(attrs, "id")[3:] )
 
class SongInfoParser(HTMLParser):
	# song = [ name, singer, size, format ]
	tags = {
			"td-song-name":"name",
			"td-singer":"singer",
			"td-size":"size",
			"td-format":"format"
	}
	song = {}
	attr = None
	def parse(self, htm):
		self.feed(decode(htm.read()))
		return self.song.copy()
 
	def handle_starttag(self, tag, attrs):
		if tag == "a":
			tag_href = get_attr(attrs, "href")
			if tag_href[0:7] == "/music/":
				self.song["address"] = "http://www.google.cn"+tag_href
		elif get_attr(attrs, "class") == "song-meta-data-table":
			self.attr = ''
		elif self.attr == '':
			tag_class = get_attr(attrs, "class")
			if tag_class in self.tags:
				self.attr = self.tags[tag_class]
 
	def handle_data(self, data):
		if self.attr:
			self.song[self.attr] = data
 
	def handle_endtag(self, tag):
		self.attr = ''
 
conn = httplib.HTTPConnection("www.google.cn")
 
if len(sys.argv) == 1:
	exit(0)
 
"""
query = ' '.join(sys.argv[1:])
print "send query: %s" %query
qeuery = urllib.quote(query)
conn.request("GET", "http://www.google.cn/music/search?q="+query)
result = conn.getresponse()
"""
result = urllib.urlopen(sys.argv[1])
 
#print result.read().decode("utf-8")
 
print "Get song list..."
 
p = SongParser()
song_ids = p.parse(result)
songs = []
parser = SongInfoParser()
 
for i, id in enumerate(song_ids):
	conn.request("GET", "/music/top100/musicdownload?id="+id)
	response = conn.getresponse()
	song = parser.parse(response)
	name = song["name"]
	time.sleep(1)
	print "%d\t%s\t%s\t%s\t%s" %(i, name, song["singer"],song["format"], song["size"])
	songs.append(song)
 
choice = range(len(songs))
 
for i in choice:
	song = songs[ int(i) ]
	if isinstance(song, dict):
		print "download: \t\t%s" %(song["address"])
		Popen(['wget', '-c', '-P', song["singer"], song["address"]]).wait()
conn.close()

如果你想用,可以在这里下载。

下载完了以后用mutagen自带工具mid3iconv可以转换mp3的tag编码,不过这里有个小问题,就是对于谷歌高质量音乐有一点不爽,谷歌音乐都是自带歌词的,这个工具不能转换歌词,我就改了改,让他可以该歌词编码了,这样iTunes等只支持unicode的就没问题了,ipod touch/iphone中也可以真长看到歌词了。其实主要就是改了很小一点,原来mid3iconv只是修改T开头的tag,我加上了对歌词所在的”USLT”tag的处理就OK了,代码如下:

#!/usr/bin/python
 
import os
import sys
import locale
 
from optparse import OptionParser
 
VERSION = (0, 1)
 
def isascii(string):
    return not string or min(string) < '\x127'
 
class ID3OptionParser(OptionParser):
    def __init__(self):
        mutagen_version = ".".join(map(str, mutagen.version))
        my_version = ".".join(map(str, VERSION))
        version = "mid3iconv %s\nUses Mutagen %s" % (
            my_version, mutagen_version)
        return OptionParser.__init__(
            self, version=version,
            usage="%prog [OPTION] [FILE]...",
            description=("Mutagen-based replacement the id3iconv utility, "
                         "which converts ID3 tags from legacy encodings "
                         "to Unicode and stores them using the ID3v2 format."))
 
    def format_help(self, *args, **kwargs):
        text = OptionParser.format_help(self, *args, **kwargs)
        return text + "\nFiles are updated in-place, so use --dry-run first.\n"
 
def update(options, filenames):
    encoding = options.encoding or locale.getpreferredencoding()
    verbose = options.verbose
    noupdate = options.noupdate
    force_v1 = options.force_v1
    remove_v1 = options.remove_v1
 
    def conv(uni):
        return uni.encode('iso-8859-1').decode(encoding)
 
    for filename in filenames:
        if verbose != "quiet":
            print "Updating", filename
 
        if has_id3v1(filename) and not noupdate and force_v1:
            mutagen.id3.delete(filename, False, True)
 
        try: id3 = mutagen.id3.ID3(filename)
        except mutagen.id3.ID3NoHeaderError:
            if verbose != "quiet":
                print "No ID3 header found; skipping..."
            continue
        except Exception, err:
            if verbose != "quiet":
                print str(err)
            continue
 
        for tag in filter(lambda t: t.startswith("T"), id3):
            frame = id3[tag]
            if isinstance(frame, mutagen.id3.TimeStampTextFrame): # non-unicode fields
                continue
 
            try:
                text = map(conv, frame.text)
            except (UnicodeError, LookupError):
                continue
            else:
                frame.text = text
                if min(map(isascii, text)):
                    frame.encoding = 3
                else:
                    frame.encoding = 1
 
        print "Process USLT"
        for tag in filter(lambda t: t.startswith("U"), id3):
            frame = id3[tag]
            if isinstance(frame, mutagen.id3.TimeStampTextFrame): # non-unicode fields
                continue
            if frame.encoding == 1:
				continue
 
            text=frame.text
            text = text.encode('iso-8859-1').decode(encoding)
 
            frame.text = text
            if min(map(isascii, text)):
                frame.encoding = 3
            else:
                frame.encoding = 1
 
        enc = locale.getpreferredencoding()
        if verbose == "debug":
            print id3.pprint().encode(enc, "replace")
 
        if not noupdate:
            if remove_v1: id3.save(filename, v1=False)
            else: id3.save(filename)
 
def has_id3v1(filename):
    f = open(filename, 'rb+')
    try: f.seek(-128, 2)
    except IOError: pass
    else: return (f.read(3) == "TAG")
 
def main(argv):
    parser = ID3OptionParser()
    parser.add_option(
        "-e", "--encoding", metavar="ENCODING", action="store",
        type="string", dest="encoding",
        help=("Specify original tag encoding (default is %s)" %(
        locale.getpreferredencoding())))
    parser.add_option(
        "-p", "--dry-run", action="store_true", dest="noupdate",
        help="Do not actually modify files")
    parser.add_option(
        "--force-v1", action="store_true", dest="force_v1",
        help="Use an ID3v1 tag even if an ID3v2 tag is present")
    parser.add_option(
        "--remove-v1", action="store_true", dest="remove_v1",
        help="Remove v1 tag after processing the files")
    parser.add_option(
        "-q", "--quiet", action="store_const", dest="verbose",
        const="quiet", help="Only output errors")
    parser.add_option(
        "-d", "--debug", action="store_const", dest="verbose",
        const="debug", help="Output updated tags")
 
    for i, arg in enumerate(sys.argv):
        if arg == "-v1": sys.argv[i] = "--force-v1"
        elif arg == "-removev1": sys.argv[i] = "--remove-v1"
 
    (options, args) = parser.parse_args(argv[1:])
 
    if args:
        update(options, args)
    else:
        parser.print_help()
 
if __name__ == "__main__":
    try: import mutagen, mutagen.id3
    except ImportError:
        # Run out of tools/
        sys.path.append(os.path.abspath("../"))
        import mutagen, mutagen.id3
    main(sys.argv)

可以到这里下载。

记住这个或许有点用

闲言碎语 — ronnie @ 5:21 pm

天朝成都市发生了一起惨不忍睹的公交车着火事件,27名乘客被烧死,还有18命生命垂危。姑且不管火灾是怎么发生的,先来说说发生火灾了怎么办吧。

那辆公交车是传说中的空调车,全部封闭,只有两个门可以打开。发生火灾以后,电子门就打不开了,整个车就此完全封闭。我就很奇怪,为什么没有人打碎玻璃呢,一方面可能车里面都乱了套,另一方面或许是没有使用恰当的方法去敲玻璃。公交车上面使用的是钢化玻璃,这种玻璃现在随处可见,大楼门窗,车窗等处都有使用。先把普通玻璃切割成需要的尺寸,然后加热软化,接着突然冷却,这样就形成了钢化玻璃,这种玻璃表面形成了均匀的压应力,内部形成张应力,简单说就是特别抗压了,不容易碎。如果想要去敲碎钢化玻璃还是很难的,除非你足够牛逼,上肢能够产生足够的冲击力。不过它有个弱点,就是边缘和角上特别容易碎,因为这里张应力最大,所以要想敲碎钢化玻璃,从四角下手是最明智的选择。这些都有依据,来源于伟大的wiki

… The glass is most susceptible to breakage due to damage to the edge of the glass where the tensile stress is the greatest, but shattering can also occur in the event of a hard impact in the middle of the glass pane or if the impact is concentrated (for example, striking the glass with a point)…

好了,大家记住这一点,指不定您乘坐的哪路公交或地铁着火了呢,天朝很危险,还是武装自己为妙。

My Posterior cruciate ligament tears

我的后十字韧带断了,到底是怎么回事呢,看看右边的图就明白了。这个伤是我在两星期前踢球的时候受的,当时是我带球的时候,被对方队员从后面踢到膝盖,然后我就重重摔倒了。就在我摔倒的时候,一阵疼痛从左腿传来,我立刻就站不起来了。过了几秒钟,痛苦有所减轻,我以为只是一般轻伤,就没在意继续比赛了,虽然后面我也没有再怎么跑,我觉得这也是我伤势加重的原因。等踢完比赛以后,我当时觉得应该没事了,就吃饭,休息,去实验室了。可是到了实验室我坐了一会,想站起来的时候就发现,我已经站不起了。左腿不能伸直,也不能太弯曲。根本不敢用力,否则就是巨痛。

第二天我去校医院检查,有一位大夫直接告诉我说:“没事,你回去休息几天就好了”。我当时就想这个大夫肯定害了不少人,我不能被他害了。我就要求他给我转院,去北医三院看。他说不能做主,给我换了个大夫,这位大夫看出了问题的严重性,马上让我转院了。第三天早上,我就早早(大概早上5点)起来去排队挂号,幸好取得早,挂到了一个比较靠前的号。三院的一位大夫为我检查后说,我的韧带断了,让我去拍核磁共振。我当时就愣了,韧带断了,我都没想到这么严重。拍核磁的人太多了,我只能拍到一周后。我就买了个夹板回去带着,等了一周,才拍到核磁共振,最终结果就是左膝后十字韧带断裂(Posterior cruciate ligament tears),有检查报告单为证。

center

我以后的职业生涯就算是完了,我宣布挂靴。希望我一年以后能够完全康复。

How to write a full screen cocoa progam

Cocoa, Program — Tags: — ronnie @ 4:50 pm

最近正好要写一个全屏的cocoa程序,所以就研究了一些用cocoa怎么写全屏的程序。

说起来全屏程序很简单,就是首先要拿到你要全屏的显示设备的ID,然后获取这个设备。接着建立一个无边界的窗口,将其大小设置为屏幕的大小,然后显示就可以了,这个窗口里面可以显示你需要的任何东东,包括按钮,滚动条等等,不过一般全屏要么显示图片,要么显示视频,再就是3D程序,所以也不会放上很丑的这些按钮什么的。

首先是获得显示设备的ID,你可以使用

CGDisplayErr CGGetActiveDisplayList (
   CGDisplayCount maxDisplays,
   CGDirectDisplayID *activeDspys,
   CGDisplayCount *dspyCnt
);

去获得所有的可用的显示设备,然后用设备ID调用函数

CGDisplayErr CGDisplayCapture (
   CGDirectDisplayID display
);

去获得这个设备。接着,我们建立一个无边界的窗口:

- (id)initWithContentRect:(NSRect)contentRect 
styleMask:(NSUInteger)windowStyle 
backing:(NSBackingStoreType)bufferingType 
defer:(BOOL)deferCreation 
screen:(NSScreen *)screen

其中参数windowStyle设置为NSBorderlessWindowMask就是无边界窗口,screen要设置成为屏幕大小。我的程序里面完整的调用如下:

[[YLFullScreenWindow alloc] initWithContentRect:screenRect 
styleMask:NSBorderlessWindowMask 
backing:NSBackingStoreBuffered 
defer:NO 
screen:[NSScreen mainScreen]];

然后显示这个窗口就可以了。
我的程序中之所以使用YLFullScreenWindow,是因为要想全屏窗口响应鼠标事件,必须自己重载NSWindow这个类,重写一下函数- (BOOL)canBecomeKeyWindow,使其总是返回YES:

- (BOOL)canBecomeKeyWindow
{
	return YES;
}

好了,全屏程序就这样建立了。

无题

闲言碎语 — ronnie @ 9:53 pm

最近一段时间忙项目,也没时间写东西。前两天刚忙完,只顾休息了,也没上来写。好不容易今天才有时间来写点东西。

读书:最近读了清华老教授何兆武的回忆录,书名是《上学记》。从他的回忆中能感到他对西南联大那段时期自由民主的学校氛围的怀念,他解释说那段时间除了那么多学术牛人的原因就是自由,他强调搞学术就是要自由。的确是这样,如果教授不能教自己喜欢交的,学生不能学自己喜欢学的,学术研究当然会停滞不前。那段时期的教授还真的都是大家学者,专心学术,同时心里还有一个民主自由的梦想为之奋斗。看看当今校园中大部分所谓教授,有哪些是专心学术,敢称自己为大家,哪个不为了项目资金使劲剥削学生。同时何先生的回忆也改变了我对那段时期的认识。虽然那时中国处于战乱年代,但远没有今天封闭,大家真的可以有各种思想,各种信仰。那时的北京也很发达了,可以看到好莱坞大片哦。

电影:今天看了《star trek》,总体还算可以,特效也不错,但没有什么新意。就算是为延续了近40年的星际迷航传奇一个开始吧。不过还是不如《star wars》来的好。

How StarWars change the world

Movie — Tags: — ronnie @ 12:24 am

忘记在哪里看到这张图了,特别喜欢,就顺手存了下来。

这幅图展示了《星球大战》系列和乔治卢卡斯是如何影响世界的,不仅仅是电影圈哦。话说卢卡斯青年时期也和大多数青年一样,追求速度,喜欢赛车,可是赛车事故使其最终放弃了这个梦想。卢卡斯同学大学学的就是电影,在南加州吧。毕业时拍了处女作《THX1138》,此时,卢卡斯已经对好莱坞的电影制度很不满了,可是没办法。到了拍摄《美国风情画》,卢卡斯就开始尝试独立制作了。《星球大战》拍摄期间,卢卡斯为了完全掌握自己的影片,他放弃了作为导演的酬劳,换取了电影的拥有权。还记得《星球大战》开始前慢慢升起的介绍字幕吗?卢卡斯为了影片的整体科幻效果,违反当时美国导演协会规定的“片头设计规范”,不把电影工作人员名单列在影片开始,才有了现在《星球大战》中经典的字幕。在《星球大战.新希望》大获成功之后,卢卡斯完全受不了电影公司对自己影片的指手画脚,从而创立了自己的制片厂卢卡斯电影。卢卡斯为了使自己的《星球大战》系列拥有更好的特效,成立了现在大名鼎鼎的工业光魔(Industrial Light & Magic),这个公司现在可以说是视觉特效界的大哥,每年上映的大片中几乎都能看到它的身影。话说20多年前,卢卡斯为了和老婆离婚,需要一大笔钱,这时候他就把工业光魔的一个动画部门卖给了Apple前总裁乔布斯,这个动画部门就是后来牛逼轰轰的Pixar。现在一款极其流行的软件也是在工业光魔诞生的,这个软件就是photoshop。同时卢卡斯还成立了自己的音效部门——天行者音效(Skywalker Sound),目前流行的高保真标准THX也是从这里出来的哦。

卢卡斯和星球大战还有很多很多牛逼的地方,哪位感兴趣可以研究研究哦。

Create panorama using Photoshop CS3

Graphics — Tags: — ronnie @ 2:13 pm

其实我很土,刚刚学会用photoshop。

今天看这篇文章的时候,发现原来photoshop cs3可以拼接全景图,其中一步叫做“ Auto Blend Layers”,加速这种融合的算法正是这篇siggraph 2007 paper的方法。步骤在这里,我用这个功能拼出来一个大连某某光场的全景图,如下。

更大的图片从这里可以看到。

看看人家,做个产品,还能发个siggraph;或者说发个siggraph,还能用到产品里面。

IPhone Theme for Wordpress

wordpress — Tags: — ronnie @ 3:04 pm

无意中发现了这个好东西,叫做WPtouch,为你的wordpress blog加上IPhone的主题,也就是当别人使用IPhone登陆wordpress的blog时,就会有特别的效果,比如我的blog就有下面的效果哦:

Build blender and gimp on Leopard

Program — Tags: — ronnie @ 4:17 pm

昨天花了一整天去编译这两个家伙:blender和gimp,环境是Leopard(Mac OS X 10.5.6)。下面说说我的经验吧。

blender:

这个软件主要由Python和c++写成的,完全使用OpenGL来搭建界面。编译过程如下:

  1. 首先得有代码吧,建议用svn把最新的check下来,同时还要把一些库文件搞出来。
    $ svn checkout https://svn.blender.org/svnroot/bf-blender/trunk/blender
    $ mkdir lib
    $ cd lib
    $ svn checkout https://svn.blender.org/svnroot/bf-blender/trunk/lib/darwin-8.x-i386
  2. 把库文件链接到你自己的darwin系统需要的库目录。
    $ ln -s darwin-8.x.i386 $(uname -a | awk{print “darwin-”$3″-”$NF})
    $ cd ..
  3. 为blender设置python库的路径,主要是修改blender/source/nan_definitions.mk文件。我的系统中有两个python,分别是系统自己的Framework和我自己Port安装的,版本都是2.5。首先打开blender/source/nan_definitions.mk文件,找到:
    ifeq ($(OS),darwin)
    export ID = $(shell whoami)
    export HOST = $(shell hostname -s)
    export PY_FRAMEWORK = 1
    ifdef PY_FRAMEWORK
    export NAN_PYTHON ?= /System/Library/Frameworks/Python.framework/Versions/2.3
    export NAN_PYTHON_VERSION ?= 2.3

    替换成:

    ifeq ($(OS),darwin)
    export ID = $(shell whoami)
    export HOST = $(shell hostname -s)
    export PY_FRAMEWORK = 1
    ifdef PY_FRAMEWORK
    export NAN_PYTHON ?= /System/Library/Frameworks/Python.framework/Versions/2.5
    export NAN_PYTHON_VERSION ?= 2.5

    这里的替换成了系统的Python位置,如果你想要自己的,也可以改成自己的位置,只不过就不能再定义PY_FRAMEWORK了。

  4. 修改gettext库文件,不知道为什么这里居然写错了,还是说我没有理解它的意思。它提供了两个库,一个是libintl.a,另一个是libiconv.a。但是它还是只指定了一个,很奇怪吧。打开文件blender/source/nan_definitions.mk文件,找到
    export NAN_GETTEXT ?= $(LCGDIR)/gettext
    export NAN_GETTEXT_LIB ?= $(NAN_GETTEXT)/lib/libintl.a
    ifeq (($CPU), i386)
    export NAN_GETTEXT_LIB += $(NAN_GETTEXT)/lib/libintl.a
    endif

    替换成:

    export NAN_GETTEXT ?= $(LCGDIR)/gettext
    export NAN_GETTEXT_LIB ?= $(NAN_GETTEXT)/lib/libintl.a $(NAN_GETTEXT)/lib/libiconv.a
  5. 定义两个环境变量,分别如下:
    NANBLENDERHOME : 你的blender源代码位置,我的就在 ***/bf-blender/trunk/blend
    MAKEFLAGS: “-w -I$NANBLENDERHOME/source”
  6. 注意,如果你是英文系统,且时间格式是United States,那没问题,如果不是,请赶快改,时间格式很重要。
    一切搞定之后,make,搞定。

gimp:

这个软件使用gtk+写成,使用gegl和babl等一大堆的库,实在是麻烦啊,主要难点在于把这些库找到,并且安装,如果缺少哪个库,configure的时候会提示您的。主要步骤就是./configure, make, make install。

不过我还遇到一些问题,make install的时候,没有把全部的倚赖库和配置文件安装,所以最后还是我自己把这些库装上去的,最终可以使用gimp了。

无处不在的山寨

闲言碎语 — ronnie @ 11:42 pm

前几天想买一本书:《秘密》,就去china-pub搜了搜,找到了一本。等买回来突然发现,这根本不是我想买的,我想买的是这本!看看两本封面多像啊,很明显前者是仿后者的,中文名字一样,英文名字后面多了两个单词(本来是《The secret》,山寨版的是《The secret of the Ages》),这两个单词隐藏的很好,不仔细看就会疏忽。而且封面的相似程度更高,只有细微的区别,很难发现。不仅感叹山寨的力量,真是无孔不入啊,这种岂不是迷惑人嘛!

想想最早接触这种山寨东西还是初中,大约10年前。记得那是1999年,当时全球正在上映一部电影,叫做《二十二世纪杀人网络》,也就是《黑客帝国》了。在电视上面看到介绍之后,我很想一睹芳容,就去当时很流行的VCD店里搜寻。很快我就找到了,等回家就开始看了,可是越看越不对劲啊,怎么和电视上面介绍的对不上呢?我翻开封皮看了看,大呼上当啊,原来我拿了个《二十一世纪杀人网络》。也怪当时弱,不懂看英文名啊。

同时期,还解除接触了很多山寨小说。当时很喜欢金庸的小说,在我看遍了租书店中所有金庸的小说后,就开始四处寻觅金庸的书。只怪当时傻,不知道金大侠只写了15本。所以就经常遇见“金康”、“全庸”和“金庸新”著等等,全被我拿来当作金庸的读。等发现文笔和内容根本比不上金大侠时,才发现原来又上当了。

昨天经过路边买杂志的,突然看见一本山寨版的《看电影》,他在杂志封面“看电影”三个字前面,有两个很小的“全民”,所以这个山寨版杂志叫做《全民看电影》,封面做的和《看电影》几乎一样!以前也见过山寨版的《午夜场》,实际应该是《看电影 午夜场》。山寨已经全面进攻杂志了啊。

我国山寨文化由来已久啊,据我记忆都有十余年,且多数是从国外引进的。看到现在山寨文化盛行,真是感慨啊!!!

Next Page »
This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.
(c) 2009 To Be A Brave One | powered by WordPress with Barecity