Skip to content

Commit

Permalink
yt-dlp importer
Browse files Browse the repository at this point in the history
  • Loading branch information
jeanslack committed Jun 20, 2024
1 parent 5ab537d commit e926eec
Show file tree
Hide file tree
Showing 10 changed files with 189 additions and 49 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@ License: GPL3
Change Log:

+------------------------------------+
Sat, 15 June 2024 V.5.0.14
Thu, 20 June 2024 V.5.0.15

* Videomass now uses `hatchling` as the default build backend which replaces
`setuptools`.
* Improved startup configuration script.
* Created a new convenient `__about__` script to store program description
data which replace `msg_info`.
* New feature created that allows you to import the yt_dlp module externally,
replacing the one installed on your system or the one on your virtual
environment or the one on the standalone application (see #328) .

+------------------------------------+
Thu, 30 May 2024 V.5.0.14
Expand Down
5 changes: 4 additions & 1 deletion debian/changelog
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ videomass (5.0.15-1) UNRELEASED; urgency=medium
* Improved startup configuration script.
* Created a new convenient `__about__` script to store program description
data which replace `msg_info`.
* New feature created that allows you to import the yt_dlp module externally,
replacing the one installed on your system or the one on your virtual
environment or the one on the standalone application (see #328) .

-- Gianluca Pernigotto <[email protected]> Sat, 15 Jun 2024 14:00:00 +0200
-- Gianluca Pernigotto <[email protected]> Thu, 20 Jun 2024 17:00:00 +0200

videomass (5.0.14-1) UNRELEASED; urgency=medium

Expand Down
13 changes: 11 additions & 2 deletions videomass/gui_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
Author: Gianluca Pernigotto <[email protected]>
Copyleft - 2024 Gianluca Pernigotto <[email protected]>
license: GPL3
Rev: Jan.13.2023
Rev: June.19.2024
Code checker: flake8, pylint
This file is part of Videomass.
Expand Down Expand Up @@ -37,6 +37,7 @@
from videomass.vdms_sys.configurator import DataSource
from videomass.vdms_sys import app_const as appC
from videomass.vdms_utils.utils import del_filecontents
from videomass.vdms_sys.external_package import importer

# add translation macro to builtin similar to what gettext does
builtins.__dict__['_'] = wx.GetTranslation
Expand Down Expand Up @@ -121,7 +122,15 @@ def check_youtube_dl(self):
"""
msg = (_("To suppress this message on startup, please install "
"yt-dlp or disable it from the preferences."))
if self.appset['use-downloader']:

if self.appset['enable-ytdlp']:
if (self.appset['ytdlp-module-path']
and self.appset['ytdlp-usemodule']):
test = importer("yt_dlp", self.appset['ytdlp-module-path'])
if test:
wx.MessageBox(f"ERROR: {test}\n\n{msg}",
_('Videomass - Error!'), wx.ICON_ERROR)
return False
try:
import yt_dlp
self.appset['yt_dlp'] = True
Expand Down
137 changes: 104 additions & 33 deletions videomass/vdms_dialogs/preferences.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
Author: Gianluca Pernigotto <[email protected]>
Copyleft - 2024 Gianluca Pernigotto <[email protected]>
license: GPL3
Rev: Apr.19.2024
Rev: June.20.2024
Code checker: flake8, pylint
This file is part of Videomass.
Expand All @@ -28,6 +28,7 @@
import sys
import webbrowser
import wx
import wx.lib.agw.hyperlink as hpl
from videomass.vdms_utils.utils import detect_binaries
from videomass.vdms_io import io_tools
from videomass.vdms_sys.settings_manager import ConfigManager
Expand Down Expand Up @@ -208,17 +209,40 @@ def __init__(self, parent):
labytexec = wx.StaticText(tabThree, wx.ID_ANY, msg)
sizerytdlp.Add(labytexec, 0, wx.ALL | wx.EXPAND, 5)
msg = _('Use the executable for downloads rather than API')
self.ckbx_dlexe = wx.CheckBox(tabThree, wx.ID_ANY, (msg))
sizerytdlp.Add(self.ckbx_dlexe, 0, wx.LEFT | wx.TOP, 5)
self.ckbx_ytexe = wx.CheckBox(tabThree, wx.ID_ANY, (msg))
sizerytdlp.Add(self.ckbx_ytexe, 0, wx.LEFT | wx.TOP, 5)

self.btn_ytdlp = wx.Button(tabThree, wx.ID_ANY, _('Change'))
self.txtctrl_ytdlp = wx.TextCtrl(tabThree, wx.ID_ANY, "",
style=wx.TE_READONLY
)
self.btn_ytexec = wx.Button(tabThree, wx.ID_ANY, _('Change'))
self.txtctrl_ytexec = wx.TextCtrl(tabThree, wx.ID_ANY, "",
style=wx.TE_READONLY
)
gridytdlp = wx.BoxSizer(wx.HORIZONTAL)
sizerytdlp.Add(gridytdlp, 0, wx.EXPAND)
gridytdlp.Add(self.txtctrl_ytdlp, 1, wx.ALL, 5)
gridytdlp.Add(self.btn_ytdlp, 0, wx.RIGHT | wx.CENTER, 5)
gridytdlp.Add(self.txtctrl_ytexec, 1, wx.ALL, 5)
gridytdlp.Add(self.btn_ytexec, 0, wx.RIGHT | wx.CENTER, 5)
sizerytdlp.Add((0, 20))
msg = (_('Import module externally. The appropriate source directory '
'is required. Click on the link below\nto directly download '
'the latest version, then extract the tarball archive and '
'indicate the path to\nthe extracted directory here.'))
labytmod = wx.StaticText(tabThree, wx.ID_ANY, msg)
sizerytdlp.Add(labytmod, 0, wx.ALL | wx.EXPAND, 5)
url1 = ("https://github.com/yt-dlp/yt-dlp/releases/latest/"
"download/yt-dlp.tar.gz")
link1 = hpl.HyperLinkCtrl(tabThree, -1, url1, URL=(url1))
sizerytdlp.Add(link1, 0, wx.LEFT | wx.EXPAND, 15)
msg = _('Import yt-dlp externally')
self.ckbx_ytmod = wx.CheckBox(tabThree, wx.ID_ANY, (msg))
sizerytdlp.Add(self.ckbx_ytmod, 0, wx.LEFT | wx.TOP, 5)

self.btn_ytmod = wx.Button(tabThree, wx.ID_ANY, _('Change'))
self.txtctrl_ytmod = wx.TextCtrl(tabThree, wx.ID_ANY, "",
style=wx.TE_READONLY
)
gridytmod = wx.BoxSizer(wx.HORIZONTAL)
sizerytdlp.Add(gridytmod, 0, wx.EXPAND)
gridytmod.Add(self.txtctrl_ytmod, 1, wx.ALL, 5)
gridytmod.Add(self.btn_ytmod, 0, wx.RIGHT | wx.CENTER, 5)
tabThree.SetSizer(sizerytdlp)
notebook.AddPage(tabThree, "yt-dlp")

Expand Down Expand Up @@ -457,6 +481,7 @@ def __init__(self, parent):
labytdlp.SetFont(wx.Font(13, wx.DEFAULT, wx.NORMAL, wx.BOLD))
labytdescr.SetFont(wx.Font(11, wx.SWISS, wx.NORMAL, wx.NORMAL))
labytexec.SetFont(wx.Font(11, wx.SWISS, wx.NORMAL, wx.NORMAL))
labytmod.SetFont(wx.Font(11, wx.SWISS, wx.NORMAL, wx.NORMAL))
labappe.SetFont(wx.Font(13, wx.DEFAULT, wx.NORMAL, wx.BOLD))
labLog.SetFont(wx.Font(11, wx.SWISS, wx.NORMAL, wx.NORMAL))
labrem.SetFont(wx.Font(13, wx.DEFAULT, wx.NORMAL, wx.BOLD))
Expand All @@ -474,6 +499,7 @@ def __init__(self, parent):
labytdlp.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD))
labytdescr.SetFont(wx.Font(8, wx.SWISS, wx.NORMAL, wx.NORMAL))
labytexec.SetFont(wx.Font(8, wx.SWISS, wx.NORMAL, wx.NORMAL))
labytmod.SetFont(wx.Font(8, wx.SWISS, wx.NORMAL, wx.NORMAL))
labappe.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD))
labLog.SetFont(wx.Font(8, wx.SWISS, wx.NORMAL, wx.NORMAL))
labrem.SetFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD))
Expand Down Expand Up @@ -513,8 +539,10 @@ def __init__(self, parent):
self.Bind(wx.EVT_CHECKBOX, self.exeFFplay, self.ckbx_exeFFplay)
self.Bind(wx.EVT_BUTTON, self.open_path_ffplay, self.btn_ffplay)
self.Bind(wx.EVT_CHECKBOX, self.on_ytdlp_pref, self.ckbx_ytdlp)
self.Bind(wx.EVT_CHECKBOX, self.on_ytdlp_exec, self.ckbx_dlexe)
self.Bind(wx.EVT_BUTTON, self.open_path_ytdlp, self.btn_ytdlp)
self.Bind(wx.EVT_CHECKBOX, self.on_ytdlp_exec, self.ckbx_ytexe)
self.Bind(wx.EVT_BUTTON, self.open_path_ytdlp, self.btn_ytexec)
self.Bind(wx.EVT_CHECKBOX, self.on_ytdlp_module, self.ckbx_ytmod)
self.Bind(wx.EVT_BUTTON, self.open_path_ytmodule, self.btn_ytmod)
self.Bind(wx.EVT_COMBOBOX, self.on_Iconthemes, self.cmbx_icons)
self.Bind(wx.EVT_RADIOBOX, self.on_toolbarPos, self.rdbTBpref)
self.Bind(wx.EVT_COMBOBOX, self.on_toolbarSize, self.cmbx_iconsSize)
Expand Down Expand Up @@ -546,18 +574,23 @@ def current_settings(self):
self.ckbx_exitconfirm.SetValue(self.appdata['warnexiting'])
self.ckbx_logclr.SetValue(self.appdata['clearlogfiles'])
self.ckbx_trash.SetValue(self.settings['move_file_to_trash'])
self.ckbx_ytdlp.SetValue(self.settings['use-downloader'])
self.ckbx_dlexe.SetValue(self.settings['download-using-exec'])
self.txtctrl_ytdlp.SetValue(self.appdata['yt-dlp-executable-path'])
self.ckbx_ytdlp.SetValue(self.settings['enable-ytdlp'])
self.ckbx_ytexe.SetValue(self.settings['ytdlp-useexec'])
self.txtctrl_ytexec.SetValue(self.appdata['ytdlp-executable-path'])
self.ckbx_ytmod.SetValue(self.settings['ytdlp-usemodule'])
self.txtctrl_ytmod.SetValue(self.appdata['ytdlp-module-path'])
self.ckbx_exitapp.SetValue(self.appdata["auto_exit"])
self.ckbx_turnoff.SetValue(self.appdata["shutdown"])
self.txtctrl_sudo.SetValue(self.appdata.get("sudo_password", ''))
if self.ckbx_turnoff.GetValue():
if self.appdata['ostype'] != 'Windows':
self.labsudo.Enable(), self.txtctrl_sudo.Enable()

if not self.settings['download-using-exec']:
self.txtctrl_ytdlp.Disable(), self.btn_ytdlp.Disable()
if not self.settings['ytdlp-useexec']:
self.txtctrl_ytexec.Disable(), self.btn_ytexec.Disable()

if not self.settings['ytdlp-usemodule']:
self.txtctrl_ytmod.Disable(), self.btn_ytmod.Disable()

if not self.settings['move_file_to_trash']:
self.txtctrl_trash.Disable()
Expand Down Expand Up @@ -871,7 +904,7 @@ def on_ytdlp_pref(self, event):
"""
set yt-dlp preferences
"""
self.settings['use-downloader'] = self.ckbx_ytdlp.GetValue()
self.settings['enable-ytdlp'] = self.ckbx_ytdlp.GetValue()
if self.appdata['yt_dlp'] is not True:
self.appdata['yt_dlp'] = 'reload'
# --------------------------------------------------------------------#
Expand All @@ -881,27 +914,63 @@ def on_ytdlp_exec(self, event):
Sets whether to use yt-dlp as a Python
module or as an executable.
"""
self.settings['download-using-exec'] = self.ckbx_dlexe.GetValue()
if self.ckbx_dlexe.GetValue():
self.txtctrl_ytdlp.Enable(), self.btn_ytdlp.Enable()
self.settings['ytdlp-useexec'] = self.ckbx_ytexe.GetValue()
if self.ckbx_ytexe.GetValue():
self.txtctrl_ytexec.Enable(), self.btn_ytexec.Enable()
else:
self.txtctrl_ytdlp.Disable(), self.btn_ytdlp.Disable()
self.txtctrl_ytexec.Disable(), self.btn_ytexec.Disable()
# --------------------------------------------------------------------#

def open_path_ytdlp(self, event):
"""Indicates a new yt-dlp path-name"""
with wx.FileDialog(self, _("{} location").format(self.ytdlp),
"", "", "yt-dlp binary "
f"(*{self.ytdlp})|*{self.ytdlp}| "
f"All files (*.*)|*.*",
wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) as fdlg:
"""
Indicates a new yt-dlp executable path-name
"""
fmt = (f'*{self.ytdlp};*yt-dlp;')
wild = f"yt-dlp executable ({fmt})|{fmt}| All files (*.*)|*.*"
msg = _('Location of the «yt-dlp» executable')

with wx.FileDialog(self, msg, "", "", wildcard=wild,
style=wx.FD_OPEN
| wx.FD_FILE_MUST_EXIST) as fdlg:

if fdlg.ShowModal() == wx.ID_OK:
if os.path.basename(fdlg.GetPath()) == self.ytdlp:
self.txtctrl_ytdlp.Clear()
getpath = self.appdata['getpath'](fdlg.GetPath())
self.txtctrl_ytdlp.write(getpath)
self.settings['yt-dlp-executable-path'] = getpath
self.txtctrl_ytexec.Clear()
getpath = self.appdata['getpath'](fdlg.GetPath())
self.txtctrl_ytexec.write(getpath)
self.settings['ytdlp-executable-path'] = getpath
# --------------------------------------------------------------------#

def on_ytdlp_module(self, event):
"""
Enables external yt_dlp .
"""
self.settings['ytdlp-usemodule'] = self.ckbx_ytmod.GetValue()
if self.ckbx_ytmod.GetValue():
self.txtctrl_ytmod.Enable(), self.btn_ytmod.Enable()
else:
self.txtctrl_ytmod.Disable(), self.btn_ytmod.Disable()
self.txtctrl_ytmod.Clear()
self.settings['ytdlp-module-path'] = ""
# --------------------------------------------------------------------#

def open_path_ytmodule(self, event):
"""
Sets path to yt-dlp module. Note
"""
dlg = wx.DirDialog(self, _("Open yt-dlp source directory"),
"", wx.DD_DEFAULT_STYLE
)
if dlg.ShowModal() == wx.ID_OK:
self.txtctrl_ytmod.Clear()
getpath = self.appdata['getpath'](dlg.GetPath())
self.txtctrl_ytmod.AppendText(getpath)
self.settings['ytdlp-module-path'] = getpath
ytexec = os.path.join(getpath, 'yt-dlp')
if os.path.exists(ytexec) and os.path.isfile(ytexec):
self.txtctrl_ytexec.Clear()
self.txtctrl_ytexec.write(ytexec)
self.settings['ytdlp-executable-path'] = ytexec
dlg.Destroy()
# --------------------------------------------------------------------#

def on_Iconthemes(self, event):
Expand Down Expand Up @@ -1006,7 +1075,9 @@ def on_ok(self, event):
self.settings['trashdir_loc'] = self.appdata['trashdir_default']
self.retcode = (
self.settings['locale_name'] == self.appdata['locale_name'],
self.settings['use-downloader'] == self.appdata['use-downloader'],
self.settings['enable-ytdlp'] == self.appdata['enable-ytdlp'],
(self.settings['ytdlp-module-path']
== self.appdata['ytdlp-module-path']),
self.settings['icontheme'] == self.appdata['icontheme'],
self.settings['toolbarsize'] == self.appdata['toolbarsize'],
self.settings['toolbarpos'] == self.appdata['toolbarpos'])
Expand Down
2 changes: 1 addition & 1 deletion videomass/vdms_dialogs/wizard_dlg.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def write_changes(ffmpeg, ffplay, ffprobe, youtubedl, binfound):
dataread['ffmpeg_islocal'] = local
dataread['ffprobe_islocal'] = local
dataread['ffplay_islocal'] = local
dataread['use-downloader'] = youtubedl
dataread['enable-ytdlp'] = youtubedl

conf.write_options(**dataread)

Expand Down
2 changes: 1 addition & 1 deletion videomass/vdms_main/main_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -1806,7 +1806,7 @@ def youtubedl(self, event):
for yt-dlp GUI functionality.
"""
msg = None
if not self.appdata['use-downloader']:
if not self.appdata['enable-ytdlp']:
msg = _("yt-dlp is disabled. Check your preferences.")

elif self.appdata['yt_dlp'] == 'reload':
Expand Down
46 changes: 46 additions & 0 deletions videomass/vdms_sys/external_package.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# -*- coding: UTF-8 -*-
"""
Name: external_package.py
Porpose: finds and loads a module
Compatibility: Python3
Author: Gianluca Pernigotto <[email protected]>
Copyleft - 2024 Gianluca Pernigotto <[email protected]>
license: GPL3
Rev: June.19.2024
Code checker: flake8, pylint
This file is part of Videomass.
Videomass is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Videomass is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Videomass. If not, see <http://www.gnu.org/licenses/>.
"""
import sys
import importlib
import importlib.machinery
import importlib.util


def importer(pkg, path):
"""
An object that both finds and loads a module;
both a finder and loader object.
"""
spec = importlib.machinery.PathFinder().find_spec(pkg, [path])
try:
mod = importlib.util.module_from_spec(spec)
except AttributeError as err:
return err
sys.modules[pkg] = mod
spec.loader.exec_module(mod)
sys.modules[pkg] = importlib.import_module(pkg)
return None
Loading

0 comments on commit e926eec

Please sign in to comment.