Skip to content

Commit

Permalink
add auto-exit & shutdown
Browse files Browse the repository at this point in the history
  • Loading branch information
jeanslack committed May 13, 2024
1 parent bfcbb55 commit d9e3986
Show file tree
Hide file tree
Showing 10 changed files with 549 additions and 205 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@ License: GPL3
Change Log:

+------------------------------------+
Thu, 10 May 2024 V.5.0.13
Mon, 13 May 2024 V.5.0.13

* [YouTube Downloader] Fix `--playlist-items` using executable.
* [YouTube Downloader] Improved playlists/channels check before start
download.
* Update english user guide documentation (pdf docs) and related references.
* Fixed wrong deinterlace command option using w3fdif filter.
* [YouTube Downloader] Fixed audio/video qualities (see #305 #307)
* Added shutdown system and auto-exit the application. These settings are
found on the "Exit and Shutdown" tab of Preferences dialog (see #306).

+------------------------------------+
Mon, 29 Apr 2024 V.5.0.12
Expand Down
4 changes: 3 additions & 1 deletion debian/changelog
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ videomass (5.0.13-1) UNRELEASED; urgency=medium
* Update english user guide documentation (pdf docs) and related references.
* Fixed wrong deinterlace command option using w3fdif filter.
* [YouTube Downloader] Fixed audio/video qualities (see #305 #307)
* Added shutdown system and auto-exit the application. These settings are
found on the "Exit and Shutdown" tab of Preferences dialog (see #306).

-- Gianluca Pernigotto <[email protected]> Fri, 10 May 2024 13:00:00 +0200
-- Gianluca Pernigotto <[email protected]> Mon, 13 May 2024 14:00:00 +0200

videomass (5.0.12-1) UNRELEASED; urgency=medium

Expand Down
383 changes: 230 additions & 153 deletions videomass/vdms_dialogs/preferences.py

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions videomass/vdms_dialogs/showlogs.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class ShowLogs(wx.Dialog):
'generic_task.log',
'YouTube Downloader.log',
'Queue Processing.log',
'Shutdown.log',
)

def __init__(self, parent, dirlog, OS):
Expand Down
87 changes: 87 additions & 0 deletions videomass/vdms_dialogs/widget_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,3 +157,90 @@ def getMessage(self, status):
# self.Destroy() # do not work
# self.ai.Stop()
self.EndModal(1)


class CountDownDlg(wx.Dialog):
"""
This dialog notifies the user that something will happen
when the countdown expires, e.g. exiting the application
or shutting down the system.
At the end of the countdown this dialogue will
self-destroy and events will be allowed to continue unless
the user clicks on the cancel button.
Usage:
dlg = CountDownDlg(self,
timeout=10,
message='Something happens in {0} seconds',
caption='My awesome title'
)
res = dlg.ShowModal() == wx.ID_OK
dlg.Destroy()
if res:
...other code here
"""
get = wx.GetApp() # get data from bootstrap
APPICON = get.iconset['videomass']
TIMER_INTERVAL = 1000 # milliseconds

def __init__(self, parent, timeout, message, caption):
"""
parent: -1 to make parent, use 'None' otherwise
timeout: time second (int)
message: a message including the format {0} (str)
caption: title for caption (str)
"""
wx.Dialog.__init__(self, parent, -1, style=wx.DEFAULT_DIALOG_STYLE)

self.timeout = timeout
self.message = message

# ------ Add widget controls
sizbase = wx.BoxSizer(wx.VERTICAL)
sizbase.Add((0, 20), 0)
self.msgtxt = wx.StaticText(self, wx.ID_ANY,
self.message.format(self.timeout),
style=wx.ALIGN_CENTRE_VERTICAL
)
sizbase.Add(self.msgtxt, 1, wx.ALL | wx.ALIGN_CENTRE, 5)
# ------ bottom layout buttons
sizbott = wx.BoxSizer(wx.HORIZONTAL)
btn_cancel = wx.Button(self, wx.ID_CANCEL, "")
sizbott.Add(btn_cancel, 0)
btn_ok = wx.Button(self, wx.ID_OK)
sizbott.Add(btn_ok, 0, wx.LEFT, 5)
sizbase.Add(sizbott, 0, wx.ALL | wx.ALIGN_RIGHT | wx.RIGHT, border=5)
# ------ Properties
icon = wx.Icon()
icon.CopyFromBitmap(wx.Bitmap(CountDownDlg.APPICON,
wx.BITMAP_TYPE_ANY))
self.SetIcon(icon)
self.SetTitle(caption)
self.SetMinSize((400, 150))
self.SetSizer(sizbase)
sizbase.Fit(self)
self.Layout()
self.Center()

self.timer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.on_timer, self.timer)
self.timer.Start(self.TIMER_INTERVAL)
# ------------------------------------------------------------------#

def autodestroy(self):
"""
stop the timer and destroy this dialog.
"""
self.timer.Stop()
return self.Destroy()

# ----------------------Event handler (callback)----------------------#

def on_timer(self, event):
"""
Set the timer countdown on message
"""
self.timeout -= 1
self.msgtxt.SetLabel(self.message.format(self.timeout))
if self.timeout <= 0:
self.EndModal(wx.ID_OK)
157 changes: 112 additions & 45 deletions videomass/vdms_main/main_frame.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.09.2024
Rev: May.11.2024
Code checker: flake8, pylint
This file is part of Videomass.
Expand Down Expand Up @@ -46,6 +46,7 @@
from videomass.vdms_dialogs.mediainfo import MediaStreams
from videomass.vdms_dialogs.showlogs import ShowLogs
from videomass.vdms_dialogs.ffmpeg_help import FFmpegHelp
from videomass.vdms_dialogs.widget_utils import CountDownDlg
from videomass.vdms_miniframes import timeline
from videomass.vdms_panels import choose_topic
from videomass.vdms_panels import filedrop
Expand All @@ -60,6 +61,7 @@
from videomass.vdms_sys.settings_manager import ConfigManager
from videomass.vdms_sys.argparser import info_this_platform
from videomass.vdms_utils.utils import copydir_recursively
from videomass.vdms_threads.shutdown import shutdown_system


class MainFrame(wx.Frame):
Expand Down Expand Up @@ -358,35 +360,11 @@ def destroy_orphaned_window(self):
self.audivolnormalize = False
# ------------------------------------------------------------------#

def on_close(self, event):
def write_option_before_exit(self):
"""
Where possible, it destroys the application and
its children programmatically, saving the size
and position of the window.
Write user settings to the configuration file
before exit the application.
"""
if self.ProcessPanel.IsShown():
if self.ProcessPanel.thread_type is not None:
wx.MessageBox(_('There are still processes running. if you '
'want to stop them, use the "Abort" button.'),
_('Videomass - Warning!'), wx.ICON_WARNING, self)
return

if self.appdata['warnexiting']:
if wx.MessageBox(_('Are you sure you want to exit '
'the application?'),
_('Exit'), wx.ICON_QUESTION | wx.CANCEL
| wx.YES_NO, self) != wx.YES:
return

if self.ytdlframe:
if self.ytdlframe.ProcessPanel.thread_type:
wx.MessageBox(_("There are still active windows with running "
"processes, make sure you finish your work "
"before closing them."),
"Videomass - Warning!", wx.ICON_WARNING, self)
return
self.ytdlframe.on_exit(self, warn=False)

confmanager = ConfigManager(self.appdata['fileconfpath'])
sett = confmanager.read_options()
sett['main_window_size'] = list(self.GetSize())
Expand All @@ -406,27 +384,71 @@ def on_close(self, event):
]
sett['filedrop_column_width'] = filedropcolwidth
confmanager.write_options(**sett)
self.destroy_orphaned_window()
self.Destroy()
# ------------------------------------------------------------------#

def on_Kill(self):
def checks_running_processes(self):
"""
This method tries to destroy the application and its
children more directly than the `on_close` method above.
Note that this method may also be called from the `Setup()`
method.
Check currently running processes
"""
if self.ProcessPanel.IsShown():
if self.ProcessPanel.thread_type is not None:
return True
if self.ytdlframe:
if self.ytdlframe.ProcessPanel.thread_type:
wx.MessageBox(_("There are still active windows with running "
"processes, make sure you finish your work "
"before closing them."),
"Videomass - Warning!", wx.ICON_WARNING, self)
return True

return False
# ------------------------------------------------------------------#

def on_close(self, event, ):
"""
Application exit request given by the user.
"""
if self.checks_running_processes():
wx.MessageBox(_("There are still active windows with running "
"processes, make sure you finish your work "
"before exit."),
_('Videomass - Warning!'), wx.ICON_WARNING, self)
return

if self.appdata['warnexiting']:
if wx.MessageBox(_('Are you sure you want to exit '
'the application?'),
_('Exit'), wx.ICON_QUESTION | wx.CANCEL
| wx.YES_NO, self) != wx.YES:
return
self.ytdlframe.destroy_orphaned_window()

if self.ytdlframe:
self.ytdlframe.on_exit(self, warn=False)
self.write_option_before_exit()
self.destroy_orphaned_window()
self.destroy_application()
# ------------------------------------------------------------------#

def on_Kill(self):
"""
This method is called after from the `Setup()` method.
"""
if self.checks_running_processes():
wx.MessageBox(_("There are still active windows with running "
"processes, make sure you finish your work "
"before exit."),
_('Videomass - Warning!'), wx.ICON_WARNING, self)
return

if self.ytdlframe:
self.ytdlframe.on_exit(self, warn=False)
self.destroy_orphaned_window()
self.destroy_application()
# ------------------------------------------------------------------#

def destroy_application(self):
"""
Permanent exit from the application.
Do not use this method directly.
"""
self.Destroy()
# ------------------------------------------------------------------#

# ------------- BUILD THE MENU BAR ----------------###

Expand Down Expand Up @@ -1090,11 +1112,6 @@ def Setup(self, event):
changes = set_up.getvalue()
self.fileDnDTarget.on_file_save(self.appdata['outputdir'])
if [x for x in changes if x is False]:
if self.ProcessPanel.IsShown():
if self.ProcessPanel.thread_type is not None:
wx.MessageBox(msg, _('Videomass - Warning!'),
wx.ICON_WARNING, self)
return
if wx.MessageBox(_("{0}\n\nDo you want to restart "
"the application now?").format(msg),
_('Restart Videomass?'), wx.ICON_QUESTION
Expand Down Expand Up @@ -1757,6 +1774,11 @@ def process_terminated(self, msg):
self.rename.Enable(True)
if self.file_src:
self.rename_batch.Enable(True)

if self.appdata['shutdown']:
self.auto_shutdown()
elif self.appdata['auto_exit']:
self.auto_exit()
# ------------------------------------------------------------------#

def panelShown(self, panelshown=None):
Expand Down Expand Up @@ -1799,3 +1821,48 @@ def youtubedl(self, event):
self.ytdlframe = MainYtdl(self.appdata,
parent=wx.GetTopLevelParent(self))
self.ytdlframe.Show()
# ------------------------------------------------------------------#

def auto_shutdown(self):
"""
Turn off the system when processing is finished
"""
if self.checks_running_processes():
return
if self.ytdlframe:
self.ytdlframe.on_exit(self, warn=False)
self.write_option_before_exit()

msgdlg = 'The system will turn off in {0} seconds'
title = _('Videomass - Shutdown!')
dlg = CountDownDlg(self, timeout=59, message=msgdlg, caption=title)
res = dlg.ShowModal() == wx.ID_OK
dlg.Destroy()
if res:
succ = shutdown_system(self.appdata['sudo_password'])
if not succ:
msg = (_("Error while shutting down. Please see\" "
"Shutdown.log\" file for details."))
self.statusbar_msg(msg,
self.appdata['colorscheme']['ERR1'],
'#fbf4f4')
# ------------------------------------------------------------------#

def auto_exit(self):
"""
Auto-exit the application when processing is finished
"""
if self.checks_running_processes():
return

msgdlg = 'Exiting the application in {0} seconds'
title = _('Videomass - Exiting!')
dlg = CountDownDlg(self, timeout=10, message=msgdlg, caption=title)
res = dlg.ShowModal() == wx.ID_OK
dlg.Destroy()
if res:
if self.ytdlframe:
self.ytdlframe.on_exit(self, warn=False)
self.write_option_before_exit()
self.destroy_orphaned_window()
self.destroy_application()
20 changes: 19 additions & 1 deletion videomass/vdms_sys/settings_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,21 @@ class ConfigManager:
Options description:
shutdown (bool):
If True turn off the system when operation is finished.
Name space only, the setting will not be stored in the
configuration file.
sudo_password (str):
SUDO password for the shutdown process if the user does
not have elevated privileges. Name space only, the setting
will not be stored in the configuration file.
auto_exit (bool):
exit the application programmatically when processing is
finished. Name space only, the setting will not be stored
in the configuration file.
confversion (float):
current version of this configuration file
Expand Down Expand Up @@ -200,8 +215,11 @@ class ConfigManager:
column width in the format code panel (ytdownloader).
"""
VERSION = 7.5
VERSION = 7.7
DEFAULT_OPTIONS = {"confversion": VERSION,
"shutdown": False,
"sudo_password": "",
"auto_exit": False,
"encoding": "utf-8",
"outputdir": f"{os.path.expanduser('~')}",
"outputdir_asinput": False,
Expand Down
Loading

0 comments on commit d9e3986

Please sign in to comment.