Skip to content

Commit

Permalink
3.2.0 Update
Browse files Browse the repository at this point in the history
  • Loading branch information
devhotteok committed Jun 28, 2024
1 parent f81756b commit 7b4ad59
Show file tree
Hide file tree
Showing 187 changed files with 1,076 additions and 283 deletions.
6 changes: 3 additions & 3 deletions AppData/EncoderDecoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,13 @@ def encode(cls, obj: typing.Any) -> typing.Any:
elif isinstance(obj, QtCore.QDateTime):
return f"datetime:{obj.toString(QtCore.Qt.DateFormat.ISODateWithMs)}"
elif isinstance(obj, QtCore.QTimeZone):
return f"timezone:{obj.id().data().decode()}"
return f"timezone:{obj.id().data().decode(errors='ignore')}"
elif isinstance(obj, QtCore.QUrl):
return f"url:{obj.toString()}"
elif isinstance(obj, bytes):
return f"bytes:{obj.decode()}"
return f"bytes:{obj.decode(errors='ignore')}"
elif isinstance(obj, bytearray):
return f"bytearray:{obj.decode()}"
return f"bytearray:{obj.decode(errors='ignore')}"
elif isinstance(obj, tuple):
return cls._encodeTuple(obj)
elif isinstance(obj, list):
Expand Down
11 changes: 10 additions & 1 deletion AppData/Preferences.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,17 @@ def getClipFilename(self) -> str:

class Advanced(Serializable):
def __init__(self):
self._themeMode = App.ThemeManager.getThemeMode().value
self._searchExternalContent = True

def __setup__(self):
App.ThemeManager.setThemeMode(App.ThemeManager.Modes.fromString(self._themeMode))
del self._themeMode

def __save__(self):
self._themeMode = App.ThemeManager.getThemeMode().value
return super().__save__()

def setSearchExternalContentEnabled(self, enabled: bool) -> None:
self._searchExternalContent = enabled

Expand Down Expand Up @@ -162,7 +171,7 @@ def __save__(self):
self._downloadHistory = App.DownloadHistory.getHistoryList()
return super().__save__()

def getDownloadOptionHistory(self, historyType: DownloadOptionHistory.BaseOptionHistory) -> None:
def getDownloadOptionHistory(self, historyType: DownloadOptionHistory.BaseOptionHistory) -> DownloadOptionHistory.BaseOptionHistory:
return self._downloadOptionHistory[historyType.getId()]

def updateDownloadStats(self, fileSize: int) -> None:
Expand Down
8 changes: 7 additions & 1 deletion AppData/Updater.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,11 @@ def Update_3_1_0(data: dict) -> dict:
}
return data

@staticmethod
def Update_3_2_0(data: dict) -> dict:
data["advanced"]["_themeMode"] = "str:"
return data

@classmethod
def getUpdaters(cls, versionFrom: str) -> list[typing.Callable[[dict], dict]] | None:
VERSIONS = {
Expand All @@ -151,7 +156,8 @@ def getUpdaters(cls, versionFrom: str) -> list[typing.Callable[[dict], dict]] |
"3.1.0": cls.Update_3_1_0,
"3.1.1": None,
"3.1.2": None,
"3.1.3": None
"3.1.3": None,
"3.2.0": cls.Update_3_2_0
}
updaters = []
versionFound = False
Expand Down
3 changes: 3 additions & 0 deletions Core/App.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ def restart(self) -> None:
from Services.Account.TwitchAccount import TwitchAccount as _TwitchAccount
Account = _TwitchAccount(parent=Instance)

from Services.Theme.ThemeManager import ThemeManager as _ThemeManager
ThemeManager = _ThemeManager(parent=Instance)

from Download.Downloader.Core.Engine.File.FileDownloadManager import FileDownloadManager as _FileDownloadManager
FileDownloadManager = _FileDownloadManager(parent=Instance)

Expand Down
2 changes: 1 addition & 1 deletion Core/GlobalExceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class NetworkError(Exception):
def __init__(self, reply: QtNetwork.QNetworkReply):
self.reasonCode = reply.error()
self.reasonText = reply.errorString()
self.responseText = "" if self.reasonCode == QtNetwork.QNetworkReply.NetworkError.OperationCanceledError else reply.readAll().data().decode()
self.responseText = "" if self.reasonCode == QtNetwork.QNetworkReply.NetworkError.OperationCanceledError else reply.readAll().data().decode(errors="ignore")

def __str__(self):
if self.responseText == "":
Expand Down
2 changes: 1 addition & 1 deletion Core/Meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
class Meta:
APP_NAME = "TwitchLink"

APP_VERSION = "3.1.3"
APP_VERSION = "3.2.0"

AUTHOR = "DevHotteok"

Expand Down
2 changes: 1 addition & 1 deletion Core/Notification.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ def __init__(self, systemTrayIcon: QtWidgets.QSystemTrayIcon, parent: QtCore.QOb
self.systemTrayIcon = systemTrayIcon

def toastMessage(self, title: str, message: str, icon: QtWidgets.QSystemTrayIcon.MessageIcon | QtGui.QIcon | None = None) -> None:
self.systemTrayIcon.showMessage(title, message, icon or QtGui.QIcon(Icons.APP_LOGO_ICON))
self.systemTrayIcon.showMessage(title, message, icon or Icons.APP_LOGO.icon)
2 changes: 1 addition & 1 deletion Core/Qt/QtCore/QTimeZone.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@

class _QTimeZone_Patcher(QtCore.QTimeZone):
def name(self) -> str:
return self.id().data().decode()
return self.id().data().decode(errors="ignore")
QtCore.QTimeZone.name = _QTimeZone_Patcher.name #Direct Attribute Patch - [Info] Affects all embedded objects
2 changes: 1 addition & 1 deletion Core/Qt/QtWidgets/QMessageBox.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
class _QMessageBox(QtWidgets.QMessageBox):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setWindowIcon(QtGui.QIcon(Icons.APP_LOGO_ICON))
self.setWindowIcon(Icons.APP_LOGO.icon)
self.setIcon(QtWidgets.QMessageBox.Icon.Information)
QtWidgets.QMessageBox = _QMessageBox #Direct Class Patch - [Warning] Does not affect embedded objects (Use with caution)
4 changes: 2 additions & 2 deletions Core/Qt/QtWidgets/QProgressDialog.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
from Services.Image.Presets import Icons

from PyQt6 import QtCore, QtGui, QtWidgets
from PyQt6 import QtCore, QtWidgets


class _QProgressDialog(QtWidgets.QProgressDialog):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setWindowFlag(QtCore.Qt.WindowType.WindowContextHelpButtonHint, False)
self.setWindowIcon(QtGui.QIcon(Icons.APP_LOGO_ICON))
self.setWindowIcon(Icons.APP_LOGO.icon)
self.progressBar = QtWidgets.QProgressBar(parent=self)
self.setMaximum = self.progressBar.setMaximum
self.setMinimum = self.progressBar.setMinimum
Expand Down
4 changes: 2 additions & 2 deletions Core/SystemTrayIcon.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
from Core.Config import Config
from Services.Image.Presets import Icons

from PyQt6 import QtCore, QtGui, QtWidgets
from PyQt6 import QtCore, QtWidgets


class SystemTrayIcon(QtWidgets.QSystemTrayIcon):
clicked = QtCore.pyqtSignal()

def __init__(self, parent: QtCore.QObject | None = None):
super().__init__(parent=parent)
self.setIcon(QtGui.QIcon(Icons.APP_LOGO_ICON))
self.setIcon(Icons.APP_LOGO.icon)
self.setContextMenu(QtWidgets.QMenu())
self.activated.connect(self._activatedHandler)
self.messageClicked.connect(self._messageClickedHandler)
Expand Down
2 changes: 1 addition & 1 deletion Core/Ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def setupInstance(cls, instance: QtWidgets.QWidget) -> None:
instance.setAttribute(QtCore.Qt.WidgetAttribute.WA_DeleteOnClose)
if isinstance(instance, QtWidgets.QMainWindow) or isinstance(instance, QtWidgets.QDialog):
instance.setWindowFlag(QtCore.Qt.WindowType.WindowContextHelpButtonHint, False)
instance.setWindowIcon(QtGui.QIcon(Icons.APP_LOGO_ICON))
instance.setWindowIcon(Icons.APP_LOGO.icon)
instance.setWindowTitle(instance.windowTitle() or Config.APP_NAME)
cls.setPartnerContent(instance)

Expand Down
2 changes: 1 addition & 1 deletion Core/Updater.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ def _sendRequest(self, url: str) -> None:
def _finished(self) -> None:
if self._networkReply.error() == QtNetwork.QNetworkReply.NetworkError.NoError:
try:
text = self._networkReply.readAll().data().decode()
text = self._networkReply.readAll().data().decode(errors="ignore")
if text.startswith("redirect:"):
if self._redirectCount < Config.STATUS_UPDATE_MAX_REDIRECT_COUNT:
self._redirectCount += 1
Expand Down
2 changes: 1 addition & 1 deletion Download/DownloadInfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import os


class DownloadInfoType(Serializable):
class DownloadInfoType:
class Types(enum.Enum):
STREAM = "stream"
VIDEO = "video"
Expand Down
2 changes: 1 addition & 1 deletion Download/DownloadManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def onFinish(self, downloader: StreamDownloader | VideoDownloader | ClipDownload
self.runningCountChangedSignal.emit(len(self.runningDownloaders))
self.completedSignal.emit(downloader.getId())

def create(self, downloadInfo: DownloadInfo) -> None:
def create(self, downloadInfo: DownloadInfo) -> uuid.UUID:
downloader = TwitchDownloader.create(downloadInfo, parent=self)
downloader.started.connect(self.onStart)
downloader.finished.connect(self.onFinish)
Expand Down
4 changes: 2 additions & 2 deletions Download/Downloader/Core/Engine/FFmpeg/FFmpeg.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,11 @@ def _onProcessFinish(self, exitCode: int, exitStatus: QtCore.QProcess.ExitStatus
self.finished.emit()

def _readStandardOutput(self) -> None:
for line in self._process.readAllStandardOutput().data().decode().splitlines():
for line in self._process.readAllStandardOutput().data().decode(errors="ignore").splitlines():
self.logger.debug(line)

def _readStandardError(self) -> None:
for line in self._process.readAllStandardError().data().decode().splitlines():
for line in self._process.readAllStandardError().data().decode(errors="ignore").splitlines():
self.logger.debug(line)

def _getCodecParams(self, fileName: str, transcode: bool = False) -> tuple[str, ...]:
Expand Down
1 change: 0 additions & 1 deletion Download/GlobalDownloadManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
from Core.App import T
from Core.Config import Config
from Core.GlobalExceptions import Exceptions
from Services.Script import Script
from Download.Downloader.TwitchDownloader import TwitchDownloader
from Download.Downloader.Core.StreamDownloader import StreamDownloader
from Download.Downloader.Core.VideoDownloader import VideoDownloader
Expand Down
2 changes: 1 addition & 1 deletion Download/ScheduledDownloadManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def isError(self) -> bool:
def isDownloaderError(self) -> bool:
return self._status == self.DOWNLOADER_ERROR

def getError(self) -> Exception:
def getError(self) -> Exception | None:
return self._error

def cleanup(self) -> None:
Expand Down
2 changes: 1 addition & 1 deletion Search/Engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ def _raiseException(self, exception: Exception) -> None:
self._error = exception
self._setFinished()

def getError(self) -> Exception:
def getError(self) -> Exception | None:
return self._error

def getData(self) -> TwitchGQLModels.Channel | TwitchGQLModels.Video | TwitchGQLModels.Clip | ExternalPlaybackGenerator.ExternalPlayback:
Expand Down
6 changes: 3 additions & 3 deletions Search/ExternalPlaybackGenerator.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def _checkUrl(self) -> None:

def _replyFinished(self) -> None:
if self._reply.error() == QtNetwork.QNetworkReply.NetworkError.NoError:
text = self._reply.readAll().data().decode()
text = self._reply.readAll().data().decode(errors="ignore")
self._resolutions = VariantPlaylistReader.loads(text, baseUrl=self._reply.url())
if len(self._resolutions) == 0:
try:
Expand All @@ -69,7 +69,7 @@ def _playlistCheckFinished(self) -> None:
if self._playlistCheckReply.error() == QtNetwork.QNetworkReply.NetworkError.NoError:
try:
playlist = Playlist()
playlist.loads(self._playlistCheckReply.readAll().data().decode(), baseUrl=self._playlistCheckReply.url())
playlist.loads(self._playlistCheckReply.readAll().data().decode(errors="ignore"), baseUrl=self._playlistCheckReply.url())
except Exception as e:
self._raiseException(e)
else:
Expand All @@ -89,7 +89,7 @@ def _raiseException(self, exception: Exception) -> None:
self._error = exception
self._setFinished()

def getError(self) -> Exception:
def getError(self) -> Exception | None:
return self._error

def getData(self) -> ExternalPlayback:
Expand Down
100 changes: 65 additions & 35 deletions Services/Image/Presets.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from Core.Config import Config as CoreConfig, _P
from Services.Theme.ThemedIconManager import ThemedIconManager
from Services.Theme.ThemedIcon import ThemedIcon


class Images:
Expand All @@ -20,39 +22,67 @@ class ImageSize:
CATEGORY = (90, 120)


class IconPath:
ROOT = _P(CoreConfig.RESOURCE_ROOT, "icons")
LIGHT = _P(ROOT, "light")
DARK = _P(ROOT, "dark")


class Icons:
ICON_ROOT = _P(CoreConfig.RESOURCE_ROOT, "icons")

APP_LOGO_ICON = _P(ICON_ROOT, "icon.ico")

SEARCH_ICON = _P(ICON_ROOT, "search.svg")
DOWNLOAD_ICON = _P(ICON_ROOT, "download.svg")
SCHEDULED_ICON = _P(ICON_ROOT, "scheduled.svg")
ACCOUNT_ICON = _P(ICON_ROOT, "account.svg")
SETTINGS_ICON = _P(ICON_ROOT, "settings.svg")
INFO_ICON = _P(ICON_ROOT, "info.svg")
HOME_ICON = _P(ICON_ROOT, "home.svg")
FOLDER_ICON = _P(ICON_ROOT, "folder.svg")
FILE_ICON = _P(ICON_ROOT, "file.svg")
FILE_NOT_FOUND_ICON = _P(ICON_ROOT, "file_not_found.svg")
UPDATE_FOUND_ICON = _P(ICON_ROOT, "update_found.svg")
LOADING_ICON = _P(ICON_ROOT, "loading.svg")
DOWNLOADING_FILE_ICON = _P(ICON_ROOT, "downloading_file.svg")
CREATING_FILE_ICON = _P(ICON_ROOT, "creating_file.svg")
CLOSE_ICON = _P(ICON_ROOT, "close.svg")
SAVE_ICON = _P(ICON_ROOT, "save.svg")
MOVE_ICON = _P(ICON_ROOT, "move.svg")
LOGIN_ICON = _P(ICON_ROOT, "login.svg")
ANNOUNCEMENT_ICON = _P(ICON_ROOT, "announcement.svg")
NOTICE_ICON = _P(ICON_ROOT, "notice.svg")
TEXT_FILE_ICON = _P(ICON_ROOT, "text_file.svg")
IMAGE_ICON = _P(ICON_ROOT, "image.svg")
ALERT_RED_ICON = _P(ICON_ROOT, "alert_red.svg")
TOGGLE_OFF_ICON = _P(ICON_ROOT, "toggle_off.svg")
TOGGLE_ON_ICON = _P(ICON_ROOT, "toggle_on.svg")
WEB_ICON = _P(ICON_ROOT, "web.svg")
VIEWER_ICON = _P(ICON_ROOT, "viewer.svg")
VERIFIED_ICON = _P(ICON_ROOT, "verified.svg")
CHANNEL_BACKGROUND_WHITE_ICON = _P(ICON_ROOT, "channel_background_white.svg")
STORAGE_ICON = _P(ICON_ROOT, "storage.svg")
HISTORY_ICON = _P(ICON_ROOT, "history.svg")
@staticmethod
def I(name: str, route: bool = True) -> ThemedIcon:
if route:
return ThemedIconManager.create(_P(IconPath.LIGHT, name), _P(IconPath.DARK, name))
else:
return ThemedIconManager.create(_P(IconPath.ROOT, name), _P(IconPath.ROOT, name))


APP_LOGO = I("icon.ico", route=False)

ACCOUNT = I("account.svg")
ALERT_RED = I("alert_red.svg")
ANNOUNCEMENT = I("announcement.svg")
BACK = I("back.svg")
CANCEL = I("cancel.svg")
CHANNEL_BACKGROUND_WHITE = I("channel_background_white.svg")
CLOSE = I("close.svg")
COPY = I("copy.svg")
CREATING_FILE = I("creating_file.svg")
DOWNLOAD = I("download.svg")
DOWNLOADING_FILE = I("downloading_file.svg")
FILE = I("file.svg")
FILE_NOT_FOUND = I("file_not_found.svg")
FOLDER = I("folder.svg")
FORWARD = I("forward.svg")
HELP = I("help.svg")
HISTORY = I("history.svg")
HOME = I("home.svg")
IMAGE = I("image.svg")
INFO = I("info.svg")
INSTANT_DOWNLOAD = I("instant_download.svg")
LAUNCH = I("launch.svg")
LIST = I("list.svg")
LOADING = I("loading.svg")
LOGIN = I("login.svg")
MOVE = I("move.svg")
NOTICE = I("notice.svg")
PLUS = I("plus.svg")
RELOAD = I("reload.svg")
RETRY = I("retry.svg")
SAVE = I("save.svg")
SCHEDULED = I("scheduled.svg")
SEARCH = I("search.svg")
SETTINGS = I("settings.svg")
STORAGE = I("storage.svg")
TEXT_FILE = I("text_file.svg")
THEME_AUTOMATIC = I("theme_automatic.svg")
THEME_DARK = I("theme_dark.svg")
THEME_LIGHT = I("theme_light.svg")
TOGGLE_OFF = I("toggle_off.svg")
TOGGLE_ON = I("toggle_on.svg")
TRASH = I("trash.svg")
UPDATE_FOUND = I("update_found.svg")
VERIFIED = I("verified.svg")
VIEWER = I("viewer.svg")
WARNING_RED = I("warning_red.svg")
WEB = I("web.svg")
2 changes: 1 addition & 1 deletion Services/Playlist/PlaylistManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def _requestDone(self) -> None:
if reply.error() == QtNetwork.QNetworkReply.NetworkError.NoError:
self._currentNetworkError = None
try:
self.playlist.loads(reply.readAll().data().decode(), baseUrl=self.url)
self.playlist.loads(reply.readAll().data().decode(errors="ignore"), baseUrl=self.url)
except Exception as e:
self._raiseException(e)
else:
Expand Down
2 changes: 1 addition & 1 deletion Services/Temp/TempManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def cleanTempDirKeyFile(self, tempDirKeyFile: str) -> None:
if OSUtils.isFile(tempDirKeyFile):
file = QtCore.QFile(tempDirKeyFile, self)
if file.open(QtCore.QIODevice.OpenModeFlag.ReadOnly):
tempDir = file.readAll().data().decode()
tempDir = file.readAll().data().decode(errors="ignore")
if OSUtils.isDirectory(tempDir):
self.logger.info(f"Removing temp directory: {tempDir}")
OSUtils.removeDirectory(tempDir)
Expand Down
Loading

0 comments on commit 7b4ad59

Please sign in to comment.