update gui

This commit is contained in:
Yaronzz
2022-01-18 11:59:37 +08:00
parent 133def9722
commit 69a7ff6813
10 changed files with 201 additions and 62 deletions

View File

@@ -12,7 +12,7 @@
import logging
import os
import time
from urllib import request
import requests
import aigpy
import lyricsgenius
@@ -318,7 +318,7 @@ def convert(srcPath, stream):
return srcPath
def downloadTrack(track: Track, album=None, playlist=None, userProgress=None):
def downloadTrack(track: Track, album=None, playlist=None, userProgress=None, partSize=1048576):
try:
msg, stream = API.getStreamUrl(track.id, CONF.audioQuality)
if not aigpy.string.isNull(msg) or stream is None:
@@ -326,6 +326,8 @@ def downloadTrack(track: Track, album=None, playlist=None, userProgress=None):
return False, msg
if CONF.showTrackInfo:
Printf.track(track, stream)
if userProgress is not None:
userProgress.updateStream(stream)
path = getTrackPath(CONF, track, stream, album, playlist)
# check exist
@@ -337,6 +339,7 @@ def downloadTrack(track: Track, album=None, playlist=None, userProgress=None):
logging.info("[DL Track] name=" + aigpy.path.getFileName(path) + "\nurl=" + stream.url)
tool = aigpy.download.DownloadTool(path + '.part', [stream.url])
tool.setUserProgress(userProgress)
tool.setPartSize(partSize)
check, err = tool.start(CONF.showProgress)
if not check:
Printf.err("Download failed! " + aigpy.path.getFileName(path) + ' (' + str(err) + ')')
@@ -377,7 +380,7 @@ def downloadVideo(video: Video, album=None, playlist=None):
path = getVideoPath(CONF, video, album, playlist)
logging.info("[DL Video] name=" + aigpy.path.getFileName(path) + "\nurl=" + stream.m3u8Url)
m3u8content = request.get(stream.m3u8Url).content
m3u8content = requests.get(stream.m3u8Url).content
if m3u8content is None:
Printf.err(video.title + ' get m3u8 content failed.')
return False, "Get m3u8 content failed"
@@ -488,7 +491,7 @@ def getBasePath(model):
if isinstance(model, tidal_dl.model.Playlist):
return getPlaylistPath(CONF, model)
if isinstance(model, tidal_dl.model.Track):
return getAlbumPath(CONF, model)
return getAlbumPath(CONF, model.album)
if isinstance(model, tidal_dl.model.Video):
filePath = getVideoPath(CONF, model, model.album, model.playlist)
return aigpy.pathHelper.getDirName(filePath)

View File

@@ -27,3 +27,6 @@ class ListWidget(QListWidget):
# item.setSizeHint(QSize(widget.width(), widget.height()))
self.addItem(item)
self.setItemWidget(item, widget)
def setAdjustMode(self):
self.setResizeMode(QListWidget.Adjust)

View File

@@ -8,14 +8,15 @@
@Contact : yaronhuang@foxmail.com
@Desc :
"""
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QWidget, QScrollArea, QVBoxLayout
from PyQt5.QtGui import QResizeEvent
class ScrollWidget(QScrollArea):
def __init__(self):
super(ScrollWidget, self).__init__()
self._numWidget = 0
self._layout = QVBoxLayout()
self._layout.addStretch(1)
@@ -26,4 +27,12 @@ class ScrollWidget(QScrollArea):
self.setWidgetResizable(True)
def addWidgetItem(self, widget: QWidget):
self._layout.insertWidget(0, widget)
self._layout.insertWidget(self._numWidget, widget)
self._numWidget += 1
def resizeEvent(self, e: QResizeEvent):
super().resizeEvent(e)
width = e.size().width()
if width > 0:
self._mainW.setMaximumWidth(width)

View File

@@ -82,6 +82,8 @@ QWidget#BaseWidget {
background: var(--Color_Default);
}
QWidget#TaskItemView {
background: var(--Color_Default);
border-style: solid;
@@ -543,6 +545,15 @@ QLabel#BoldLabel {
font-weight: bold;
}
QLabel#ItalicLabel {
font-style: italic;
}
QLabel#TagLabel {
background: var(--Color_DangerPressed);
}
/* QFrame */
QFrame#VLineQFrame
{
@@ -678,6 +689,20 @@ QListWidget#TaskContentListWidget::item:selected
background: var(--Color_Default);
}
QWidget#DownloadItemsWidget {
border-left: none;
border-right: none;
border-top: 1px solid var(--Color_Border);
border-bottom: none;
background: var(--Color_Default);
outline:none;
}
QWidget#DownloadItemView {
border-style: none;
margin-top: 2px;
background: var(--Color_Default);
}
QListWidget#DownloadItemsListWidget {

View File

@@ -50,6 +50,8 @@ class LabelStyle(Enum):
SearchErr = 5,
Icon = 6,
Bold = 7,
Italic = 9,
Tag = 10
class ThemeStyle(Enum):

View File

@@ -19,15 +19,21 @@ class DownloadItemView(QWidget):
def __init__(self):
super(DownloadItemView, self).__init__()
self.__initView__()
self.setObjectName('DownloadItemView')
self.setAttribute(Qt.WA_StyledBackground)
def __initView__(self):
self._indexLabel = Label('1')
self._codecLabel = Label('', LabelStyle.Tag)
self._titleLabel = Label('title', LabelStyle.Bold)
self._ownLabel = Label('own')
self._ownLabel = Label('own', LabelStyle.Italic)
self._ownLabel.setMaximumWidth(200)
self._actionLabel = Label('')
self._actionLabel = Label('', LabelStyle.Italic)
self._actionLabel.setFixedWidth(80)
self._errLabel = Label('')
self._errLabel.setVisible(False)
self._sizeLabel = Label('/')
self._speedLabel = Label('')
@@ -37,22 +43,28 @@ class DownloadItemView(QWidget):
self._progress.setFixedWidth(300)
self._progress.setRange(0, 100)
titleLayout = QHBoxLayout()
titleLayout.setSpacing(3)
titleLayout.setContentsMargins(0, 0, 0, 0)
titleLayout.addWidget(self._indexLabel, Qt.AlignLeft)
titleLayout.addWidget(self._titleLabel, Qt.AlignLeft)
titleLayout.addStretch(50)
titleLayout.addWidget(self._codecLabel, Qt.AlignRight)
titleLayout.addWidget(self._ownLabel, Qt.AlignRight)
speedLayout = QHBoxLayout()
speedLayout.setSpacing(30)
speedLayout.addWidget(self._sizeLabel)
speedLayout.addWidget(self._speedLabel)
grid = QGridLayout(self)
grid.addWidget(self._indexLabel, 0, 0, Qt.AlignLeft | Qt.AlignVCenter)
grid.addWidget(self._titleLabel, 0, 1, Qt.AlignLeft | Qt.AlignVCenter)
grid.addWidget(self._ownLabel, 0, 2, Qt.AlignRight | Qt.AlignVCenter)
grid.addWidget(self._progress, 0, 3, Qt.AlignRight | Qt.AlignVCenter)
grid.addWidget(self._actionLabel, 0, 4, Qt.AlignRight | Qt.AlignVCenter)
grid.addWidget(self._errLabel, 1, 1, Qt.AlignLeft | Qt.AlignVCenter)
grid.setColumnStretch(1, 1)
layout = QHBoxLayout()
layout.setSpacing(30)
layout.addWidget(self._sizeLabel)
layout.addWidget(self._speedLabel)
grid.addLayout(layout, 1, 3, Qt.AlignLeft | Qt.AlignVCenter)
grid.setContentsMargins(0,0,0,0)
grid.setSpacing(2)
grid.addLayout(titleLayout, 0, 0, Qt.AlignLeft | Qt.AlignVCenter)
grid.addWidget(self._progress, 0, 1, Qt.AlignRight | Qt.AlignVCenter)
grid.addWidget(self._actionLabel, 0, 2, Qt.AlignRight | Qt.AlignVCenter)
grid.addWidget(self._errLabel, 1, 0, Qt.AlignLeft | Qt.AlignVCenter)
grid.addLayout(speedLayout, 1, 1, Qt.AlignLeft | Qt.AlignVCenter)
def setLabel(self, index, title, own):
self._indexLabel.setText(str(index))
@@ -61,6 +73,7 @@ class DownloadItemView(QWidget):
def setErrmsg(self, msg):
self._errLabel.setText(msg)
self._errLabel.setVisible(len(msg) > 0)
def setAction(self, msg):
self._actionLabel.setText(msg)
@@ -70,7 +83,10 @@ class DownloadItemView(QWidget):
pass
def setSize(self, curSize: str, totalSize: str):
self._sizeLabel.setText(f'{curSize}/{totalSize}')
self._sizeLabel.setText(f'{curSize} / {totalSize}')
def setSpeed(self, speed: str):
self._speedLabel.setText(speed)
def setCodec(self, codec: str):
self._codecLabel.setText(codec)

View File

@@ -127,7 +127,7 @@ class SearchView(QWidget):
item.title,
item.artists[0].name,
str(item.releaseDate),
API.getDurationString(item.duration)]
getDurationString(item.duration)]
datas.append(rowData)
elif stype == Type.Track:

View File

@@ -29,7 +29,7 @@ class TaskItemView(QWidget):
def __initView__(self):
layout = QVBoxLayout()
layout.addLayout(self.__initHead__(), Qt.AlignTop)
layout.addWidget(self.__initList__(), Qt.AlignTop)
layout.addWidget(self.__initList__())
self.setLayout(layout)
@@ -40,8 +40,10 @@ class TaskItemView(QWidget):
self._btnOpen = PushButton('', ButtonStyle.TaskOpen)
self._btnExpand = PushButton('', ButtonStyle.TaskExpand)
self._btnExpand.clicked.connect(self.__expandClick__)
btnLayout = createHBoxLayout([self._btnRetry, self._btnCancel,
self._btnDelete, self._btnOpen,
btnLayout = createHBoxLayout([self._btnRetry,
self._btnCancel,
#self._btnDelete,
self._btnOpen,
self._btnExpand])
self._titleLabel = Label('', LabelStyle.PageTitle)
@@ -49,6 +51,8 @@ class TaskItemView(QWidget):
self._errLabel = Label()
self._errLabel.hide()
labelLayout = createVBoxLayout([self._titleLabel, self._descLabel, self._errLabel])
labelLayout.insertStretch(0, 1)
labelLayout.addStretch(1)
self._picLabel = Label('', LabelStyle.Icon)
self._picLabel.setMinimumHeight(64)
@@ -61,8 +65,10 @@ class TaskItemView(QWidget):
return headLayout
def __initList__(self):
self._list = ListWidget(ListWidgetStyle.DownloadItems)
self._list.setMinimumHeight(200)
self._list = QWidget()
self._list.setObjectName("DownloadItemsWidget")
self._listLayout = QVBoxLayout(self._list)
self._listLayout.setSpacing(0)
return self._list
def setLabel(self, title, desc):
@@ -78,7 +84,7 @@ class TaskItemView(QWidget):
self._picLabel.setPixmap(pic.scaled(64, 64))
def addListItem(self, view):
self._list.addWidgetItem(view)
self._listLayout.addWidget(view)
def __expandClick__(self):
if self._list.isHidden():

View File

@@ -10,6 +10,7 @@
"""
import os
import aigpy
from abc import ABC, ABCMeta
from enum import Enum
from pickle import FALSE
@@ -23,26 +24,39 @@ from tidal_gui.viewModel.viewModel import ViewModel
class DownloadStatus(Enum):
Wait = 0,
Running = 1,
Finish = 2,
Error = 3,
Cancel = 4,
WAIT = 0,
RUNNING = 1,
SUCCESS = 2,
ERROR = 3,
CANCEL = 4,
_endStatus_ = [DownloadStatus.Finish, DownloadStatus.Error, DownloadStatus.Cancel]
_endStatus_ = [DownloadStatus.SUCCESS, DownloadStatus.ERROR, DownloadStatus.CANCEL]
class Progress(UserProgress):
def __init__(self, model):
super().__init__()
self.model = model
self.curStr = ''
self.maxStr = ''
def __toMBStr__(self, num):
size = aigpy.memory.convert(num, aigpy.memory.Unit.BYTE, aigpy.memory.Unit.MB)
return str(round(size, 2)) + ' MB'
def updateCurNum(self):
self.model.update(self.curNum, self.maxNum)
per = self.curNum * 100 / self.maxNum
self.curStr = self.__toMBStr__(self.curNum)
self.model.SIGNAL_REFRESH_VIEW.emit('updateCurNum', {'per': per,
'curStr': self.curStr,
'maxStr': self.maxStr})
def updateMaxNum(self):
pass
self.maxStr = self.__toMBStr__(self.maxNum)
def updateStream(self, stream):
self.model.SIGNAL_REFRESH_VIEW.emit('updateStream', {'stream': stream})
class DownloadItemModel(ViewModel):
@@ -53,13 +67,27 @@ class DownloadItemModel(ViewModel):
self.basePath = basePath
self.isTrack = isinstance(data, Track)
self.progress = Progress(self)
self.__setStatus__(DownloadStatus.Wait)
self.__setStatus__(DownloadStatus.WAIT)
if self.isTrack:
self.__initTrack__(index)
else:
self.__initVideo__(index)
self.SIGNAL_REFRESH_VIEW.connect(self.__refresh__)
def __refresh__(self, stype: str, object):
if stype == "updateCurNum":
per = object['per']
curStr = object['curStr']
maxStr = object['maxStr']
self.view.setSize(curStr, maxStr)
self.view.setProgress(per)
elif stype == "updateStream":
codec = object['stream'].codec
self.view.setCodec(codec)
def __setStatus__(self, status: DownloadStatus, desc: str = ''):
self.status = status
if desc == '':
@@ -68,7 +96,7 @@ class DownloadItemModel(ViewModel):
self.view.setAction(status.name + '-' + desc)
def __setErrStatus__(self, errmsg: str):
self.status = DownloadStatus.Error
self.status = DownloadStatus.ERROR
self.view.setAction(self.status.name)
self.view.setErrmsg(errmsg)
@@ -82,33 +110,28 @@ class DownloadItemModel(ViewModel):
own = getArtistsNames(self.data.artists)
self.view.setLabel(index, title, own)
def update(self, curNum, maxNum):
per = curNum * 100 / maxNum
self.view.setProgress(per)
def isInWait(self):
return self.status == DownloadStatus.Wait
return self.status == DownloadStatus.WAIT
def stopDownload(self):
if self.status not in _endStatus_:
self.__setStatus__(DownloadStatus.Cancel)
self.__setStatus__(DownloadStatus.CANCEL)
def retry(self):
self.__setStatus__(DownloadStatus.Wait)
if self.status in [DownloadStatus.ERROR, DownloadStatus.CANCEL]:
self.__setStatus__(DownloadStatus.WAIT)
def download(self):
self.__setStatus__(DownloadStatus.Running)
self.__setStatus__(DownloadStatus.RUNNING)
if self.isTrack:
check, msg = downloadTrack(self.data, self.data.album, self.data.playlist, self.progress)
else:
check, msg = downloadVideo(self.data)
if check is False:
self.__setErrStatus__(msg)
else:
self.__setStatus__(DownloadStatus.Finish)
return
self.view.setProgress(100)
self.__setStatus__(DownloadStatus.Finish)
self.__setStatus__(DownloadStatus.SUCCESS)

View File

@@ -49,7 +49,7 @@ class TaskItemModel(ViewModel):
def __refresh__(self, stype: str, obj):
if stype == "setPic":
self.view.setPic(obj)
elif stype == "addListItem":
elif stype == "addListItems":
for index, item in enumerate(obj):
downItem = DownloadItemModel(index + 1, item, self.path)
self.view.addListItem(downItem.view)
@@ -84,7 +84,7 @@ class TaskItemModel(ViewModel):
self.view.setLabel(title, desc)
def __thread_func__(model: TaskItemModel, album: Album):
cover = API.getCoverData(album.cover, '1280', '1280')
cover = API.getCoverData(album.cover)
model.SIGNAL_REFRESH_VIEW.emit('setPic', cover)
msg, tracks, videos = API.getItems(album.id, Type.Album)
@@ -97,17 +97,69 @@ class TaskItemModel(ViewModel):
for item in videos:
item.album = album
model.SIGNAL_REFRESH_VIEW.emit('addListItem', tracks + videos)
print('__initAlbum__')
model.SIGNAL_REFRESH_VIEW.emit('addListItems', tracks + videos)
time.sleep(1)
_thread.start_new_thread(__thread_func__, (self, data))
def __initTrack__(self, data: Track):
pass
title = data.title
desc = f"by {getArtistsNames(data.artists)} " \
f"{getDurationString(data.duration)} "
self.view.setLabel(title, desc)
def __thread_func__(model: TaskItemModel, track: Track):
mag, track.album = API.getAlbum(track.album.id)
model.path = getBasePath(track)
cover = API.getCoverData(track.album.cover)
model.SIGNAL_REFRESH_VIEW.emit('setPic', cover)
model.SIGNAL_REFRESH_VIEW.emit('addListItems', [track])
time.sleep(1)
_thread.start_new_thread(__thread_func__, (self, data))
def __initVideo__(self, data: Video):
pass
self.path = getBasePath(data)
title = data.title
desc = f"by {getArtistsNames(data.artists)} " \
f"{getDurationString(data.duration)} "
self.view.setLabel(title, desc)
def __thread_func__(model: TaskItemModel, video: Video):
cover = API.getCoverData(video.imageID)
model.SIGNAL_REFRESH_VIEW.emit('setPic', cover)
model.SIGNAL_REFRESH_VIEW.emit('addListItems', [video])
time.sleep(1)
_thread.start_new_thread(__thread_func__, (self, data))
def __initPlaylist__(self, data: Playlist):
pass
self.path = getBasePath(data)
title = data.title
desc = f"{getDurationString(data.duration)} " \
f"Track-{data.numberOfTracks} " \
f"Video-{data.numberOfVideos}"
self.view.setLabel(title, desc)
def __thread_func__(model: TaskItemModel, playlist: Playlist):
cover = API.getCoverData(playlist.squareImage)
model.SIGNAL_REFRESH_VIEW.emit('setPic', cover)
msg, tracks, videos = API.getItems(playlist.uuid, Type.Playlist)
if not aigpy.stringHelper.isNull(msg):
model.view.setErrmsg(msg)
return
for item in tracks:
mag, album = API.getAlbum(item.album.id)
item.playlist = playlist
item.album = album
for item in videos:
item.playlist = playlist
model.SIGNAL_REFRESH_VIEW.emit('addListItems', tracks + videos)
time.sleep(1)
_thread.start_new_thread(__thread_func__, (self, data))