class MainUi(QWidget): def __init__(self): super(MainUi, self).__init__() self.setFixedSize(600,500) self.setWindowTitle("妹子图爬虫工具 version: 1.0.0 ") self.download_progressbar = QProgressBar() self.download_progressbar.setAlignment(QtCore.Qt.Alignment.AlignCenter)#文字居中 self.download_progressbar.setStyleSheet(".QProgressBar::chunk { background-color: red;}")#背景 self.download_progressbar.setValue(100) label01 = QLabel("下载URL:") label02 = QLabel("下载目录:") self.url_input = QLineEdit() self.url_input.setText("https://www.mzitu.com/221746") self.url_input.setContentsMargins(0,0,0,0) self.download_dir = QLineEdit() self.download_dir.setContentsMargins(0,0,0,0) self.start_btn = QPushButton("开始爬虫") self.start_btn.setFixedHeight(50) self.start_btn.setContentsMargins(0,0,0,0) inputlayout = QGridLayout() inputlayout.addWidget(label01, 0, 0) #第0行 0列 inputlayout.addWidget(label02, 1, 0) inputlayout.addWidget(self.url_input, 0, 1) inputlayout.addWidget(self.download_dir, 1, 1) inputlayout.addWidget(self.start_btn, 0, 2, 2,1,QtCore.Qt.Alignment.AlignRight) #起始行,起始列, 占行数,占列数 inputlayout.setColumnStretch(0, 1) #设置每一列比例 inputlayout.setColumnStretch(1, 10) inputlayout.setColumnStretch(2, 1) vlayout = QVBoxLayout() vlayout.addLayout(inputlayout) vlayout.addWidget(self.download_progressbar) self.frame = QFrame() self.frame.setFixedHeight(400) vlayout.addWidget(self.frame) vlayout.addStretch() inputlayout.setContentsMargins(0,0,0,0) vlayout01 = QVBoxLayout() self.frame.setLayout(vlayout01) self.qtablewidget = QTableWidget(1,3) self.qtablewidget.setHorizontalHeaderLabels(['目录','下载图片总数目', '删除']) vlayout01.addWidget(self.qtablewidget) self.qtablewidget.setColumnWidth(0, 358) # 将第0列的单元格,设置成300宽度 self.qtablewidget.setColumnWidth(1, 100 ) # 将第0列的单元格,设置成50宽度 self.qtablewidget.verticalHeader().setVisible(False) #隐藏水平表头 #self.qtablewidget.setDisabled(True) #设置不可编辑 self.setLayout(vlayout) self.current_index = 0 def tableupdate(self,dir, pic_num, pushbtn ) -> None: self.qtablewidget.setRowCount(self.current_index+1) #设置行 diritem = QTableWidgetItem(str(dir)) self.qtablewidget.setItem( self.current_index, 0, diritem) pic_numitem = QTableWidgetItem(str(pic_num)) self.qtablewidget.setItem( self.current_index, 1, pic_numitem) self.qtablewidget.setCellWidget( self.current_index, 2, pushbtn ) self.current_index += 1
class MainWidget(QWidget): def __init__(self): super(MainWidget, self).__init__() self.resize(500, 600) self.setWindowTitle("喜马拉雅下载 by[Zero] " + __VERSION__) self.mainlayout = QVBoxLayout() self.setLayout(self.mainlayout) self.groupbox = QGroupBox("选择类型") self.groupbox.setFixedHeight(50) hlayout = QHBoxLayout(self.groupbox) self.signal_m4a = QRadioButton("单个下载") self.mut_m4a = QRadioButton("专辑下载") self.vip_signal_m4a = QRadioButton("VIP单个下载") self.vip_m4a = QRadioButton("VIP专辑下载") hlayout.addWidget(self.signal_m4a) hlayout.addWidget(self.mut_m4a) hlayout.addWidget(self.vip_signal_m4a) hlayout.addWidget(self.vip_m4a) self.mainlayout.addWidget(self.groupbox) frame01 = QFrame(self) child_layout = QVBoxLayout() print(self.width()) label01 = QLabel("链 接", self) label02 = QLabel("下载目录", self) self.url_lineedit = QLineEdit(self) self.dir_lineedit = QLineEdit(self) hlayout01 = QHBoxLayout() hlayout01.addWidget(label01, 1) hlayout01.addWidget(self.url_lineedit, 9) hlayout02 = QHBoxLayout() hlayout02.addWidget(label02, 1) hlayout02.addWidget(self.dir_lineedit, 9) child_layout.addLayout(hlayout01) child_layout.addLayout(hlayout02) child_layout.setContentsMargins( 5, 0, 5, 0) #(int left, int top, int right, int bottom) frame01.setLayout(child_layout) self.download_progressbar = QProgressBar() self.download_progressbar.setAlignment( QtCore.Qt.Alignment.AlignCenter) #文字居中 self.download_progressbar.setValue(88) self.download_btn = QPushButton("开始下载") self.show_plaintextedit = QPlainTextEdit() self.show_plaintextedit.setMinimumHeight(400) self.mainlayout.addWidget(frame01) self.mainlayout.addWidget(self.download_progressbar) self.mainlayout.addWidget(self.download_btn) self.mainlayout.addWidget(self.show_plaintextedit) self.mainlayout.addStretch() ### 设置stylesheet self.download_btn.setStyleSheet( 'QPushButton:pressed{ text-align: center;background-color:red;}')
def exerciseLayout(self, index): hLayout = QHBoxLayout() setSpinBox = QSpinBox() setSpinBox.setRange(1, 100) setSpinBox.setValue(5) setSpinBox.setMaximumWidth(80) startButton = QPushButton(self.classifyExercises.exercises[index].name) startButton.setMaximumWidth(120) assignedKey = QPushButton( self.classifyExercises.exercises[index].assigned_key[0]) assignedKey.setStyleSheet('background-color: grey; color: white;') assignedKey.setMaximumWidth(50) assignedKey.setEnabled(False) progress = QProgressBar() progress.setMaximumWidth(150) progress.setValue(randint(1, 100)) progress.setAlignment(QtCore.Qt.Alignment.AlignCenter) latency = QLabel(str(randint(50, 250)) + 'ms') avgLatency = QLabel(str(randint(50, 250)) + 'ms') hLayout.addWidget(setSpinBox) hLayout.setAlignment(setSpinBox, QtCore.Qt.Alignment.AlignHCenter) hLayout.addWidget(startButton) hLayout.setAlignment(startButton, QtCore.Qt.Alignment.AlignHCenter) hLayout.addWidget(assignedKey) hLayout.setAlignment(assignedKey, QtCore.Qt.Alignment.AlignHCenter) hLayout.addWidget(progress) hLayout.setAlignment(progress, QtCore.Qt.Alignment.AlignHCenter) hLayout.addWidget(latency) hLayout.setAlignment(latency, QtCore.Qt.Alignment.AlignHCenter) hLayout.addWidget(avgLatency) hLayout.setAlignment(avgLatency, QtCore.Qt.Alignment.AlignHCenter) hLayout.setContentsMargins(0, 10, 0, 10) self.exerciseLayouts.append(hLayout) return hLayout
class ConfigDialog(QDialog): def __init__(self, parent=None): super(ConfigDialog, self).__init__(parent) self.classifyExercises = parent.classifyExercises self.setFixedSize(500, 400) self.setWindowTitle("Model Configurations") self.epochValue = QLabel() self.vbox = QVBoxLayout() self.label_maximum = QLabel() self.label_minimum = QLabel() self.slider_hbox = QHBoxLayout() self.slider_vbox = QVBoxLayout() self.batchSizeMenu = QComboBox() self.properties = QFormLayout() self.epochSlider = Slider(orientation=Qt.Orientations.Horizontal) self.trainButton = QPushButton('Train Model') self.resultButton = QPushButton('Show result image') self.progress = QProgressBar() self.batchSizeMenu.addItems(['2', '4', '8', '16', '32', '64', '128']) self.batchSizeMenu.setCurrentIndex(3) self.batchSizeMenu.setMaximumWidth(100) self.initSlider() self.properties.addRow('Batch Size', self.batchSizeMenu) self.resultButton.setEnabled(False) self.actionsLayout = QHBoxLayout() self.actionsLayout.addWidget(self.trainButton) self.actionsLayout.addWidget(self.resultButton) self.optionsLayout = QVBoxLayout() self.optionsLayout.addWidget(QLabel('Model properties')) self.optionsLayout.addLayout(self.vbox) self.optionsLayout.addLayout(self.properties) self.optionsLayout.addLayout(self.actionsLayout) self.progress.setAlignment(QtCore.Qt.Alignment.AlignCenter) self.optionsLayout.addWidget(self.progress) # self.options_layout.addWidget(self.label) # self.options_layout.addWidget(self.list_widget) self.setLayout(self.optionsLayout) self.trainThread = TrainThread(self.classifyExercises) self.connections() print("init config") def initSlider(self): self.epochValue.setAlignment(QtCore.Qt.Alignment.AlignHCenter) self.epochSlider.setMinimum(2) self.epochSlider.setMaximum(10) self.epochSlider.setTickInterval(1) # self.epochSlider.setInterval(1) # self.epochSlider.setValue(8) # no idea why, but 8 is the middle somehow self.epochSlider.setSliderPosition(6) self.epochSlider.setTickPosition(QSlider.TickPosition.TicksBelow) self.label_minimum.setNum(self.epochSlider.minimum().real * 50) self.label_minimum.setAlignment(QtCore.Qt.Alignment.AlignLeft) self.label_maximum.setNum(self.epochSlider.maximum().real * 50) self.label_maximum.setAlignment(QtCore.Qt.Alignment.AlignRight) self.epochSlider.minimumChanged.connect(self.label_minimum.setNum) self.epochSlider.maximumChanged.connect(self.label_maximum.setNum) self.slider_hbox.addWidget(self.label_minimum, QtCore.Qt.Alignment.AlignLeft) self.slider_hbox.addWidget(self.epochValue) self.slider_hbox.addWidget(self.label_maximum, QtCore.Qt.Alignment.AlignRight) self.slider_vbox.addWidget(self.epochSlider) self.slider_vbox.addLayout(self.slider_hbox) # self.slider_vbox.addStretch() self.vbox.addLayout(self.slider_vbox) def connections(self): self.batchSizeMenu.currentIndexChanged.connect( self.onBatchSizeSelected) self.resultButton.clicked.connect(self.onResultClicked) self.trainButton.clicked.connect(self.onTrainClicked) self.epochSlider.valueChanged.connect(self.updateEpochValue) self.trainThread.taskFinished.connect(self.onFinished) def updateEpochValue(self, num): print(num) epochs = num * 50 self.epochValue.setNum(epochs) self.classifyExercises.epochs = epochs def onBatchSizeSelected(self, ind): self.classifyExercises.training_batch_size = int( self.batchSizeMenu.currentText()) def onResultClicked(self): print("open image") self.classifyExercises.DisplayResults() def onTrainClicked(self): if self.classifyExercises.subject is not None: if self.classifyExercises.DataAvailable(): if self.resultButton.isEnabled: self.resultButton.setEnabled(False) self.trainThread.start() self.progress.setRange(0, 0) else: CustomMessage.showDialog( "Message", "Calibrate for patient to obtain data.", QMessageBox.StandardButtons.Ok) else: CustomMessage.showDialog( "Message", "You must either select or enter a subject name.", QMessageBox.StandardButtons.Ok) print("Subject is none!") def onFinished(self): # Stop the progress self.progress.setRange(0, 1) self.progress.setValue(1) CustomMessage.showDialog("Message", "Training model finished!", QMessageBox.StandardButtons.Ok) self.resultButton.setEnabled(True)
class YTdownloader(QWidget): def __init__(self): super().__init__() # setup some flags self.isFetching = False self.isDownloading = False # default output path self.outputPath = f'{QDir.homePath()}/videos' # setup some window specific things self.setWindowTitle('YouTube Downloader') self.setWindowIcon(QIcon('assets/yt-icon.ico')) self.setFixedSize(705, 343) # parent layout layout = QVBoxLayout() layout.setContentsMargins(15, 15, 15, 10) self.setLayout(layout) # top bar layout topBar = QHBoxLayout() # detail section detailSec = QHBoxLayout() metaSec = QVBoxLayout() # download section downloadSec = QHBoxLayout() downloadBtn = QVBoxLayout() # output path link button self.outputBtn = QPushButton('📂 Output Path') self.outputBtn.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) self.outputBtn.setToolTip(self.outputPath) self.outputBtn.clicked.connect(self.setOutputPath) # status bar self.statusBar = QStatusBar() # message box self.message = QMessageBox() # setting up widgets self.urlBox = QLineEdit() self.urlBox.setFocusPolicy(Qt.FocusPolicy.ClickFocus or Qt.FocusPolicy.NoFocus) self.urlBox.setPlaceholderText('🔍 Enter or paste video URL...') self.button = QPushButton('Get') self.button.setDefault(True) self.button.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) self.button.clicked.connect(self.getDetails) # thumbnail pixmap = QPixmap('assets\placeholder.jpg') self.thumb = QLabel() self.thumb.setFixedSize(250, 141) self.thumb.setScaledContents(True) self.thumb.setPixmap(pixmap) # detail widgets self.title = QLabel('Title: ') self.author = QLabel('Author: ') self.length = QLabel('Duration: ') self.publish_date = QLabel('Published: ') # progress bar self.progress_bar = QProgressBar() # download options self.download = QComboBox() self.download.setPlaceholderText('Download Video') self.download.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) self.download.activated.connect(lambda: self.getContent(0)) self.download.setEnabled(False) # download audio button self.download_audio = QPushButton('Download Audio') self.download_audio.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) self.download_audio.clicked.connect(lambda: self.getContent(1)) self.download_audio.setEnabled(False) # add widgets and layouts topBar.addWidget(self.urlBox) topBar.addWidget(self.button) # detail section metaSec.addWidget(self.title) metaSec.addWidget(self.author) metaSec.addWidget(self.length) metaSec.addWidget(self.publish_date) detailSec.addWidget(self.thumb) detailSec.addSpacing(20) detailSec.addLayout(metaSec) # download section downloadBtn.addWidget(self.download) downloadBtn.addWidget(self.download_audio) downloadSec.addWidget(self.progress_bar) downloadSec.addSpacing(10) downloadSec.addLayout(downloadBtn) # status bar self.statusBar.setSizeGripEnabled(False) self.statusBar.addPermanentWidget(self.outputBtn) # add content to parent layout layout.addLayout(topBar) layout.addSpacing(20) layout.addLayout(detailSec) layout.addSpacing(5) layout.addLayout(downloadSec) layout.addWidget(self.statusBar) # setup a connection thread to keep checking internet connectivity self.connection = ConnectionThread() self.connection.start() # catch the connection response signal self.connection.con_response.connect(self.connection_slot) # connection slot def connection_slot(self, status): curMsg = self.statusBar.currentMessage() # connection succeeded if status: if curMsg == '🔴 Disconnected': self.statusBar.showMessage('🟢 Connection restored!', 3000) elif curMsg != '🟢 Connected': self.statusBar.showMessage('🟢 Connected') # connection failed elif curMsg == '🟢 Connected': self.statusBar.showMessage('🔴 Connection interrupted!', 3000) elif curMsg != '🔴 Disconnected': self.statusBar.showMessage('🔴 Disconnected') # set output path slot def setOutputPath(self): # update the output path path = str(QFileDialog.getExistingDirectory(self, "Select Output Directory")) if path: self.outputPath = path # update tooltip self.outputBtn.setToolTip(path) # get button slot def getDetails(self): curMsg = self.statusBar.currentMessage() if curMsg == '🔴 Disconnected' or curMsg == '🔴 Connection interrupted!': self.message.critical( self, 'Error', 'Connection failed!\nAre you sure you\'re connected to the internet ? ' ) elif self.button.text() == 'Get': self.button.setText('Stop') # indicate progress bar as busy self.progress_bar.setRange(0, 0) # set fetching flag self.isFetching = True # setup a worker thread to keep UI responsive self.worker = WorkerThread(self.urlBox.text()) self.worker.start() # catch the finished signal self.worker.finished.connect(self.finished_slot) # catch the response signal self.worker.worker_response.connect(self.response_slot) # catch the error signal self.worker.worker_err_response.connect(self.err_slot) elif self.button.text() == 'Stop': if self.isFetching: # stop worker thread self.worker.terminate() # set back the button text self.button.setText('Get') elif self.isDownloading: # stop download thread self.download_thread.terminate() # show the warning message self.message.information( self, 'Interrupted', 'Download interrupted!\nThe process was aborted while the file was being downloaded... ' ) # reset pogress bar self.progress_bar.reset() # download options slot def getContent(self, id): if self.isFetching: # show the warning message self.message.warning( self, 'Warning', 'Please wait!\nWait while the details are being fetched... ' ) else: # disable the download options self.download.setDisabled(True) self.download_audio.setDisabled(True) # set downloading flag self.isDownloading = True # set button to stop self.button.setText('Stop') # setup download thread if id == 0: self.download_thread = DownloadThread(self.yt, self.download.currentText()[:4], self.outputPath) else: self.download_thread = DownloadThread(self.yt, 'audio', self.outputPath) # start the thread self.download_thread.start() # catch the finished signal self.download_thread.finished.connect(self.download_finished_slot) # catch the response signal self.download_thread.download_response.connect(self.download_response_slot) # catch the complete signal self.download_thread.download_complete.connect(self.download_complete_slot) # catch the error signal self.download_thread.download_err.connect(self.download_err_slot) # finished slot def finished_slot(self): # remove progress bar busy indication self.progress_bar.setRange(0, 100) # unset fetching flag self.isFetching = False # response slot def response_slot(self, res): # set back the button text self.button.setText('Get') # save the yt object for speeding up download self.yt = res[0] # set the actual thumbnail of requested video self.thumb.setPixmap(res[1]) # slice the title if it is more than the limit if len(res[2]) > 50: self.title.setText(f'Title: {res[2][:50]}...') else: self.title.setText(f'Title: {res[2]}') # set leftover details self.author.setText(f'Author: {res[3]}') self.length.setText(f'Duration: {timedelta(seconds=res[4])}') self.publish_date.setText(f'Published: {res[5].strftime("%d/%m/%Y")}') # clear any previous items if any self.download.clear() # add resolutions as items to the download button and enable them self.download.addItems([item for item in res[6]]) self.download.setDisabled(False) self.download_audio.setDisabled(False) # error slot def err_slot(self): # show the warning message self.message.warning( self, 'Warning', 'Something went wrong!\nProbably a broken link or some restricted content... ' ) # set back the button text self.button.setText('Get') # download finished slot def download_finished_slot(self): # set back the button text self.button.setText('Get') # now enable the download options self.download.setDisabled(False) self.download_audio.setDisabled(False) # unset downloading flag self.isDownloading = False # reset pogress bar self.progress_bar.reset() # download response slot def download_response_slot(self, per): # update progress bar self.progress_bar.setValue(per) # adjust the font color to maintain the contrast if per > 52: self.progress_bar.setStyleSheet('QProgressBar { color: #fff }') else: self.progress_bar.setStyleSheet('QProgressBar { color: #000 }') # download complete slot def download_complete_slot(self, location): # use native separators location = QDir.toNativeSeparators(location) # show the success message if self.message.information( self, 'Downloaded', f'Download complete!\nFile was successfully downloaded to :\n{location}\n\nOpen the downloaded file now ?', QMessageBox.StandardButtons.Open, QMessageBox.StandardButtons.Cancel ) is QMessageBox.StandardButtons.Open: subprocess.Popen(f'explorer /select,{location}') # download error slot def download_err_slot(self): # show the error message self.message.critical( self, 'Error', 'Error!\nSomething unusual happened and was unable to download...' )
class B23Download(QWidget): def __init__(self): super(B23Download, self).__init__() # setup some flags self.is_fetching = False self.is_downloading = False # default output path basepath = os.path.dirname(os.path.abspath(__file__)) path = os.path.join(basepath, "videos") self.output_path = path # setup some window specific things self.setWindowTitle("Bilibili Favorite Downloader") self.setWindowIcon(QIcon("images/icon_bilibili.ico")) self.setFixedSize(705, 343) # parent layout main_layout = QVBoxLayout() main_layout.setContentsMargins(15, 15, 15, 10) self.setLayout(main_layout) # top bar layout top_layout = QHBoxLayout() # detail section mid_main_layout = QHBoxLayout() mid_right_layout = QVBoxLayout() # download section bottom_main_layout = QHBoxLayout() bottom_right_layout = QVBoxLayout() # output path link button self.output_btn = QPushButton("📂 Output Path") self.output_btn.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) self.output_btn.setToolTip(self.output_path) self.output_btn.clicked.connect(self.set_output_path) # status bar self.status_bar = QStatusBar() # message box self.message_box = QMessageBox() # setting up widgets self.url_edit = QLineEdit() self.url_edit.setPlaceholderText("🔍 Enter or paste favorite URL...") self.get_btn = QPushButton("Get") self.get_btn.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) self.get_btn.clicked.connect(self.get_details) # thumbnail pixmap = QPixmap("images/placeholder.png") self.thumb = QLabel() self.thumb.setFixedSize(250, 141) self.thumb.setScaledContents(True) self.thumb.setPixmap(pixmap) # detail widgets self.title = QLabel("Title: ") self.author = QLabel("Author: ") self.length = QLabel("Videos: ") self.publish_date = QLabel("Published: ") # progress bar self.progress_bar = QProgressBar() # download options self.download_btn = QPushButton(" Download Videos ") self.download_btn.setCursor(QCursor(Qt.CursorShape.PointingHandCursor)) self.download_btn.clicked.connect(self.get_content) self.download_btn.setEnabled(False) self.download_btn.setShortcut("Ctrl+Return") self.download_btn.setMinimumWidth(200) # add widgets and layouts top_layout.addWidget(self.url_edit) top_layout.addWidget(self.get_btn) # detail section mid_right_layout.addWidget(self.title) mid_right_layout.addWidget(self.author) mid_right_layout.addWidget(self.length) mid_right_layout.addWidget(self.publish_date) mid_main_layout.addWidget(self.thumb) mid_main_layout.addSpacing(20) mid_main_layout.addLayout(mid_right_layout) # download section bottom_right_layout.addWidget(self.download_btn) bottom_main_layout.addWidget(self.progress_bar) bottom_main_layout.addSpacing(10) bottom_main_layout.addLayout(bottom_right_layout) # status bar self.status_bar.setSizeGripEnabled(False) self.status_bar.addPermanentWidget(self.output_btn) # add content to parent layout main_layout.addLayout(top_layout) main_layout.addSpacing(20) main_layout.addLayout(mid_main_layout) main_layout.addSpacing(5) main_layout.addLayout(bottom_main_layout) main_layout.addWidget(self.status_bar) # set output path slot def set_output_path(self): # update the output path path = str( QFileDialog.getExistingDirectory(self, "Select Output Directory")) if path: self.output_path = path # update tooltip self.output_btn.setToolTip(path) # get button slot def get_details(self): text = self.url_edit.text().strip() if not text: return if text.find("fid") < 0: self.message_box.warning( self, "Error", ("Input a correct favorite URL!\n" "For example: https://space.bilibili.com/xxx/favlist?fid=xxx..." ), ) return if self.get_btn.text() == "Get": self.get_btn.setText("Stop") # indicate progress bar as busy self.progress_bar.setRange(0, 0) # set fetching flag self.is_fetching = True # setup a worker thread to keep UI responsive self.media_id = text.split("fid=")[-1].split("&")[0] self.worker = WorkerThread(self.media_id) self.worker.start() # catch the finished signal self.worker.finished.connect(self.finished_slot) # catch the response signal self.worker.worker_response.connect(self.response_slot) # catch the error signal self.worker.worker_err_response.connect(self.err_slot) elif self.get_btn.text() == "Stop": if self.is_fetching: # stop worker thread self.worker.terminate() # set back the get_btn text self.get_btn.setText("Get") elif self.is_downloading: # stop download thread self.download_thread.terminate() # show the warning message_box self.message_box.information( self, "Interrupted", "Download interrupted!\nThe process was aborted while the file was being downloaded... ", ) # reset progress bar self.progress_bar.reset() # download options slot def get_content(self): if self.is_fetching: # show the warning message self.message_box.critical( self, "Error", "Please wait!\nWait while the details are being fetched... ", ) else: # disable the download options self.download_btn.setDisabled(True) # set downloading flag self.is_downloading = True # set button to stop self.get_btn.setText("Stop") self.download_thread = DownloadThread( self.media_id, self.media_counts, self.first_page_medias, self.output_path, ) # start the thread self.download_thread.start() # catch the finished signal self.download_thread.finished.connect(self.download_finished_slot) # catch the response signal self.download_thread.download_response.connect( self.download_response_slot) # catch the complete signal self.download_thread.download_complete.connect( self.download_complete_slot) # catch the error signal self.download_thread.download_err.connect(self.download_err_slot) # handling enter key for get/stop button def keyPressEvent(self, event): self.url_edit.setFocus() if (event.key() == Qt.Key.Key_Enter.value or event.key() == Qt.Key.Key_Return.value): self.get_details() # finished slot def finished_slot(self): # remove progress bar busy indication self.progress_bar.setRange(0, 100) # unset fetching flag self.is_fetching = False # response slot def response_slot(self, res): # set back the button text self.get_btn.setText("Get") # set the actual thumbnail of requested video self.thumb.setPixmap(res.thumb_img) # slice the title if it is more than the limit if len(res.title) > 50: self.title.setText(f"Title: {res.title[:50]}...") else: self.title.setText(f"Title: {res.title}") # cache first page medias self.first_page_medias = res.medias self.media_counts = res.media_counts # set leftover details self.author.setText(f"Author: {res.author}") self.length.setText(f"Videos: {res.media_counts}") self.publish_date.setText( f'Published: {time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(res.publish_date))}' ) self.download_btn.setDisabled(False) # error slot def err_slot(self): # show the warning message self.message_box.warning( self, "Warning", "Something went wrong!\nProbably a broken link or some restricted content... ", ) # set back the button text self.get_btn.setText("Get") # download finished slot def download_finished_slot(self): # set back the button text self.get_btn.setText("Get") # now enable the download options self.download_btn.setDisabled(False) # unset downloading flag self.is_downloading = False # reset pogress bar self.progress_bar.reset() # download response slot def download_response_slot(self, per): # update progress bar self.progress_bar.setValue(per) # adjust the font color to maintain the contrast if per > 52: self.progress_bar.setStyleSheet("QProgressBar { color: #fff }") else: self.progress_bar.setStyleSheet("QProgressBar { color: #000 }") # download complete slot def download_complete_slot(self, location): # use native separators location = QDir.toNativeSeparators(location) # show the success message if (self.message_box.information( self, "Downloaded", f"Download complete!\nFile was successfully downloaded to :\n{location}\n\nOpen the downloaded file now ?", QMessageBox.StandardButtons.Open, QMessageBox.StandardButtons.Cancel, ) is QMessageBox.StandardButtons.Open): subprocess.Popen(f"explorer /select,{location}") # download error slot def download_err_slot(self): # show the error message self.message_box.critical( self, "Error", "Error!\nSomething unusual happened and was unable to download...", )
class DownLoadTaskWidget(QWidget): update_task_signa = QtCore.pyqtSignal() def __init__(self, task: DownloadTask): super().__init__() self.task = task constant.download_task_widget_map[task.chapterInfo.url] = self self.setMinimumHeight(40) self.setMaximumHeight(40) self.groupBox = QGroupBox(self) self.title = QLabel(self.groupBox) self.title.setText(task.comicInfo.title + task.chapterInfo.title) self.title.setGeometry(10, 5, 300, 20) # 下载进度 self.schedule = QLabel(self.groupBox) self.schedule.setText( f"总页数:{len(self.task.imageInfos)} 已下载:{len(self.task.success)} 下载失败:{len(self.task.error)}") self.schedule.setGeometry(310, 5, 200, 20) # 进度条 self.pbar = QProgressBar(self.groupBox) self.pbar.setGeometry(10, 25, 600, 10) self.pbar.setMinimum(0) self.pbar.setMaximum(len(task.imageInfos)) self.pbar.setValue(0) self.update_task_signa.connect(self.update_task_thread) # 状态 self.status = QLabel(self.groupBox) self.status.setGeometry(620, 12, 70, 20) self.status.setText("等待下载") # 按钮 self.button = ButtonQLabel(self.groupBox) self.button.setGeometry(700, 12, 100, 20) self.button.setText("暂停") self.button.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.PointingHandCursor)) button_font = QtGui.QFont() button_font.setUnderline(True) self.button.setFont(button_font) self.button.onclick(self.button_click) def change_status(self): # 按钮逻辑 if self.task.status == 0: self.status.setText("等待下载") self.button.setVisible(False) elif self.task.status == 1: self.button.setVisible(True) self.button.setText("暂停") self.status.setText("正在下载") elif self.task.status == 2 or self.task.status == -3: self.button.setVisible(True) self.button.setText("继续") self.status.setText("暂停") elif self.task.status == -1: self.button.setVisible(False) self.status.setText("下载完成") elif self.task.status == -2: self.button.setVisible(True) self.button.setText("重试") self.status.setText("下载错误") def button_click(self): if self.task.status == 1: # 正在下载,点击暂停 self.task.status = 2 elif self.task.status == 2 or self.task.status == -3: # 暂停 ,点击等待下载,添加到队列 self.task.status = 0 constant.SERVICE.add_task(self.task) elif self.task.status == -2: # 错误,点击重试 constant.SERVICE.add_task(self.task) self.change_status() def update_task_thread(self): self.schedule.setText( f"总页数:{len(self.task.imageInfos)} 已下载:{len(self.task.success)} 下载失败:{len(self.task.error)}") self.pbar.setValue(len(self.task.success)) self.change_status() def update_task(self, task: DownloadTask): self.task = task self.update_task_signa.emit()
class CalibrateWizard(QWizard): def __init__(self, parent): super().__init__(parent) self.parent = parent self.setWizardStyle(QWizard.WizardStyle.ModernStyle) # CREATE PAGE 1, LINE EDIT, TITLES buttons_layout = [QWizard.WizardButton.NextButton] self.page1 = QWizardPage() self.page1.setTitle('Select the exercises you wish to do later') self.page1.setSubTitle( 'Below are listed all the available and selected exercises by you.' ) self.listSelection = TwoListSelection() # listSelection.addAvailableItems(["item-{}".format(i) for i in range(5)]) hLayout1 = QHBoxLayout(self.page1) hLayout1.addWidget(self.listSelection) # CREATE PAGE 2, LABEL, TITLES self.page2 = QWizardPage() self.page2.setFinalPage(True) self.setButtonLayout(buttons_layout) self.page2.setTitle('Calibrate every exercise') self.page2.setSubTitle( 'Do every exercise once, record after pressing button.') self.contentLayout = QVBoxLayout(self.page2) self.hLayout2 = QHBoxLayout() # Create progress bar, buttons self.actionsLayout = QHBoxLayout() self.finishButton = QPushButton('Ready') self.finishButton.setStyleSheet(CustomQStyles.buttonStyle) self.finishButton.setFixedSize(120, 35) self.progress = QProgressBar() self.progress.setRange(0, 1) self.actionsLayout.addWidget(self.progress) self.actionsLayout.setAlignment(self.progress, Qt.Alignment.AlignBottom) self.actionsLayout.addWidget(self.finishButton) self.actionsLayout.setAlignment(self.finishButton, Qt.Alignment.AlignBottom) self.contentLayout.addLayout(self.hLayout2) self.contentLayout.addLayout(self.actionsLayout) self.actionsLayout.setContentsMargins(15, 35, 15, 0) itemsTextList = [ str(self.listSelection.mInput.item(i).text()) for i in range(self.listSelection.mInput.count()) ] print("items:", itemsTextList) self.button(QWizard.WizardButton.NextButton).clicked.connect( self.onWizardNextButton) self.finishButton.clicked.connect(self.onWizardFinishButton) self.addPage(self.page1) self.addPage(self.page2) # Recording data self.buttons = [] self.images = [] self.labels = [] self.exerciseLayouts = [] self.recordReady = [] self.recordThread = RecordThread(self.parent.classifyExercises) # Training recorded data self.trained = False self.trainThread = TrainThread(self.parent.classifyExercises) self.trainThread.taskFinished.connect(self.onTrainFinished) # Send list to next page def onWizardNextButton(self): self.setPage(1, self.page1) self.trained = False itemsTextList = [ str(self.listSelection.mInput.item(i).text()) for i in range(self.listSelection.mInput.count()) ] # Update list if self.parent.classifyExercises is not None: self.parent.classifyExercises.UpdateExerciseList(itemsTextList) # Set elements on UI self.setMinimumWidth(len(itemsTextList) * 200) self.deleteItemsOfLayout(self.hLayout2) self.images.clear() self.labels.clear() self.buttons.clear() self.recordReady.clear() for x, i in zip(itemsTextList, range(len(itemsTextList))): self.exerciseLayouts.append(QVBoxLayout()) self.buttons.append(QPushButton('Record')) self.recordReady.append(False) image = QLabel() image.setPixmap( QPixmap(os.getcwd() + "/resources/images/" + itemsTextList[i] + ".png")) self.labels.append(QLabel(itemsTextList[i])) self.images.append(image) self.buttons[i].setFixedSize(100, 35) self.buttons[i].clicked.connect( functools.partial(self.onRecordExerciseButtonClicked, x, i)) self.buttons[i].setStyleSheet(CustomQStyles.outlineButtonStyle) self.exerciseLayouts[i].addWidget(self.labels[i]) self.exerciseLayouts[i].addWidget(self.images[i]) self.exerciseLayouts[i].addWidget(self.buttons[i]) self.exerciseLayouts[i].setAlignment(self.labels[i], Qt.Alignment.AlignCenter) self.exerciseLayouts[i].setAlignment(self.images[i], Qt.Alignment.AlignCenter) self.exerciseLayouts[i].setAlignment(self.buttons[i], Qt.Alignment.AlignCenter) self.hLayout2.addLayout(self.exerciseLayouts[i]) def onRecordExerciseButtonClicked(self, exercise, ind): print("Recording - ", exercise) if self.parent.classifyExercises is not None: self.recordThread.exercise = exercise self.recordThread.taskFinished.connect( functools.partial(self.recordFinished, exercise, ind), Qt.ConnectionType.SingleShotConnection) self.recordThread.start() self.recordReady[ind] = False self.buttons[ind].setStyleSheet(CustomQStyles.recordButtonStyle) self.images[ind].setPixmap( QPixmap(os.getcwd() + "/resources/images/" + exercise + ".png")) def recordFinished(self, exercise, index): imagePath = os.getcwd() + "/resources/images/" + exercise + ".png" if self.recordThread.result == 0: imagePath = os.getcwd( ) + "/resources/images/" + exercise + "-fail.png" elif self.recordThread.result == 1: imagePath = os.getcwd( ) + "/resources/images/" + exercise + "-success.png" self.recordReady[index] = True else: print("None.") self.images[index].setPixmap(QPixmap(imagePath)) self.buttons[index].setStyleSheet(CustomQStyles.outlineButtonStyle) print(self.recordReady) def onWizardFinishButton(self): if all(x == True for x in self.recordReady): print("All recorded!") if not self.trained: if self.parent.classifyExercises is not None: self.progress.setRange(0, 0) # indefinite progress bar self.parent.classifyExercises.SaveProcessedData() self.parent.classifyExercises.SavePatientData() self.parent.ui.loadPatientList() self.trainThread.start() else: self.close() else: print("Not all recorded!") def onTrainFinished(self): self.progress.setRange(0, 1) self.progress.setValue(1) self.trained = True CustomMessage.showDialog("Message", "Training model finished!", QMessageBox.StandardButtons.Ok) self.finishButton.setText('Finish') def deleteItemsOfLayout(self, layout): if layout is not None: while layout.count(): item = layout.takeAt(0) widget = item.widget() if widget is not None: widget.setParent(None) else: self.deleteItemsOfLayout(item.layout())