forked from LBRYCommunity/lbry-sdk
192ac6959a
More specific exceptions are raised when problems are encountered looking up metadata and validating stream descriptor files, and on the GUI those more specific exceptions are used to prevent errors from being presented to the user. If the user has selected the option to re-upload data for some stream, blobs downloaded for that purpose will not be deleted when they are finished being output. Instead, by default, for the GUI they will be deleted when the stream is removed from the GUI. That can be changed so they are not deleted at all, using the lbry.conf file.
398 lines
No EOL
16 KiB
Python
398 lines
No EOL
16 KiB
Python
import Tkinter as tk
|
|
import sys
|
|
import tkFont
|
|
import ttk
|
|
import locale
|
|
import os
|
|
|
|
|
|
class StreamFrame(object):
|
|
def __init__(self, app, uri):
|
|
self.app = app
|
|
self.uri = uri
|
|
self.stream_hash = None
|
|
self.cancel_func = None
|
|
|
|
self.stream_frame = ttk.Frame(self.app.streams_frame, style="B.TFrame")
|
|
|
|
self.stream_frame.pack(fill=tk.X, side=tk.BOTTOM, pady=(30, 0))
|
|
|
|
self.stream_frame_header = ttk.Frame(self.stream_frame, style="C.TFrame")
|
|
self.stream_frame_header.grid(sticky=tk.E + tk.W)
|
|
|
|
self.uri_font = tkFont.Font(size=8)
|
|
self.uri_label = ttk.Label(
|
|
self.stream_frame_header, text=self.uri, font=self.uri_font, foreground="#666666"
|
|
)
|
|
self.uri_label.grid(row=0, column=0, sticky=tk.W)
|
|
|
|
if os.name == "nt":
|
|
self.button_cursor = ""
|
|
else:
|
|
self.button_cursor = "hand1"
|
|
|
|
close_file_name = "close2.gif"
|
|
if os.name == "nt":
|
|
close_file = os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])), "lbrynet",
|
|
"lbrynet_downloader_gui", close_file_name)
|
|
else:
|
|
close_file = os.path.join(os.path.dirname(__file__), close_file_name)
|
|
|
|
self.close_picture = tk.PhotoImage(
|
|
file=close_file
|
|
)
|
|
self.close_button = ttk.Button(
|
|
self.stream_frame_header, command=self.cancel, style="Stop.TButton", cursor=self.button_cursor
|
|
)
|
|
self.close_button.config(image=self.close_picture)
|
|
self.close_button.grid(row=0, column=1, sticky=tk.E + tk.N)
|
|
|
|
self.stream_frame_header.grid_columnconfigure(0, weight=1)
|
|
|
|
self.stream_frame.grid_columnconfigure(0, weight=1)
|
|
|
|
self.stream_frame_body = ttk.Frame(self.stream_frame, style="C.TFrame")
|
|
self.stream_frame_body.grid(row=1, column=0, sticky=tk.E + tk.W)
|
|
|
|
self.name_frame = ttk.Frame(self.stream_frame_body, style="D.TFrame")
|
|
self.name_frame.grid(sticky=tk.W + tk.E)
|
|
self.name_frame.grid_columnconfigure(0, weight=1)
|
|
|
|
self.stream_frame_body.grid_columnconfigure(0, weight=1)
|
|
|
|
self.metadata_frame = ttk.Frame(self.stream_frame_body, style="D.TFrame")
|
|
self.metadata_frame.grid(sticky=tk.W + tk.E, row=1)
|
|
self.metadata_frame.grid_columnconfigure(0, weight=1)
|
|
|
|
self.options_frame = ttk.Frame(self.stream_frame_body, style="D.TFrame")
|
|
|
|
self.outer_button_frame = ttk.Frame(self.stream_frame_body, style="D.TFrame")
|
|
self.outer_button_frame.grid(sticky=tk.W + tk.E, row=4)
|
|
|
|
show_options_picture_file_name = "show_options.gif"
|
|
if os.name == "nt":
|
|
show_options_picture_file = os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])),
|
|
"lbrynet", "lbrynet_downloader_gui",
|
|
show_options_picture_file_name)
|
|
else:
|
|
show_options_picture_file = os.path.join(os.path.dirname(__file__),
|
|
show_options_picture_file_name)
|
|
|
|
self.show_options_picture = tk.PhotoImage(
|
|
file=show_options_picture_file
|
|
)
|
|
|
|
hide_options_picture_file_name = "hide_options.gif"
|
|
if os.name == "nt":
|
|
hide_options_picture_file = os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])),
|
|
"lbrynet", "lbrynet_downloader_gui",
|
|
hide_options_picture_file_name)
|
|
else:
|
|
hide_options_picture_file = os.path.join(os.path.dirname(__file__),
|
|
hide_options_picture_file_name)
|
|
|
|
self.hide_options_picture = tk.PhotoImage(
|
|
file=hide_options_picture_file
|
|
)
|
|
|
|
self.show_options_button = None
|
|
|
|
self.status_label = None
|
|
self.name_label = None
|
|
self.bytes_downloaded_label = None
|
|
self.button_frame = None
|
|
self.download_buttons = []
|
|
self.option_frames = []
|
|
self.name_font = None
|
|
self.description_label = None
|
|
self.file_name_frame = None
|
|
self.cost_frame = None
|
|
self.cost_description = None
|
|
self.remaining_cost_description = None
|
|
self.cost_label = None
|
|
self.remaining_cost_label = None
|
|
self.progress_frame = None
|
|
|
|
def cancel(self):
|
|
if self.cancel_func is not None:
|
|
self.cancel_func()
|
|
self.stream_frame.destroy()
|
|
self.app.stream_removed()
|
|
|
|
def show_name(self, name):
|
|
self.name_font = tkFont.Font(size=16)
|
|
self.name_label = ttk.Label(
|
|
self.name_frame, text=name, font=self.name_font
|
|
)
|
|
self.name_label.grid(row=0, column=0, sticky=tk.W)
|
|
|
|
def show_description(self, description):
|
|
if os.name == "nt":
|
|
wraplength = 580
|
|
else:
|
|
wraplength = 600
|
|
self.description_label = ttk.Label(
|
|
self.name_frame, text=description, wraplength=wraplength
|
|
)
|
|
self.description_label.grid(row=1, column=0, sticky=tk.W)
|
|
|
|
def show_metadata_status(self, value):
|
|
if self.status_label is None:
|
|
self.status_label = ttk.Label(
|
|
self.metadata_frame, text=value
|
|
)
|
|
self.status_label.grid()
|
|
self.metadata_frame.grid_columnconfigure(0, weight=1)
|
|
else:
|
|
self.status_label.config(text=value)
|
|
|
|
@staticmethod
|
|
def get_formatted_stream_size(stream_size):
|
|
if isinstance(stream_size, (int, long)):
|
|
if stream_size >= 2**40:
|
|
units = "TB"
|
|
factor = 2**40
|
|
elif stream_size >= 2**30:
|
|
units = "GB"
|
|
factor = 2**30
|
|
elif stream_size >= 2**20:
|
|
units = "MB"
|
|
factor = 2**20
|
|
elif stream_size >= 2**10:
|
|
units = "KB"
|
|
factor = 2**10
|
|
else:
|
|
return str(stream_size) + " B"
|
|
return "%.1f %s" % (round((stream_size * 1.0 / factor), 1), units)
|
|
return stream_size
|
|
|
|
def show_stream_metadata(self, stream_name, stream_size):
|
|
if self.status_label is not None:
|
|
self.status_label.destroy()
|
|
|
|
self.file_name_frame = ttk.Frame(self.metadata_frame, style="F.TFrame")
|
|
self.file_name_frame.grid(row=0, column=0, sticky=tk.W)
|
|
self.metadata_frame.grid_columnconfigure(0, weight=1, uniform="metadata")
|
|
|
|
file_size_label = ttk.Label(
|
|
self.file_name_frame,
|
|
text=self.get_formatted_stream_size(stream_size)
|
|
)
|
|
file_size_label.grid(row=0, column=2)
|
|
|
|
file_name_label = ttk.Label(
|
|
self.file_name_frame,
|
|
text=" - " + stream_name,
|
|
)
|
|
file_name_label.grid(row=0, column=3)
|
|
|
|
self.button_frame = ttk.Frame(self.outer_button_frame, style="E.TFrame")
|
|
self.button_frame.grid(row=0, column=1)
|
|
|
|
self.outer_button_frame.grid_columnconfigure(0, weight=1, uniform="buttons")
|
|
self.outer_button_frame.grid_columnconfigure(1, weight=2, uniform="buttons1")
|
|
self.outer_button_frame.grid_columnconfigure(2, weight=1, uniform="buttons")
|
|
|
|
def add_download_factory(self, factory, download_func):
|
|
download_button = ttk.Button(
|
|
self.button_frame, text=factory.get_description(), command=download_func,
|
|
style='LBRY.TButton', cursor=self.button_cursor
|
|
)
|
|
self.download_buttons.append(download_button)
|
|
download_button.grid(row=0, column=len(self.download_buttons) - 1, padx=5, pady=(1, 2))
|
|
|
|
def disable_download_buttons(self):
|
|
for download_button in self.download_buttons:
|
|
download_button.config(state=tk.DISABLED)
|
|
|
|
def remove_download_buttons(self):
|
|
for download_button in self.download_buttons:
|
|
download_button.destroy()
|
|
self.download_buttons = []
|
|
|
|
def get_option_widget(self, option_type, option_frame):
|
|
if option_type.value == float:
|
|
entry_frame = ttk.Frame(
|
|
option_frame,
|
|
style="H.TFrame"
|
|
)
|
|
entry_frame.grid()
|
|
col = 0
|
|
if option_type.short_description is not None:
|
|
entry_label = ttk.Label(
|
|
entry_frame,
|
|
#text=option_type.short_description
|
|
text=""
|
|
)
|
|
entry_label.grid(row=0, column=0, sticky=tk.W)
|
|
col = 1
|
|
entry = ttk.Entry(
|
|
entry_frame,
|
|
width=10,
|
|
style="Float.TEntry"
|
|
)
|
|
entry_frame.entry = entry
|
|
entry.grid(row=0, column=col, sticky=tk.W)
|
|
return entry_frame
|
|
if option_type.value == bool:
|
|
bool_frame = ttk.Frame(
|
|
option_frame,
|
|
style="H.TFrame"
|
|
)
|
|
bool_frame.chosen_value = tk.BooleanVar()
|
|
true_text = "True"
|
|
false_text = "False"
|
|
if option_type.bool_options_description is not None:
|
|
true_text, false_text = option_type.bool_options_description
|
|
true_radio_button = ttk.Radiobutton(
|
|
bool_frame, text=true_text, variable=bool_frame.chosen_value, value=True
|
|
)
|
|
true_radio_button.grid(row=0, sticky=tk.W)
|
|
false_radio_button = ttk.Radiobutton(
|
|
bool_frame, text=false_text, variable=bool_frame.chosen_value, value=False
|
|
)
|
|
false_radio_button.grid(row=1, sticky=tk.W)
|
|
return bool_frame
|
|
label = ttk.Label(
|
|
option_frame,
|
|
text=""
|
|
)
|
|
return label
|
|
|
|
def show_download_options(self, options):
|
|
left_padding = 20
|
|
for option in options:
|
|
f = ttk.Frame(
|
|
self.options_frame,
|
|
style="E.TFrame"
|
|
)
|
|
f.grid(sticky=tk.W + tk.E, padx=left_padding)
|
|
self.option_frames.append((option, f))
|
|
description_label = ttk.Label(
|
|
f,
|
|
text=option.long_description
|
|
)
|
|
description_label.grid(row=0, sticky=tk.W)
|
|
if len(option.option_types) > 1:
|
|
f.chosen_type = tk.IntVar()
|
|
choices_frame = ttk.Frame(
|
|
f,
|
|
style="F.TFrame"
|
|
)
|
|
f.choices_frame = choices_frame
|
|
choices_frame.grid(row=1, sticky=tk.W, padx=left_padding)
|
|
choices_frame.choices = []
|
|
for i, option_type in enumerate(option.option_types):
|
|
choice_frame = ttk.Frame(
|
|
choices_frame,
|
|
style="G.TFrame"
|
|
)
|
|
choice_frame.grid(sticky=tk.W)
|
|
option_text = ""
|
|
if option_type.short_description is not None:
|
|
option_text = option_type.short_description
|
|
option_radio_button = ttk.Radiobutton(
|
|
choice_frame, text=option_text, variable=f.chosen_type, value=i
|
|
)
|
|
option_radio_button.grid(row=0, column=0, sticky=tk.W)
|
|
option_widget = self.get_option_widget(option_type, choice_frame)
|
|
option_widget.grid(row=0, column=1, sticky=tk.W)
|
|
choices_frame.choices.append(option_widget)
|
|
if i == 0:
|
|
option_radio_button.invoke()
|
|
else:
|
|
choice_frame = ttk.Frame(
|
|
f,
|
|
style="F.TFrame"
|
|
)
|
|
choice_frame.grid(sticky=tk.W, padx=left_padding)
|
|
option_widget = self.get_option_widget(option.option_types[0], choice_frame)
|
|
option_widget.grid(row=0, column=0, sticky=tk.W)
|
|
f.option_widget = option_widget
|
|
self.show_options_button = ttk.Button(
|
|
self.stream_frame_body, command=self._toggle_show_options, style="Stop.TButton",
|
|
cursor=self.button_cursor
|
|
)
|
|
self.show_options_button.config(image=self.show_options_picture)
|
|
self.show_options_button.grid(sticky=tk.W, row=2, column=0)
|
|
|
|
def _get_chosen_option(self, option_type, option_widget):
|
|
if option_type.value == float:
|
|
return float(option_widget.entry.get())
|
|
if option_type.value == bool:
|
|
return option_widget.chosen_value.get()
|
|
return option_type.value
|
|
|
|
def get_chosen_options(self):
|
|
chosen_options = []
|
|
for o, f in self.option_frames:
|
|
if len(o.option_types) > 1:
|
|
chosen_index = f.chosen_type.get()
|
|
option_type = o.option_types[chosen_index]
|
|
option_widget = f.choices_frame.choices[chosen_index]
|
|
chosen_options.append(self._get_chosen_option(option_type, option_widget))
|
|
else:
|
|
option_type = o.option_types[0]
|
|
option_widget = f.option_widget
|
|
chosen_options.append(self._get_chosen_option(option_type, option_widget))
|
|
return chosen_options
|
|
|
|
def _toggle_show_options(self):
|
|
if self.options_frame.winfo_ismapped():
|
|
self.show_options_button.config(image=self.show_options_picture)
|
|
self.options_frame.grid_forget()
|
|
else:
|
|
self.show_options_button.config(image=self.hide_options_picture)
|
|
self.options_frame.grid(sticky=tk.W + tk.E, row=3)
|
|
|
|
def show_progress(self, total_bytes, bytes_left_to_download, points_paid,
|
|
points_remaining):
|
|
if self.bytes_downloaded_label is None:
|
|
self.remove_download_buttons()
|
|
self.button_frame.destroy()
|
|
for option, frame in self.option_frames:
|
|
frame.destroy()
|
|
self.options_frame.destroy()
|
|
self.show_options_button.destroy()
|
|
|
|
self.progress_frame = ttk.Frame(self.outer_button_frame, style="F.TFrame")
|
|
self.progress_frame.grid(row=0, column=0, sticky=tk.W, pady=(0, 8))
|
|
|
|
self.bytes_downloaded_label = ttk.Label(
|
|
self.progress_frame,
|
|
text=""
|
|
)
|
|
self.bytes_downloaded_label.grid(row=0, column=0)
|
|
|
|
self.cost_frame = ttk.Frame(self.outer_button_frame, style="F.TFrame")
|
|
self.cost_frame.grid(row=1, column=0, sticky=tk.W, pady=(0, 7))
|
|
|
|
self.cost_label = ttk.Label(
|
|
self.cost_frame,
|
|
text="",
|
|
foreground="red"
|
|
)
|
|
self.cost_label.grid(row=0, column=1, padx=(1, 0))
|
|
self.outer_button_frame.grid_columnconfigure(2, weight=0, uniform="")
|
|
|
|
if self.bytes_downloaded_label.winfo_exists():
|
|
percent_done = 0
|
|
if total_bytes > 0:
|
|
percent_done = 100.0 * (total_bytes - bytes_left_to_download) / total_bytes
|
|
percent_done_string = locale.format_string(" (%.2f%%)", percent_done)
|
|
self.bytes_downloaded_label.config(
|
|
text=self.get_formatted_stream_size(total_bytes - bytes_left_to_download) + percent_done_string
|
|
)
|
|
if self.cost_label.winfo_exists():
|
|
total_points = points_remaining + points_paid
|
|
self.cost_label.config(text=locale.format_string("%.2f/%.2f LBC",
|
|
(round(points_paid, 2), round(total_points, 2)),
|
|
grouping=True))
|
|
|
|
def show_download_done(self, total_points_paid):
|
|
if self.bytes_downloaded_label is not None and self.bytes_downloaded_label.winfo_exists():
|
|
self.bytes_downloaded_label.destroy()
|
|
if self.cost_label is not None and self.cost_label.winfo_exists():
|
|
self.cost_label.config(text=locale.format_string("%.2f LBC",
|
|
(round(total_points_paid, 2),),
|
|
grouping=True)) |