You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
330 lines
13 KiB
Python
330 lines
13 KiB
Python
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_())
|