mirror of
https://github.com/yaronzz/Tidal-Media-Downloader.git
synced 2026-01-16 16:04:25 -05:00
upload new version
This commit is contained in:
Binary file not shown.
@@ -11,6 +11,6 @@ setup(
|
||||
packages=find_packages(exclude=['tidal_dl*']),
|
||||
include_package_data = True,
|
||||
platforms = "any",
|
||||
install_requires=["tidal-dl", "PyQt5"],
|
||||
install_requires=["tidal-dl"],
|
||||
entry_points={'console_scripts': [ 'tidal-gui = tidal_gui:main', ]}
|
||||
)
|
||||
|
||||
@@ -17,8 +17,6 @@ setup(
|
||||
"requests>=2.22.0",
|
||||
"pycryptodome",
|
||||
"pydub",
|
||||
"prettytable",
|
||||
"PyQt5",
|
||||
"qt-material"],
|
||||
"prettytable"],
|
||||
entry_points={'console_scripts': ['tidal-dl = tidal_dl:main', ]}
|
||||
)
|
||||
|
||||
@@ -13,7 +13,7 @@ import getopt
|
||||
|
||||
from tidal_dl.events import *
|
||||
from tidal_dl.settings import *
|
||||
from tidal_dl.gui import *
|
||||
from tidal_dl.gui import startGui
|
||||
|
||||
|
||||
def mainCommand():
|
||||
|
||||
@@ -120,12 +120,12 @@ def downloadVideo(video: Video, album: Album = None, playlist: Playlist = None):
|
||||
m3u8content = requests.get(stream.m3u8Url).content
|
||||
if m3u8content is None:
|
||||
Printf.err(f"DL Video[{video.title}] getM3u8 failed.{str(e)}")
|
||||
return False
|
||||
return False, f"GetM3u8 failed.{str(e)}"
|
||||
|
||||
urls = aigpy.m3u8.parseTsUrls(m3u8content)
|
||||
if len(urls) <= 0:
|
||||
Printf.err(f"DL Video[{video.title}] getTsUrls failed.{str(e)}")
|
||||
return False
|
||||
return False, "GetTsUrls failed.{str(e)}"
|
||||
|
||||
check, msg = aigpy.m3u8.downloadByTsUrls(urls, path)
|
||||
if check:
|
||||
@@ -133,10 +133,10 @@ def downloadVideo(video: Video, album: Album = None, playlist: Playlist = None):
|
||||
return True
|
||||
else:
|
||||
Printf.err(f"DL Video[{video.title}] failed.{msg}")
|
||||
return False
|
||||
return False, msg
|
||||
except Exception as e:
|
||||
Printf.err(f"DL Video[{video.title}] failed.{str(e)}")
|
||||
return False
|
||||
return False, str(e)
|
||||
|
||||
|
||||
def downloadTrack(track: Track, album=None, playlist=None, userProgress=None, partSize=1048576):
|
||||
@@ -153,7 +153,7 @@ def downloadTrack(track: Track, album=None, playlist=None, userProgress=None, pa
|
||||
# check exist
|
||||
if __isSkip__(path, stream.url):
|
||||
Printf.success(aigpy.path.getFileName(path) + " (skip:already exists!)")
|
||||
return True
|
||||
return True, ''
|
||||
|
||||
# download
|
||||
logging.info("[DL Track] name=" + aigpy.path.getFileName(path) + "\nurl=" + stream.url)
|
||||
@@ -164,7 +164,7 @@ def downloadTrack(track: Track, album=None, playlist=None, userProgress=None, pa
|
||||
check, err = tool.start(SETTINGS.showProgress)
|
||||
if not check:
|
||||
Printf.err(f"DL Track[{track.title}] failed.{str(err)}")
|
||||
return False
|
||||
return False, str(err)
|
||||
|
||||
# encrypted -> decrypt and remove encrypted file
|
||||
__encrypted__(stream, path + '.part', path)
|
||||
@@ -186,7 +186,7 @@ def downloadTrack(track: Track, album=None, playlist=None, userProgress=None, pa
|
||||
|
||||
__setMetaData__(track, album, path, contributors, lyrics)
|
||||
Printf.success(track.title)
|
||||
return True
|
||||
return True, ''
|
||||
except Exception as e:
|
||||
Printf.err(f"DL Track[{track.title}] failed.{str(e)}")
|
||||
return False
|
||||
return False, str(e)
|
||||
|
||||
@@ -8,169 +8,179 @@
|
||||
@Contact : yaronhuang@foxmail.com
|
||||
@Desc :
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import _thread
|
||||
import importlib
|
||||
|
||||
from tidal_dl.events import *
|
||||
from tidal_dl.settings import *
|
||||
from tidal_dl.printf import *
|
||||
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtCore import pyqtSignal
|
||||
from PyQt5 import QtWidgets
|
||||
from qt_material import apply_stylesheet
|
||||
enableGui = False
|
||||
try:
|
||||
params = importlib.import_module('PyQt5')
|
||||
enableGui = True
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
if enableGui:
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtCore import pyqtSignal
|
||||
from PyQt5 import QtWidgets
|
||||
from qt_material import apply_stylesheet
|
||||
|
||||
class MainView(QtWidgets.QWidget):
|
||||
s_downloadEnd = pyqtSignal(str, bool, str)
|
||||
class MainView(QtWidgets.QWidget):
|
||||
s_downloadEnd = pyqtSignal(str, bool, str)
|
||||
|
||||
def __init__(self, ) -> None:
|
||||
super().__init__()
|
||||
self.initView()
|
||||
self.setMinimumSize(600, 500)
|
||||
self.setWindowTitle("Tidal-dl")
|
||||
|
||||
def __info__(self, msg):
|
||||
QtWidgets.QMessageBox.information(self,
|
||||
'Info',
|
||||
msg,
|
||||
QtWidgets.QMessageBox.Yes)
|
||||
|
||||
def initView(self):
|
||||
self.c_lineSearch = QtWidgets.QLineEdit()
|
||||
self.c_btnSearch = QtWidgets.QPushButton("Search")
|
||||
self.c_btnDownload = QtWidgets.QPushButton("Download")
|
||||
|
||||
self.m_supportType = [Type.Album, Type.Playlist, Type.Track, Type.Video]
|
||||
self.c_combType = QtWidgets.QComboBox()
|
||||
for item in self.m_supportType:
|
||||
self.c_combType.addItem(item.name, item)
|
||||
|
||||
columnNames = ['#', 'Title', 'Artists', 'Quality']
|
||||
self.c_tableInfo = QtWidgets.QTableWidget()
|
||||
self.c_tableInfo.setColumnCount(len(columnNames))
|
||||
self.c_tableInfo.setRowCount(0)
|
||||
self.c_tableInfo.setShowGrid(False)
|
||||
self.c_tableInfo.verticalHeader().setVisible(False)
|
||||
self.c_tableInfo.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
|
||||
self.c_tableInfo.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
|
||||
self.c_tableInfo.horizontalHeader().setStretchLastSection(True)
|
||||
self.c_tableInfo.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.ResizeMode.ResizeToContents)
|
||||
self.c_tableInfo.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
|
||||
self.c_tableInfo.setFocusPolicy(Qt.NoFocus)
|
||||
for index, name in enumerate(columnNames):
|
||||
item = QtWidgets.QTableWidgetItem(name)
|
||||
self.c_tableInfo.setHorizontalHeaderItem(index, item)
|
||||
|
||||
self.lineGrid = QtWidgets.QHBoxLayout()
|
||||
self.lineGrid.addWidget(self.c_combType)
|
||||
self.lineGrid.addWidget(self.c_lineSearch)
|
||||
self.lineGrid.addWidget(self.c_btnSearch)
|
||||
|
||||
self.mainGrid = QtWidgets.QVBoxLayout(self)
|
||||
self.mainGrid.addLayout(self.lineGrid)
|
||||
self.mainGrid.addWidget(self.c_tableInfo)
|
||||
self.mainGrid.addWidget(self.c_btnDownload)
|
||||
|
||||
self.c_btnSearch.clicked.connect(self.search)
|
||||
self.c_btnDownload.clicked.connect(self.download)
|
||||
self.s_downloadEnd.connect(self.downloadEnd)
|
||||
|
||||
def addItem(self, rowIdx: int, colIdx: int, text):
|
||||
if isinstance(text, str):
|
||||
item = QtWidgets.QTableWidgetItem(text)
|
||||
self.c_tableInfo.setItem(rowIdx, colIdx, item)
|
||||
|
||||
def search(self):
|
||||
self.c_tableInfo.setRowCount(0)
|
||||
def __init__(self, ) -> None:
|
||||
super().__init__()
|
||||
self.initView()
|
||||
self.setMinimumSize(600, 500)
|
||||
self.setWindowTitle("Tidal-dl")
|
||||
|
||||
self.s_type = self.c_combType.currentData()
|
||||
self.s_text = self.c_lineSearch.text()
|
||||
if self.s_text.startswith('http'):
|
||||
tmpType, tmpId = TIDAL_API.parseUrl(self.s_text)
|
||||
if tmpType == Type.Null:
|
||||
self.__info__('Url not support!')
|
||||
return
|
||||
elif tmpType not in self.m_supportType:
|
||||
self.__info__(f'Type[{tmpType.name}] not support!')
|
||||
return
|
||||
def __info__(self, msg):
|
||||
QtWidgets.QMessageBox.information(self,
|
||||
'Info',
|
||||
msg,
|
||||
QtWidgets.QMessageBox.Yes)
|
||||
|
||||
def initView(self):
|
||||
self.c_lineSearch = QtWidgets.QLineEdit()
|
||||
self.c_btnSearch = QtWidgets.QPushButton("Search")
|
||||
self.c_btnDownload = QtWidgets.QPushButton("Download")
|
||||
|
||||
self.m_supportType = [Type.Album, Type.Playlist, Type.Track, Type.Video]
|
||||
self.c_combType = QtWidgets.QComboBox()
|
||||
for item in self.m_supportType:
|
||||
self.c_combType.addItem(item.name, item)
|
||||
|
||||
columnNames = ['#', 'Title', 'Artists', 'Quality']
|
||||
self.c_tableInfo = QtWidgets.QTableWidget()
|
||||
self.c_tableInfo.setColumnCount(len(columnNames))
|
||||
self.c_tableInfo.setRowCount(0)
|
||||
self.c_tableInfo.setShowGrid(False)
|
||||
self.c_tableInfo.verticalHeader().setVisible(False)
|
||||
self.c_tableInfo.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
|
||||
self.c_tableInfo.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
|
||||
self.c_tableInfo.horizontalHeader().setStretchLastSection(True)
|
||||
self.c_tableInfo.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.ResizeMode.ResizeToContents)
|
||||
self.c_tableInfo.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
|
||||
self.c_tableInfo.setFocusPolicy(Qt.NoFocus)
|
||||
for index, name in enumerate(columnNames):
|
||||
item = QtWidgets.QTableWidgetItem(name)
|
||||
self.c_tableInfo.setHorizontalHeaderItem(index, item)
|
||||
|
||||
self.lineGrid = QtWidgets.QHBoxLayout()
|
||||
self.lineGrid.addWidget(self.c_combType)
|
||||
self.lineGrid.addWidget(self.c_lineSearch)
|
||||
self.lineGrid.addWidget(self.c_btnSearch)
|
||||
|
||||
self.mainGrid = QtWidgets.QVBoxLayout(self)
|
||||
self.mainGrid.addLayout(self.lineGrid)
|
||||
self.mainGrid.addWidget(self.c_tableInfo)
|
||||
self.mainGrid.addWidget(self.c_btnDownload)
|
||||
|
||||
self.c_btnSearch.clicked.connect(self.search)
|
||||
self.c_btnDownload.clicked.connect(self.download)
|
||||
self.s_downloadEnd.connect(self.downloadEnd)
|
||||
|
||||
def addItem(self, rowIdx: int, colIdx: int, text):
|
||||
if isinstance(text, str):
|
||||
item = QtWidgets.QTableWidgetItem(text)
|
||||
self.c_tableInfo.setItem(rowIdx, colIdx, item)
|
||||
|
||||
def search(self):
|
||||
self.c_tableInfo.setRowCount(0)
|
||||
|
||||
tmpData = TIDAL_API.getTypeData(tmpId, tmpType)
|
||||
if tmpData is None:
|
||||
self.__info__('Url is wrong!')
|
||||
self.s_type = self.c_combType.currentData()
|
||||
self.s_text = self.c_lineSearch.text()
|
||||
if self.s_text.startswith('http'):
|
||||
tmpType, tmpId = TIDAL_API.parseUrl(self.s_text)
|
||||
if tmpType == Type.Null:
|
||||
self.__info__('Url not support!')
|
||||
return
|
||||
elif tmpType not in self.m_supportType:
|
||||
self.__info__(f'Type[{tmpType.name}] not support!')
|
||||
return
|
||||
|
||||
tmpData = TIDAL_API.getTypeData(tmpId, tmpType)
|
||||
if tmpData is None:
|
||||
self.__info__('Url is wrong!')
|
||||
return
|
||||
self.s_type = tmpType
|
||||
self.s_array = [tmpData]
|
||||
self.s_result = None
|
||||
self.c_combType.setCurrentText(tmpType.name)
|
||||
else:
|
||||
self.s_result = TIDAL_API.search(self.s_text, self.s_type)
|
||||
self.s_array = TIDAL_API.getSearchResultItems(self.s_result, self.s_type)
|
||||
|
||||
if len(self.s_array) <= 0:
|
||||
self.__info__('No result!')
|
||||
return
|
||||
self.s_type = tmpType
|
||||
self.s_array = [tmpData]
|
||||
self.s_result = None
|
||||
self.c_combType.setCurrentText(tmpType.name)
|
||||
else:
|
||||
self.s_result = TIDAL_API.search(self.s_text, self.s_type)
|
||||
self.s_array = TIDAL_API.getSearchResultItems(self.s_result, self.s_type)
|
||||
|
||||
if len(self.s_array) <= 0:
|
||||
self.__info__('No result!')
|
||||
return
|
||||
|
||||
self.c_tableInfo.setRowCount(len(self.s_array))
|
||||
for index, item in enumerate(self.s_array):
|
||||
self.addItem(index, 0, str(index + 1))
|
||||
if self.s_type in [Type.Album, Type.Track]:
|
||||
self.addItem(index, 1, item.title)
|
||||
self.addItem(index, 2, TIDAL_API.getArtistsName(item.artists))
|
||||
self.addItem(index, 3, item.audioQuality)
|
||||
elif self.s_type in [Type.Video]:
|
||||
self.addItem(index, 1, item.title)
|
||||
self.addItem(index, 2, TIDAL_API.getArtistsName(item.artists))
|
||||
self.addItem(index, 3, item.quality)
|
||||
elif self.s_type in [Type.Playlist]:
|
||||
self.addItem(index, 1, item.title)
|
||||
self.addItem(index, 2, '')
|
||||
self.addItem(index, 3, '')
|
||||
self.c_tableInfo.setRowCount(len(self.s_array))
|
||||
for index, item in enumerate(self.s_array):
|
||||
self.addItem(index, 0, str(index + 1))
|
||||
if self.s_type in [Type.Album, Type.Track]:
|
||||
self.addItem(index, 1, item.title)
|
||||
self.addItem(index, 2, TIDAL_API.getArtistsName(item.artists))
|
||||
self.addItem(index, 3, item.audioQuality)
|
||||
elif self.s_type in [Type.Video]:
|
||||
self.addItem(index, 1, item.title)
|
||||
self.addItem(index, 2, TIDAL_API.getArtistsName(item.artists))
|
||||
self.addItem(index, 3, item.quality)
|
||||
elif self.s_type in [Type.Playlist]:
|
||||
self.addItem(index, 1, item.title)
|
||||
self.addItem(index, 2, '')
|
||||
self.addItem(index, 3, '')
|
||||
|
||||
def download(self):
|
||||
index = self.c_tableInfo.currentIndex().row()
|
||||
if index < 0:
|
||||
self.__info__('Please select a row first.')
|
||||
return
|
||||
def download(self):
|
||||
index = self.c_tableInfo.currentIndex().row()
|
||||
if index < 0:
|
||||
self.__info__('Please select a row first.')
|
||||
return
|
||||
|
||||
self.c_btnDownload.setEnabled(False)
|
||||
self.c_btnDownload.setText(f"Downloading [{self.s_array[index].title}]...")
|
||||
self.c_btnDownload.setEnabled(False)
|
||||
self.c_btnDownload.setText(f"Downloading [{self.s_array[index].title}]...")
|
||||
|
||||
def __thread_download__(model: MainView):
|
||||
try:
|
||||
type = model.s_type
|
||||
item = model.s_array[index]
|
||||
start_type(type, item)
|
||||
model.s_downloadEnd.emit(item.title, True, '')
|
||||
except Exception as e:
|
||||
model.s_downloadEnd.emit(item.title, False, str(e))
|
||||
def __thread_download__(model: MainView):
|
||||
try:
|
||||
type = model.s_type
|
||||
item = model.s_array[index]
|
||||
start_type(type, item)
|
||||
model.s_downloadEnd.emit(item.title, True, '')
|
||||
except Exception as e:
|
||||
model.s_downloadEnd.emit(item.title, False, str(e))
|
||||
|
||||
_thread.start_new_thread(__thread_download__, (self, ))
|
||||
_thread.start_new_thread(__thread_download__, (self, ))
|
||||
|
||||
def downloadEnd(self, title, result, msg):
|
||||
self.c_btnDownload.setEnabled(True)
|
||||
self.c_btnDownload.setText(f"Download")
|
||||
def downloadEnd(self, title, result, msg):
|
||||
self.c_btnDownload.setEnabled(True)
|
||||
self.c_btnDownload.setText(f"Download")
|
||||
|
||||
if result:
|
||||
self.__info__(f'Download [{title}] finish')
|
||||
else:
|
||||
self.__info__(f'Download [{title}] failed:{msg}')
|
||||
if result:
|
||||
self.__info__(f'Download [{title}] finish')
|
||||
else:
|
||||
self.__info__(f'Download [{title}] failed:{msg}')
|
||||
|
||||
def checkLogin(self):
|
||||
if not loginByConfig():
|
||||
self.__info__('Login failed. Please log in using the command line first.')
|
||||
def checkLogin(self):
|
||||
if not loginByConfig():
|
||||
self.__info__('Login failed. Please log in using the command line first.')
|
||||
|
||||
|
||||
def startGui():
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
apply_stylesheet(app, theme='dark_blue.xml')
|
||||
def startGui():
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
apply_stylesheet(app, theme='dark_blue.xml')
|
||||
|
||||
window = MainView()
|
||||
window.show()
|
||||
window.checkLogin()
|
||||
|
||||
app.exec_()
|
||||
window = MainView()
|
||||
window.show()
|
||||
window.checkLogin()
|
||||
|
||||
app.exec_()
|
||||
else:
|
||||
def startGui():
|
||||
Printf.err("Not support gui. Please type: `pip3 install PyQt5 qt_material`")
|
||||
|
||||
if __name__ == '__main__':
|
||||
SETTINGS.read(getProfilePath())
|
||||
|
||||
@@ -20,7 +20,7 @@ from tidal_dl.settings import *
|
||||
from tidal_dl.lang.language import *
|
||||
|
||||
|
||||
VERSION = '2022.06.23.3'
|
||||
VERSION = '2022.06.24.1'
|
||||
__LOGO__ = f'''
|
||||
/$$$$$$$$ /$$ /$$ /$$ /$$ /$$
|
||||
|__ $$__/|__/ | $$ | $$ | $$| $$
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
cd TIDALDL-PY
|
||||
rm -rf dist
|
||||
rm -rf build
|
||||
rm -rf exe/tidal-dl.exe
|
||||
rm MANIFEST.in
|
||||
rm -rf tidal_dl.egg-info
|
||||
rm -rf tidal_gui.egg-info
|
||||
rm -rf tidal_dl_test.egg-info
|
||||
mkdir exe
|
||||
|
||||
# pack
|
||||
python setup.py sdist bdist_wheel
|
||||
# creat exe file
|
||||
pyinstaller -F tidal_dl/__init__.py
|
||||
# rename exe name
|
||||
mv dist/__init__.exe exe/tidal-dl.exe
|
||||
|
||||
pip uninstall -y tidal-dl
|
||||
|
||||
# creat requirements.txt
|
||||
# pipreqs ./ --force --encoding=utf8
|
||||
|
||||
# python setup.py install
|
||||
|
||||
# upload
|
||||
twine upload dist/*
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cd TIDALDL-PY
|
||||
rm -rf dist
|
||||
rm -rf build
|
||||
rm -rf exe/tidal-gui.exe
|
||||
cp -rf guiStatic.in MANIFEST.in
|
||||
rm -rf tidal_dl.egg-info
|
||||
rm -rf tidal_gui.egg-info
|
||||
rm -rf tidal_dl_test.egg-info
|
||||
|
||||
# pack
|
||||
python setup-gui.py sdist bdist_wheel
|
||||
# creat exe file
|
||||
pyinstaller -F tidal_gui/__init__.py -w
|
||||
pyinstaller -F -w -p C:/Windows/System32/downlevel tidal_gui/__init__.py
|
||||
|
||||
|
||||
# rename exe name
|
||||
mv dist/__init__.exe exe/tidal-gui.exe
|
||||
|
||||
pip uninstall -y tidal-gui
|
||||
|
||||
# upload
|
||||
twine upload dist/*
|
||||
20
build.sh
Normal file
20
build.sh
Normal file
@@ -0,0 +1,20 @@
|
||||
rm -rf dist
|
||||
rm -rf build
|
||||
rm -rf __init__.spec
|
||||
|
||||
cd TIDALDL-PY
|
||||
rm -rf __init__.spec
|
||||
rm -rf dist
|
||||
rm -rf build
|
||||
rm -rf exe
|
||||
rm -rf MANIFEST.in
|
||||
rm -rf *.egg-info
|
||||
|
||||
python setup.py sdist bdist_wheel
|
||||
pyinstaller -F tidal_dl/__init__.py
|
||||
mkdir exe
|
||||
mv dist/__init__.exe exe/tidal-dl.exe
|
||||
|
||||
pip uninstall -y tidal-dl
|
||||
|
||||
cd ..
|
||||
BIN
tidallog.png
BIN
tidallog.png
Binary file not shown.
|
Before Width: | Height: | Size: 4.9 KiB |
Reference in New Issue
Block a user