desktop lyric. downloading songs. fixed some bugs.

This commit is contained in:
weiy
2018-01-06 19:38:05 +08:00
parent c7abd4db18
commit 40334b24ef
10 changed files with 640 additions and 92 deletions
+9
View File
@@ -82,4 +82,13 @@ QHeaderView::section {
QHeaderView::section:hover {
background-color: #232529;
}
QMenu {
background: #302F33;
color: #D1D1D7;
}
QMenu::item:selected {
background: #3B3A3D;
}
+1 -58
View File
@@ -1,60 +1,3 @@
/*QWidget#MainWindow{
background: #222225;
}
QFrame#line1{
color: qlineargradient(spread:reflect, x1:0.5, y1:0, x2:1, y2:0, stop:0 rgba(102, 4, 4, 255), stop:0.397727 rgba(184, 37, 37, 255));
}
QFrame {
border: none;
}
QScrollBar:vertical{
background: #191B1F;
width: 7px;
margin: 0px 0 0px 0;
}
QScrollBar::handle:vertical{
background: #2F3134;
min-height: 20px;
margin: 0 0 0 0;
border-radius: 3px;
border: none;
}
QScrollBar::handle:hover{
background: #3B3C40;
min-height: 20px;
margin: 0 0 0 0;
border-radius: 3px;
border: none;
}
QScrollBar::add-line:vertical{
background: #191B1F;
height: 0px;
subcontrol-position: bottom;
subcontrol-origin: margin;
}
QScrollBar::sub-line:vertical{
background: #191B1F;
height: 0px;
subcontrol-position: top;
subcontrol-origin: margin;
}
QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical{
background: none;
}
QScrollBar:horizontal {
height: 0px;
}*/
QWidget#MainWindow{
background: #222225;
}
@@ -119,4 +62,4 @@ QTabWidget {
QTabBar#mainTab::tab{
width: 0px;
height: 0px;
}
}
+83 -5
View File
@@ -1,19 +1,23 @@
__author__ = 'cyrbuzz'
import re
import os
import asyncio
import pickle
from apiRequestsBase import HttpRequest
from asyncBase import aAsync, toTask
from base import QAction, checkFolder, QIcon, QLabel, QObject, RequestThread, QTableWidgetItem
from base import QAction, QMenu, checkFolder, QIcon, QLabel, QObject, RequestThread, QTableWidgetItem, QCursor
from singsFrameBase import PlaylistButton
from netEaseApi import netease
from xiamiApi import xiami
from qqApi import qqApi
# import xiamiApi
import addition
# netEase = netEaseApi.NetEaseWebApi()
# xiami = xiamiApi.XiamiApi()
myRequests = HttpRequest()
class ConfigWindow(QObject):
@@ -363,25 +367,81 @@ class ConfigSearchArea(QObject):
def __init__(self, searchArea):
super(ConfigSearchArea, self).__init__()
# current show-table's index.
self.currentIndex = 0
# current widgets name。
self.currentName = '网易云'
# parent.
self.searchArea = searchArea
self.transTime = addition.itv2time
self.searchEngineers = {'网易云': netease, '虾米': xiami, 'QQ': qqApi}
# TODO
# to config singsFrameBase instead of configing them respective.
self.searchResultTableIndexs = {'网易云':self.searchArea.neteaseSearchFrame.singsResultTable,
'虾米':self.searchArea.xiamiSearchFrame.singsResultTable ,
'QQ':self.searchArea.qqSearchFrame.singsResultTable}
self.musicList = []
self.noContents = "很抱歉 未能找到关于<font style='text-align: center;' color='#23518F'>“{0}”</font>的{1}"
self.bindConnect()
self.setContextMenu()
def bindConnect(self):
self.searchArea.contentsTab.tabBarClicked.connect(self.searchBy)
self.searchArea.neteaseSearchFrame.singsResultTable.itemDoubleClicked.connect(self.itemDoubleClickedEvent)
self.searchArea.xiamiSearchFrame.singsResultTable.itemDoubleClicked.connect(self.itemDoubleClickedEvent)
self.searchArea.qqSearchFrame.singsResultTable.itemDoubleClicked.connect(self.itemDoubleClickedEvent)
self.searchArea.neteaseSearchFrame.singsResultTable.contextMenuEvent = self.contextEvent
self.searchArea.xiamiSearchFrame.singsResultTable.contextMenuEvent = self.contextEvent
self.searchArea.qqSearchFrame.singsResultTable.contextMenuEvent = self.contextEvent
def setContextMenu(self):
self.actionDownloadSong = QAction('下载', self)
self.actionDownloadSong.triggered.connect(self.downloadSong)
@toTask
def downloadSong(self, x):
# x is not to use, but must be.
musicInfo = self.musicList[self.currentIndex]
url = musicInfo.get('url')
if 'http:' not in url and 'https:' not in url:
songId = musicInfo.get('music_id')
future = aAsync(netease.singsUrl, [songId])
url = yield from future
url = url[0].get('url')
musicInfo['url'] = url
else:
url = musicInfo.get('url')
future = aAsync(myRequests.httpRequest, url, 'GET')
data = yield from future
if 'downloads' not in os.listdir('.'):
os.mkdir('downloads')
allMusicName = re.search(r'.*\.[a-zA-Z0-9]+', url[url.rfind('/')+1:]).group(0)
if allMusicName:
musicSuffix = allMusicName[allMusicName.rfind('.')+1:]
musicName = '{name}.{suf}'.format(name=musicInfo.get('name') + ' - ' + musicInfo.get('author'), suf=musicSuffix)
else:
# TODO MD5。
musicName = "random_name.mp3"
with open('downloads/{musicName}'.format(musicName=musicName), 'wb') as f:
f.write(data.content)
self.searchArea.parent.systemTray.showMessage("~~~", '{musicName} 下载完成'.format(musicName=musicName))
def searchBy(self, index):
currentWidgetName = self.searchArea.contentsTab.tabText(index)
self.currentName = currentWidgetName
self.search(currentWidgetName)
@toTask
@@ -460,6 +520,24 @@ class ConfigSearchArea(QObject):
data = self.musicList[currentRow]
self.searchArea.parent.playWidgets.setPlayerAndPlayList(data)
def contextEvent(self, event):
currentWidget = self.searchResultTableIndexs.get(self.currentName)
if not currentWidget:
return
item = currentWidget.itemAt(currentWidget.mapFromGlobal(QCursor.pos()))
self.menu = QMenu(currentWidget)
self.menu.addAction(self.actionDownloadSong)
try:
self.currentIndex = item.row() - 1
# 在索引是最后一行时会获取不到。
except:
self.currentIndex = -1
self.menu.exec_(QCursor.pos())
class ConfigSystemTray(QObject):
+17 -10
View File
@@ -63,24 +63,31 @@ class ConfigNative(QObject):
self.native.singsTable.setRowCount(self.native.singsTable.rowCount()+length)
self.musicList = []
for i in enumerate(mediaFiles):
music = eyed3.load(i[1])
if not music:
self.singsTable.removeRow(i[0])
continue
try:
name = music.tag.title
except:
print('获取该歌曲信息出错: {},已跳过。'.format(i))
self.singsTable.removeRow(i[0])
continue
author = music.tag.artist
if not name:
name = i[1].split('\\')[-1][:-4]
author = music.tag.artist
if not author:
author = '未知歌手'
if not name:
filePath = i[1].replace(selectFolder, '')
name = filePath[1:][:-4]
if not author:
author = ''
except:
try:
# TODO
# if more folders exist.
filePath = i[1].replace(selectFolder, '')
name = filePath[1:][:-4]
except Exception as e:
name = i[1]
author = ''
time = itv2time(music.info.time_secs)
self.musicList.append({'name': name, 'author': author, 'time': time, 'url': i[1], 'music_img': 'None'})
@@ -3,6 +3,7 @@
"""
__author__ = 'cyrbuzz'
import os
import re
import network
import addition
@@ -12,6 +13,15 @@ from base import (QAction, QCursor, QFrame, QLabel, QObject, QPixmap, QRunnable,
from netEaseApi import netease
from singsFrameBase import OneSing, PlaylistButton
# ../features
from asyncBase import aAsync, toTask
# ../apis
from netEaseApi import netease
from apiRequestsBase import HttpRequest
myRequests = HttpRequest()
transTime = addition.itv2time
@@ -231,12 +241,48 @@ class ConfigDetailSings(QObject):
self.actionNextPlay = QAction('下一首播放', self)
self.actionNextPlay.triggered.connect(self.addToNextPlay)
self.actionDownloadSong = QAction('下载', self)
self.actionDownloadSong.triggered.connect(self.downloadSong)
def addToNextPlay(self):
data = self.musicList[self.currentIndex]
self.player.setAllMusics([data])
self.playList.playList.addMusic(data)
self.playList.playList.addPlayList(data['name'], data['author'], data['time'])
@toTask
def downloadSong(self, x):
musicInfo = self.musicList[self.currentIndex]
url = musicInfo.get('url')
if 'http:' not in url and 'https:' not in url:
songId = musicInfo.get('music_id')
future = aAsync(netease.singsUrl, [songId])
url = yield from future
url = url[0].get('url')
musicInfo['url'] = url
else:
url = musicInfo.get('url')
future = aAsync(myRequests.httpRequest, url, 'GET')
data = yield from future
if 'downloads' not in os.listdir('.'):
os.mkdir('downloads')
allMusicName = re.search(r'.*\.[a-zA-Z0-9]+', url[url.rfind('/')+1:]).group(0)
if allMusicName:
musicSuffix = allMusicName[allMusicName.rfind('.')+1:]
musicName = '{name}.{suf}'.format(name=musicInfo.get('name') + ' - ' + musicInfo.get('author'), suf=musicSuffix)
else:
# TODO MD5。
musicName = "random_name.mp3"
with open('downloads/{musicName}'.format(musicName=musicName), 'wb') as f:
f.write(data.content)
self.grandparent.systemTray.showMessage("~~~", '{musicName} 下载完成'.format(musicName=musicName))
def addAllMusicToPlayer(self):
self.playList.setPlayerAndPlaylists(self.musicList)
@@ -295,6 +341,7 @@ class ConfigDetailSings(QObject):
self.menu = QMenu(self.detailSings.singsTable)
self.menu.addAction(self.actionNextPlay)
self.menu.addAction(self.actionDownloadSong)
try:
self.currentIndex = item.row() - 1
+24 -13
View File
@@ -35,7 +35,7 @@ import logging
from quamash import QEventLoop
# widgets
from base import (QApplication, QDialog, QFrame, QHBoxLayout, HBoxLayout, QIcon, QLabel, QListWidget, QListWidgetItem,
from base import (QApplication, cacheFolder, QDialog, QFrame, QHBoxLayout, HBoxLayout, QIcon, QLabel, QListWidget, QListWidgetItem,
QPushButton, PicLabel, QScrollArea, ScrollArea, Qt, QTabWidget, TableWidget, QVBoxLayout, VBoxLayout,
QWidget)
from player import PlayWidgets
@@ -65,6 +65,8 @@ logger.loggerConfig('logger/running_log.log')
# 覆盖原logger变量。
logger = logging.getLogger(__name__)
logger.info("当前图片缓存目录: {0}".format(os.path.join(os.getcwd(), cacheFolder)))
# 用于承载整个界面。所有窗口的父窗口,所有窗口都可以在父窗口里找到索引。
class Window(QWidget):
@@ -178,6 +180,12 @@ class Window(QWidget):
self.indexNetEaseSings.config.initThread()
self.indexXiamiSings.config.initThread()
self.indexQQSings.config.initThread()
# test desktop lyric。
screen = QApplication.desktop().availableGeometry()
self.playWidgets.desktopLyric.resize(screen.width(), 50)
self.playWidgets.desktopLyric.move(0, screen.height() - 100)
self.playWidgets.desktopLyric.show()
def closeEvent(self, event):
# 主要是保存cookies.
@@ -252,7 +260,7 @@ class Header(QFrame):
self.logoLabel = PicLabel(r'resource/format.png', 32, 32)
self.descriptionLabel = QLabel(self)
self.descriptionLabel.setText("<b>Music<b>")
self.descriptionLabel.setText("<b>Music</b>")
self.userPix = PicLabel(r'resource/no_music.png', 32, 32, r'resource/user_pic_mask.png')
self.userPix.setMinimumSize(22, 22)
@@ -489,20 +497,23 @@ def start():
# 是被asyncio重写的事件循环。
eventLoop = QEventLoop(app)
asyncio.set_event_loop(eventLoop)
main = Window()
main.show()
# 当前音乐的显示信息。
# 因为需要布局之后重新绘制的宽高。
# 这个宽高会在show之后才会改变。
# 需要获取宽,高并嵌入到父窗口里。
main.playWidgets.currentMusic.resize(main.navigation.width(), 64)
with eventLoop:
eventLoop.run_forever()
try:
main = Window()
sys.exit(0)
main.show()
# 当前音乐的显示信息。
# 因为需要布局之后重新绘制的宽高。
# 这个宽高会在show之后才会改变。
# 需要获取宽,高并嵌入到父窗口里。
main.playWidgets.currentMusic.resize(main.navigation.width(), 64)
with eventLoop:
eventLoop.run_forever()
sys.exit(0)
except:
logger.error("got some error", exc_info=True)
if __name__ == '__main__':
start()
-1
View File
@@ -287,7 +287,6 @@ picsQueue = QueueObject()
# 缓存目录。
cacheFolder = 'cache'
logger.info("当前缓存目录: {0}".format(os.getcwd()+cacheFolder))
## 对<img src=1.jpg>的初步探索。
# 暂只接受http(s)和本地目录。
+160
View File
@@ -0,0 +1,160 @@
# -*- coding: utf-8 -*-
# This file copy from https://github.com/wn0112/PPlayer
from PyQt5 import QtWidgets, QtGui, QtCore
def _fromUtf8(s):
return s
class Button(QtWidgets.QPushButton):
def __init__(self,parent = None):
super(Button,self).__init__(parent)
self.status = 0
def loadPixmap(self, pic_name):
self.pixmap = QtGui.QPixmap(pic_name)
self.btn_width = self.pixmap.width()
self.btn_height = self.pixmap.height()/6
self.setFixedSize(self.btn_width, self.btn_height)
def mousePressEvent(self,event):
if event.button() == QtCore.Qt.LeftButton:
self.status = 2
self.update()
self.clicked.emit(True)
def mouseReleaseEvent(self,event):
if event.button() == QtCore.Qt.LeftButton:
self.status = 0
self.update()
self.released.emit()
def rst(self):
self.status = 0
self.update()
def rbReleased(self):
self.status = 0
self.update()
def rbPressed(self):
self.status = 4
self.update()
def lbPressed(self):
self.status = 3
self.update()
def lbReleased(self):
self.status = 0
self.update()
def bothPressed(self):
self.status = 5
self.update()
def bothReleased(self):
self.status = 0
self.update()
def paintEvent(self,event):
self.painter = QtGui.QPainter()
self.painter.begin(self)
self.painter.drawPixmap(self.rect(), self.pixmap.copy(0, self.btn_height * self.status, self.btn_width, self.btn_height))
self.painter.end()
class PlayButton(Button):
def __init__(self,parent = None):
super(PlayButton,self).__init__(parent)
self.setCheckable(True)
def mouseReleaseEvent(self, event):
self.released.emit()
class SRButton(PlayButton):
def __init__(self,parent = None):
super(SRButton,self).__init__(parent)
self.syn = 0
def mousePressEvent(self,event):
if event.button() == QtCore.Qt.LeftButton:
self.status = 2
self.update()
if not self.isChecked():
self.syn = 1
self.clicked.emit(True)
def mouseReleaseEvent(self, event):
if self.isChecked() and self.syn != 1:
self.clicked.emit(True)
self.released.emit()
else:
self.syn = 0
class PushButton(QtWidgets.QPushButton):
def __init__(self,parent = None):
super(PushButton,self).__init__(parent)
self.status = 0
def loadPixmap(self, pic_name):
self.pixmap = QtGui.QPixmap(pic_name)
self.btn_width = self.pixmap.width()/4
self.btn_height = self.pixmap.height()
self.setFixedSize(self.btn_width, self.btn_height)
def enterEvent(self,event):
if not self.isChecked() and self.isEnabled():
self.status = 1
self.update()
def setDisabled(self, bool):
super(PushButton,self).setDisabled(bool)
if not self.isEnabled():
self.status = 2
self.update()
else:
self.status = 0
self.update()
def mousePressEvent(self,event):
if event.button() == QtCore.Qt.LeftButton:
self.status = 2
self.update()
def mouseReleaseEvent(self,event):
if event.button() == QtCore.Qt.LeftButton:
self.clicked.emit(True)
if not self.isChecked():
self.status = 3
if self.menu():
self.menu().exec_(event.globalPos())
self.update()
def leaveEvent(self,event):
if not self.isChecked() and self.isEnabled():
self.status = 0
self.update()
def paintEvent(self,event):
self.painter = QtGui.QPainter()
self.painter.begin(self)
self.painter.drawPixmap(self.rect(), self.pixmap.copy(self.btn_width * self.status, 0, self.btn_width, self.btn_height))
self.painter.end()
class PushButton2(QtWidgets.QPushButton):
def __init__(self,parent = None):
super(PushButton2,self).__init__(parent)
def loadPixmap(self, pic_name):
self.pixmap = QtGui.QPixmap(pic_name)
self.btn_width = self.pixmap.width()
self.btn_height = self.pixmap.height()
self.setFixedSize(self.btn_width, self.btn_height)
def paintEvent(self,event):
self.painter = QtGui.QPainter()
self.painter.begin(self)
self.painter.drawPixmap(self.rect(), self.pixmap.copy(0, 0, self.btn_width, self.btn_height))
self.painter.end()
+285 -5
View File
@@ -17,10 +17,10 @@ import sys
import random
import logging
from PyQt5.QtWidgets import (QAction, QAbstractItemView, QFrame, QHBoxLayout, QLabel, QMenu, QPushButton, QSlider, QTableWidget,
QTableWidgetItem, QVBoxLayout, QApplication)
from PyQt5.QtGui import QBrush, QColor, QCursor
from PyQt5.QtCore import QUrl, Qt, QObject, QPropertyAnimation, QRect, QEasingCurve, QAbstractAnimation
from PyQt5.QtWidgets import (QAction, QAbstractItemView, QDialog, QFrame, QHBoxLayout, QLabel, QMenu, QPushButton, QSlider,
QTableWidget, QTableWidgetItem, QVBoxLayout, QApplication)
from PyQt5.QtGui import QBrush, QColor, QCursor, QPixmap, QFont, QPainter, QPen, QLinearGradient
from PyQt5.QtCore import QUrl, Qt, QObject, QPropertyAnimation, QPoint, QRect, QEasingCurve, QAbstractAnimation, QTime, QTimer, QRegExp, QRectF
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent, QMediaMetaData, QMediaPlaylist
import addition
@@ -33,6 +33,14 @@ from netEaseApi import netease
from xiamiApi import xiami
from qqApi import qqApi
# support desktop lyric.
from desktopLyricButtons import *
def _fromUtf8(s):
return s
QString = str
# for desktop lyric too.
logger = logging.getLogger(__name__)
@@ -55,6 +63,9 @@ class PlayWidgets(QFrame):
self.currentMusic = CurrentMusic(self)
self.player = Player(self)
# test desktopLyric
self.desktopLyric = DesktopLyric(self)
self.setButtons()
self.setLabels()
self.setSliders()
@@ -597,6 +608,9 @@ class CurrentMusic(QFrame):
result = future.result().split('\n')
# set desktop lyric list.
self.parent.player.lrc_lst = getLyric(result)
signal = self.parent.player.timeChanged
for x, i in enumerate(result):
@@ -618,6 +632,7 @@ class CurrentMusic(QFrame):
self.detailInfo.addLyricLabel(_LyricLabel(data[0][0], data[0][1], x, signal, self))
self.count = x
# 这边并不会返回添加了控件后的Value值。
# self.sliderValue = self.detailInfo.maximumValue()
# self.slideValue = round(self.sliderValue/x)
@@ -650,6 +665,9 @@ class CurrentMusic(QFrame):
lyricUrl = data['songs'][0].get('lyric')
future = aAsync(xiami.lyric, lyricUrl)
data = yield from future
self.lyricCache = data
return data
musicId = musicInfo.get('music_id')
@@ -881,6 +899,9 @@ class Player(QMediaPlayer):
# 默认列表循环。
self.playList.setPlaybackMode(self.playList.Loop)
# lyric from CurrentMusic setting.
self.lrc_lst = []
self.setConnects()
# 功能。
@@ -992,7 +1013,7 @@ class Player(QMediaPlayer):
self.playWidgets.countTime.setText(self.transTime(self.musicTime))
self.playList.duration = duration
def positionChangedEvent(self):
def positionChangedEvent(self, position):
"""音乐在Media里以毫秒的形式保存,这里是播放时的进度条。"""
currentTime = self.position()/1000
transedTime = self.transTime(currentTime)
@@ -1004,12 +1025,51 @@ class Player(QMediaPlayer):
return
# *1000是为了与进度条的范围相匹配。
self.playWidgets.slider.setValue(currentTime/self.musicTime*1000)
self.setLyricEvent(position)
def stateChangedEvent(self):
""""""
if self.state() == 0 and self.playList.mediaCount() == 0 and self.playWidgets.pauseButton.isVisible():
self.playWidgets.stopEvent(self)
def setLyricEvent(self, position):
# copy from https://github.com/wn0112/PPlayer
t = QTime(0, 0, 0)
t = t.addMSecs(int(position))
lycF = ''
lycL = ''
lycM = ''
if self.lrc_lst:
lenOfLrc = len(self.lrc_lst)
for i in range(lenOfLrc):
if t.toString("mm:ss") in self.lrc_lst[i][0]:
t1 = t
if i < lenOfLrc - 1:
x = self.lrc_lst[i+1][0].replace('[', '')
x = x.replace(']', '')
t1 = QTime().fromString(x, 'mm:ss.z')
intervel = t.msecsTo(t1)
else:
t1 = QTime().fromString('00:10.99')
intervel = 3000
self.parent.desktopLyric.stopMask()
self.parent.desktopLyric.setText(self.lrc_lst[i][1], intervel)
self.parent.desktopLyric.startMask()
if i > 0:
lycM = self.lrc_lst[i-1][1]
j = 0
while(j < i-1):
lycF += self.lrc_lst[j][1]+'\n'
j += 1
j = i
while(j < lenOfLrc - 1):
lycL += self.lrc_lst[j+1][1]+'\n'
j += 1
# self.parent.desktopLyric.setText(lycF, lycM, self.lrc_lst[i][1], lycL, intervel)
# self.parent.desktopLyric.setText(lycF, lycM, self.lrc_lst[i][1], lycL, intervel)
break
# def mediaStatusChangedEvent(self, status):
""""""
# 8是无效音频。
@@ -1400,6 +1460,226 @@ class _LyricLabel(QLabel):
self.setText(self.myLyric)
class DesktopLyric(QDialog):
def __init__(self, parent=None):
super(DesktopLyric, self).__init__()
self.lyric = QString('Lyric Show.')
self.intervel = 0
self.maskRect = QRectF(0, 0, 0, 0)
self.maskWidth = 0
self.widthBlock = 0
self.t = QTimer()
self.screen = QApplication.desktop().availableGeometry()
self.setObjectName(_fromUtf8("Dialog"))
self.setWindowFlags(Qt.CustomizeWindowHint | Qt.FramelessWindowHint | Qt.Dialog | Qt.WindowStaysOnTopHint | Qt.Tool)
self.setMinimumHeight(65)
self.setAttribute(Qt.WA_TranslucentBackground)
self.handle = lyric_handle(self)
self.verticalLayout = QVBoxLayout(self)
self.verticalLayout.setSpacing(0)
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
self.font = QFont(_fromUtf8('微软雅黑, verdana'), 50)
self.font.setPixelSize(50)
# QMetaObject.connectSlotsByName(self)
self.handle.lyricmoved.connect(self.newPos)
self.t.timeout.connect(self.changeMask)
def changeMask(self):
self.maskWidth += self.widthBlock
self.update()
def setText(self, s, intervel=0):
self.lyric = s
self.intervel = intervel
self.maskWidth = 0
self.update()
def hideLyric(self):
self.hide()
# self.emit(SIGNAL('lyrichide()'))
def leaveEvent(self, event):
self.handle.leaveEvent(event)
def show(self):
super(DesktopLyric, self).show()
def hide(self):
super(DesktopLyric, self).hide()
self.handle.hide()
def enterEvent(self, event):
pass
# self.handle.handler.setFocus()
# self.handle.show()
def newPos(self, p):
self.move(self.pos().x() + p.x(), self.pos().y() + p.y())
# self.move(500, 600)
def startMask(self):
self.t.start(100)
def stopMask(self):
self.t.stop()
self.update()
def paintEvent(self, event):
painter = QPainter(self)
painter.setFont(self.font)
linear = QLinearGradient(QPoint(self.rect().topLeft()), QPoint(self.rect().bottomLeft()))
linear.setStart(0, 10)
linear.setFinalStop(0, 50)
linear.setColorAt(0.1, QColor(14, 179, 255));
linear.setColorAt(0.5, QColor(154, 232, 255));
linear.setColorAt(0.9, QColor(14, 179, 255));
linear2 = QLinearGradient(QPoint(self.rect().topLeft()), QPoint(self.rect().bottomLeft()))
linear2.setStart(0, 10)
linear2.setFinalStop(0, 50)
linear2.setColorAt(0.1, QColor(222, 54, 4));
linear2.setColorAt(0.5, QColor(255, 172, 116));
linear2.setColorAt(0.9, QColor(222, 54, 4));
painter.setPen(QColor(0, 0, 0, 200));
painter.drawText(QRect(1, 1, self.screen.width(), 60), Qt.AlignHCenter | Qt.AlignVCenter, self.lyric)
painter.setPen(QColor('transparent'));
self.textRect = painter.drawText(QRect(0, 0, self.screen.width(), 60), Qt.AlignHCenter | Qt.AlignVCenter, self.lyric)
painter.setPen(QPen(linear, 0))
painter.drawText(self.textRect, Qt.AlignLeft | Qt.AlignVCenter, self.lyric)
if self.intervel != 0:
self.widthBlock = self.textRect.width()/(self.intervel/150.0)
else:
self.widthBlock = 0
self.maskRect = QRectF(self.textRect.x(), self.textRect.y(), self.textRect.width(), self.textRect.height())
self.maskRect.setWidth(self.maskWidth)
painter.setPen(QPen(linear2, 0));
painter.drawText(self.maskRect, Qt.AlignLeft | Qt.AlignVCenter, self.lyric)
def mousePressEvent(self, event):
if event.buttons() == Qt.LeftButton:
self.m_drag = True
self.m_DragPosition = event.globalPos()-self.pos()
event.accept()
def mouseMoveEvent(self, event):
try:
if event.buttons() and Qt.LeftButton:
self.move(event.globalPos()-self.m_DragPosition)
event.accept()
except AttributeError:
pass
def mouseReleaseEvent(self, event):
if event.buttons() == Qt.LeftButton:
self.m_drag = False
class lyric_handle(QDialog):
# copy from https://github.com/wn0112/PPlayer
lyricmoved = pyqtSignal(QPoint)
def __init__(self, parent=None):
super(lyric_handle, self).__init__(parent)
self.timer = QTimer()
self.setObjectName(_fromUtf8("Dialog"))
self.setWindowFlags(Qt.CustomizeWindowHint | Qt.FramelessWindowHint | Qt.Dialog | Qt.WindowStaysOnTopHint | Qt.Tool)
self.setStyleSheet('QDialog { background: #2c7ec8; border: 0px solid black;}')
self.horiLayout = QHBoxLayout(self)
self.horiLayout.setSpacing(5)
self.horiLayout.setContentsMargins(0, 0, 0, 0)
self.horiLayout.setObjectName(_fromUtf8("horiLayout"))
self.handler = QLabel(self)
self.handler.setToolTip('Move Lyric')
self.handler.setPixmap(QPixmap(':/icons/handler.png'))
self.handler.setMouseTracking(True)
self.lockBt = PushButton2(self)
self.lockBt.setToolTip('Unlocked')
self.lockBt.loadPixmap(QPixmap(':/icons/unlock.png'))
self.hideBt = PushButton2(self)
self.hideBt.setToolTip('Hide Lyric')
self.hideBt.loadPixmap(QPixmap(':/icons/close.png').copy(48, 0, 16, 16))
self.lockBt.setCheckable(True)
self.horiLayout.addWidget(self.handler)
self.horiLayout.addWidget(self.lockBt)
self.horiLayout.addWidget(self.hideBt)
self.lockBt.clicked.connect(self.lockLyric)
self.hideBt.clicked.connect(self.hideLyric)
self.timer.timeout.connect(self.hide)
def lockLyric(self):
if self.lockBt.isChecked():
self.lockBt.loadPixmap(QPixmap(':/icons/lock.png'))
self.lockBt.setToolTip('Locked')
self.lockBt.update()
else:
self.lockBt.loadPixmap(QPixmap(':/icons/unlock.png'))
self.lockBt.setToolTip('Unlocked')
self.lockBt.update()
def hideLyric(self):
# self.parent().emit(SIGNAL('lyrichide()'))
self.parent().lyrichide.emit()
self.parent().hide()
self.hide()
def isInTitle(self, xPos, yPos):
if self.lockBt.isChecked():
return False
else:
return yPos <= self.height() and 0 <= xPos <= self.handler.width()
def moveEvent(self, event):
# self.emit(SIGNAL("lyricmoved(QPoint)"), event.pos() - event.oldPos())
self.lyricmoved.emit(QPoint(event.pos() - event.oldPos()))
def enterEvent(self, event):
# print(1)
self.setFocus()
self.timer.stop()
def leaveEvent(self, event):
self.timer.stop()
self.timer.start(3000)
def getLyric(rawLyric):
# copu from https://github.com/wn0112/PPlayer
lrc = rawLyric
r1 = re.compile("\[(\d{2}:\d{2}(.\d+)?)\]")
r2 = re.compile("\[\d+:+.+\](.*)")
r3 = re.compile("\[offset:(-?\d+)\]")
item = []
lrc_lst = []
offset = 0
for line in lrc:
times = r1.findall(line)
lrc_words = r2.findall(line)
if lrc_words:
lrc_words = lrc_words[0]
else:
lrc_words = []
if len(lrc_words) and lrc_words[0].rstrip():
for i in times:
item.append(i[0])
item.append(lrc_words)
lrc_lst.append(item)
item = []
lrc_lst.sort()
return lrc_lst
if __name__ == '__main__':
import sys
os.chdir('..')
+14
View File
@@ -1,3 +1,17 @@
## 2018/01/06 更新: <br />
以下功能为测试版:
0. 新增桌面歌词,目前不能取消。
1. 新增歌单内歌曲/搜索的歌曲下载。下载后在当前目录的downloads文件夹。
BUG修复:
0. 现在获取歌曲信息失败的本地音乐只显示文件名不显示歌手信息,播放方面不影响。
其他:
0. 新增异步方法的报错调试日志。
感谢小姐姐提供~。
桌面歌词感谢<a href="https://github.com/wn0112/">wn0112</a>.
## 2018/01/03 更新: <br />
0. 新增本地音乐歌词显示。
1. 修复一些原本有歌词的虾米音乐显示不了歌词的情况。