1788 lines
50 KiB
Python
1788 lines
50 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
#
|
|
# Copyright (C) 2019-2021 A S Lewis
|
|
#
|
|
# This program 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.
|
|
#
|
|
# This program 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
|
|
# this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
"""Wizard window classes."""
|
|
|
|
|
|
# Import Gtk modules
|
|
import gi
|
|
gi.require_version('Gtk', '3.0')
|
|
from gi.repository import Gtk, GObject, Gdk, GdkPixbuf
|
|
|
|
|
|
# Import other modules
|
|
import os
|
|
import re
|
|
|
|
|
|
# Import our modules
|
|
import __main__
|
|
import formats
|
|
import mainapp
|
|
import utils
|
|
# Use same gettext translations
|
|
from mainapp import _
|
|
|
|
|
|
# Classes
|
|
|
|
|
|
class GenericWizWin(Gtk.Window):
|
|
|
|
"""Generic Python class for windows in which the user can modify various
|
|
system settings.
|
|
|
|
Unlike classes inheriting from GenericEditWin, widgets are arranged in
|
|
pages, with only page visible at a time. The user can cycle through pages
|
|
(when allowed) by clicking the 'Next' or 'Previous' buttons.
|
|
|
|
Modifications are usually applied immediately, but the code provides an
|
|
.apply_changes() function for anything that should be applied, when the
|
|
user has cycled through all the pages.
|
|
"""
|
|
|
|
|
|
# Standard class methods
|
|
|
|
|
|
# def __init__(): # Provided by child object
|
|
|
|
|
|
# Public class methods
|
|
|
|
|
|
def is_duplicate(self, app_obj):
|
|
|
|
"""Called by self.__init__.
|
|
|
|
Don't open this wizard window, if another wizard window (if any class)
|
|
is already open.
|
|
|
|
Args:
|
|
|
|
app_obj (mainapp.TartubeApp): The main application object
|
|
|
|
Return values:
|
|
|
|
True if a duplicate is found, False if not
|
|
|
|
"""
|
|
|
|
if app_obj.main_win_obj.wiz_win_obj:
|
|
|
|
# Duplicate found
|
|
app_obj.main_win_obj.wiz_win_obj.present()
|
|
return True
|
|
|
|
else:
|
|
|
|
# Not a duplicate
|
|
return False
|
|
|
|
|
|
def setup(self):
|
|
|
|
"""Called by self.__init__().
|
|
|
|
Sets up the wizard window when it opens.
|
|
"""
|
|
|
|
# Set the default window size
|
|
self.set_default_size(
|
|
self.app_obj.config_win_width,
|
|
self.app_obj.config_win_height,
|
|
)
|
|
|
|
# Set the window's Gtk icon list
|
|
self.set_icon_list(self.app_obj.main_win_obj.win_pixbuf_list)
|
|
|
|
# Set up main widgets
|
|
self.setup_grid()
|
|
self.setup_button_strip()
|
|
|
|
# Set up the first page (a widget layout on self.inner_grid)
|
|
self.setup_page()
|
|
|
|
# Procedure complete
|
|
self.show_all()
|
|
|
|
# Inform the main window of this window's birth (so that Tartube
|
|
# doesn't allow an operation to start until all configuration windows
|
|
# have closed)
|
|
self.app_obj.main_win_obj.add_child_window(self)
|
|
|
|
# Add a callback so we can inform the main window of this window's
|
|
# destruction
|
|
self.connect('destroy', self.close)
|
|
|
|
|
|
def setup_grid(self):
|
|
|
|
"""Called by self.setup().
|
|
|
|
Sets up two Gtk.Grids. The first one contains an inner grid, and a
|
|
button strip.
|
|
"""
|
|
|
|
box = Gtk.Box()
|
|
self.add(box)
|
|
box.set_border_width(self.spacing_size)
|
|
|
|
self.grid = Gtk.Grid()
|
|
box.add(self.grid)
|
|
self.grid.set_row_spacing(self.spacing_size)
|
|
self.grid.set_column_spacing(self.spacing_size)
|
|
|
|
frame = Gtk.Frame()
|
|
self.grid.attach(frame, 0, 0, 1, 1)
|
|
frame.set_hexpand(True)
|
|
frame.set_vexpand(True)
|
|
|
|
self.vbox = Gtk.VBox()
|
|
frame.add(self.vbox)
|
|
self.vbox.set_border_width(self.spacing_size * 2)
|
|
|
|
self.inner_grid = Gtk.Grid()
|
|
self.vbox.pack_start(self.inner_grid, True, False, 0)
|
|
self.inner_grid.set_row_spacing(self.spacing_size)
|
|
self.inner_grid.set_column_spacing(self.spacing_size)
|
|
|
|
|
|
def setup_button_strip(self):
|
|
|
|
"""Called by self.setup().
|
|
|
|
Creates a strip of buttons at the bottom of the window: a 'cancel'
|
|
button on the left, and 'next'/'previous' buttons on the right.
|
|
|
|
The window is closed by using the 'cancel' button, or by clicking the
|
|
'next' button on the last page.
|
|
"""
|
|
|
|
hbox = Gtk.HBox()
|
|
self.grid.attach(hbox, 0, 1, 1, 1)
|
|
|
|
# 'Cancel' button
|
|
self.cancel_button = Gtk.Button(_('Cancel'))
|
|
hbox.pack_start(self.cancel_button, False, False, 0)
|
|
self.cancel_button.get_child().set_width_chars(10)
|
|
self.cancel_button.set_tooltip_text(
|
|
_('Close this window without completing it'),
|
|
);
|
|
self.cancel_button.connect('clicked', self.on_button_cancel_clicked)
|
|
|
|
# 'Next' button
|
|
self.next_button = Gtk.Button(_('Next'))
|
|
hbox.pack_end(self.next_button, False, False, 0)
|
|
self.next_button.get_child().set_width_chars(10)
|
|
self.next_button.set_tooltip_text(_('Go to the next page'));
|
|
self.next_button.connect('clicked', self.on_button_next_clicked)
|
|
|
|
# 'Previous' button
|
|
self.prev_button = Gtk.Button(_('Previous'))
|
|
hbox.pack_end(self.prev_button, False, False, self.spacing_size)
|
|
self.prev_button.get_child().set_width_chars(10)
|
|
self.prev_button.set_tooltip_text(_('Go to the previous page'));
|
|
self.prev_button.connect('clicked', self.on_button_prev_clicked)
|
|
|
|
|
|
def setup_page(self):
|
|
|
|
"""Called initially by self.setup(), then by .on_button_next_clicked()
|
|
or .on_button_prev_clicked().
|
|
|
|
Sets up the page specified by self.current_page.
|
|
"""
|
|
|
|
index = self.current_page
|
|
page_func = self.page_list[self.current_page]
|
|
if page_func is None:
|
|
|
|
# Emergency fallback
|
|
index = 0
|
|
page_func = self.page_list[0]
|
|
|
|
if len(self.page_list) <= 1:
|
|
self.next_button.set_sensitive(False)
|
|
self.prev_button.set_sensitive(False)
|
|
elif index == 0:
|
|
self.next_button.set_sensitive(True)
|
|
self.prev_button.set_sensitive(False)
|
|
else:
|
|
self.next_button.set_sensitive(True)
|
|
self.prev_button.set_sensitive(True)
|
|
|
|
if index >= len(self.page_list) - 1:
|
|
self.next_button.set_label(_('OK'))
|
|
else:
|
|
self.next_button.set_label(_('Next'))
|
|
|
|
self.next_button.get_child().set_width_chars(10)
|
|
|
|
# Replace the inner grid...
|
|
self.vbox.remove(self.inner_grid)
|
|
|
|
self.inner_grid = Gtk.Grid()
|
|
self.vbox.pack_start(self.inner_grid, True, False, 0)
|
|
self.inner_grid.set_row_spacing(self.spacing_size)
|
|
self.inner_grid.set_column_spacing(self.spacing_size)
|
|
|
|
# ...and then refill it, with the widget layout for the new page
|
|
method = getattr(self, page_func)
|
|
method()
|
|
|
|
self.show_all()
|
|
|
|
|
|
def convert_next_button(self):
|
|
|
|
"""Can be called by anything.
|
|
|
|
Converts the 'Next' to an 'OK' button, and sensitises it.
|
|
|
|
Should usually be called from the last page, when the code is ready to
|
|
let the window finish the wizard.
|
|
"""
|
|
|
|
self.next_button.set_label(_('Finish'))
|
|
self.next_button.get_child().set_width_chars(10)
|
|
self.next_button.set_sensitive(True)
|
|
|
|
|
|
def apply_changes(self):
|
|
|
|
"""Called by self.on_button_next_clicked().
|
|
|
|
The default function is empty. Any changes that need to be applied,
|
|
when the wizard window closes, can be applied in a function with this
|
|
name.
|
|
"""
|
|
|
|
pass
|
|
|
|
|
|
def reset_changes(self):
|
|
|
|
"""Called by self.on_button_cancel_clicked().
|
|
|
|
The default function is empty. Any changes that need to be applied,
|
|
when the wizard window is closed by clicking the 'Cancel' button, can
|
|
be applied in a function with this name.
|
|
"""
|
|
|
|
pass
|
|
|
|
|
|
def close(self, widget):
|
|
|
|
"""Called from callback in self.setup().
|
|
|
|
Inform the main application that this window is closing.
|
|
|
|
Args:
|
|
|
|
widget (GenericWizWin): This window
|
|
|
|
"""
|
|
|
|
self.app_obj.main_win_obj.del_child_window(self)
|
|
|
|
|
|
# (Add widgets)
|
|
|
|
|
|
def add_image(self, image_path, x, y, wid, hei):
|
|
|
|
"""Called by various functions in the child wizard window.
|
|
|
|
Adds a Gtk.Image to self.inner_grid, with more than the usual padding.
|
|
|
|
Args:
|
|
|
|
image_path (str): Full path to the image file to load
|
|
|
|
x, y, wid, hei (int): Position on the grid at which the widget is
|
|
placed
|
|
|
|
Returns:
|
|
|
|
The Gtk.Box containing the image
|
|
|
|
"""
|
|
|
|
box = Gtk.Box()
|
|
self.inner_grid.attach(box, x, y, wid, hei)
|
|
box.set_border_width(self.spacing_size * 2)
|
|
|
|
image = Gtk.Image()
|
|
box.add(image)
|
|
image.set_from_pixbuf(
|
|
self.app_obj.file_manager_obj.load_to_pixbuf(image_path),
|
|
)
|
|
image.set_hexpand(True)
|
|
|
|
return box
|
|
|
|
|
|
def add_label(self, text, x, y, wid, hei):
|
|
|
|
"""Called by various functions in the child wizard window.
|
|
|
|
Adds a Gtk.Label to self.inner_grid.
|
|
|
|
Args:
|
|
|
|
text (str): Pango markup displayed in the label
|
|
|
|
x, y, wid, hei (int): Position on the grid at which the widget is
|
|
placed
|
|
|
|
Returns:
|
|
|
|
The label widget created
|
|
|
|
"""
|
|
|
|
label = Gtk.Label()
|
|
self.inner_grid.attach(label, x, y, wid, hei)
|
|
label.set_markup(text)
|
|
label.set_hexpand(True)
|
|
label.set_alignment(0.5, 0.5)
|
|
|
|
return label
|
|
|
|
|
|
def add_empty_label(self, x, y, wid, hei):
|
|
|
|
"""Called by various functions in the child wizard window.
|
|
|
|
Adds an empty Gtk.Label (for spacing) to self.inner_grid.
|
|
|
|
Args:
|
|
|
|
x, y, wid, hei (int): Position on the grid at which the widget is
|
|
placed
|
|
|
|
Returns:
|
|
|
|
The label widget created
|
|
|
|
"""
|
|
|
|
label = Gtk.Label()
|
|
self.inner_grid.attach(label, x, y, wid, hei)
|
|
# (Using a space, rather than an empty string, better preserves the
|
|
# intended layout)
|
|
label.set_text(' ')
|
|
label.set_hexpand(True)
|
|
label.set_alignment(0.5, 0.5)
|
|
|
|
return label
|
|
|
|
|
|
def add_radiobutton(self, prev_button, text, x, y, wid, hei):
|
|
|
|
"""Called by various functions in the child wizard window.
|
|
|
|
Adds a Gtk.RadioButton to self.inner_grid.
|
|
|
|
Args:
|
|
|
|
prev_button (Gtk.RadioButton or None): When this is the first
|
|
radio button in the group, None. Otherwise, the previous
|
|
radio button in the group. Use of this argument links the radio
|
|
buttons together, ensuring that only one of them can be active
|
|
at any time
|
|
|
|
text (string or None): The text to display in the radiobutton's
|
|
label. No label is used if 'text' is an empty string or None
|
|
|
|
x, y, wid, hei (int): Position on the grid at which the widget is
|
|
placed
|
|
|
|
Returns:
|
|
|
|
The radiobutton widget created
|
|
|
|
"""
|
|
|
|
radiobutton = Gtk.RadioButton.new_from_widget(prev_button)
|
|
self.inner_grid.attach(radiobutton, x, y, wid, hei)
|
|
radiobutton.set_hexpand(True)
|
|
if text is not None and text != '':
|
|
radiobutton.set_label(text)
|
|
|
|
return radiobutton
|
|
|
|
|
|
def add_textview(self, x, y, wid, hei):
|
|
|
|
"""Called by various functions in the child wizard window.
|
|
|
|
Adds a Gtk.TextView to self.inner_grid.
|
|
|
|
Args:
|
|
|
|
x, y, wid, hei (int): Position on the grid at which the widget is
|
|
placed
|
|
|
|
Returns:
|
|
|
|
The scroller, textview and textbuffer widgets created
|
|
|
|
"""
|
|
|
|
frame = Gtk.Frame()
|
|
self.inner_grid.attach(frame, x, y, wid, hei)
|
|
|
|
scrolled = Gtk.ScrolledWindow()
|
|
frame.add(scrolled)
|
|
scrolled.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
|
|
scrolled.set_size_request(-1, 150)
|
|
|
|
textview = Gtk.TextView()
|
|
scrolled.add(textview)
|
|
textview.set_wrap_mode(Gtk.WrapMode.WORD)
|
|
textview.set_editable(False)
|
|
textview.set_cursor_visible(False)
|
|
|
|
return scrolled, textview, textview.get_buffer()
|
|
|
|
|
|
# Callback class methods
|
|
|
|
|
|
def on_button_cancel_clicked(self, button):
|
|
|
|
"""Called from a callback in self.setup_button_strip().
|
|
|
|
Closes the wizard window without applying any changes.
|
|
|
|
Args:
|
|
|
|
button (Gtk.Button): The widget clicked
|
|
|
|
"""
|
|
|
|
self.reset_changes()
|
|
self.destroy()
|
|
|
|
|
|
def on_button_next_clicked(self, button):
|
|
|
|
"""Called from a callback in self.setup_button_strip().
|
|
|
|
Goes to the the next page, or (if already on the last page) applies
|
|
any changes waiting to be applied, then closes the window.
|
|
|
|
Args:
|
|
|
|
button (Gtk.Button): The widget clicked
|
|
|
|
"""
|
|
|
|
if self.current_page >= (len(self.page_list) - 1):
|
|
self.apply_changes()
|
|
self.destroy()
|
|
|
|
else:
|
|
|
|
self.current_page += 1
|
|
self.setup_page()
|
|
|
|
|
|
def on_button_prev_clicked(self, button):
|
|
|
|
"""Called from a callback in self.setup_button_strip().
|
|
|
|
Goes to the previous page.
|
|
|
|
Args:
|
|
|
|
button (Gtk.Button): The widget clicked
|
|
|
|
"""
|
|
|
|
if self.current_page > 0:
|
|
self.current_page -= 1
|
|
self.setup_page()
|
|
|
|
|
|
class SetupWizWin(GenericWizWin):
|
|
|
|
"""Python class for a 'wizard window' displayed when Tartube starts and
|
|
no config file can be loaded (meaning that this is a new installation).
|
|
|
|
Args:
|
|
|
|
app_obj (mainapp.TartubeApp): The main application object
|
|
|
|
"""
|
|
|
|
|
|
# Standard class methods
|
|
|
|
|
|
def __init__(self, app_obj):
|
|
|
|
Gtk.Window.__init__(self, title=_('Tartube setup'))
|
|
|
|
if self.is_duplicate(app_obj):
|
|
return
|
|
|
|
# IV list - class objects
|
|
# -----------------------
|
|
# The mainapp.TartubeApp object
|
|
self.app_obj = app_obj
|
|
|
|
|
|
# IV list - Gtk widgets
|
|
# ---------------------
|
|
self.grid = None # Gtk.Grid
|
|
self.vbox = None # Gtk.VBox
|
|
self.inner_grid = None # Gtk.Grid
|
|
self.cancel_button = None # Gtk.Button
|
|
self.next_button = None # Gtk.Button
|
|
self.prev_button = None # Gtk.Button
|
|
# (Textbuffers used to display output of an update operation, and the
|
|
# buttons used to initiate that operation)
|
|
self.downloader_button = None # Gtk.Button
|
|
self.update_button = None # Gtk.Button
|
|
self.update_combo = None # Gtk.ComboBox
|
|
self.update_liststore = None # Gtk.ListStore
|
|
self.downloader_scrolled = None # Gtk.ScrolledWindow
|
|
self.downloader_textview = None # Gtk.TextView
|
|
self.downloader_textbuffer = None # Gtk.TextBuffer
|
|
self.ffmpeg_button = None # Gtk.Button
|
|
self.ffmpeg_scrolled = None # Gtk.ScrolledWindow
|
|
self.ffmpeg_textview = None # Gtk.TextView
|
|
self.ffmpeg_textbuffer = None # Gtk.TextBuffer
|
|
|
|
# IV list - other
|
|
# ---------------
|
|
# Size (in pixels) of gaps between preference window widgets
|
|
self.spacing_size = self.app_obj.default_spacing_size
|
|
|
|
# Make the code a little simpler, by checking for MS Windows just once
|
|
# (set below)
|
|
self.mswin_flag = False
|
|
|
|
# List of 'pages' (widget layouts on self.inner_grid). Each item in the
|
|
# list is the function to call
|
|
self.page_list = [] # Set below
|
|
# The number of the current page (the first is 0), matching an index in
|
|
# self.page_list
|
|
self.current_page = 0
|
|
|
|
# User choices; they are applied when the window is closed (and
|
|
# self.apply_changes() is called)
|
|
# Path to Tartube's data directory
|
|
self.data_dir = None
|
|
# The name of the youtube-dl fork to use, by default ('None' when
|
|
# youtube-dl itself should be used)
|
|
self.ytdl_fork = None
|
|
# The new value of mainapp.TartubeApp.ytdl_update_current(), if any.
|
|
self.ytdl_update_current = None
|
|
|
|
# Flag set to True, once the 'More options' button has been clicked,
|
|
# so that it is never visible again
|
|
self.more_options_flag = False
|
|
|
|
# Code
|
|
# ----
|
|
|
|
# Check for MS Windows
|
|
if os.name == 'nt':
|
|
|
|
self.mswin_flag = True
|
|
|
|
# Set the page list, which depends on operating system and packaging
|
|
self.page_list = [
|
|
'setup_start_page',
|
|
'setup_db_page',
|
|
'setup_set_downloader_page',
|
|
]
|
|
|
|
if self.mswin_flag:
|
|
self.page_list.append('setup_fetch_downloader_page')
|
|
self.page_list.append('setup_fetch_ffmpeg_page')
|
|
self.page_list.append('setup_finish_page_mswin')
|
|
|
|
elif __main__.__pkg_strict_install_flag__:
|
|
self.page_list.append('setup_finish_page_strict')
|
|
|
|
else:
|
|
self.page_list.append('setup_fetch_downloader_page')
|
|
self.page_list.append('setup_finish_page_default')
|
|
|
|
# Set up the wizard window
|
|
self.setup()
|
|
|
|
|
|
# Public class methods
|
|
|
|
|
|
# def is_duplicate(): # Inherited from GenericWizWin
|
|
|
|
|
|
# def setup(): # Inherited from GenericWizWin
|
|
|
|
|
|
# def setup_grid(): # Inherited from GenericWizWin
|
|
|
|
|
|
# def setup_button_strip(): # Inherited from GenericWizWin
|
|
|
|
|
|
# def setup_page(): # Inherited from GenericWizWin
|
|
|
|
|
|
# def convert_next_button(): # Inherited from GenericWizWin
|
|
|
|
|
|
def apply_changes(self):
|
|
|
|
"""Called by self.on_button_next_clicked().
|
|
|
|
Apply the settings the user has specified.
|
|
"""
|
|
|
|
if self.data_dir is not None:
|
|
self.app_obj.set_data_dir(self.data_dir)
|
|
self.app_obj.set_data_dir_alt_list( [ self.data_dir ] )
|
|
self.app_obj.update_data_dirs()
|
|
|
|
# (None values are acceptable)
|
|
self.app_obj.set_ytdl_fork(self.ytdl_fork)
|
|
|
|
# (A None value, only if it hasn't been changed)
|
|
if self.ytdl_update_current is not None:
|
|
self.app_obj.set_ytdl_update_current(self.ytdl_update_current)
|
|
|
|
# Continue with general initialisation
|
|
self.app_obj.open_wiz_win_continue()
|
|
|
|
|
|
def reset_changes(self):
|
|
|
|
"""Called by self.on_button_cancel_clicked().
|
|
|
|
Tartube needs to be shut down (unless an update operation is running,
|
|
in which case we stop it.)
|
|
"""
|
|
|
|
if self.app_obj.update_manager_obj:
|
|
|
|
self.app_obj.update_manager_obj.stop_update_operation()
|
|
|
|
else:
|
|
|
|
# (Prevent the shutdown code from saving the config file and/or
|
|
# database)
|
|
self.app_obj.disable_load_save()
|
|
|
|
# (Delete the config file, so that this window will appear again,
|
|
# the next time Tartube runs)
|
|
config_path = self.app_obj.get_config_path()
|
|
if os.path.isfile(config_path):
|
|
os.remove(config_path)
|
|
|
|
# Shut down Tartube
|
|
self.app_obj.stop()
|
|
|
|
|
|
# def close(): # Inherited from GenericWizWin
|
|
|
|
|
|
# (Setup pages)
|
|
|
|
|
|
def setup_start_page(self):
|
|
|
|
"""Called by self.setup_page().
|
|
|
|
Sets up the widget layout for a page.
|
|
"""
|
|
|
|
self.add_image(
|
|
self.app_obj.main_win_obj.icon_dict['system_icon'],
|
|
0, 0, 1, 1,
|
|
)
|
|
|
|
self.add_label(
|
|
'<span font_size="large" font_weight="bold">' \
|
|
+ _('Welcome to Tartube!') + '</span>',
|
|
0, 1, 1, 1,
|
|
)
|
|
|
|
if __main__.__pkg_no_download_flag__:
|
|
|
|
edition = _('Video downloads are disabled in this package')
|
|
|
|
elif __main__.__pkg_strict_install_flag__:
|
|
|
|
edition = _(
|
|
'For this package, youtube-dl(c) and FFmpeg must be' \
|
|
+ ' installed separately',
|
|
)
|
|
|
|
elif __main__.__pkg_install_flag__:
|
|
|
|
edition = _('Package edition')
|
|
|
|
elif os.name == 'nt':
|
|
|
|
edition = _('MS Windows edition')
|
|
|
|
else:
|
|
|
|
edition = _('Standard edition')
|
|
|
|
self.add_label(
|
|
'<span style="italic">' + edition + '</span>',
|
|
0, 2, 1, 1,
|
|
)
|
|
|
|
# (Empty label for spacing)
|
|
self.add_empty_label(0, 3, 1, 1)
|
|
|
|
self.add_label(
|
|
'<span font_size="large" style="italic">' \
|
|
+ _('Please take a few moments to set up the application') \
|
|
+ '</span>',
|
|
0, 4, 1, 1,
|
|
)
|
|
|
|
self.add_label(
|
|
'<span font_size="large" style="italic">' \
|
|
+ _('Click the <b>Next</b> button to get started') \
|
|
+ '</span>',
|
|
0, 5, 1, 1,
|
|
)
|
|
|
|
|
|
def setup_db_page(self):
|
|
|
|
"""Called by self.setup_page().
|
|
|
|
Sets up the widget layout for a page.
|
|
"""
|
|
|
|
grid_width = 3
|
|
|
|
self.add_label(
|
|
'<span font_size="large" style="italic">' \
|
|
+ _('Tartube stores all of its downloads in one place.') \
|
|
+ '</span>',
|
|
0, 0, grid_width, 1,
|
|
)
|
|
|
|
# (Empty label for spacing)
|
|
self.add_empty_label(0, 1, grid_width, 1)
|
|
|
|
if not self.mswin_flag:
|
|
|
|
msg = utils.tidy_up_long_string(
|
|
_(
|
|
'If you don\'t want to use the default location, then' \
|
|
+ ' click <b>Choose</b> to select a different one.',
|
|
),
|
|
60,
|
|
)
|
|
|
|
msg2 = utils.tidy_up_long_string(
|
|
_(
|
|
'If you have used Tartube before, you can select an' \
|
|
+ ' existing directory, instead of creating a new one.',
|
|
),
|
|
60,
|
|
)
|
|
|
|
else:
|
|
|
|
msg = _('Click <b>Choose</b> to create a new folder.')
|
|
msg2 = utils.tidy_up_long_string(
|
|
_(
|
|
'If you have used Tartube before, you can select an' \
|
|
+ ' existing folder, instead of creating a new one.',
|
|
),
|
|
60,
|
|
)
|
|
|
|
self.add_label(
|
|
'<span font_size="large" style="italic">' + msg + '</span>',
|
|
0, 2, grid_width, 1,
|
|
)
|
|
|
|
# (Empty label for spacing)
|
|
self.add_empty_label(0, 3, grid_width, 1)
|
|
|
|
self.add_label(
|
|
'<span font_size="large" style="italic">' + msg2 + '</span>',
|
|
0, 4, grid_width, 1,
|
|
)
|
|
|
|
# (Empty label for spacing)
|
|
self.add_empty_label(0, 5, grid_width, 1)
|
|
|
|
button = Gtk.Button(_('Choose'))
|
|
self.inner_grid.attach(button, 1, 6, 1, 1)
|
|
# (Signal connect appears below)
|
|
|
|
if not self.mswin_flag:
|
|
button2 = Gtk.Button(_('Use default location'))
|
|
self.inner_grid.attach(button2, 1, 7, 1, 1)
|
|
# (Signal connect appears below)
|
|
|
|
# (Empty label for spacing)
|
|
self.add_empty_label(0, 8, grid_width, 1)
|
|
|
|
# The specified path appears here, after it has been selected
|
|
if self.data_dir is None:
|
|
|
|
label = self.add_label(
|
|
'',
|
|
0, 9, grid_width, 1,
|
|
)
|
|
|
|
else:
|
|
|
|
label = self.add_label(
|
|
'<span font_size="large" font_weight="bold">' \
|
|
+ self.data_dir + '</span>',
|
|
0, 9, grid_width, 1,
|
|
)
|
|
|
|
# (Signal connects from above)
|
|
button.connect(
|
|
'clicked',
|
|
self.on_button_choose_folder_clicked,
|
|
label,
|
|
)
|
|
|
|
if not self.mswin_flag:
|
|
|
|
button2.connect(
|
|
'clicked',
|
|
self.on_button_default_folder_clicked,
|
|
label,
|
|
)
|
|
|
|
# Disable the Next button until a folder has been created/selected
|
|
if self.data_dir is None:
|
|
self.next_button.set_sensitive(False)
|
|
|
|
|
|
def setup_set_downloader_page(self):
|
|
|
|
"""Called by self.setup_page().
|
|
|
|
Sets up the widget layout for a page.
|
|
"""
|
|
|
|
grid_width = 3
|
|
|
|
self.add_label(
|
|
'<span font_size="large" style="italic">' \
|
|
+ _('Choose which downloader to use.') \
|
|
+ '</span>',
|
|
0, 0, grid_width, 1,
|
|
)
|
|
|
|
# youtube-dlc
|
|
radiobutton = self.setup_set_downloader_page_add_button(
|
|
2, # Row number
|
|
'<b>youtube-dlc</b>: <i>' \
|
|
+ self.app_obj.ytdl_fork_descrip_dict['youtube-dlc'] \
|
|
+ '</i>',
|
|
_('Use youtube-dlc'),
|
|
)
|
|
|
|
# youtube-dl
|
|
radiobutton2 = self.setup_set_downloader_page_add_button(
|
|
1, # Row number
|
|
'<b>youtube-dl</b>: <i>' \
|
|
+ self.app_obj.ytdl_fork_descrip_dict['youtube-dl'] \
|
|
+ '</i>',
|
|
_('Use youtube-dl'),
|
|
radiobutton,
|
|
)
|
|
|
|
# Any other fork
|
|
radiobutton3, entry = self.setup_set_downloader_page_add_button(
|
|
3, # Row number
|
|
self.app_obj.ytdl_fork_descrip_dict['custom'],
|
|
_('Use a different fork of youtube-dl'),
|
|
radiobutton2,
|
|
True, # Show an entry
|
|
)
|
|
|
|
# Set widgets to their initial state
|
|
if self.ytdl_fork is None or self.ytdl_fork == 'youtube-dl':
|
|
radiobutton2.set_active(True)
|
|
entry.set_sensitive(False)
|
|
elif self.ytdl_fork == 'youtube-dlc':
|
|
radiobutton.set_active(True)
|
|
entry.set_sensitive(False)
|
|
else:
|
|
radiobutton3.set_active(True)
|
|
if self.ytdl_fork is not None:
|
|
entry.set_text(self.ytdl_fork)
|
|
else:
|
|
entry.set_text('')
|
|
entry.set_sensitive(True)
|
|
|
|
# (Signal connects from the call to
|
|
# self.setup_set_downloader_page_add_button() )
|
|
radiobutton.connect(
|
|
'toggled',
|
|
self.on_button_ytdl_fork_toggled,
|
|
entry,
|
|
'youtube-dlc',
|
|
)
|
|
radiobutton2.connect(
|
|
'toggled',
|
|
self.on_button_ytdl_fork_toggled,
|
|
entry,
|
|
'youtube-dl',
|
|
)
|
|
radiobutton3.connect(
|
|
'toggled',
|
|
self.on_button_ytdl_fork_toggled,
|
|
entry,
|
|
)
|
|
entry.connect(
|
|
'changed',
|
|
self.on_entry_ytdl_fork_changed,
|
|
radiobutton3,
|
|
)
|
|
|
|
|
|
def setup_set_downloader_page_add_button(self, row, label_text, radio_text,
|
|
radiobutton=None, custom_flag=False):
|
|
|
|
"""Called by self.setup_set_downloader_page().
|
|
|
|
Adds widgets for a single downloader option.
|
|
|
|
Args:
|
|
|
|
row (int): Row number in self.inner_grid
|
|
|
|
label_text (str): Text to use in a Gtk.Label
|
|
|
|
radio_text (str): Text to use in a Gtk.RadioButton
|
|
|
|
radiobutton (Gtk.RadioButton): The previous radiobutton in the same
|
|
group
|
|
|
|
custom_flag (bool): True for the third option, in which case we
|
|
add an extra Gtk.Entry
|
|
|
|
Return values:
|
|
|
|
If custom_flag is False, returns the radiobutton. If custom_flag is
|
|
True, returns the radiobutton and entry box as a list
|
|
|
|
"""
|
|
|
|
if not custom_flag:
|
|
grid_width = 1
|
|
else:
|
|
grid_width = 2
|
|
|
|
# (Use an event box so the downloader can be selected by clicking
|
|
# anywhere in the frame)
|
|
event_box = Gtk.EventBox()
|
|
self.inner_grid.attach(event_box, 1, row, 1, 1)
|
|
# (Signal connect appears below)
|
|
|
|
frame = Gtk.Frame()
|
|
event_box.add(frame)
|
|
frame.set_border_width(self.spacing_size)
|
|
frame.set_hexpand(False)
|
|
|
|
grid = Gtk.Grid()
|
|
frame.add(grid)
|
|
grid.set_border_width(self.spacing_size)
|
|
grid.set_row_spacing(self.spacing_size)
|
|
|
|
label = Gtk.Label()
|
|
grid.attach(label, 0, 0, grid_width, 1)
|
|
label.set_markup(utils.tidy_up_long_string(label_text))
|
|
label.set_hexpand(False)
|
|
label.set_alignment(0, 0.5)
|
|
|
|
radiobutton2 = Gtk.RadioButton.new_from_widget(radiobutton)
|
|
grid.attach(radiobutton2, 0, 1, 1, 1)
|
|
radiobutton2.set_hexpand(False)
|
|
radiobutton2.set_label(' ' + radio_text)
|
|
# (Signal connect appears in the calling function)
|
|
|
|
# (Signal connect from above)
|
|
event_box.connect(
|
|
'button-press-event',
|
|
self.on_frame_downloader_clicked,
|
|
radiobutton2,
|
|
)
|
|
|
|
if not custom_flag:
|
|
|
|
return radiobutton2
|
|
|
|
else:
|
|
|
|
# For other forks, add an entry, and return it with the radiobutton
|
|
entry = Gtk.Entry()
|
|
grid.attach(entry, 1, 1, 1, 1)
|
|
entry.set_hexpand(False)
|
|
entry.set_editable(True)
|
|
# (Signal connect appears in the calling function)
|
|
|
|
return radiobutton2, entry
|
|
|
|
|
|
def setup_fetch_downloader_page(self):
|
|
|
|
"""Called by self.setup_page().
|
|
|
|
Sets up the widget layout for a page.
|
|
"""
|
|
|
|
grid_width = 3
|
|
|
|
self.add_label(
|
|
'<span font_size="large" style="italic">' \
|
|
+ _('Click the button to install or update the downloader.') \
|
|
+ '</span>',
|
|
0, 0, grid_width, 1,
|
|
)
|
|
|
|
self.add_label(
|
|
'<span font_size="large" style="italic">' \
|
|
+ _(
|
|
'You should do this, even if you think it is already' \
|
|
+ ' installed.',
|
|
) + '</span>',
|
|
0, 1, grid_width, 1,
|
|
)
|
|
|
|
# (Empty label for spacing)
|
|
self.add_empty_label(0, 2, grid_width, 1)
|
|
|
|
self.downloader_button = Gtk.Button(_('Install and update downloader'))
|
|
self.inner_grid.attach(self.downloader_button, 1, 3, 1, 1)
|
|
self.downloader_button.set_hexpand(False)
|
|
# (Signal connect appears below)
|
|
|
|
self.update_button = Gtk.Button(_('More options'))
|
|
# (Making the button invisible doesn't work, so instead don't add it
|
|
# to the grid at all)
|
|
if os.name != 'nt' and not self.more_options_flag:
|
|
self.inner_grid.attach(self.update_button, 1, 4, 1, 1)
|
|
self.update_button.set_hexpand(False)
|
|
# (Signal connect appears below)
|
|
|
|
# (When the update button is clicked, it is made invisible, and this
|
|
# widget is made visible instead)
|
|
self.update_liststore = Gtk.ListStore(str, str)
|
|
for item in self.app_obj.ytdl_update_list:
|
|
self.update_liststore.append(
|
|
[item, formats.YTDL_UPDATE_DICT[item]],
|
|
)
|
|
|
|
self.update_combo = Gtk.ComboBox.new_with_model(self.update_liststore)
|
|
if os.name != 'nt':
|
|
self.inner_grid.attach(self.update_combo, 1, 4, 1, 1)
|
|
if not self.more_options_flag:
|
|
self.update_combo.set_visible(False)
|
|
|
|
renderer_text = Gtk.CellRendererText()
|
|
self.update_combo.pack_start(renderer_text, True)
|
|
self.update_combo.add_attribute(renderer_text, 'text', 1)
|
|
self.update_combo.set_entry_text_column(1)
|
|
|
|
if self.ytdl_update_current is not None:
|
|
ytdl_update_current = self.ytdl_update_current
|
|
else:
|
|
ytdl_update_current = self.app_obj.ytdl_update_current
|
|
|
|
self.update_combo.set_active(
|
|
self.app_obj.ytdl_update_list.index(ytdl_update_current),
|
|
)
|
|
# (Signal connect appears below)
|
|
|
|
# Update the combo, so that the youtube-dl fork, rather than
|
|
# youtube-dl itself, is visible (if applicable)
|
|
self.refresh_update_combo()
|
|
|
|
# (Empty label for spacing)
|
|
self.add_empty_label(0, 4, grid_width, 1)
|
|
|
|
self.downloader_scrolled, self.downloader_textview, \
|
|
self.downloader_textbuffer = self.add_textview(
|
|
0, 5, grid_width, 1,
|
|
)
|
|
|
|
# (Signal connects from above)
|
|
self.downloader_button.connect(
|
|
'clicked',
|
|
self.on_button_fetch_downloader_clicked,
|
|
)
|
|
|
|
self.update_button.connect(
|
|
'clicked',
|
|
self.on_button_update_path_clicked,
|
|
)
|
|
|
|
# (Signal connects from above)
|
|
self.update_combo.connect('changed', self.on_combo_update_changed)
|
|
|
|
|
|
def setup_fetch_ffmpeg_page(self):
|
|
|
|
"""Called by self.setup_page().
|
|
|
|
Sets up the widget layout for a page.
|
|
"""
|
|
|
|
grid_width = 3
|
|
|
|
self.add_label(
|
|
'<span font_size="large" style="italic">' \
|
|
+ _('Click the button to install FFmpeg.') \
|
|
+ '</span>',
|
|
0, 0, grid_width, 1,
|
|
)
|
|
|
|
self.add_label(
|
|
'<span font_size="large" style="italic">' \
|
|
+ utils.tidy_up_long_string(
|
|
_(
|
|
'Without FFmpeg, Tartube cannot download high-resolution' \
|
|
+ ' videos, and cannot display video thumbnails from' \
|
|
+ ' YouTube.',
|
|
),
|
|
60,
|
|
) + '</span>',
|
|
0, 1, grid_width, 1,
|
|
)
|
|
|
|
# (Empty label for spacing)
|
|
self.add_empty_label(0, 2, grid_width, 1)
|
|
|
|
self.add_label(
|
|
'<span font_size="large" style="italic">' \
|
|
+ _(
|
|
'The operation might take several minutes. Please be' \
|
|
+ ' patient.',
|
|
) + '</span>',
|
|
0, 3, grid_width, 1,
|
|
)
|
|
|
|
# (Empty label for spacing)
|
|
self.add_empty_label(0, 4, grid_width, 1)
|
|
|
|
self.ffmpeg_button = Gtk.Button(_('Install FFmpeg'))
|
|
self.inner_grid.attach(self.ffmpeg_button, 1, 5, 1, 1)
|
|
self.ffmpeg_button.set_hexpand(False)
|
|
# (Signal connect appears below)
|
|
|
|
# (Empty label for spacing)
|
|
self.add_empty_label(0, 6, grid_width, 1)
|
|
|
|
self.ffmpeg_scrolled, self.ffmpeg_textview, self.ffmpeg_textbuffer \
|
|
= self.add_textview(
|
|
0, 7, grid_width, 1,
|
|
)
|
|
|
|
# (Signal connects from above)
|
|
self.ffmpeg_button.connect(
|
|
'clicked',
|
|
self.on_button_fetch_ffmpeg_clicked,
|
|
)
|
|
|
|
|
|
def setup_finish_page_mswin(self):
|
|
|
|
"""Called by self.setup_page().
|
|
|
|
Sets up the widget layout for a page, shown only on MS Windows.
|
|
"""
|
|
|
|
self.add_image(
|
|
self.app_obj.main_win_obj.icon_dict['ready_icon'],
|
|
0, 0, 1, 1,
|
|
)
|
|
|
|
self.add_label(
|
|
'<span font_size="large" font_weight="bold">' \
|
|
+ _('All done!') + '</span>',
|
|
0, 1, 1, 1,
|
|
)
|
|
|
|
# (Empty label for spacing)
|
|
self.add_empty_label(0, 2, 1, 1)
|
|
|
|
self.add_label(
|
|
'<span font_size="large" style="italic">' \
|
|
+ utils.tidy_up_long_string(
|
|
_(
|
|
'If you need to re-install or update the downloader or' \
|
|
+ ' FFmpeg, you can do it from the main window\'s menu.',
|
|
),
|
|
60,
|
|
) + '</span>',
|
|
0, 3, 1, 1,
|
|
)
|
|
|
|
# (Empty label for spacing)
|
|
self.add_empty_label(0, 4, 1, 1)
|
|
|
|
self.add_label(
|
|
'<span font_size="large" style="italic">' \
|
|
+ _('Click the <b>OK</b> button to start Tartube!') \
|
|
+ '</span>',
|
|
0, 5, 1, 1,
|
|
)
|
|
|
|
|
|
def setup_finish_page_strict(self):
|
|
|
|
"""Called by self.setup_page().
|
|
|
|
Sets up the widget layout for a page, shown only after a STRICT install
|
|
from a DEB/RPM package.
|
|
"""
|
|
|
|
self.add_image(
|
|
self.app_obj.main_win_obj.icon_dict['ready_icon'],
|
|
0, 0, 1, 1,
|
|
)
|
|
|
|
self.add_label(
|
|
'<span font_size="large" font_weight="bold">' \
|
|
+ _('All done!') + '</span>',
|
|
0, 1, 1, 1,
|
|
)
|
|
|
|
# (Empty label for spacing)
|
|
self.add_empty_label(0, 2, 1, 1)
|
|
|
|
self.add_label(
|
|
'<span font_size="large" style="italic">' \
|
|
+ utils.tidy_up_long_string(
|
|
_(
|
|
'You must install the downloader on your system, before' \
|
|
+ ' you can use Tartube.'
|
|
),
|
|
60,
|
|
) + '</span>',
|
|
0, 3, 1, 1,
|
|
)
|
|
|
|
# (Empty label for spacing)
|
|
self.add_empty_label(0, 4, 1, 1)
|
|
|
|
self.add_label(
|
|
'<span font_size="large" style="italic">' \
|
|
+ 'It is strongly recommended that you install FFmpeg.</span>',
|
|
0, 5, 1, 1,
|
|
)
|
|
|
|
self.add_label(
|
|
'<span font_size="large" style="italic">' \
|
|
+ utils.tidy_up_long_string(
|
|
_(
|
|
'Without FFmpeg, Tartube cannot download high-resolution' \
|
|
+ ' videos, and cannot display video thumbnails from' \
|
|
+ ' YouTube.',
|
|
),
|
|
60,
|
|
) + '</span>',
|
|
0, 6, 1, 1,
|
|
)
|
|
|
|
# (Empty label for spacing)
|
|
self.add_empty_label(0, 7, 1, 1)
|
|
|
|
self.add_label(
|
|
'<span font_size="large" style="italic">' \
|
|
+ _('Click the <b>OK</b> button to start Tartube!') \
|
|
+ '</span>',
|
|
0, 8, 1, 1,
|
|
)
|
|
|
|
|
|
def setup_finish_page_default(self):
|
|
|
|
"""Called by self.setup_page().
|
|
|
|
Sets up the widget layout for a page, for all operating systems except
|
|
MS Windows.
|
|
"""
|
|
|
|
self.add_image(
|
|
self.app_obj.main_win_obj.icon_dict['ready_icon'],
|
|
0, 0, 1, 1,
|
|
)
|
|
|
|
self.add_label(
|
|
'<span font_size="large" font_weight="bold">' \
|
|
+ _('All done!') + '</span>',
|
|
0, 1, 1, 1,
|
|
)
|
|
|
|
# (Empty label for spacing)
|
|
self.add_empty_label(0, 2, 1, 1)
|
|
|
|
self.add_label(
|
|
'<span font_size="large" style="italic">' \
|
|
+ 'It is stronly recommended that you install FFmpeg.</span>',
|
|
0, 3, 1, 1,
|
|
)
|
|
|
|
self.add_label(
|
|
'<span font_size="large" style="italic">' \
|
|
+ utils.tidy_up_long_string(
|
|
_(
|
|
'Without FFmpeg, Tartube cannot download high-resolution' \
|
|
+ ' videos, and cannot display video thumbnails from' \
|
|
+ ' YouTube.',
|
|
),
|
|
60,
|
|
) + '</span>',
|
|
0, 4, 1, 1,
|
|
)
|
|
|
|
# (Empty label for spacing)
|
|
self.add_empty_label(0, 5, 1, 1)
|
|
|
|
self.add_label(
|
|
'<span font_size="large" style="italic">' \
|
|
+ _('Click the <b>OK</b> button to start Tartube!') \
|
|
+ '</span>',
|
|
0, 6, 1, 1,
|
|
)
|
|
|
|
|
|
# (Support functions)
|
|
|
|
|
|
def downloader_page_write(self, msg):
|
|
|
|
"""Called by updates.UpdateManager.install_ytdl_write_output() or
|
|
self.downloader_fetch_finished().
|
|
|
|
When installing/updating youtube-dl (or a fork), write a message in the
|
|
textview.
|
|
|
|
Args:
|
|
|
|
msg (str): The message to display
|
|
|
|
"""
|
|
|
|
# v2.2.209 This install sometimes freezes on MS Windows, due to some
|
|
# Gtk problem or other. Solution is to split up long messages in the
|
|
# textview
|
|
msg = utils.tidy_up_long_string(msg)
|
|
for line in msg.split('\n'):
|
|
|
|
self.downloader_textbuffer.insert(
|
|
self.downloader_textbuffer.get_end_iter(),
|
|
line + '\n',
|
|
)
|
|
|
|
adjust = self.downloader_scrolled.get_vadjustment()
|
|
adjust.set_value(adjust.get_upper())
|
|
|
|
self.downloader_textview.queue_draw()
|
|
|
|
|
|
def downloader_fetch_finished(self, msg):
|
|
|
|
"""Called by mainapp.TartubeApp.update_manager_finished().
|
|
|
|
Display the success/failure message in the textview, and re-sensitise
|
|
buttons.
|
|
|
|
Args:
|
|
|
|
msg (str): The success/failure message to display
|
|
|
|
"""
|
|
|
|
self.downloader_page_write(msg)
|
|
|
|
self.downloader_button.set_sensitive(True)
|
|
self.next_button.set_sensitive(True)
|
|
self.prev_button.set_sensitive(True)
|
|
|
|
|
|
def ffmpeg_page_write(self, msg):
|
|
|
|
"""Called by updates.UpdateManager.install_ytdl_write_output() or
|
|
self.ffmpeg_fetch_finished().
|
|
|
|
When installing FFmpeg, write a message in the textview.
|
|
|
|
Args:
|
|
|
|
msg (str): The message to display
|
|
|
|
"""
|
|
|
|
# v2.2.209 This install sometimes freezes on MS Windows, due to some
|
|
# Gtk problem or other. Solution is to split up long messages in the
|
|
# textview
|
|
msg = utils.tidy_up_long_string(msg)
|
|
for line in msg.split('\n'):
|
|
|
|
self.ffmpeg_textbuffer.insert(
|
|
self.ffmpeg_textbuffer.get_end_iter(),
|
|
line + '\n',
|
|
)
|
|
|
|
adjust = self.ffmpeg_scrolled.get_vadjustment()
|
|
adjust.set_value(adjust.get_upper())
|
|
|
|
self.downloader_textview.queue_draw()
|
|
|
|
|
|
def ffmpeg_fetch_finished(self, msg):
|
|
|
|
"""Called by mainapp.TartubeApp.update_manager_finished().
|
|
|
|
Display the success/failure message in the textview, and re-sensitise
|
|
buttons.
|
|
|
|
Args:
|
|
|
|
msg (str): The success/failure message to display
|
|
|
|
"""
|
|
|
|
self.ffmpeg_page_write(msg)
|
|
|
|
self.ffmpeg_button.set_sensitive(True)
|
|
self.next_button.set_sensitive(True)
|
|
self.prev_button.set_sensitive(True)
|
|
|
|
|
|
def refresh_update_combo(self):
|
|
|
|
"""Called by self.setup_fetch_downloader_page().
|
|
|
|
When the youtube-dl fork is changed, updates the contents of the
|
|
combo created by self.setup_fetch_downloader_page().
|
|
"""
|
|
|
|
fork = standard = 'youtube-dl'
|
|
if self.ytdl_fork is not None:
|
|
fork = self.ytdl_fork
|
|
|
|
count = -1
|
|
for item in self.app_obj.ytdl_update_list:
|
|
|
|
count += 1
|
|
descrip = re.sub(standard, fork, formats.YTDL_UPDATE_DICT[item])
|
|
self.update_liststore.set(
|
|
self.update_liststore.get_iter(Gtk.TreePath(count)),
|
|
1,
|
|
descrip,
|
|
)
|
|
|
|
|
|
# (Callbacks)
|
|
|
|
|
|
def on_button_cancel_clicked(self, button):
|
|
|
|
"""Modified version of the standard function, called from a callback in
|
|
self.setup_button_strip().
|
|
|
|
Closes the wizard window without applying any changes, unless an
|
|
update operation is in progress.
|
|
|
|
Args:
|
|
|
|
button (Gtk.Button): The widget clicked
|
|
|
|
"""
|
|
|
|
self.reset_changes()
|
|
if not self.app_obj.update_manager_obj:
|
|
self.destroy()
|
|
|
|
|
|
def on_button_choose_folder_clicked(self, button, label):
|
|
|
|
"""Called from a callback in self.setup_db_page().
|
|
|
|
Opens a file chooser dialogue, so the user can set the location of
|
|
Tartube's data directory.
|
|
|
|
Args:
|
|
|
|
button (Gtk.Button): The widget clicked
|
|
|
|
label (Gtk.Label): Once set, the path to the directory is displayed
|
|
in this label
|
|
|
|
"""
|
|
|
|
if not self.mswin_flag:
|
|
title = _('Select Tartube\'s data directory')
|
|
else:
|
|
title = _('Select Tartube\'s data folder')
|
|
|
|
dialogue_win = self.app_obj.dialogue_manager_obj.show_file_chooser(
|
|
title,
|
|
self,
|
|
'folder',
|
|
)
|
|
|
|
# Get the user's response
|
|
response = dialogue_win.run()
|
|
if response == Gtk.ResponseType.OK:
|
|
|
|
self.data_dir = dialogue_win.get_filename()
|
|
label.set_markup(
|
|
'<span font_size="large" font_weight="bold">' + self.data_dir \
|
|
+ '</span>',
|
|
)
|
|
|
|
# Data directory set, so re-enable the Next button
|
|
self.next_button.set_sensitive(True)
|
|
|
|
dialogue_win.destroy()
|
|
|
|
|
|
def on_button_default_folder_clicked(self, button, label):
|
|
|
|
"""Called from a callback in self.setup_db_page().
|
|
|
|
Sets the default location for Tartube's data directory (not on MS
|
|
Windows).
|
|
|
|
Args:
|
|
|
|
button (Gtk.Button): The widget clicked
|
|
|
|
label (Gtk.Label): Once set, the path to the directory is displayed
|
|
in this label
|
|
|
|
"""
|
|
|
|
self.data_dir = self.app_obj.data_dir
|
|
label.set_markup(
|
|
'<span font_size="large" font_weight="bold">' \
|
|
+ self.app_obj.data_dir + '</span>',
|
|
)
|
|
|
|
# Data directory set, so re-enable the Next button
|
|
self.next_button.set_sensitive(True)
|
|
|
|
|
|
def on_button_fetch_downloader_clicked(self, button):
|
|
|
|
"""Called from a callback in self.setup_fetch_page().
|
|
|
|
Starts an update operation to download and install the selected fork of
|
|
youtube-dl.
|
|
|
|
Args:
|
|
|
|
button (Gtk.Button): The widget clicked
|
|
|
|
"""
|
|
|
|
# Desensitise buttons until the operation is complete
|
|
button.set_sensitive(False)
|
|
self.next_button.set_sensitive(False)
|
|
self.prev_button.set_sensitive(False)
|
|
|
|
# Start the update operation
|
|
if not self.app_obj.update_manager_start_from_wizwin(self, 'ytdl'):
|
|
|
|
# Operation did not start
|
|
button.set_sensitive(True)
|
|
self.next_button.set_sensitive(True)
|
|
self.prev_button.set_sensitive(True)
|
|
|
|
|
|
def on_button_fetch_ffmpeg_clicked(self, button):
|
|
|
|
"""Called from a callback in self.setup_fetch_page().
|
|
|
|
Starts an update operation to download and install FFmpeg.
|
|
|
|
Args:
|
|
|
|
button (Gtk.Button): The widget clicked
|
|
|
|
"""
|
|
|
|
# Desensitise buttons until the operation is complete
|
|
button.set_sensitive(False)
|
|
self.next_button.set_sensitive(False)
|
|
self.prev_button.set_sensitive(False)
|
|
|
|
# Start the update operation
|
|
if not self.app_obj.update_manager_start_from_wizwin(self, 'ffmpeg'):
|
|
|
|
# Operation did not start
|
|
button.set_sensitive(True)
|
|
self.next_button.set_sensitive(True)
|
|
self.prev_button.set_sensitive(True)
|
|
|
|
|
|
def on_button_update_path_clicked(self, button):
|
|
|
|
"""Called from a callback in self.setup_fetch_page().
|
|
|
|
Makes the 'More options' button invisible, and the update path combo
|
|
visible.
|
|
|
|
Args:
|
|
|
|
button (Gtk.Button): The widget clicked
|
|
|
|
"""
|
|
|
|
button.set_visible(False)
|
|
self.update_combo.set_visible(True)
|
|
|
|
# Flag set to True, once the 'More options' button has been clicked,
|
|
# so that it is never visible again
|
|
self.more_options_flag = True
|
|
|
|
|
|
def on_button_ytdl_fork_toggled(self, radiobutton, entry, fork_type=None):
|
|
|
|
"""Called from callback in self.setup_set_downloader_page().
|
|
|
|
Sets the youtube-dl fork to be used. See also
|
|
self.on_entry_ytdl_fork_changed().
|
|
|
|
Args:
|
|
|
|
radiobutton (Gtk.Radiobutton): The widget clicked
|
|
|
|
entry (Gtk.Entry): Another widget to be updated
|
|
|
|
fork_type (str): 'youtube-dlc', 'youtube-dl', or None for any other
|
|
fork
|
|
|
|
"""
|
|
|
|
if radiobutton.get_active():
|
|
|
|
if fork_type is None:
|
|
|
|
fork_name = entry.get_text()
|
|
# (As in the preference window, if the 'other fork' option is
|
|
# selected, but nothing is entered in the entry box, use
|
|
# youtube-dl as the downloader)
|
|
if fork_name == '':
|
|
self.ytdl_fork = None
|
|
else:
|
|
self.ytdl_fork = fork_name
|
|
|
|
entry.set_sensitive(True)
|
|
|
|
elif fork_type == 'youtube-dl':
|
|
|
|
self.ytdl_fork = None
|
|
entry.set_text('')
|
|
entry.set_sensitive(False)
|
|
|
|
elif fork_type == 'youtube-dlc':
|
|
|
|
self.ytdl_fork = fork_type
|
|
entry.set_text('')
|
|
entry.set_sensitive(False)
|
|
|
|
|
|
def on_combo_update_changed(self, combo):
|
|
|
|
"""Called from callback in self.setup_fetch_downloader_page().
|
|
|
|
Sets the youtube-dl install/update method.
|
|
|
|
Args:
|
|
|
|
combo (Gtk.ComboBox): The widget clicked
|
|
|
|
"""
|
|
|
|
tree_iter = combo.get_active_iter()
|
|
model = combo.get_model()
|
|
self.ytdl_update_current = model[tree_iter][0]
|
|
|
|
|
|
def on_entry_ytdl_fork_changed(self, entry, radiobutton):
|
|
|
|
"""Called from callback in self.setup_set_downloader_page().
|
|
|
|
Sets the youtube-dl fork to be used. See also
|
|
self.on_button_ytdl_fork_toggled().
|
|
|
|
Args:
|
|
|
|
entry (Gtk.Entry): The widget changed
|
|
|
|
"""
|
|
|
|
if radiobutton.get_active():
|
|
|
|
entry_text = utils.strip_whitespace(entry.get_text())
|
|
# (As in the preference window, if the 'other fork' option is
|
|
# selected, but nothing is entered in the entry box, use
|
|
# youtube-dl as the system default)
|
|
if entry_text == '':
|
|
self.ytdl_fork = None
|
|
else:
|
|
self.ytdl_fork = entry_text
|
|
|
|
|
|
def on_frame_downloader_clicked(self, event_box, event_button,
|
|
radiobutton):
|
|
|
|
"""Called from callback in self.setup_set_downloader_page().
|
|
|
|
Enables/disables selecting a downloader by clicking anywhere in its
|
|
containing frame.
|
|
|
|
Args:
|
|
|
|
event_box (Gtk.EventBox): Ignored
|
|
|
|
event_button (Gdk.EventButton): Ignored
|
|
|
|
radiobutton (Gtk.RadioButton): The radiobutton inside the clicked
|
|
frame, which should be made active
|
|
|
|
"""
|
|
|
|
if not radiobutton.get_active():
|
|
radiobutton.set_active(True)
|
|
|