from PyQt5 import QtWidgets as qtw from PyQt5 import QtGui as qtg from PyQt5 import QtCore as qtc from pytube import Playlist, YouTube, exceptions import sys import os from range_slider import RangeSlider from PyQt5.QtWidgets import QApplication, QGridLayout, QWidget, QListWidget, QVBoxLayout, QLabel, QPushButton, QListWidgetItem, \ QHBoxLayout #Todo ersetzen durch QNetworkRequest and QNetworkReply -> soll besser und sicherer funktionieren da urllib blocken kann from urllib.request import urlopen import urllib.request import resources class QYTVidItem(qtw.QWidget): def __init__(self, parent=None): super(QYTVidItem, self).__init__(parent) sizePolicy = qtw.QSizePolicy(qtw.QSizePolicy.Expanding, qtw.QSizePolicy.Minimum) #self.sizePolicy = qtw.QSizePolicy(qtw.QSizePolicy.Maximum, qtw.QSizePolicy.Maximum) #sizePolicy.setHeightForWidth(messageformForm.sizePolicy().hasHeightForWidth()) #self.sizePolicy.setHorizontalStretch(True) self.setSizePolicy(sizePolicy) self.vid_layout = qtw.QHBoxLayout() self.vidDetailLayout = qtw.QVBoxLayout() self.vidHeaderLayout = qtw.QHBoxLayout() self.vidSpecsLayout = qtw.QHBoxLayout() self.vidStartEndLayout = qtw.QHBoxLayout() self.buttonLayout = qtw.QHBoxLayout() self.buttonLayout.setSizeConstraint(qtw.QLayout.SizeConstraint.SetMinimumSize) self.title = "" self.url = "" self.currentFormat = 'mp4' self.currentRes = 'best' self.defaultThumbPix = qtg.QPixmap(":/assets/bagi_default.png") #debug -> Rosa hintergrund für Size test pal = qtg.QPalette() pal.setColor(qtg.QPalette.Background, qtg.QColor(218, 94, 242)) self.setPalette(pal) self.setAutoFillBackground(True) def setData(self,purl): print("setdata for: {}".format(purl)) self.url = purl.strip() errTxt = self.checkLink(purl) if (errTxt != "OK"): return errTxt # Youtube vid infos laden #debug #purl = "https://www.youtube.com/watch?v=Lrj2Hq7xqQ8" self.yt_vid = YouTube(url=purl) print("Url Found. Title:{}".format(self.yt_vid.title)) self.title = self.yt_vid.title #url = "https://i.ytimg.com/vi/Lrj2Hq7xqQ8/maxresdefault.jpg" thumbNail_url = self.yt_vid.thumbnail_url thumbPixmap = qtg.QPixmap() try: #wenn thumbnail url ungültig oder nicht geladen werden konnte -> default setzen request = urllib.request.Request(thumbNail_url) response = urllib.request.urlopen(request) data = response.read() thumbPixmap.loadFromData(data) except Exception: self.thumbPixmap.load(":/assets/bragi_default.png") ##Linke Seite: # Thumbnail des Videos (oder default wenn keins vorhanden) icoLabel = qtw.QLabel() icoLabel.setPixmap(thumbPixmap.scaled(150,150,aspectRatioMode=qtc.Qt.KeepAspectRatio)) self.vid_layout.addWidget(icoLabel) ##Rechte Seite des Widgets # Oberste Reihe: # Titel, btn_edit, btn_remove self.title_edit = qtw.QLineEdit(self.yt_vid.title) self.title_edit.setReadOnly(True) self.vidHeaderLayout.addWidget(self.title_edit) #self.vidHeaderLayout.addStretch() pixmap_edit = qtg.QPixmap(":/assets/edit.svg") icon_edit = qtg.QIcon(pixmap_edit.scaled(50,50,aspectRatioMode=qtc.Qt.KeepAspectRatio)) self.btn_edit = qtw.QToolButton() self.btn_edit.setIcon(icon_edit) self.btn_edit.clicked.connect(self.toggleTitleEditable) self.vidHeaderLayout.addWidget(self.btn_edit) pixmap_remove = qtg.QPixmap(":/assets/cancel2.svg") icon_remove = qtg.QIcon(pixmap_remove.scaled(50,50,aspectRatioMode=qtc.Qt.KeepAspectRatio)) self.btn_remove = qtw.QToolButton() self.btn_remove.setIcon(icon_remove) self.vidHeaderLayout.addWidget(self.btn_remove) self.vidDetailLayout.addItem(self.vidHeaderLayout) # Mittlere Reihe: # Video Specs dur_time = self.yt_vid.length duration = qtw.QLabel("Duration: {} sec".format(dur_time)) self.vidSpecsLayout.addWidget(duration) #self.vidSpecsLayout.addStretch() self.vidDetailLayout.addItem(self.vidSpecsLayout) # vorletze reihe: # Start/Ende Marker self.vidStartEndLayout.setContentsMargins(5,0,5,0) self.vidStartEndLayout.setSpacing(10); self.vidStartEndLayout.setAlignment(qtc.Qt.AlignLeft) slider = RangeSlider(qtc.Qt.Horizontal) slider.setMinimumHeight(10) slider.setMaximumWidth(200) slider.setMinimum(0) slider.setMaximum(dur_time) slider.setLow(0) slider.setHigh(dur_time) slider.setTickPosition(qtw.QSlider.TicksBelow) slider.sliderMoved.connect(self.updateSliderVal) #QtCore.QObject.connect(slider, QtCore.SIGNAL('sliderMoved(int)'), echo) slider.show() slider.raise_() self.vidStartEndLayout.addWidget(slider) #self.vidStartEndLayout.addStretch() vid_start_txt = qtw.QLabel("start at(sec):") vid_start_txt.setAlignment(qtc.Qt.AlignLeft|qtc.Qt.AlignVCenter) self.vidStartEndLayout.addWidget(vid_start_txt) lowVal = slider.low() self.vid_start = qtw.QLabel(str(lowVal)) self.vid_start.setAlignment(qtc.Qt.AlignLeft|qtc.Qt.AlignVCenter) self.vidStartEndLayout.addWidget(self.vid_start) vid_end_txt = qtw.QLabel("end at(sec):") vid_end_txt.setAlignment(qtc.Qt.AlignLeft|qtc.Qt.AlignVCenter) self.vidStartEndLayout.addWidget(vid_end_txt) highVal = slider.high() self.vid_end = qtw.QLabel(str(highVal)) self.vidStartEndLayout.addWidget(self.vid_end) self.vidStartEndLayout.setAlignment(qtc.Qt.AlignLeft|qtc.Qt.AlignVCenter) self.vidDetailLayout.addItem(self.vidStartEndLayout) # Unterste Reihe: # Combobox für Streamauswahl + # Video spezifische Buttons (ordentliche pics) #self.buttonLayout.setContentsMargins(5,0,5,0) self.buttonLayout.setSpacing(10); self.buttonLayout.setAlignment(qtc.Qt.AlignLeft) self.format_combo = qtw.QComboBox() self.format_combo.addItem('mp4(Video)') self.format_combo.addItem('mp3(Audio)') self.format_combo.setCurrentIndex(0) self.buttonLayout.addWidget(self.format_combo) self.resolution_combo = qtw.QComboBox() #print(self.yt_vid.streams[0].itag) for stream in self.yt_vid.streams: print("{}\n".format(stream)) #self.resolution_combo.addItem(stream.value) self.buttonLayout.addWidget(self.resolution_combo) #self.buttonLayout.addStretch() pixmap_play = qtg.QPixmap(":/assets/play2.svg") icon_play = qtg.QIcon() icon_play.addPixmap(pixmap_play.scaled(50,50,aspectRatioMode=qtc.Qt.KeepAspectRatio)) btn_play = qtw.QToolButton() #btn_play.setPixmap(pixmap_play.scaled(25,25,aspectRatioMode=qtc.Qt.KeepAspectRatio)) btn_play.setIcon(icon_play) btn_play.clicked.connect(self.playItem) self.buttonLayout.addWidget(btn_play) pixmap_stop = qtg.QPixmap(":/assets/stop2.svg") icon_stop = qtg.QIcon() icon_stop.addPixmap(pixmap_stop.scaled(50,50,aspectRatioMode=qtc.Qt.KeepAspectRatio)) btn_stop = qtw.QToolButton() #btn_stop.setPixmap(pixmap_stop.scaled(25,25,aspectRatioMode=qtc.Qt.KeepAspectRatio)) btn_stop.setIcon(icon_stop) btn_play.clicked.connect(self.stopItem) self.buttonLayout.addWidget(btn_stop) pixmap_download = qtg.QPixmap(":/assets/download.svg") icon_download = qtg.QIcon() icon_download.addPixmap(pixmap_download.scaled(50,50,aspectRatioMode=qtc.Qt.KeepAspectRatio)) self.btn_download = qtw.QToolButton() #btn_download.setPixmap(pixmap_download.scaled(25,25,aspectRatioMode=qtc.Qt.KeepAspectRatio)) self.btn_download.setIcon(icon_download) #self.btn_download.clicked.connect(self.downloadItem) self.buttonLayout.addWidget(self.btn_download) self.vidDetailLayout.addItem(self.buttonLayout) #Layouts zusammenfügen und setzen self.vid_layout.addItem(self.vidDetailLayout) #self.vid_layout.setSizeConstraint() self.setLayout(self.vid_layout) return errTxt def toggleTitleEditable(self): if self.title_edit.isReadOnly(): self.title_edit.setReadOnly(False) self.title_edit.selectAll() self.btn_download.setEnabled(False) pixmap_edit = qtg.QPixmap(":/assets/check.svg") icon_edit = qtg.QIcon(pixmap_edit.scaled(50,50,aspectRatioMode=qtc.Qt.KeepAspectRatio)) self.btn_edit.setIcon(icon_edit) else: self.title_edit.deselect() self.title_edit.setReadOnly(True) self.btn_download.setEnabled(True) pixmap_edit = qtg.QPixmap(":/assets/edit.svg") icon_edit = qtg.QIcon(pixmap_edit.scaled(50,50,aspectRatioMode=qtc.Qt.KeepAspectRatio)) self.btn_edit.setIcon(icon_edit) def toggleFormatResolution(self): if self.currentFormat == 'mp4': pass else: pass def updateSliderVal(self,low_value, high_value): self.vid_start.setText(str(low_value)) self.vid_end.setText(str(high_value)) def playItem(self): pass def stopItem(self): pass def downloadItem(self,path): #self.yt_vid.streams.get_by_itag(251).download(path) # download the file out_file = self.yt_vid.streams.get_highest_resolution().download(output_path=path) # save the file base, ext = os.path.splitext(out_file) print("base:{}".format(base)) new_file = base + '.mp4' print("new:{}".format(new_file)) os.rename(out_file, new_file) print("Download Triggered") def checkLink(self,url):#done try: yttest = YouTube(url) yttest.check_availability() return "OK" except exceptions.RegexMatchError: errTxt = "Video Link invalid({}). Link is no valid url.".format(url) print(errTxt) return errTxt except exceptions.MembersOnly: errTxt = "Video Link invalid({}). Only available to Members of that group.".format(url) print(errTxt) return errTxt except exceptions.RecordingUnavailable: errTxt = "Video Link invalid({}). Live-Stream not available.".format(url) print(errTxt) return errTxt except exceptions.VideoRegionBlocked: errTxt = "Video Link invalid({}). Not available in your region.".format(url) print(errTxt) return errTxt except exceptions.VideoPrivate: errTxt = "Video Link invalid({}). Video is set to private.".format(url) print(errTxt) return errTxt except exceptions.VideoUnavailable: errTxt = "Video Link invalid({}).".format(url) print(errTxt) return errTxt else: return "OK" if __name__ == '__main__': #Zum testen des Widget-Designs app = QApplication(sys.argv) window = QWidget() title = QLabel("Demo for widgets in a QListWidget") scrollA = qtw.QScrollArea() scrollLayout = QGridLayout() item_1 =QYTVidItem() item_2 =QYTVidItem() item_3 =QYTVidItem() scrollLayout.addWidget(item_1,scrollLayout.count(),0) item_1.setData("https://www.youtube.com/watch?v=Lrj2Hq7xqQ8") scrollLayout.addWidget(item_2,scrollLayout.count(),0) item_2.setData("https://www.youtube.com/watch?v=lL7jwhWAU_k") #scrollLayout.addWidget(item_3) scrollA.setLayout(scrollLayout) window_layout = QVBoxLayout(window) window_layout.addWidget(title) window_layout.addWidget(scrollA) window.setLayout(window_layout) window.show() sys.exit(app.exec_())