Skip to content

Commit

Permalink
2.0.2 Update
Browse files Browse the repository at this point in the history
  • Loading branch information
devhotteok committed Jun 19, 2022
1 parent 2f70d41 commit ce13313
Show file tree
Hide file tree
Showing 43 changed files with 668 additions and 439 deletions.
2 changes: 1 addition & 1 deletion Core/Launcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class SingleApplicationLauncher(QtWidgets.QApplication):

def __init__(self, guid, argv):
super(SingleApplicationLauncher, self).__init__(argv)
self.logger = Logger(fileName=f"{Config.APP_NAME}_{id(self)}.txt")
self.logger = Logger(fileName=f"{Config.APP_NAME}_{id(self)}.log")
self.logger.info(f"\n\n{Config.getProjectInfo()}\n")
self.logger.info(OSUtils.getOSInfo())
self.shared = QtCore.QSharedMemory(guid, parent=self)
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"

VERSION = "2.0.1"
VERSION = "2.0.2"

AUTHOR = "DevHotteok"

Expand Down
5 changes: 2 additions & 3 deletions Core/Qt/QtWidgets/QLabel.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,12 @@ def keepImageRatio(self, keepImageRatio):
self._keepImageRatio = keepImageRatio

def setText(self, text):
super().setText(str(text))
if isinstance(text, datetime):
self._useAutoToolTip = False
super().setText(text.strftime("%Y-%m-%d %H:%M:%S"))
self.setToolTip(f"{self.text()} {text.tzname()} ({text.tzinfo.zone})")
self.setToolTip(text.details())
else:
self._useAutoToolTip = True
super().setText(str(text))

def paintEvent(self, event):
if self.pixmap() == None:
Expand Down
6 changes: 3 additions & 3 deletions Core/Ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from Services.Utils.Utils import Utils
from Services.Image.Presets import *
from Services.Translator.Translator import Translator, T
from Services.Ad import AdManager
from Services import Ad
from Database.Database import DB

from PyQt5 import QtCore, QtGui, QtWidgets, QtWebEngineWidgets, uic
Expand Down Expand Up @@ -54,9 +54,9 @@ def ask(self, title, content, titleTranslate=True, contentTranslate=True, okText
def setAds(self):
adArea = self.findChildren(QtWidgets.QWidget, QtCore.QRegExp("^adArea_\d+$"))
adGroup = self.findChildren(QtWidgets.QWidget, QtCore.QRegExp("^adGroup_\d+$"))
if AdManager.Config.SHOW:
if Ad.Config.SHOW:
for widget in adArea:
Utils.setPlaceholder(widget, AdManager.Ad(minimumSize=widget.minimumSize(), responsive=True, parent=self))
Utils.setPlaceholder(widget, Ad.AdWidget(adId=f"{self.__class__.__name__}.{widget.objectName()}", adSize=widget.minimumSize(), responsive=True, parent=self))
else:
for widget in adArea + adGroup:
widget.setParent(None)
Expand Down
16 changes: 13 additions & 3 deletions Core/Updater.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,21 @@ def updateStatusData(self, data):
def updateNotifications(self, data):
self.notifications = [
DocumentData(
**(notification | {"buttons": [
contentId=notification.get("contentId", None),
contentVersion=notification.get("contentVersion", 0),
title=notification.get("title", ""),
content=notification.get("content", ""),
contentType=notification.get("contentType", ""),
modal=notification.get("modal", False),
blockExpiry=notification.get("blockExpiry", False),
buttons=[
DocumentButtonData(
**button
text=button.get("text", ""),
action=button.get("action", None),
role=button.get("role", "accept"),
default=button.get("default", False)
) for button in notification.get("buttons", [])
]})
]
) for notification in data.get(Translator.getLanguage(), [])
]

Expand Down
16 changes: 15 additions & 1 deletion Database/Database.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import json

from datetime import datetime
from datetime import datetime, timedelta


class Setup:
Expand Down Expand Up @@ -163,6 +163,7 @@ def __init__(self):
ImageConfig.DATA_TYPE: DownloadHistory.ThumbnailHistory()
}
self._windowGeometry = {}
self._blockedContent = {}

def getDownloadHistory(self, contentType):
return self._downloadHistory[contentType]
Expand All @@ -176,6 +177,19 @@ def setWindowGeometry(self, windowName, windowGeometry):
def getWindowGeometry(self, windowName):
return self._windowGeometry[windowName]

def isContentBlocked(self, contentId, contentVersion):
if contentId in self._blockedContent:
oldContentVersion, blockExpiry = self._blockedContent[contentId]
if contentVersion != oldContentVersion or (blockExpiry != None and blockExpiry < datetime.now()):
del self._blockedContent[contentId]
return False
else:
return True
else:
return False

def blockContent(self, contentId, contentVersion, blockExpiry=None):
self._blockedContent[contentId] = (contentVersion, None if blockExpiry == None else datetime.now() + timedelta(days=blockExpiry))

class Download:
def __init__(self):
Expand Down
3 changes: 2 additions & 1 deletion Database/Updater.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ def getUpdaters(cls, versionFrom):
"1.1.0": None,
"1.1.1": None,
"2.0.0": cls.Update_2_0_0,
"2.0.1": None
"2.0.1": None,
"2.0.2": None
}
updaters = []
versionFound = False
Expand Down
2 changes: 1 addition & 1 deletion Download/DownloadHistory.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ class VideoHistory(FileHistory, AudioFormatHistory):

def __init__(self):
super(VideoHistory, self).__init__()
self.setUnmuteVideoEnabled(True)
self.setUnmuteVideoEnabled(False)
self.setUpdateTrackEnabled(False)

def setUnmuteVideoEnabled(self, unmuteVideo):
Expand Down
39 changes: 30 additions & 9 deletions Download/DownloadInfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ def __init__(self, videoData, accessToken):

def getFileNameTemplateVariables(self):
if self.type.isStream():
startedAt = self.stream.createdAt.asTimezone(DB.localization.getTimezone())
return {
"type": T(self.type.toString()),
"id": self.stream.id,
Expand All @@ -37,12 +38,19 @@ def getFileNameTemplateVariables(self):
"channel": self.stream.broadcaster.login,
"channel_name": self.stream.broadcaster.displayName,
"channel_formatted_name": self.stream.broadcaster.formattedName(),
"started_at": self.stream.createdAt.asTimezone(DB.localization.getTimezone()),
"date": self.stream.createdAt.date(DB.localization.getTimezone()),
"time": self.stream.createdAt.time(DB.localization.getTimezone()),
"started_at": startedAt,
"date": startedAt.date(),
"year": f"{startedAt.year:04}",
"month": f"{startedAt.month:02}",
"day": f"{startedAt.day:02}",
"time": startedAt.time(),
"hour": f"{startedAt.hour:02}",
"minute": f"{startedAt.minute:02}",
"second": f"{startedAt.second:02}",
"resolution": self.resolution.resolutionName
}
elif self.type.isVideo():
publishedAt = self.video.publishedAt.asTimezone(DB.localization.getTimezone())
return {
"type": T(self.type.toString()),
"id": self.video.id,
Expand All @@ -52,13 +60,20 @@ def getFileNameTemplateVariables(self):
"channel_name": self.video.owner.displayName,
"channel_formatted_name": self.video.owner.formattedName(),
"duration": self.video.lengthSeconds,
"published_at": self.video.publishedAt.asTimezone(DB.localization.getTimezone()),
"date": self.video.publishedAt.date(DB.localization.getTimezone()),
"time": self.video.publishedAt.time(DB.localization.getTimezone()),
"published_at": publishedAt,
"date": publishedAt.date(),
"year": f"{publishedAt.year:04}",
"month": f"{publishedAt.month:02}",
"day": f"{publishedAt.day:02}",
"time": publishedAt.time(),
"hour": f"{publishedAt.hour:02}",
"minute": f"{publishedAt.minute:02}",
"second": f"{publishedAt.second:02}",
"views": self.video.viewCount,
"resolution": self.resolution.resolutionName
}
else:
createdAt = self.clip.createdAt.asTimezone(DB.localization.getTimezone())
return {
"type": T(self.type.toString()),
"id": self.clip.id,
Expand All @@ -72,9 +87,15 @@ def getFileNameTemplateVariables(self):
"creator_name": self.clip.curator.displayName,
"creator_formatted_name": self.clip.curator.formattedName(),
"duration": self.clip.durationSeconds,
"created_at": self.clip.createdAt.asTimezone(DB.localization.getTimezone()),
"date": self.clip.createdAt.date(DB.localization.getTimezone()),
"time": self.clip.createdAt.time(DB.localization.getTimezone()),
"created_at": createdAt,
"date": createdAt.date(),
"year": f"{createdAt.year:04}",
"month": f"{createdAt.month:02}",
"day": f"{createdAt.day:02}",
"time": createdAt.time(),
"hour": f"{createdAt.hour:02}",
"minute": f"{createdAt.minute:02}",
"second": f"{createdAt.second:02}",
"views": self.clip.viewCount,
"resolution": self.resolution.resolutionName
}
Expand Down
7 changes: 4 additions & 3 deletions Download/DownloadManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
class _DownloadManager(QtCore.QObject):
createdSignal = QtCore.pyqtSignal(object)
destroyedSignal = QtCore.pyqtSignal(object)
startedSignal = QtCore.pyqtSignal(object)
completedSignal = QtCore.pyqtSignal(object)
runningCountChangedSignal = QtCore.pyqtSignal(int)

Expand All @@ -23,6 +24,7 @@ def onStart(self, downloader):
self.hideDownloaderProgress(complete=False)
self.runningDownloaders.append(downloader)
self.runningCountChangedSignal.emit(len(self.runningDownloaders))
self.startedSignal.emit(downloader.getId())

def onFinish(self, downloader):
self.runningDownloaders.remove(downloader)
Expand All @@ -49,8 +51,8 @@ def hideDownloaderProgress(self, complete):

def create(self, downloadInfo):
downloader = TwitchDownloader(downloadInfo, parent=self)
downloader.needSetup.connect(self.onStart)
downloader.needCleanup.connect(self.onFinish)
downloader.started.connect(self.onStart)
downloader.finished.connect(self.onFinish)
downloaderId = downloader.getId()
self.downloaders[downloaderId] = downloader
self.createdSignal.emit(downloaderId)
Expand Down Expand Up @@ -114,5 +116,4 @@ def handleClipProgress(self, downloader):
progress = downloader.progress
App.taskbar.setValue(progress.byteSizeProgress)


DownloadManager = _DownloadManager()
16 changes: 11 additions & 5 deletions Download/Downloader/Engine/Setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@


class EngineSetup(QtCore.QThread):
needSetup = QtCore.pyqtSignal(object)
needCleanup = QtCore.pyqtSignal(object)
started = QtCore.pyqtSignal(object)
finished = QtCore.pyqtSignal(object)
statusUpdate = QtCore.pyqtSignal(Modules.Status)
progressUpdate = QtCore.pyqtSignal(Modules.Progress)
dataUpdate = QtCore.pyqtSignal(dict)
Expand All @@ -24,6 +24,14 @@ def __init__(self, downloadInfo, parent=None):
self.progress = Modules.Progress()
self.actionLock = MutexLocker()
self.setupLogger()
super().started.connect(self.emitStartedSignal)
super().finished.connect(self.emitFinishedSignal)

def emitStartedSignal(self):
self.started.emit(self)

def emitFinishedSignal(self):
self.finished.emit(self)

def getId(self):
return id(self)
Expand All @@ -32,12 +40,11 @@ def setupLogger(self):
name = f"{Config.APP_NAME}_Download_{self.getId()}"
self.logger = Logger(
name=name,
fileName=f"{name}.txt",
fileName=f"{name}.log",
)
self.logger.debug(f"{Config.APP_NAME} {Config.VERSION}\n\n[Download Info]\n{ObjectLogger.generateObjectLog(self.setup.downloadInfo)}")

def run(self):
self.needSetup.emit(self)
self.logger.info("Download Started")
try:
self.download()
Expand All @@ -64,7 +71,6 @@ def run(self):
self.logger.info("Download Failed")
else:
self.logger.info("Download Completed")
self.needCleanup.emit(self)

def download(self):
pass
Expand Down
12 changes: 6 additions & 6 deletions Download/Downloader/Engine/Video/Video.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def downloadSegments(self):
url = self.setup.downloadInfo.getUrl().rsplit("/", 1)[0]
processedFiles = []
with self.actionLock:
self.taskManager.taskCompleteSignal.connect(self.segmentDownloadResult)
self.taskManager.taskCompleteSignal.connect(self.segmentDownloadComplete)
self.taskManager.ifPaused.connect(self.taskPaused)
self.taskManager.start()
while self.status.terminateState.isFalse():
Expand Down Expand Up @@ -108,11 +108,11 @@ def downloadSegments(self):
except:
break

def segmentDownloadResult(self, result):
if not result.success:
urls = "\n".join(result.task.urls)
self.logger.warning(f"Failed to download segment: {result.task.segment.fileName} [{result.error}]\n{urls}")
if isinstance(result.error, Exceptions.FileSystemError):
def segmentDownloadComplete(self, task):
if not task.result.success:
urls = "\n".join(task.urls)
self.logger.warning(f"Failed to download segment: {task.segment.fileName} [{task.result.error}]\n{urls}")
if isinstance(task.result.error, Exceptions.FileSystemError):
self.cancel()
self.status.raiseError(Exceptions.FileSystemError)
return
Expand Down
10 changes: 6 additions & 4 deletions Download/Downloader/FFmpeg/FFmpeg.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ def start(self, target, saveAs, logLevel=LogLevel.INFO, priority=Priority.NORMAL
startupinfo=startupinfo,
creationflags=priority
)
self.process.notResponding = False

def output(self, logger=None):
return FFmpegOutputReader(self.process, logger).reader()
Expand All @@ -75,10 +76,11 @@ def kill(self):

def _killProcess(self):
try:
self.process.communicate(input="q", timeout=Config.KILL_TIMEOUT)
except:
self.process.notResponding = True
try:
self.process.communicate(input="q", timeout=Config.KILL_TIMEOUT)
except:
self.process.kill()
self.process.communicate()
except:
pass
except:
pass
27 changes: 18 additions & 9 deletions Download/Downloader/FFmpeg/OutputReader.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,29 @@ def reader(self):

def _read(self):
line = ""
for line in self.process.stdout:
progressData = self.getProgressData(line)
if progressData != None:
yield progressData
try:
for line in self.process.stdout:
progressData = self.getProgressData(line)
if progressData != None:
yield progressData
except:
pass
self.checkError(self.process.wait(), line)

def _readWithLogs(self):
line = ""
for line in self.process.stdout:
self.logger.debug(line.strip("\n"))
progressData = self.getProgressData(line)
if progressData != None:
yield progressData
try:
for line in self.process.stdout:
self.logger.debug(line.strip("\n"))
progressData = self.getProgressData(line)
if progressData != None:
yield progressData
except Exception as e:
self.logger.error("Unable to read output properly.")
self.logger.exception(e)
returnCode = self.process.wait()
if self.process.notResponding:
self.logger.info("Subprocess was unresponsive and forced to terminate.")
self.logger.info(f"Subprocess ended with exit code {returnCode}.")
self.checkError(returnCode, line)

Expand Down
Loading

0 comments on commit ce13313

Please sign in to comment.