aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesús <heckyel@hyperbola.info>2019-12-10 15:36:46 -0500
committerJesús <heckyel@hyperbola.info>2019-12-10 15:36:46 -0500
commit52e48f3a2941d9c1f0d29213095ed24586afa5cd (patch)
tree1faa49fbff70292670daf5a0b033dbc8701290a2
parent83c95f563bff9b716033c7994a330a9238b44447 (diff)
downloadhypervideo-gui-52e48f3a2941d9c1f0d29213095ed24586afa5cd.tar.lz
hypervideo-gui-52e48f3a2941d9c1f0d29213095ed24586afa5cd.tar.xz
hypervideo-gui-52e48f3a2941d9c1f0d29213095ed24586afa5cd.zip
update gitignore
-rw-r--r--flycheck_hypervideo_gui.py359
1 files changed, 0 insertions, 359 deletions
diff --git a/flycheck_hypervideo_gui.py b/flycheck_hypervideo_gui.py
deleted file mode 100644
index 5cc9c52..0000000
--- a/flycheck_hypervideo_gui.py
+++ /dev/null
@@ -1,359 +0,0 @@
-import sys
-import os
-import re
-
-from PyQt5.QtWidgets import *
-from PyQt5.QtGui import QIcon
-from PyQt5.QtCore import (
- pyqtSlot,
-)
-
-import threading
-import hypervideo
-import json
-
-__version__ = "0.1"
-__license__ = "GPL-3"
-
-__path__ = os.environ['HOME']
-__pathBASE__ = r'%s/.config/hypervideo_gui/' % __path__
-if not os.path.exists(__pathBASE__):
- os.makedirs(__pathBASE__)
-
-GUI_STATE_JSON_FILE = '%s/.config/hypervideo_gui/hypervideo_gui_state.json' % __path__
-
-if not GUI_STATE_JSON_FILE:
- f = open(GUI_STATE_JSON_FILE, "a+")
- f.close()
-
-
-class App(QMainWindow):
- """
- Simple applicaction for download using hypervideo
- """
- _VALID_URL = r"""^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\(\)\*\+,;=.]+$"""
-
- def __init__(self):
- super().__init__()
-
- gui_state = self.loadGUIState() # load GUI state from file, load default state if save file not found
- self.download_folder_list = gui_state['DownloadFolderList']
- self.default_video_formats_menu_items = ['Video/Audio - Best Quality', 'Audio Only - Best Quality', 'Detect All Available Formats']
-
- # initialize window dimensions
- self.left = 100
- self.top = 100
- self.width = 640
- self.height = 200
- self.setFixedSize(self.width, self.height)
-
- self.initUI()
-
- def on_button_clicked(self):
- msg = QMessageBox()
- msg.setWindowTitle('About us')
- msg.setText("<p align='center'>Written with Python3 and PyQt5<br>"
- "Version: %s <br> License: %s </p>" % (__version__, __license__))
- msg.setIcon(QMessageBox.Information)
- # msg.setInformativeText("Version: %s" % __version__)
-
- x = msg.exec_()
-
- def initUI(self):
- self.setWindowTitle('Simple Hypervideo Downloader GUI')
- self.setGeometry(self.left, self.top, self.width, self.height)
- # Initialize status bar
- self.statusBar().showMessage('Welcome to Simple Hypervideo Downloader GUI!')
-
- # Menu
- mainMenu = self.menuBar()
- fileMenu = mainMenu.addMenu('File')
- helpMenu = mainMenu.addMenu('Help')
-
- # Exit button
- exitButton = QAction('Exit', self)
- exitButton.setShortcut('Ctrl+Q')
- exitButton.setStatusTip('Exit application')
- exitButton.triggered.connect(self.close)
-
- # About button
- aboutButton = QAction('About', self)
- aboutButton.triggered.connect(self.on_button_clicked)
-
- # Adding buttons to Menu
- helpMenu.addAction(aboutButton)
- fileMenu.addAction(exitButton)
-
- # Create URL entry buttons and entry textbox
- urlEntryLabel = QLabel('Enter URL:')
- self.urlEntryText = QLineEdit()
- self.urlEntryText.setPlaceholderText('https://invidio.us/watch?v=8SdPLG-_wtA')
- # set default video to download
- # self.urlEntryText.setText('https://invidio.us/watch?v=8SdPLG-_wtA')
- # set up callback to update video formats when URL is changed
- self.urlEntryText.textChanged.connect(self.resetVideoFormats)
-
- # create output folder button and entry textbox
- outputFolderButton = QPushButton('Select Output Folder')
- outputFolderButton.setToolTip('Select output folder')
- outputFolderButton.clicked.connect(self.updateOutputFolder)
- self.outputEntryCombobox = QComboBox()
- self.outputEntryCombobox.setEditable(True)
-
- for item in self.download_folder_list:
- self.outputEntryCombobox.addItem(item) # set default output folder to be downloads folder
- # self.outputEntryCombobox.editTextChanged[str].connect(self.downloadTextChanged)
-
- # add combobox for video download format and detect formats button
- detectFormatsLabel = QLabel('Download Format:')
-
- self.videoFormatCombobox = QComboBox()
- self.populateVideoFormatCombobox(self.default_video_formats_menu_items) # set default values for format select combobox
- self.videoFormatCombobox.activated[str].connect(self.videoFormatChange)
-
- # add download button
- downloadButton = QPushButton('Download')
- downloadButton.clicked.connect(self.downloadVideo_callback)
-
- # create grid layout
- layout = QGridLayout()
-
- # add widgets to the layout
- layout.addWidget(urlEntryLabel, 1, 0)
- layout.addWidget(self.urlEntryText, 1, 1)
- layout.addWidget(outputFolderButton, 2, 0)
- layout.addWidget(self.outputEntryCombobox, 2, 1)
- layout.addWidget(detectFormatsLabel, 3, 0)
- layout.addWidget(self.videoFormatCombobox, 3, 1)
- layout.addWidget(downloadButton, 5, 0)
-
- # add grid layout as central widget for main window
- main_widget = QWidget()
- main_widget.setLayout(layout)
- self.setCentralWidget(main_widget)
-
- self.show()
-
- def url_entry(self):
- ''' Return URL EntryText'''
- url = self.urlEntryText.text()
- url = url.strip()
- return url
-
- def downloadVideo_callback(self):
- ''' Callback for the "Download Video" button
- '''
-
- def downloadVideo_thread_helper(self, ydl_opts):
- '''Download the video. Meant to be called in a background daemon thread
- '''
- with hypervideo.YoutubeDL(ydl_opts) as ydl:
- ydl.download([self.urlEntryText.text()])
-
- self.statusBar().showMessage('Downloading Video... Done!', msecs=0)
-
- # make sure a valid output directory was entered
- if not os.path.isdir(self.outputEntryCombobox.currentText()):
- self.statusBar().showMessage('Invalid download directory!')
- return
-
- # make sure the Download Folder List combobox is populated with the latest entry
- # this covers the case where the user uses the edittext portion of the combobox
- self.addItemToDownloadsCombobox(self.outputEntryCombobox.currentText())
-
- # set output path/format
- outtmpl = os.path.join(self.outputEntryCombobox.currentText(), r'%(title)s.%(ext)s')
-
- # create the youtube downloader options based on video format combobox selection
- if self.videoFormatCombobox.currentText() == self.default_video_formats_menu_items[0]:
- # download best video quality
- ydl_opts = {
- 'format': 'bestvideo+bestaudio/best',
- 'outtmpl': outtmpl,
- }
- elif self.videoFormatCombobox.currentText() == self.default_video_formats_menu_items[1]:
- # for downloading best audio and converting to mp3
- ydl_opts = {
- 'format': 'bestaudio/best',
- 'outtmpl': outtmpl,
- 'postprocessors': [{
- 'key': 'FFmpegExtractAudio',
- 'preferredcodec': 'mp3',
- 'preferredquality': '192', # not actually best quality...
- }],
- }
- else:
- # grab video format from the dropdown string: ie. "135 - some video metadata here" -> "135"
- video_format = self.videoFormatCombobox.currentText()[0:self.videoFormatCombobox.currentText().find('-')-1]
- # set output path/format
- outformat = os.path.join(self.outputEntryCombobox.currentText(), r'%(title)s.f%(format_id)s.%(ext)s')
- ydl_opts = {
- 'format': video_format,
- 'outtmpl': outformat,
- }
-
- # download the video in daemon thread
- if re.match(self._VALID_URL, str(self.url_entry())) is None:
- self.statusBar().showMessage('Please add a URL...') # update status bar
- else:
- self.statusBar().showMessage('Downloading Video...') # update status bar
- thread = threading.Thread(target=downloadVideo_thread_helper, args=(self, ydl_opts, ))
- thread.daemon = True
- thread.start()
-
- def updateVideoFormats(self):
- '''Grabs the list of available video formats in background thread and populates
- video format combobox with results when complete.
- '''
-
- def getVideoFormats_thread_helper(self, url):
- ''' Grabs the available video formats. Intended to be run as background thread.
- '''
- self.options = {
- 'format': 'best',
- 'noplaylist': True, # only download single song, not playlist
- }
-
- with hypervideo.YoutubeDL(self.options) as ydl:
- meta = ydl.extract_info(url, download=False)
- formats = meta.get('formats', [meta])
-
- # add formats to combobox
- item_list = self.default_video_formats_menu_items[0:2]
- item_list.extend([f['format_id'] + ' - ' + f['ext'] for f in formats])
- self.populateVideoFormatCombobox(item_list)
- self.statusBar().showMessage('Finished Downloading Video Formats')
- self.videoFormatCombobox.setCurrentIndex(0)
-
- # check if is valid url
- # should probably be reworked to be compatible with non-YouTube websites
- if re.match(self._VALID_URL, str(self.url_entry())) is None:
- self.populateVideoFormatCombobox(self.default_video_formats_menu_items)
- return
- else:
- # valid url - fetch the video formats in background daemon thread
- self.statusBar().showMessage('Downloading Video Formats')
- thread = threading.Thread(target=getVideoFormats_thread_helper, args=(self, str(self.url_entry()), ))
- thread.daemon = True
- thread.start()
-
- def videoFormatChange(self, text):
- if text == self.default_video_formats_menu_items[2]:
- # detect video formats was selected
-
- # update statusbar to let user know something is happening
- self.statusBar().showMessage('Loading available formats...')
- # update video formats
- self.updateVideoFormats()
-
- def populateVideoFormatCombobox(self, labels):
- '''Populate the video format combobox with video formats. Clear the previous labels.
- labels {list} -- list of strings representing the video format combobox options
- '''
- self.videoFormatCombobox.clear()
- for label in labels:
- self.videoFormatCombobox.addItem(label)
-
- def resetVideoFormats(self):
- idx = self.videoFormatCombobox.currentIndex()
-
- self.populateVideoFormatCombobox(self.default_video_formats_menu_items)
-
- # preserve combobox index if possible
- if idx > 1:
- self.videoFormatCombobox.setCurrentIndex(0)
- else:
- self.videoFormatCombobox.setCurrentIndex(idx)
-
- @pyqtSlot()
- def updateOutputFolder(self):
- ''' Callback for "Update Output Folder" button. Allows user to select
- output directory via standard UI.
- '''
- file = str(QFileDialog.getExistingDirectory(self, "Select Directory"))
-
- if len(file) > 0:
- self.addItemToDownloadsCombobox(file)
- else:
- self.statusBar().showMessage('Select a folder!')
-
- def downloadTextChanged(self, text):
- # function not used right now
- if text not in self.download_folder_list and os.path.isdir(text):
- self.addItemToDownloadsCombobox(text)
-
- def addItemToDownloadsCombobox(self, text):
- if text not in self.download_folder_list:
- # if it's not in the list, add it to the list
- self.download_folder_list = [text]+self.download_folder_list
- else:
- # if it's in the list already, move it to the top of the list
- self.download_folder_list = [text]+[folder for folder in self.download_folder_list if not folder == text]
-
- # maximum download folder history of 5
- if len(self.download_folder_list) > 5:
- self.download_folder_list = self.download_folder_list[0:6]
-
- # update the combobox
- self.outputEntryCombobox.clear()
- for item in self.download_folder_list:
- self.outputEntryCombobox.addItem(item)
-
- self.outputEntryCombobox.setCurrentIndex(0) # reset index - just in case
-
- def saveGUIState(self):
- save_dict = {'DownloadFolderList': self.download_folder_list, }
-
- with open(GUI_STATE_JSON_FILE, 'w') as file:
- json.dump(save_dict, file)
-
- def loadGUIState(self):
- if os.path.isfile(GUI_STATE_JSON_FILE):
- with open(GUI_STATE_JSON_FILE, 'r') as file:
- save_data = json.load(file)
-
- if isinstance(save_data['DownloadFolderList'], str):
- # convert to list
- save_data['DownloadFolderList'] = [save_data['DownloadFolderList']]
-
- else:
- save_data = {'DownloadFolderList': [get_default_download_path()], }
-
- return save_data
-
- def closeEvent(self, event):
- '''This function gets called when the user closes the GUI.
- It saves the GUI state to the json file
- GUI_STATE_JSON_FILE.
- '''
- self.saveGUIState()
-
- close = QMessageBox()
- close.setIcon(QMessageBox.Question)
- close.setWindowTitle('Exit')
- close.setText('You sure?')
- close.setStandardButtons(QMessageBox.Yes | QMessageBox.Cancel)
- close = close.exec()
-
- if close == QMessageBox.Yes:
- event.accept()
- else:
- event.ignore()
-
-
-def get_default_download_path():
- """Returns the path for the "Downloads" folder in GNU
- Used as default directory for videos to be saved to.
- #From: https://stackoverflow.com/questions/35851281/python-finding-the-users-downloads-folder
- """
- if os.name == 'posix':
- dpath = '/tmp/hypervideo-gui/'
- if not os.path.exists(dpath):
- os.makedirs(dpath)
- return os.path.join(dpath)
-
-if __name__ == '__main__':
- app = QApplication(sys.argv)
- app.setStyle('Fusion')
- ex = App()
- sys.exit(app.exec_())