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 Ui_TrainPanel(object): def setupUi(self, TrainPanel): self.parent = TrainPanel self.mainLayout = QHBoxLayout(TrainPanel) self.bigFont = QLabel().font() self.bigFont.setPointSize(13) self.actionsLayout = QHBoxLayout(TrainPanel) # self.checkRecording = QCheckBox(TrainPanel) self.calibrateButton = QPushButton("Calibrate", parent=TrainPanel) self.calibrateButton.setFont(self.bigFont) self.calibrateButton.setStyleSheet(CustomQStyles.buttonStyle) self.calibrateButton.setMinimumHeight(50) self.calibrateButton.setMaximumWidth(170) self.calibrateButton.setMinimumWidth(120) self.sessionButton = QPushButton("Session", parent=TrainPanel) self.sessionButton.setFont(self.bigFont) self.sessionButton.setStyleSheet(CustomQStyles.outlineButtonStyle) self.sessionButton.setMinimumHeight(50) self.sessionButton.setMaximumWidth(170) self.sessionButton.setMinimumWidth(120) self.listFiles = QListWidget(TrainPanel) self.listFiles.setFont(self.bigFont) self.label = QLabel('or select', parent=TrainPanel) self.subjectLayout = QVBoxLayout(TrainPanel) print("init") self.box1 = QGroupBox(parent=TrainPanel) self.box2 = QGroupBox(parent=TrainPanel) self.wizard = CalibrateWizard(parent=TrainPanel) self.setPatientsBox(TrainPanel) # right panel self.setActionsBox(TrainPanel) # left panel self.mainLayout.addWidget(self.box1, stretch=2) self.mainLayout.addWidget(self.box2, stretch=3) # self.mainLayout.setAlignment(self.box2, Qt.Alignment.AlignCenter) # Display progress bar, checkbox - to record new gestures or not, start train def setActionsBox(self, TrainPanel): hLayout = QVBoxLayout() hLayout.addWidget(self.calibrateButton) hLayout.addWidget(self.sessionButton) hLayout.setAlignment(self.calibrateButton, Qt.Alignment.AlignCenter) hLayout.setAlignment(self.sessionButton, Qt.Alignment.AlignCenter) self.box2.setLayout(hLayout) # Display list of subjects, or new subject def setPatientsBox(self, TrainPanel): # Button to create new patient self.addPatient = QPushButton('Create Patient') self.addPatient.setFixedSize(120, 35) self.addPatient.setStyleSheet(CustomQStyles.outlineButtonStyle) self.label.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) self.label.setAlignment(QtCore.Qt.Alignment.AlignCenter) self.loadPatientList() self.listFiles.setStyleSheet(CustomQStyles.listStyle) self.listFiles.setFocusPolicy(Qt.FocusPolicy.NoFocus) self.subjectLayout.addWidget(self.addPatient) self.subjectLayout.setAlignment(self.addPatient, Qt.Alignment.AlignCenter) self.subjectLayout.addWidget(self.label) self.subjectLayout.addWidget(self.listFiles) self.box1.setLayout(self.subjectLayout) def loadPatientList(self): self.listFiles.clear() self.parent.patients.clear() files = [ f for f in listdir(PATIENTS_PATH) if isfile(join(PATIENTS_PATH, f)) ] for x, ind in zip(files, range(0, len(files))): item = QListWidgetItem(x.split('.')[0]) item.setTextAlignment(Qt.Alignment.AlignHCenter) self.listFiles.addItem(item) with open(PATIENTS_PATH + x, 'r') as f: person_dict = json.load(f) patient = Patient(person_dict['Name'], person_dict['Age'], person_dict['Exercises']) self.parent.patients.append(patient) print(self.parent.patients) 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())