├── .project
├── .pydevproject
├── Groove
├── README.md
├── fm_ui.py
├── image
├── Selection_003.png
├── Selection_004.png
├── Selection_005.png
├── cover.jpg
├── douban.jpg
├── grep.png
├── grepheart.png
├── ic_play_current1a.gif
├── logo.jpg
├── mute.png
├── play.png
├── redheart.png
├── splay.png
├── trash.png
├── user.png
├── volumnbutton.png
├── wrench.png
└── x_alt.png
├── main.py
├── sDialog.py
├── setting.py
└── songinfo.py
/.project:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 | ##运行
15 | >在ubuntu 12.04 Gnome和Kde环境下都可运行
16 |
17 | >下载后运行
18 |
19 | >`chmod +x Groove`
20 |
21 | >然后运行Groove就可以启动程序
22 |
23 | ##后续版本要增加的功能
24 | * 歌词
25 | * 完善收藏兆赫
26 |
27 | ##Bug
28 | * 连续点击下一首,可能出现歌与歌曲信息不符合的情况
29 |
--------------------------------------------------------------------------------
/fm_ui.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'doubanFM_revision.ui'
4 | #
5 | # Created: Wed May 29 22:26:19 2013
6 | # by: PyQt4 UI code generator 4.9.1
7 | #
8 | # WARNING! All changes made in this file will be lost!
9 |
10 | from PyQt4 import QtCore, QtGui
11 |
12 | try:
13 | _fromUtf8 = QtCore.QString.fromUtf8
14 | except AttributeError:
15 | _fromUtf8 = lambda s: s
16 |
17 | class Ui_Form(object):
18 | def setupUi(self, Form):
19 | Form.setObjectName(_fromUtf8("Form"))
20 | Form.setWindowModality(QtCore.Qt.NonModal)
21 | Form.resize(250, 550)
22 | Form.setMinimumSize(QtCore.QSize(250, 550))
23 | Form.setMaximumSize(QtCore.QSize(250, 550))
24 | icon = QtGui.QIcon()
25 | icon.addPixmap(QtGui.QPixmap(_fromUtf8("image/logo.jpg")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
26 | Form.setWindowIcon(icon)
27 | Form.setAutoFillBackground(False)
28 | Form.setObjectName(_fromUtf8(""))
29 | self.layoutWidget = QtGui.QWidget(Form)
30 | self.layoutWidget.setGeometry(QtCore.QRect(12, 12, 226, 52))
31 | self.layoutWidget.setObjectName(_fromUtf8("layoutWidget"))
32 | self.opLayout = QtGui.QHBoxLayout(self.layoutWidget)
33 | self.opLayout.setSpacing(7)
34 | self.opLayout.setMargin(0)
35 | self.opLayout.setObjectName(_fromUtf8("opLayout"))
36 | self.stopButton = HexLabel(self.layoutWidget)
37 | self.stopButton.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
38 | self.stopButton.setPixmap(QtGui.QPixmap(_fromUtf8("image/Selection_005.png")))
39 | self.stopButton.setObjectName(_fromUtf8("stopButton"))
40 | self.opLayout.addWidget(self.stopButton)
41 | self.nextButton = HexLabel(self.layoutWidget)
42 | self.nextButton.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
43 | self.nextButton.setTextFormat(QtCore.Qt.AutoText)
44 | self.nextButton.setPixmap(QtGui.QPixmap(_fromUtf8("image/Selection_004.png")))
45 | self.nextButton.setObjectName(_fromUtf8("nextButton"))
46 | self.opLayout.addWidget(self.nextButton)
47 | self.likeButton = HexLabel(self.layoutWidget)
48 | self.likeButton.setEnabled(False)
49 | self.likeButton.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
50 | self.likeButton.setTextFormat(QtCore.Qt.AutoText)
51 | self.likeButton.setPixmap(QtGui.QPixmap(_fromUtf8("image/grepheart.png")))
52 | self.likeButton.setObjectName(_fromUtf8("likeButton"))
53 | self.opLayout.addWidget(self.likeButton)
54 | self.notlikeButton = HexLabel(self.layoutWidget)
55 | self.notlikeButton.setEnabled(False)
56 | self.notlikeButton.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
57 | self.notlikeButton.setTextFormat(QtCore.Qt.AutoText)
58 | self.notlikeButton.setPixmap(QtGui.QPixmap(_fromUtf8("image/Selection_003.png")))
59 | self.notlikeButton.setObjectName(_fromUtf8("notlikeButton"))
60 | self.opLayout.addWidget(self.notlikeButton)
61 | self.opLayout.setStretch(0, 10)
62 | self.tline = QtGui.QFrame(Form)
63 | self.tline.setGeometry(QtCore.QRect(0, 468, 250, 16))
64 | self.tline.setFrameShape(QtGui.QFrame.HLine)
65 | self.tline.setFrameShadow(QtGui.QFrame.Sunken)
66 | self.tline.setObjectName(_fromUtf8("tline"))
67 | self.cover = QtGui.QLabel(Form)
68 | self.cover.setGeometry(QtCore.QRect(0, 110, 250, 250))
69 | self.cover.setText(_fromUtf8(""))
70 | self.cover.setPixmap(QtGui.QPixmap(_fromUtf8("image/cover.jpg")))
71 | self.cover.setScaledContents(True)
72 | self.cover.setObjectName(_fromUtf8("cover"))
73 | self.title = QtGui.QLabel(Form)
74 | self.title.setGeometry(QtCore.QRect(10, 370, 150, 30))
75 | self.title.setMinimumSize(QtCore.QSize(250, 30))
76 | self.title.setText(_fromUtf8(""))
77 | self.title.setObjectName(_fromUtf8("title"))
78 | self.artist = QtGui.QLabel(Form)
79 | self.artist.setGeometry(QtCore.QRect(10, 410, 150, 20))
80 | self.artist.setMinimumSize(QtCore.QSize(250, 10))
81 | self.artist.setText(_fromUtf8(""))
82 | self.artist.setObjectName(_fromUtf8("artist"))
83 | self.channel = HexLabel(Form)
84 | self.channel.setGeometry(QtCore.QRect(10, 478, 240, 30))
85 | self.channel.setMinimumSize(QtCore.QSize(50, 30))
86 | self.channel.setObjectName(_fromUtf8("channel"))
87 | self.choice = QtGui.QLabel(self.channel)
88 | self.choice.setGeometry(QtCore.QRect(220, 5, 10, 20))
89 | self.choice.setText(_fromUtf8(""))
90 | self.choice.setPixmap(QtGui.QPixmap(_fromUtf8("image/play.png")))
91 | self.choice.setObjectName(_fromUtf8("choice"))
92 | self.bline = QtGui.QFrame(Form)
93 | self.bline.setGeometry(QtCore.QRect(0, 503, 250, 16))
94 | self.bline.setFrameShape(QtGui.QFrame.HLine)
95 | self.bline.setFrameShadow(QtGui.QFrame.Sunken)
96 | self.bline.setObjectName(_fromUtf8("bline"))
97 | self.layoutWidget1 = QtGui.QWidget(Form)
98 | self.layoutWidget1.setGeometry(QtCore.QRect(0, 70, 254, 31))
99 | self.layoutWidget1.setObjectName(_fromUtf8("layoutWidget1"))
100 | self.volumnLayout = QtGui.QHBoxLayout(self.layoutWidget1)
101 | self.volumnLayout.setMargin(0)
102 | self.volumnLayout.setObjectName(_fromUtf8("volumnLayout"))
103 | self.volumn = HexLabel(self.layoutWidget1)
104 | self.volumn.setMinimumSize(QtCore.QSize(20, 0))
105 | self.volumn.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
106 | self.volumn.setPixmap(QtGui.QPixmap(_fromUtf8("image/volumnbutton.png")))
107 | self.volumn.setObjectName(_fromUtf8("volumn"))
108 | self.volumnLayout.addWidget(self.volumn)
109 | self.volumnSlider = QtGui.QSlider(self.layoutWidget1)
110 | self.volumnSlider.setMinimumSize(QtCore.QSize(100, 0))
111 | self.volumnSlider.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
112 | self.volumnSlider.setOrientation(QtCore.Qt.Horizontal)
113 | self.volumnSlider.setObjectName(_fromUtf8("volumnSlider"))
114 | self.volumnSlider.setFixedWidth(150)
115 | self.volumnLayout.addWidget(self.volumnSlider)
116 | self.tpos = QtGui.QLabel(self.layoutWidget1)
117 | self.tpos.setMinimumSize(QtCore.QSize(70, 0))
118 | self.tpos.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
119 | self.tpos.setObjectName(_fromUtf8("tpos"))
120 | self.volumnLayout.addWidget(self.tpos)
121 | self.userLabel = HexLabel(Form)
122 | self.userLabel.setGeometry(QtCore.QRect(10, 520, 20, 20))
123 | self.userLabel.setMinimumSize(QtCore.QSize(20, 0))
124 | self.userLabel.setPixmap(QtGui.QPixmap(_fromUtf8("image/user.png")))
125 | self.userLabel.setObjectName(_fromUtf8("userLabel"))
126 | self.username = QtGui.QLabel(Form)
127 | self.username.setGeometry(QtCore.QRect(38, 522, 70, 17))
128 | self.username.setMinimumSize(QtCore.QSize(70, 0))
129 | self.username.setObjectName(_fromUtf8("username"))
130 | self.quitLabel = HexLabel(Form)
131 | self.quitLabel.setGeometry(QtCore.QRect(220, 520, 20, 20))
132 | self.quitLabel.setPixmap(QtGui.QPixmap(_fromUtf8("image/x_alt.png")))
133 | self.quitLabel.setObjectName(_fromUtf8("quitLabel"))
134 | self.setting = HexLabel(Form)
135 | self.setting.setGeometry(QtCore.QRect(192, 520, 20, 20))
136 | self.setting.setPixmap(QtGui.QPixmap(_fromUtf8("image/wrench.png")))
137 | self.setting.setObjectName(_fromUtf8("setting"))
138 | self.redLabel = HexLabel(Form)
139 | self.redLabel.setGeometry(QtCore.QRect(102, 520, 25, 20))
140 | self.redLabel.setPixmap(QtGui.QPixmap(_fromUtf8("image/grep.png")))
141 | self.redLabel.setObjectName(_fromUtf8("redLabel"))
142 | self.rednum = QtGui.QLabel(Form)
143 | self.rednum.setGeometry(QtCore.QRect(127, 520, 50, 20))
144 | self.rednum.setMinimumSize(QtCore.QSize(50, 0))
145 | self.rednum.setObjectName(_fromUtf8("rednum"))
146 |
147 | self.current_channel = QtGui.QLabel(Form)
148 | self.current_channel.setGeometry(QtCore.QRect(10, 442, 240, 30))
149 | self.current_channel.setMinimumSize(QtCore.QSize(50, 30))
150 | self.current_channel.setObjectName(_fromUtf8("current_channel"))
151 | self.current_channel.setStyleSheet("font-size:10pt")
152 | self.choice_2 = QtGui.QLabel(self.current_channel)
153 | self.choice_2.setGeometry(QtCore.QRect(220, 5, 10, 20))
154 | self.choice_2.setText(_fromUtf8(""))
155 | self.choice_2.setPixmap(QtGui.QPixmap(_fromUtf8("image/ic_play_current1a.gif")))
156 | self.choice_2.setObjectName(_fromUtf8("choice_2"))
157 |
158 | #Popup menu
159 | self.menu = QtGui.QMenu(Form)
160 | self.redheartChannel = QtGui.QAction(_fromUtf8("红心兆赫"),self)
161 | self.redheartChannel.setEnabled(False)
162 | self.privateChannel = QtGui.QAction(_fromUtf8("私人兆赫"),self)
163 | self.privateChannel.setEnabled(False)
164 | self.collectChannel = QtGui.QMenu("收藏兆赫")
165 | self.collectChannel.setEnabled(False)
166 | self.moreChannel = QtGui.QMenu("公共兆赫")
167 | self.chineseChannel = QtGui.QAction("华语MHz",self)
168 | self.westernChannel = QtGui.QAction("欧美MHz",self)
169 | self.seventyChannel = QtGui.QAction("70MHz",self)
170 | self.eightyChannel = QtGui.QAction("80MHz",self)
171 | self.nintyChannel = QtGui.QAction("90MHz",self)
172 | self.cantoneseChannel = QtGui.QAction("粤语MHz",self)
173 | self.rockChannel = QtGui.QAction("摇滚MHz",self)
174 | self.folkChannel = QtGui.QAction("民谣MHz",self)
175 | self.lightmusicChannnel = QtGui.QAction("轻音乐MHz",self)
176 | self.movieChannel = QtGui.QAction("电影原声MHz",self)
177 | self.jazzChannel = QtGui.QAction("爵士MHz",self)
178 | self.elecChannel = QtGui.QAction("电子MHz",self)
179 | self.rapChannel = QtGui.QAction("说唱MHz",self)
180 | self.rnbChannel = QtGui.QAction("R&BMHz",self)
181 | self.japanChannel = QtGui.QAction("日语MHz",self)
182 | self.koreanChannel = QtGui.QAction("韩语MHz",self)
183 | self.womenChannel = QtGui.QAction("女声MHz",self)
184 | self.franceChannel = QtGui.QAction("法语MHz",self)
185 | self.moreChannel.addAction(self.chineseChannel)
186 | self.moreChannel.addAction(self.westernChannel)
187 | self.moreChannel.addAction(self.seventyChannel)
188 | self.moreChannel.addAction(self.eightyChannel)
189 | self.moreChannel.addAction(self.nintyChannel)
190 | self.moreChannel.addAction(self.cantoneseChannel)
191 | self.moreChannel.addAction(self.rockChannel)
192 | self.moreChannel.addAction(self.folkChannel)
193 | self.moreChannel.addAction(self.lightmusicChannnel)
194 | self.moreChannel.addAction(self.movieChannel)
195 | self.moreChannel.addAction(self.jazzChannel)
196 | self.moreChannel.addAction(self.elecChannel)
197 | self.moreChannel.addAction(self.rapChannel)
198 | self.moreChannel.addAction(self.rnbChannel)
199 | self.moreChannel.addAction(self.japanChannel)
200 | self.moreChannel.addAction(self.koreanChannel)
201 | self.moreChannel.addAction(self.womenChannel)
202 | self.moreChannel.addAction(self.franceChannel)
203 | self.menu.addMenu(self.moreChannel)
204 | self.menu.addAction(self.redheartChannel)
205 | self.menu.addAction(self.privateChannel)
206 | self.menu.addMenu(self.collectChannel)
207 |
208 | self.retranslateUi(Form)
209 | QtCore.QMetaObject.connectSlotsByName(Form)
210 |
211 | def retranslateUi(self, Form):
212 | Form.setWindowTitle(QtGui.QApplication.translate("Form", "Groove", None, QtGui.QApplication.UnicodeUTF8))
213 | self.channel.setText(QtGui.QApplication.translate("Form", "
兆赫选择
", None, QtGui.QApplication.UnicodeUTF8)) 214 | self.tpos.setText(QtGui.QApplication.translate("Form", " ", None, QtGui.QApplication.UnicodeUTF8)) 215 | self.username.setText(QtGui.QApplication.translate("Form", "未登录
", None, QtGui.QApplication.UnicodeUTF8)) 216 | self.rednum.setText(QtGui.QApplication.translate("Form", "0", None, QtGui.QApplication.UnicodeUTF8)) 217 | 218 | class HexLabel(QtGui.QLabel): 219 | def __init__(self,parent=None): 220 | super(HexLabel,self).__init__(parent) 221 | self.checked = False; 222 | 223 | clicked = QtCore.pyqtSignal() 224 | toggled = QtCore.pyqtSignal(bool) 225 | mousemove = QtCore.pyqtSignal(QtGui.QMouseEvent) 226 | 227 | def mousePressEvent(self,event): 228 | if event.button() == QtCore.Qt.LeftButton: 229 | self.clicked.emit() 230 | self.checked = not self.checked 231 | self.toggled.emit(self.checked) 232 | def mouseMoveEvent(self,event): 233 | self.mousemove.emit(event) -------------------------------------------------------------------------------- /image/Selection_003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vstorm/Groove/cdce4f2af7320268f5c38d3681db90a428a5f1a4/image/Selection_003.png -------------------------------------------------------------------------------- /image/Selection_004.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vstorm/Groove/cdce4f2af7320268f5c38d3681db90a428a5f1a4/image/Selection_004.png -------------------------------------------------------------------------------- /image/Selection_005.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vstorm/Groove/cdce4f2af7320268f5c38d3681db90a428a5f1a4/image/Selection_005.png -------------------------------------------------------------------------------- /image/cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vstorm/Groove/cdce4f2af7320268f5c38d3681db90a428a5f1a4/image/cover.jpg -------------------------------------------------------------------------------- /image/douban.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vstorm/Groove/cdce4f2af7320268f5c38d3681db90a428a5f1a4/image/douban.jpg -------------------------------------------------------------------------------- /image/grep.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vstorm/Groove/cdce4f2af7320268f5c38d3681db90a428a5f1a4/image/grep.png -------------------------------------------------------------------------------- /image/grepheart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vstorm/Groove/cdce4f2af7320268f5c38d3681db90a428a5f1a4/image/grepheart.png -------------------------------------------------------------------------------- /image/ic_play_current1a.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vstorm/Groove/cdce4f2af7320268f5c38d3681db90a428a5f1a4/image/ic_play_current1a.gif -------------------------------------------------------------------------------- /image/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vstorm/Groove/cdce4f2af7320268f5c38d3681db90a428a5f1a4/image/logo.jpg -------------------------------------------------------------------------------- /image/mute.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vstorm/Groove/cdce4f2af7320268f5c38d3681db90a428a5f1a4/image/mute.png -------------------------------------------------------------------------------- /image/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vstorm/Groove/cdce4f2af7320268f5c38d3681db90a428a5f1a4/image/play.png -------------------------------------------------------------------------------- /image/redheart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vstorm/Groove/cdce4f2af7320268f5c38d3681db90a428a5f1a4/image/redheart.png -------------------------------------------------------------------------------- /image/splay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vstorm/Groove/cdce4f2af7320268f5c38d3681db90a428a5f1a4/image/splay.png -------------------------------------------------------------------------------- /image/trash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vstorm/Groove/cdce4f2af7320268f5c38d3681db90a428a5f1a4/image/trash.png -------------------------------------------------------------------------------- /image/user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vstorm/Groove/cdce4f2af7320268f5c38d3681db90a428a5f1a4/image/user.png -------------------------------------------------------------------------------- /image/volumnbutton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vstorm/Groove/cdce4f2af7320268f5c38d3681db90a428a5f1a4/image/volumnbutton.png -------------------------------------------------------------------------------- /image/wrench.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vstorm/Groove/cdce4f2af7320268f5c38d3681db90a428a5f1a4/image/wrench.png -------------------------------------------------------------------------------- /image/x_alt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vstorm/Groove/cdce4f2af7320268f5c38d3681db90a428a5f1a4/image/x_alt.png -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import fm_ui 4 | import time 5 | import urllib.request #python3 6 | import http.cookiejar #python3 7 | from PyQt4 import QtCore,QtGui 8 | from songinfo import getSongInfo 9 | from sDialog import sDialog 10 | from bs4 import BeautifulSoup 11 | 12 | class Widget(QtGui.QWidget,fm_ui.Ui_Form): 13 | def __init__(self,parent=None): 14 | QtGui.QWidget.__init__(self,parent) 15 | self.initUi() 16 | 17 | def initUi(self): 18 | self.setupUi(self) 19 | # http.client.HTTPConnection.debuglevel = 1 20 | url = '1' 21 | cookiefile = "cookies.txt" 22 | collectChannel = {} 23 | self.tochannel() #QSignalMapper 24 | self.get = 0 25 | if os.path.isfile(cookiefile): #cookie文件是否存在 26 | self.likeButton.setEnabled(True) 27 | self.notlikeButton.setEnabled(True) 28 | self.redheartChannel.setEnabled(True) 29 | self.privateChannel.setEnabled(True) 30 | self.collectChannel.setEnabled(True) 31 | self.install_opener(cookiefile) 32 | collectChannel=self.getcollect() 33 | self.tocollect(collectChannel) 34 | url = '0' 35 | if url == '0': 36 | self.current_channel.setText("私人兆赫") 37 | else: 38 | self.current_channel.setText("华语HMz") 39 | self.url = "http://douban.fm/j/mine/playlist?type=n&channel="+url+"&from=mainsite" 40 | 41 | self.sDialog = None 42 | self.songprocess = QtCore.QProcess() 43 | self.songprocess.setProcessChannelMode(QtCore.QProcess.MergedChannels) 44 | self.songprocess.started.connect(self.info) 45 | self.songprocess.finished[int].connect(self.finish) 46 | self.nextButton.clicked.connect(self.next) #下一首 47 | self.stopButton.toggled.connect(self.stop) #暂停 48 | self.volumnSlider.valueChanged.connect(self.changeVolumn) #改变音量 49 | self.volumn.clicked.connect(self.mute) #改变音量 50 | self.setting.clicked.connect(self.changeSetting) 51 | self.likeButton.clicked.connect(self.like) 52 | self.notlikeButton.clicked.connect(self.notlike) 53 | self.channel.mousemove.connect(self.showChannel) 54 | self.quitLabel.clicked.connect(self.clearCookie) 55 | 56 | if url == "1": 57 | self.cnum = 1 58 | else: 59 | self.cnum = -3 60 | 61 | self.songlist = getSongInfo(self.url) 62 | self.s = next(self.songlist) 63 | song = self.s["url"] 64 | self.songprocess.start('mplayer',['-slave','-quiet',song]) 65 | self.vnum = 50 66 | self.volumnSlider.setValue(self.vnum) 67 | 68 | def getcollect(self): 69 | indexurl = "http://fm.douban.com" 70 | r = urllib.request.urlopen(indexurl) 71 | soup = BeautifulSoup(r) 72 | self.username.setText(soup.find(id="user_name").get_text()) 73 | self.rednum.setText(soup.find(id="rec_liked").get_text()) 74 | if not self.get: 75 | ul = soup.find(id="fav_chls") 76 | collect={} 77 | for li in ul.find_all('li'): 78 | if li.get('class') == ['channel']: 79 | cid = li.get('cid') 80 | cname = li.a.get_text() 81 | action = QtGui.QAction(cname,self) 82 | self.collectChannel.addAction(action) 83 | collect[cid]=action 84 | self.get = 1 85 | return collect 86 | 87 | def tocollect(self,collectChannel): 88 | if len(collectChannel): 89 | for num,channel in collectChannel.items(): 90 | text = channel.text() 91 | # collectChannel 92 | self.sMapper = QtCore.QSignalMapper(self) 93 | self.tMapper = QtCore.QSignalMapper(self) 94 | self.sMapper.setMapping(channel,num) 95 | self.tMapper.setMapping(channel,text) 96 | channel.triggered.connect(self.sMapper.map) 97 | channel.triggered.connect(self.tMapper.map) 98 | self.sMapper.mapped[str].connect(self.changeChannel) 99 | self.tMapper.mapped[str].connect(self.currentChannel) 100 | 101 | def install_opener(self,cookiefile): 102 | cookie = http.cookiejar.LWPCookieJar(cookiefile) 103 | cookie.load(cookiefile, ignore_discard=True, ignore_expires=True) 104 | opener= urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cookie)) 105 | urllib.request.install_opener(opener) 106 | 107 | def tochannel(self): #QSignalMapper 108 | channellist = {'-3':self.redheartChannel,'0':self.privateChannel,'1':self.chineseChannel,'2':self.westernChannel, 109 | '3':self.seventyChannel,'4':self.eightyChannel,'5':self.nintyChannel, 110 | '6':self.cantoneseChannel,'7':self.rockChannel,'8':self.folkChannel, 111 | '9':self.lightmusicChannnel,'10':self.movieChannel,'13':self.jazzChannel, 112 | '14':self.elecChannel,'15':self.rapChannel,'16':self.rnbChannel,'17':self.japanChannel, 113 | '18':self.koreanChannel,'20':self.womenChannel,"22":self.franceChannel} 114 | for num,channel in channellist.items(): 115 | text = channel.text() 116 | self.sMapper = QtCore.QSignalMapper(self) 117 | self.tMapper = QtCore.QSignalMapper(self) 118 | self.sMapper.setMapping(channel,num) 119 | self.tMapper.setMapping(channel,text) 120 | channel.triggered.connect(self.sMapper.map) 121 | channel.triggered.connect(self.tMapper.map) 122 | self.sMapper.mapped[str].connect(self.changeChannel) 123 | self.tMapper.mapped[str].connect(self.currentChannel) 124 | 125 | def song(self): #获取歌曲 126 | url = self.s["picture"].replace("mpic","lpic") 127 | picture = urllib.request.urlopen(url).read() 128 | with open("image/cover.jpg",mode="wb") as img_file: 129 | img_file.write(picture) 130 | title = self.s["title"] 131 | artist = self.s["artist"] 132 | if len(title)>25: 133 | title = title[0:25]+'...' 134 | if len(artist)>25: 135 | artist = artist[0:25]+'...' 136 | self.cover.setPixmap(QtGui.QPixmap("image/cover.jpg")) 137 | self.artist.setText(''+artist+'
') 138 | self.title.setText(''+title+'
') 139 | self.sid = self.s['sid'] 140 | if self.s["like"] == 1: 141 | self.likeButton.setPixmap(QtGui.QPixmap("image/redheart.png")) 142 | self.like = 1 143 | else: 144 | self.likeButton.setPixmap(QtGui.QPixmap("image/grepheart.png")) 145 | self.like = 0 146 | 147 | def nextsong(self): 148 | try: 149 | self.s = next(self.songlist) 150 | except StopIteration: 151 | self.songlist = getSongInfo(self.url) 152 | self.s = next(self.songlist) 153 | 154 | @QtCore.pyqtSlot() 155 | def like(self): #加心或去掉加心 156 | num = int(self.rednum.text()) 157 | if self.like: 158 | t = "u" 159 | self.likeButton.setPixmap(QtGui.QPixmap("image/grepheart.png")) 160 | self.like = 0 161 | num = num -1 162 | else: 163 | t = "r" 164 | self.likeButton.setPixmap(QtGui.QPixmap("image/redheart.png")) 165 | self.like = 1 166 | num = num + 1 167 | self.rednum.setText(str(num)) 168 | url = "http://douban.fm/j/mine/playlist?type=" + t +"&sid=" + self.sid +"&channel=" + str(self.cnum) + "&from=mainsite" 169 | urllib.request.urlopen(url) 170 | 171 | @QtCore.pyqtSlot() #不再收听 172 | def notlike(self): 173 | url = "http://douban.fm/j/mine/playlist?type=b&sid=" + self.sid +"&channel=" + str(self.cnum) + "&from=mainsite" 174 | urllib.request.urlopen(url) 175 | if self.like: 176 | num = int(self.rednum.text()) - 1 177 | self.rednum.setText(str(num)) 178 | self.next() 179 | 180 | @QtCore.pyqtSlot() 181 | def changeSetting(self): #打开设置 182 | if self.sDialog is None: 183 | self.sDialog = sDialog(self) 184 | self.sDialog.show() 185 | self.sDialog.raise_() 186 | self.sDialog.activateWindow() 187 | 188 | @QtCore.pyqtSlot() 189 | def info(self): 190 | self.song() 191 | 192 | @QtCore.pyqtSlot(bool) 193 | def stop(self,stop): #暂停 194 | if stop: 195 | self.stopButton.setPixmap(QtGui.QPixmap("image/splay.png")) 196 | else: 197 | self.stopButton.setPixmap(QtGui.QPixmap("image/Selection_005")) 198 | self.songprocess.write("pause\n") 199 | 200 | @QtCore.pyqtSlot(int) 201 | def changeVolumn(self,num): #更改音量 202 | self.songprocess.write("volume {0} 1\n".format(num)) 203 | if not num: 204 | self.volumn.setPixmap(QtGui.QPixmap('image/mute.png')) 205 | else: 206 | self.volumn.setPixmap(QtGui.QPixmap('image/volumnbutton.png')) 207 | @QtCore.pyqtSlot() 208 | def mute(self): #静音 209 | num = self.volumnSlider.value() 210 | if(num): 211 | self.volumnSlider.setValue(0) 212 | self.vnum = num 213 | self.volumn.setPixmap(QtGui.QPixmap('image/mute.png')) 214 | else: 215 | self.volumnSlider.setValue(self.vnum) 216 | self.volumn.setPixmap(QtGui.QPixmap('image/volumnbutton.png')) 217 | # self.volumn.repaint() 218 | 219 | @QtCore.pyqtSlot() 220 | def next(self): 221 | self.nextsong() 222 | song = self.s["url"] 223 | self.songprocess.write("loadfile {0}\n".format(song)) 224 | time.sleep(1) 225 | self.song() 226 | # self.repaint() 227 | @QtCore.pyqtSlot(int) 228 | def finish(self,error): 229 | if not error: 230 | self.nextsong() 231 | song = self.s["url"] 232 | self.songprocess.start('mplayer',['-slave','-quiet',song]) 233 | 234 | @QtCore.pyqtSlot(QtGui.QMouseEvent) 235 | def showChannel(self,event): #显示兆赫选择菜单 236 | pos = QtCore.QPoint(250,478) 237 | self.menu.exec_(self.mapToParent(pos)) 238 | 239 | @QtCore.pyqtSlot(str) 240 | def changeChannel(self,num): 241 | self.url = "http://douban.fm/j/mine/playlist?type=n&sid=&pt=0.0&channel="+ num + "&from=mainsite" 242 | self.cnum = num 243 | self.songlist = getSongInfo(self.url) 244 | self.s = next(self.songlist) 245 | song = self.s["url"] 246 | self.songprocess.write("loadfile {0}\n".format(song)) 247 | self.song() 248 | 249 | @QtCore.pyqtSlot(str) 250 | def currentChannel(self,text): 251 | self.current_channel.setText(text) 252 | @QtCore.pyqtSlot() 253 | def clearCookie(self): 254 | if os.path.isfile("cookies.txt"): 255 | r = QtGui.QMessageBox.warning(self,"Groove","退出登录?", buttons=QtGui.QMessageBox.Yes|QtGui.QMessageBox.No, defaultButton=QtGui.QMessageBox.No) 256 | if r == QtGui.QMessageBox.Yes: 257 | os.remove("cookies.txt") 258 | self.likeButton.setEnabled(False) 259 | self.notlikeButton.setEnabled(False) 260 | self.redheartChannel.setEnabled(False) 261 | self.privateChannel.setEnabled(False) 262 | self.collectChannel.setEnabled(False) 263 | self.username.setText("未登录") 264 | self.rednum.setText("0") 265 | self.changeChannel('1') 266 | self.currentChannel("华语HMz") 267 | def closeEvent(self,ev): 268 | self.songprocess.write("quit\n") 269 | self.songprocess.waitForFinished(msecs=30000) 270 | ev.accept() 271 | 272 | def main(): 273 | app = QtGui.QApplication(sys.argv) 274 | widget = Widget() 275 | widget.show() 276 | app.lastWindowClosed.connect(app.quit) 277 | sys.exit(app.exec_()) 278 | 279 | if __name__ == "__main__": 280 | main() 281 | 282 | 283 | -------------------------------------------------------------------------------- /sDialog.py: -------------------------------------------------------------------------------- 1 | import os 2 | import http.cookiejar 3 | import urllib.request 4 | import setting 5 | import json 6 | from PyQt4 import QtGui,QtCore 7 | # from opener import install_opener 8 | 9 | 10 | class sDialog(QtGui.QDialog,setting.Ui_Dialog): 11 | def __init__(self,parent=None): 12 | QtGui.QDialog.__init__(self,parent) 13 | self.initUi() 14 | 15 | def initUi(self): 16 | self.setupUi(self) 17 | self.setFixedSize(QtCore.QSize(400,350)) 18 | self.glink.setText("github") 19 | self.dlink.setText("小峰") 20 | self.captchaurl_id = None 21 | self.codeButton.clicked.connect(self.getCode) 22 | self.buttonBox.accepted.connect(self.getAuth) 23 | self.buttonBox.rejected.connect(self.close) 24 | self.glink.linkActivated.connect(self.openUrl) 25 | self.dlink.linkActivated.connect(self.openUrl) 26 | def openUrl(self,url): 27 | QtGui.QDesktopServices.openUrl(QtCore.QUrl(url)) 28 | 29 | def getCode(self): 30 | captchaurl = "http://douban.fm/j/new_captcha" 31 | data = urllib.request.urlopen(captchaurl) 32 | self.captchaurl_id = data.read().decode('utf-8').split('"')[1] 33 | requrl = "http://douban.fm/misc/captcha?size=m&id={0}".format(self.captchaurl_id) 34 | urllib.request.urlretrieve(requrl,'chaptucha.jpg') 35 | self.codeImage.setPixmap(QtGui.QPixmap("chaptucha.jpg")) 36 | 37 | def getAuth(self): 38 | if self.captchaurl_id is None: 39 | QtGui.QMessageBox.information(self,"Groove","请先获取验证码") 40 | else: 41 | loginurl = "http://douban.fm/j/login" 42 | params = { 43 | "source": "radio", 44 | "alias": self.emailEdit.text(), 45 | "form_password": self.passwordEdit.text(), 46 | "captcha_solution":self.codeEdit.text(), 47 | "captcha_id":self.captchaurl_id, 48 | "task": "sync_channel_list" 49 | } 50 | user_agent = 'Mozilla/5.0 (compatible; MSIE 5.5; Windows NT)' 51 | 52 | cookiefile = "cookies.txt" 53 | cookie = http.cookiejar.LWPCookieJar(cookiefile) 54 | if os.path.isfile(cookiefile): 55 | cookie.revert(cookiefile, ignore_discard=False, ignore_expires=False) 56 | else: 57 | cookie.save(cookiefile, ignore_discard=False, ignore_expires=False) 58 | opener= urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cookie)) 59 | data = urllib.parse.urlencode(params).encode('unicode_escape') 60 | opener.addheaders = [('User-Agent',user_agent)] 61 | response = opener.open(loginurl, data) 62 | ans = json.loads(response.read().decode('utf-8')) 63 | if 'err_no' in ans: 64 | error = ans['err_msg'] 65 | if error == "验证码不正确": 66 | error += ",请刷新验证码" 67 | QtGui.QMessageBox.information(self,"Groove",error) 68 | os.remove("cookies.txt") 69 | else: 70 | self.parent().likeButton.setEnabled(True) 71 | self.parent().notlikeButton.setEnabled(True) 72 | self.parent().redheartChannel.setEnabled(True) 73 | self.parent().privateChannel.setEnabled(True) 74 | self.parent().collectChannel.setEnabled(True) 75 | self.parent().username.setText(ans['user_info']['name']) 76 | self.parent().rednum.setText(str(ans['user_info']['play_record']['liked'])) 77 | cookie.save(cookiefile, ignore_discard=True, ignore_expires=True) 78 | self.parent().install_opener("cookies.txt") 79 | self.parent().changeChannel("0") 80 | self.parent().currentChannel("私人兆赫") 81 | if not self.parent().get: 82 | collect = self.parent().getcollect() 83 | self.parent().tocollect(collect) 84 | self.close() -------------------------------------------------------------------------------- /setting.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'setting.ui' 4 | # 5 | # Created: Sun May 26 22:05:20 2013 6 | # by: PyQt4 UI code generator 4.9.1 7 | # 8 | # WARNING! All changes made in this file will be lost! 9 | 10 | from PyQt4 import QtCore, QtGui 11 | 12 | try: 13 | _fromUtf8 = QtCore.QString.fromUtf8 14 | except AttributeError: 15 | _fromUtf8 = lambda s: s 16 | 17 | class Ui_Dialog(object): 18 | def setupUi(self, Dialog): 19 | Dialog.setObjectName(_fromUtf8("Dialog")) 20 | Dialog.resize(400, 349) 21 | self.setting = QtGui.QTabWidget(Dialog) 22 | self.setting.setGeometry(QtCore.QRect(10, 20, 371, 291)) 23 | self.setting.setObjectName(_fromUtf8("setting")) 24 | # self.general = QtGui.QWidget() 25 | # self.general.setObjectName(_fromUtf8("general")) 26 | # self.setting.addTab(self.general, _fromUtf8("")) 27 | self.account = QtGui.QWidget() 28 | self.account.setContextMenuPolicy(QtCore.Qt.DefaultContextMenu) 29 | self.account.setObjectName(_fromUtf8("account")) 30 | self.widget = QtGui.QWidget(self.account) 31 | self.widget.setGeometry(QtCore.QRect(30, 30, 261, 211)) 32 | self.widget.setObjectName(_fromUtf8("widget")) 33 | self.verticalLayout = QtGui.QVBoxLayout(self.widget) 34 | self.verticalLayout.setMargin(0) 35 | self.verticalLayout.setObjectName(_fromUtf8("verticalLayout")) 36 | self.horizontalLayout = QtGui.QHBoxLayout() 37 | self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout")) 38 | spacerItem = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) 39 | self.horizontalLayout.addItem(spacerItem) 40 | self.email = QtGui.QLabel(self.widget) 41 | self.email.setObjectName(_fromUtf8("email")) 42 | self.horizontalLayout.addWidget(self.email) 43 | self.emailEdit = QtGui.QLineEdit(self.widget) 44 | self.emailEdit.setObjectName(_fromUtf8("emailEdit")) 45 | self.horizontalLayout.addWidget(self.emailEdit) 46 | self.verticalLayout.addLayout(self.horizontalLayout) 47 | self.horizontalLayout_2 = QtGui.QHBoxLayout() 48 | self.horizontalLayout_2.setObjectName(_fromUtf8("horizontalLayout_2")) 49 | spacerItem1 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) 50 | self.horizontalLayout_2.addItem(spacerItem1) 51 | self.password = QtGui.QLabel(self.widget) 52 | self.password.setObjectName(_fromUtf8("password")) 53 | self.horizontalLayout_2.addWidget(self.password) 54 | self.passwordEdit = QtGui.QLineEdit(self.widget) 55 | self.passwordEdit.setEchoMode(QtGui.QLineEdit.Password) 56 | self.passwordEdit.setObjectName(_fromUtf8("passwordEdit")) 57 | self.horizontalLayout_2.addWidget(self.passwordEdit) 58 | self.verticalLayout.addLayout(self.horizontalLayout_2) 59 | self.horizontalLayout_3 = QtGui.QHBoxLayout() 60 | self.horizontalLayout_3.setObjectName(_fromUtf8("horizontalLayout_3")) 61 | spacerItem2 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) 62 | self.horizontalLayout_3.addItem(spacerItem2) 63 | self.code = QtGui.QLabel(self.widget) 64 | self.code.setObjectName(_fromUtf8("code")) 65 | self.horizontalLayout_3.addWidget(self.code) 66 | self.codeEdit = QtGui.QLineEdit(self.widget) 67 | self.codeEdit.setObjectName(_fromUtf8("codeEdit")) 68 | self.horizontalLayout_3.addWidget(self.codeEdit) 69 | self.verticalLayout.addLayout(self.horizontalLayout_3) 70 | self.horizontalLayout_4 = QtGui.QHBoxLayout() 71 | self.horizontalLayout_4.setObjectName(_fromUtf8("horizontalLayout_4")) 72 | self.codeButton = QtGui.QPushButton(self.widget) 73 | self.codeButton.setObjectName(_fromUtf8("codeButton")) 74 | self.horizontalLayout_4.addWidget(self.codeButton) 75 | self.codeImage = QtGui.QLabel(self.widget) 76 | self.codeImage.setText(_fromUtf8("")) 77 | self.codeImage.setObjectName(_fromUtf8("codeImage")) 78 | self.codeImage.setScaledContents(True) 79 | self.horizontalLayout_4.addWidget(self.codeImage) 80 | self.verticalLayout.addLayout(self.horizontalLayout_4) 81 | self.buttonBox = QtGui.QDialogButtonBox(self.widget) 82 | self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok) 83 | self.buttonBox.setObjectName(_fromUtf8("buttonBox")) 84 | self.verticalLayout.addWidget(self.buttonBox) 85 | self.setting.addTab(self.account, _fromUtf8("")) 86 | # self.shortcut = QtGui.QWidget() 87 | # self.shortcut.setObjectName(_fromUtf8("shortcut")) 88 | # self.setting.addTab(self.shortcut, _fromUtf8("")) 89 | self.help = QtGui.QWidget() 90 | self.help.setObjectName(_fromUtf8("help")) 91 | self.widget = QtGui.QWidget(self.help) 92 | self.widget.setGeometry(QtCore.QRect(70, 50, 221, 61)) 93 | self.widget.setObjectName(_fromUtf8("widget")) 94 | self.verticalLayout_2 = QtGui.QVBoxLayout(self.widget) 95 | self.verticalLayout_2.setMargin(0) 96 | self.verticalLayout_2.setObjectName(_fromUtf8("verticalLayout_2")) 97 | self.horizontalLayout_5 = QtGui.QHBoxLayout() 98 | self.horizontalLayout_5.setObjectName(_fromUtf8("horizontalLayout_5")) 99 | self.github = QtGui.QLabel(self.widget) 100 | self.github.setObjectName(_fromUtf8("github")) 101 | self.horizontalLayout_5.addWidget(self.github) 102 | self.glink = QtGui.QLabel(self.widget) 103 | self.glink.setText(_fromUtf8("")) 104 | self.glink.setObjectName(_fromUtf8("glink")) 105 | self.horizontalLayout_5.addWidget(self.glink) 106 | self.verticalLayout_2.addLayout(self.horizontalLayout_5) 107 | self.horizontalLayout_6 = QtGui.QHBoxLayout() 108 | self.horizontalLayout_6.setObjectName(_fromUtf8("horizontalLayout_6")) 109 | self.douban = QtGui.QLabel(self.widget) 110 | self.douban.setObjectName(_fromUtf8("douban")) 111 | self.horizontalLayout_6.addWidget(self.douban) 112 | self.dlink = QtGui.QLabel(self.widget) 113 | self.dlink.setText(_fromUtf8("")) 114 | self.dlink.setObjectName(_fromUtf8("dlink")) 115 | self.horizontalLayout_6.addWidget(self.dlink) 116 | self.verticalLayout_2.addLayout(self.horizontalLayout_6) 117 | self.setting.addTab(self.help, _fromUtf8("")) 118 | 119 | self.retranslateUi(Dialog) 120 | self.setting.setCurrentIndex(0) 121 | QtCore.QMetaObject.connectSlotsByName(Dialog) 122 | 123 | def retranslateUi(self, Dialog): 124 | Dialog.setWindowTitle(QtGui.QApplication.translate("Dialog", "首选项", None, QtGui.QApplication.UnicodeUTF8)) 125 | # self.setting.setTabText(self.setting.indexOf(self.general), QtGui.QApplication.translate("Dialog", "常规", None, QtGui.QApplication.UnicodeUTF8)) 126 | self.email.setText(QtGui.QApplication.translate("Dialog", "邮箱:", None, QtGui.QApplication.UnicodeUTF8)) 127 | self.password.setText(QtGui.QApplication.translate("Dialog", "密码:", None, QtGui.QApplication.UnicodeUTF8)) 128 | self.code.setText(QtGui.QApplication.translate("Dialog", "验证码:", None, QtGui.QApplication.UnicodeUTF8)) 129 | self.codeButton.setText(QtGui.QApplication.translate("Dialog", "获取验证码", None, QtGui.QApplication.UnicodeUTF8)) 130 | self.setting.setTabText(self.setting.indexOf(self.account), QtGui.QApplication.translate("Dialog", "帐号", None, QtGui.QApplication.UnicodeUTF8)) 131 | self.github.setText(QtGui.QApplication.translate("Dialog", "项目主页:", None, QtGui.QApplication.UnicodeUTF8)) 132 | self.douban.setText(QtGui.QApplication.translate("Dialog", "豆瓣主页:", None, QtGui.QApplication.UnicodeUTF8)) 133 | # self.setting.setTabText(self.setting.indexOf(self.shortcut), QtGui.QApplication.translate("Dialog", "快捷键", None, QtGui.QApplication.UnicodeUTF8)) 134 | self.setting.setTabText(self.setting.indexOf(self.help), QtGui.QApplication.translate("Dialog", "帮助", None, QtGui.QApplication.UnicodeUTF8)) 135 | 136 | -------------------------------------------------------------------------------- /songinfo.py: -------------------------------------------------------------------------------- 1 | import urllib.request #python3 2 | import json 3 | 4 | def getSongInfo(url): 5 | req = urllib.request.Request(url) 6 | response = urllib.request.urlopen(req) #注意:返回字节串而不是字符串 7 | responseJson = json.loads(response.read().decode("utf-8")) #应用byte的decode方法解码 8 | songList = responseJson["song"] 9 | for s in songList: 10 | yield s 11 | --------------------------------------------------------------------------------