forked from LBRYCommunity/lbry-sdk
Downloader options in its own class, show options in gui downloader
Put stream downloader options into its own class, and make stream downloader options global to the stream type rather than specific to each factory. Show downloader options in the lbrynet-downloader-gui. Make a class for downloader option choices, so that the descriptions can be displayed. In the console, if there are multiple choices for the download option, make it a list selected by its index. Make sure that the ConnectionManager closes properly when some of the connections fail to open (e.g. due to a host being down)
This commit is contained in:
parent
f4b3187494
commit
c8b2b7b279
18 changed files with 583 additions and 231 deletions
|
@ -1,6 +1,16 @@
|
||||||
|
class DownloadChoice(object):
|
||||||
|
def __init__(self, value, short_description, long_description, bool_options_description=None):
|
||||||
|
self.value = value
|
||||||
|
self.short_description = short_description
|
||||||
|
self.long_description = long_description
|
||||||
|
self.bool_options_description = bool_options_description
|
||||||
|
|
||||||
|
|
||||||
class DownloadOption(object):
|
class DownloadOption(object):
|
||||||
def __init__(self, option_types, long_description, short_description, default):
|
def __init__(self, option_types, long_description, short_description, default_value,
|
||||||
|
default_value_description):
|
||||||
self.option_types = option_types
|
self.option_types = option_types
|
||||||
self.long_description = long_description
|
self.long_description = long_description
|
||||||
self.short_description = short_description
|
self.short_description = short_description
|
||||||
self.default = default
|
self.default_value = default_value
|
||||||
|
self.default_value_description = default_value_description
|
|
@ -110,9 +110,10 @@ class StreamDescriptorIdentifier(object):
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._sd_info_validators = {} # {stream_type: IStreamDescriptorValidator}
|
self._sd_info_validators = {} # {stream_type: IStreamDescriptorValidator}
|
||||||
|
self._stream_options = {} # {stream_type: IStreamOptions}
|
||||||
self._stream_downloader_factories = defaultdict(list) # {stream_type: [IStreamDownloaderFactory]}
|
self._stream_downloader_factories = defaultdict(list) # {stream_type: [IStreamDownloaderFactory]}
|
||||||
|
|
||||||
def add_stream_info_validator(self, stream_type, sd_info_validator):
|
def add_stream_type(self, stream_type, sd_info_validator, stream_options):
|
||||||
"""
|
"""
|
||||||
This is how the StreamDescriptorIdentifier learns about new types of stream descriptors.
|
This is how the StreamDescriptorIdentifier learns about new types of stream descriptors.
|
||||||
|
|
||||||
|
@ -126,9 +127,13 @@ class StreamDescriptorIdentifier(object):
|
||||||
will then be called. If the validation step fails, an exception will be thrown, preventing the stream
|
will then be called. If the validation step fails, an exception will be thrown, preventing the stream
|
||||||
descriptor from being further processed.
|
descriptor from being further processed.
|
||||||
|
|
||||||
|
@param stream_options: A class implementing the IStreamOptions interface. This class's constructor will be
|
||||||
|
passed the sd_info_validator object containing the raw metadata from the stream descriptor file.
|
||||||
|
|
||||||
@return: None
|
@return: None
|
||||||
"""
|
"""
|
||||||
self._sd_info_validators[stream_type] = sd_info_validator
|
self._sd_info_validators[stream_type] = sd_info_validator
|
||||||
|
self._stream_options[stream_type] = stream_options
|
||||||
|
|
||||||
def add_stream_downloader_factory(self, stream_type, factory):
|
def add_stream_downloader_factory(self, stream_type, factory):
|
||||||
"""
|
"""
|
||||||
|
@ -167,14 +172,23 @@ class StreamDescriptorIdentifier(object):
|
||||||
assert stream_type in self._sd_info_validators, "Unrecognized stream type: " + str(stream_type)
|
assert stream_type in self._sd_info_validators, "Unrecognized stream type: " + str(stream_type)
|
||||||
return self._sd_info_validators[stream_type]
|
return self._sd_info_validators[stream_type]
|
||||||
|
|
||||||
|
def _get_options(self, stream_type):
|
||||||
|
assert stream_type in self._sd_info_validators, "Unrecognized stream type: " + str(stream_type)
|
||||||
|
return self._stream_options[stream_type]
|
||||||
|
|
||||||
def _return_info_and_factories(self, sd_info):
|
def _return_info_and_factories(self, sd_info):
|
||||||
assert 'stream_type' in sd_info, 'Invalid stream descriptor. No stream_type parameter.'
|
assert 'stream_type' in sd_info, 'Invalid stream descriptor. No stream_type parameter.'
|
||||||
stream_type = sd_info['stream_type']
|
stream_type = sd_info['stream_type']
|
||||||
factories = self._get_factories(stream_type)
|
|
||||||
validator = self._get_validator(stream_type)(sd_info)
|
validator = self._get_validator(stream_type)(sd_info)
|
||||||
|
factories = [f for f in self._get_factories(stream_type) if f.can_download(validator)]
|
||||||
|
|
||||||
d = validator.validate()
|
d = validator.validate()
|
||||||
|
|
||||||
d.addCallback(lambda _: (validator, factories))
|
def get_options():
|
||||||
|
options = self._get_options(stream_type)
|
||||||
|
return validator, options, factories
|
||||||
|
|
||||||
|
d.addCallback(lambda _: get_options())
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,49 +7,55 @@ from lbrynet.core.client.ClientProtocol import ClientProtocolFactory
|
||||||
from lbrynet.core.Error import InsufficientFundsError
|
from lbrynet.core.Error import InsufficientFundsError
|
||||||
|
|
||||||
|
|
||||||
|
class PeerConnectionHandler(object):
|
||||||
|
def __init__(self, request_creators, factory):
|
||||||
|
self.request_creators = request_creators
|
||||||
|
self.factory = factory
|
||||||
|
self.connection = None
|
||||||
|
|
||||||
|
|
||||||
class ConnectionManager(object):
|
class ConnectionManager(object):
|
||||||
implements(interfaces.IConnectionManager)
|
implements(interfaces.IConnectionManager)
|
||||||
|
|
||||||
def __init__(self, downloader, rate_limiter, primary_request_creators, secondary_request_creators):
|
def __init__(self, downloader, rate_limiter, primary_request_creators, secondary_request_creators):
|
||||||
self.downloader = downloader
|
self.downloader = downloader
|
||||||
self.rate_limiter = rate_limiter
|
self.rate_limiter = rate_limiter
|
||||||
self.primary_request_creators = primary_request_creators
|
self._primary_request_creators = primary_request_creators
|
||||||
self.secondary_request_creators = secondary_request_creators
|
self._secondary_request_creators = secondary_request_creators
|
||||||
self.peer_connections = {} # {Peer: {'connection': connection,
|
self._peer_connections = {} # {Peer: PeerConnectionHandler}
|
||||||
# 'request_creators': [IRequestCreator if using this connection]}}
|
self._connections_closing = {} # {Peer: deferred (fired when the connection is closed)}
|
||||||
self.connections_closing = {} # {Peer: deferred (fired when the connection is closed)}
|
self._next_manage_call = None
|
||||||
self.next_manage_call = None
|
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
from twisted.internet import reactor
|
from twisted.internet import reactor
|
||||||
|
|
||||||
if self.next_manage_call is not None and self.next_manage_call.active() is True:
|
if self._next_manage_call is not None and self._next_manage_call.active() is True:
|
||||||
self.next_manage_call.cancel()
|
self._next_manage_call.cancel()
|
||||||
self.next_manage_call = reactor.callLater(0, self._manage)
|
self._next_manage_call = reactor.callLater(0, self._manage)
|
||||||
return defer.succeed(True)
|
return defer.succeed(True)
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
if self.next_manage_call is not None and self.next_manage_call.active() is True:
|
if self._next_manage_call is not None and self._next_manage_call.active() is True:
|
||||||
self.next_manage_call.cancel()
|
self._next_manage_call.cancel()
|
||||||
self.next_manage_call = None
|
self._next_manage_call = None
|
||||||
closing_deferreds = []
|
closing_deferreds = []
|
||||||
for peer in self.peer_connections.keys():
|
for peer in self._peer_connections.keys():
|
||||||
|
|
||||||
def close_connection(p):
|
def close_connection(p):
|
||||||
logging.info("Abruptly closing a connection to %s due to downloading being paused",
|
logging.info("Abruptly closing a connection to %s due to downloading being paused",
|
||||||
str(p))
|
str(p))
|
||||||
|
|
||||||
if self.peer_connections[p]['factory'].p is not None:
|
if self._peer_connections[p].factory.p is not None:
|
||||||
d = self.peer_connections[p]['factory'].p.cancel_requests()
|
d = self._peer_connections[p].factory.p.cancel_requests()
|
||||||
else:
|
else:
|
||||||
d = defer.succeed(True)
|
d = defer.succeed(True)
|
||||||
|
|
||||||
def disconnect_peer():
|
def disconnect_peer():
|
||||||
self.peer_connections[p]['connection'].disconnect()
|
|
||||||
if p in self.peer_connections:
|
|
||||||
del self.peer_connections[p]
|
|
||||||
d = defer.Deferred()
|
d = defer.Deferred()
|
||||||
self.connections_closing[p] = d
|
self._connections_closing[p] = d
|
||||||
|
self._peer_connections[p].connection.disconnect()
|
||||||
|
if p in self._peer_connections:
|
||||||
|
del self._peer_connections[p]
|
||||||
return d
|
return d
|
||||||
|
|
||||||
d.addBoth(lambda _: disconnect_peer())
|
d.addBoth(lambda _: disconnect_peer())
|
||||||
|
@ -62,7 +68,7 @@ class ConnectionManager(object):
|
||||||
|
|
||||||
logging.debug("Trying to get the next request for peer %s", str(peer))
|
logging.debug("Trying to get the next request for peer %s", str(peer))
|
||||||
|
|
||||||
if not peer in self.peer_connections:
|
if not peer in self._peer_connections:
|
||||||
logging.debug("The peer has already been told to shut down.")
|
logging.debug("The peer has already been told to shut down.")
|
||||||
return defer.succeed(False)
|
return defer.succeed(False)
|
||||||
|
|
||||||
|
@ -75,11 +81,11 @@ class ConnectionManager(object):
|
||||||
|
|
||||||
def check_if_request_sent(request_sent, request_creator):
|
def check_if_request_sent(request_sent, request_creator):
|
||||||
if request_sent is False:
|
if request_sent is False:
|
||||||
if request_creator in self.peer_connections[peer]['request_creators']:
|
if request_creator in self._peer_connections[peer].request_creators:
|
||||||
self.peer_connections[peer]['request_creators'].remove(request_creator)
|
self._peer_connections[peer].request_creators.remove(request_creator)
|
||||||
else:
|
else:
|
||||||
if not request_creator in self.peer_connections[peer]['request_creators']:
|
if not request_creator in self._peer_connections[peer].request_creators:
|
||||||
self.peer_connections[peer]['request_creators'].append(request_creator)
|
self._peer_connections[peer].request_creators.append(request_creator)
|
||||||
return request_sent
|
return request_sent
|
||||||
|
|
||||||
def check_requests(requests):
|
def check_requests(requests):
|
||||||
|
@ -89,7 +95,7 @@ class ConnectionManager(object):
|
||||||
def get_secondary_requests_if_necessary(have_request):
|
def get_secondary_requests_if_necessary(have_request):
|
||||||
if have_request is True:
|
if have_request is True:
|
||||||
ds = []
|
ds = []
|
||||||
for s_r_c in self.secondary_request_creators:
|
for s_r_c in self._secondary_request_creators:
|
||||||
d = s_r_c.send_next_request(peer, protocol)
|
d = s_r_c.send_next_request(peer, protocol)
|
||||||
ds.append(d)
|
ds.append(d)
|
||||||
dl = defer.DeferredList(ds)
|
dl = defer.DeferredList(ds)
|
||||||
|
@ -100,7 +106,7 @@ class ConnectionManager(object):
|
||||||
|
|
||||||
ds = []
|
ds = []
|
||||||
|
|
||||||
for p_r_c in self.primary_request_creators:
|
for p_r_c in self._primary_request_creators:
|
||||||
d = p_r_c.send_next_request(peer, protocol)
|
d = p_r_c.send_next_request(peer, protocol)
|
||||||
d.addErrback(handle_error)
|
d.addErrback(handle_error)
|
||||||
d.addCallback(check_if_request_sent, p_r_c)
|
d.addCallback(check_if_request_sent, p_r_c)
|
||||||
|
@ -112,11 +118,11 @@ class ConnectionManager(object):
|
||||||
return dl
|
return dl
|
||||||
|
|
||||||
def protocol_disconnected(self, peer, protocol):
|
def protocol_disconnected(self, peer, protocol):
|
||||||
if peer in self.peer_connections:
|
if peer in self._peer_connections:
|
||||||
del self.peer_connections[peer]
|
del self._peer_connections[peer]
|
||||||
if peer in self.connections_closing:
|
if peer in self._connections_closing:
|
||||||
d = self.connections_closing[peer]
|
d = self._connections_closing[peer]
|
||||||
del self.connections_closing[peer]
|
del self._connections_closing[peer]
|
||||||
d.callback(True)
|
d.callback(True)
|
||||||
|
|
||||||
def _rank_request_creator_connections(self):
|
def _rank_request_creator_connections(self):
|
||||||
|
@ -125,9 +131,9 @@ class ConnectionManager(object):
|
||||||
connections open that it likes
|
connections open that it likes
|
||||||
"""
|
"""
|
||||||
def count_peers(request_creator):
|
def count_peers(request_creator):
|
||||||
return len([p for p in self.peer_connections.itervalues() if request_creator in p['request_creators']])
|
return len([p for p in self._peer_connections.itervalues() if request_creator in p.request_creators])
|
||||||
|
|
||||||
return sorted(self.primary_request_creators, key=count_peers)
|
return sorted(self._primary_request_creators, key=count_peers)
|
||||||
|
|
||||||
def _connect_to_peer(self, peer):
|
def _connect_to_peer(self, peer):
|
||||||
|
|
||||||
|
@ -136,10 +142,10 @@ class ConnectionManager(object):
|
||||||
if peer is not None:
|
if peer is not None:
|
||||||
logging.debug("Trying to connect to %s", str(peer))
|
logging.debug("Trying to connect to %s", str(peer))
|
||||||
factory = ClientProtocolFactory(peer, self.rate_limiter, self)
|
factory = ClientProtocolFactory(peer, self.rate_limiter, self)
|
||||||
|
self._peer_connections[peer] = PeerConnectionHandler(self._primary_request_creators[:],
|
||||||
|
factory)
|
||||||
connection = reactor.connectTCP(peer.host, peer.port, factory)
|
connection = reactor.connectTCP(peer.host, peer.port, factory)
|
||||||
self.peer_connections[peer] = {'connection': connection,
|
self._peer_connections[peer].connection = connection
|
||||||
'request_creators': self.primary_request_creators[:],
|
|
||||||
'factory': factory}
|
|
||||||
|
|
||||||
def _manage(self):
|
def _manage(self):
|
||||||
|
|
||||||
|
@ -162,16 +168,16 @@ class ConnectionManager(object):
|
||||||
if peers is None:
|
if peers is None:
|
||||||
return None
|
return None
|
||||||
for peer in peers:
|
for peer in peers:
|
||||||
if not peer in self.peer_connections:
|
if not peer in self._peer_connections:
|
||||||
logging.debug("Got a good peer. Returning peer %s", str(peer))
|
logging.debug("Got a good peer. Returning peer %s", str(peer))
|
||||||
return peer
|
return peer
|
||||||
logging.debug("Couldn't find a good peer to connect to")
|
logging.debug("Couldn't find a good peer to connect to")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if len(self.peer_connections) < MAX_CONNECTIONS_PER_STREAM:
|
if len(self._peer_connections) < MAX_CONNECTIONS_PER_STREAM:
|
||||||
ordered_request_creators = self._rank_request_creator_connections()
|
ordered_request_creators = self._rank_request_creator_connections()
|
||||||
d = get_new_peers(ordered_request_creators)
|
d = get_new_peers(ordered_request_creators)
|
||||||
d.addCallback(pick_best_peer)
|
d.addCallback(pick_best_peer)
|
||||||
d.addCallback(self._connect_to_peer)
|
d.addCallback(self._connect_to_peer)
|
||||||
|
|
||||||
self.next_manage_call = reactor.callLater(1, self._manage)
|
self._next_manage_call = reactor.callLater(1, self._manage)
|
|
@ -445,10 +445,7 @@ class IQueryHandlerFactory(Interface):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class IStreamDownloaderFactory(Interface):
|
class IStreamDownloaderOptions(Interface):
|
||||||
"""
|
|
||||||
Construct IStreamDownloaders and provide options that will be passed to those IStreamDownloaders.
|
|
||||||
"""
|
|
||||||
def get_downloader_options(self, sd_validator, payment_rate_manager):
|
def get_downloader_options(self, sd_validator, payment_rate_manager):
|
||||||
"""
|
"""
|
||||||
Return the list of options that can be used to modify IStreamDownloader behavior
|
Return the list of options that can be used to modify IStreamDownloader behavior
|
||||||
|
@ -459,8 +456,28 @@ class IStreamDownloaderFactory(Interface):
|
||||||
@param payment_rate_manager: The payment rate manager currently in effect for the downloader
|
@param payment_rate_manager: The payment rate manager currently in effect for the downloader
|
||||||
@type payment_rate_manager: PaymentRateManager
|
@type payment_rate_manager: PaymentRateManager
|
||||||
|
|
||||||
@return: [(option_description, default)]
|
@return: [DownloadOption]
|
||||||
@rtype: [(string, string)]
|
@rtype: [DownloadOption]
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class IStreamDownloaderFactory(Interface):
|
||||||
|
"""
|
||||||
|
Construct IStreamDownloaders and provide options that will be passed to those IStreamDownloaders.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def can_download(self, sd_validator, payment_rate_manager):
|
||||||
|
"""
|
||||||
|
Decide whether the downloaders created by this factory can download the stream described by sd_validator
|
||||||
|
|
||||||
|
@param sd_validator: object containing stream metadata
|
||||||
|
@type sd_validator: object which implements IStreamDescriptorValidator interface
|
||||||
|
|
||||||
|
@param payment_rate_manager: The payment rate manager currently in effect for the downloader
|
||||||
|
@type payment_rate_manager: PaymentRateManager
|
||||||
|
|
||||||
|
@return: True if the downloaders can download the stream, False otherwise
|
||||||
|
@rtype: bool
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def make_downloader(self, sd_validator, options, payment_rate_manager):
|
def make_downloader(self, sd_validator, options, payment_rate_manager):
|
||||||
|
@ -470,10 +487,10 @@ class IStreamDownloaderFactory(Interface):
|
||||||
@param sd_validator: object containing stream metadata which will be given to the IStreamDownloader
|
@param sd_validator: object containing stream metadata which will be given to the IStreamDownloader
|
||||||
@type sd_validator: object which implements IStreamDescriptorValidator interface
|
@type sd_validator: object which implements IStreamDescriptorValidator interface
|
||||||
|
|
||||||
@param options: a list of strings that will be used by the IStreamDownloaderFactory to
|
@param options: a list of values that will be used by the IStreamDownloaderFactory to
|
||||||
construct the IStreamDownloader. the options are in the same order as they were given
|
construct the IStreamDownloader. the options are in the same order as they were given
|
||||||
by get_downloader_options.
|
by get_downloader_options.
|
||||||
@type options: [string]
|
@type options: [Object]
|
||||||
|
|
||||||
@param payment_rate_manager: the PaymentRateManager which the IStreamDownloader should use.
|
@param payment_rate_manager: the PaymentRateManager which the IStreamDownloader should use.
|
||||||
@type payment_rate_manager: PaymentRateManager
|
@type payment_rate_manager: PaymentRateManager
|
||||||
|
|
|
@ -3,7 +3,6 @@ import binascii
|
||||||
|
|
||||||
from zope.interface import implements
|
from zope.interface import implements
|
||||||
|
|
||||||
from lbrynet.core.DownloadOption import DownloadOption
|
|
||||||
from lbrynet.lbryfile.StreamDescriptor import save_sd_info
|
from lbrynet.lbryfile.StreamDescriptor import save_sd_info
|
||||||
from lbrynet.cryptstream.client.CryptStreamDownloader import CryptStreamDownloader
|
from lbrynet.cryptstream.client.CryptStreamDownloader import CryptStreamDownloader
|
||||||
from lbrynet.core.client.StreamProgressManager import FullStreamProgressManager
|
from lbrynet.core.client.StreamProgressManager import FullStreamProgressManager
|
||||||
|
@ -11,6 +10,7 @@ from lbrynet.interfaces import IStreamDownloaderFactory
|
||||||
from lbrynet.lbryfile.client.LBRYFileMetadataHandler import LBRYFileMetadataHandler
|
from lbrynet.lbryfile.client.LBRYFileMetadataHandler import LBRYFileMetadataHandler
|
||||||
import os
|
import os
|
||||||
from twisted.internet import defer, threads, reactor
|
from twisted.internet import defer, threads, reactor
|
||||||
|
from distutils.spawn import find_executable
|
||||||
|
|
||||||
|
|
||||||
class LBRYFileDownloader(CryptStreamDownloader):
|
class LBRYFileDownloader(CryptStreamDownloader):
|
||||||
|
@ -94,26 +94,11 @@ class LBRYFileDownloaderFactory(object):
|
||||||
self.stream_info_manager = stream_info_manager
|
self.stream_info_manager = stream_info_manager
|
||||||
self.wallet = wallet
|
self.wallet = wallet
|
||||||
|
|
||||||
def get_downloader_options(self, sd_validator, payment_rate_manager):
|
def can_download(self, sd_validator):
|
||||||
options = [
|
return True
|
||||||
DownloadOption(
|
|
||||||
[float, None],
|
|
||||||
"rate which will be paid for data (None means use application default)",
|
|
||||||
"data payment rate",
|
|
||||||
None
|
|
||||||
),
|
|
||||||
DownloadOption(
|
|
||||||
[bool],
|
|
||||||
"allow reuploading data downloaded for this file",
|
|
||||||
"allow upload",
|
|
||||||
True
|
|
||||||
),
|
|
||||||
]
|
|
||||||
return options
|
|
||||||
|
|
||||||
def make_downloader(self, sd_validator, options, payment_rate_manager, **kwargs):
|
def make_downloader(self, sd_validator, options, payment_rate_manager, **kwargs):
|
||||||
if options[0] is not None:
|
payment_rate_manager.min_blob_data_payment_rate = options[0]
|
||||||
payment_rate_manager.float(options[0])
|
|
||||||
upload_allowed = options[1]
|
upload_allowed = options[1]
|
||||||
|
|
||||||
def create_downloader(stream_hash):
|
def create_downloader(stream_hash):
|
||||||
|
@ -276,6 +261,9 @@ class LBRYFileOpener(LBRYFileDownloader):
|
||||||
|
|
||||||
|
|
||||||
class LBRYFileOpenerFactory(LBRYFileDownloaderFactory):
|
class LBRYFileOpenerFactory(LBRYFileDownloaderFactory):
|
||||||
|
def can_download(self, sd_validator):
|
||||||
|
return bool(find_executable('vlc'))
|
||||||
|
|
||||||
def _make_downloader(self, stream_hash, payment_rate_manager, stream_info, upload_allowed):
|
def _make_downloader(self, stream_hash, payment_rate_manager, stream_info, upload_allowed):
|
||||||
return LBRYFileOpener(stream_hash, self.peer_finder, self.rate_limiter, self.blob_manager,
|
return LBRYFileOpener(stream_hash, self.peer_finder, self.rate_limiter, self.blob_manager,
|
||||||
self.stream_info_manager, payment_rate_manager, self.wallet, upload_allowed)
|
self.stream_info_manager, payment_rate_manager, self.wallet, upload_allowed)
|
||||||
|
|
55
lbrynet/lbryfile/client/LBRYFileOptions.py
Normal file
55
lbrynet/lbryfile/client/LBRYFileOptions.py
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
from lbrynet.lbryfile.StreamDescriptor import LBRYFileStreamType, LBRYFileStreamDescriptorValidator
|
||||||
|
from lbrynet.core.DownloadOption import DownloadOption, DownloadChoice
|
||||||
|
|
||||||
|
|
||||||
|
def add_lbry_file_to_sd_identifier(sd_identifier):
|
||||||
|
sd_identifier.add_stream_type(LBRYFileStreamType, LBRYFileStreamDescriptorValidator, LBRYFileOptions())
|
||||||
|
|
||||||
|
|
||||||
|
class LBRYFileOptions(object):
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_downloader_options(self, sd_validator, payment_rate_manager):
|
||||||
|
prm = payment_rate_manager
|
||||||
|
|
||||||
|
def get_default_data_rate_description():
|
||||||
|
if prm.min_blob_data_payment_rate is None:
|
||||||
|
return "Application default (%s LBC/MB)" % str(prm.base.min_blob_data_payment_rate)
|
||||||
|
else:
|
||||||
|
return "%f LBC/MB" % prm.min_blob_data_payment_rate
|
||||||
|
|
||||||
|
rate_choices = []
|
||||||
|
rate_choices.append(DownloadChoice(prm.min_blob_data_payment_rate,
|
||||||
|
"No change - %s" % get_default_data_rate_description(),
|
||||||
|
"No change - %s" % get_default_data_rate_description()))
|
||||||
|
if prm.min_blob_data_payment_rate is not None:
|
||||||
|
rate_choices.append(DownloadChoice(None,
|
||||||
|
"Application default (%s LBC/MB)" % str(prm.base.min_blob_data_payment_rate),
|
||||||
|
"Application default (%s LBC/MB)" % str(prm.base.min_blob_data_payment_rate)))
|
||||||
|
rate_choices.append(DownloadChoice(float,
|
||||||
|
"Enter rate in LBC/MB",
|
||||||
|
"Enter rate in LBC/MB"))
|
||||||
|
|
||||||
|
options = [
|
||||||
|
DownloadOption(
|
||||||
|
rate_choices,
|
||||||
|
"Rate which will be paid for data",
|
||||||
|
"data payment rate",
|
||||||
|
prm.min_blob_data_payment_rate,
|
||||||
|
get_default_data_rate_description()
|
||||||
|
),
|
||||||
|
DownloadOption(
|
||||||
|
[
|
||||||
|
DownloadChoice(bool,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
bool_options_description=("Allow", "Disallow")),
|
||||||
|
],
|
||||||
|
"Allow reuploading data downloaded for this file",
|
||||||
|
"allow upload",
|
||||||
|
True,
|
||||||
|
"Allow"
|
||||||
|
),
|
||||||
|
]
|
||||||
|
return options
|
|
@ -2,7 +2,6 @@
|
||||||
Download LBRY Files from LBRYnet and save them to disk.
|
Download LBRY Files from LBRYnet and save them to disk.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from lbrynet.core.DownloadOption import DownloadOption
|
|
||||||
from zope.interface import implements
|
from zope.interface import implements
|
||||||
from lbrynet.core.client.StreamProgressManager import FullStreamProgressManager
|
from lbrynet.core.client.StreamProgressManager import FullStreamProgressManager
|
||||||
from lbrynet.lbryfile.client.LBRYFileDownloader import LBRYFileSaver, LBRYFileDownloader
|
from lbrynet.lbryfile.client.LBRYFileDownloader import LBRYFileSaver, LBRYFileDownloader
|
||||||
|
@ -117,22 +116,8 @@ class ManagedLBRYFileDownloaderFactory(object):
|
||||||
def __init__(self, lbry_file_manager):
|
def __init__(self, lbry_file_manager):
|
||||||
self.lbry_file_manager = lbry_file_manager
|
self.lbry_file_manager = lbry_file_manager
|
||||||
|
|
||||||
def get_downloader_options(self, sd_validator, payment_rate_manager):
|
def can_download(self, sd_validator):
|
||||||
options = [
|
return True
|
||||||
DownloadOption(
|
|
||||||
[float, None],
|
|
||||||
"rate which will be paid for data (None means use application default)",
|
|
||||||
"data payment rate",
|
|
||||||
None
|
|
||||||
),
|
|
||||||
DownloadOption(
|
|
||||||
[bool],
|
|
||||||
"allow reuploading data downloaded for this file",
|
|
||||||
"allow upload",
|
|
||||||
True
|
|
||||||
),
|
|
||||||
]
|
|
||||||
return options
|
|
||||||
|
|
||||||
def make_downloader(self, sd_validator, options, payment_rate_manager):
|
def make_downloader(self, sd_validator, options, payment_rate_manager):
|
||||||
data_rate = options[0]
|
data_rate = options[0]
|
||||||
|
|
|
@ -7,7 +7,6 @@ import json
|
||||||
|
|
||||||
import leveldb
|
import leveldb
|
||||||
|
|
||||||
from lbrynet.lbryfile.StreamDescriptor import LBRYFileStreamDescriptorValidator
|
|
||||||
import os
|
import os
|
||||||
from lbrynet.lbryfilemanager.LBRYFileDownloader import ManagedLBRYFileDownloader
|
from lbrynet.lbryfilemanager.LBRYFileDownloader import ManagedLBRYFileDownloader
|
||||||
from lbrynet.lbryfilemanager.LBRYFileDownloader import ManagedLBRYFileDownloaderFactory
|
from lbrynet.lbryfilemanager.LBRYFileDownloader import ManagedLBRYFileDownloaderFactory
|
||||||
|
@ -98,7 +97,6 @@ class LBRYFileManager(object):
|
||||||
|
|
||||||
def _add_to_sd_identifier(self):
|
def _add_to_sd_identifier(self):
|
||||||
downloader_factory = ManagedLBRYFileDownloaderFactory(self)
|
downloader_factory = ManagedLBRYFileDownloaderFactory(self)
|
||||||
self.sd_identifier.add_stream_info_validator(LBRYFileStreamType, LBRYFileStreamDescriptorValidator)
|
|
||||||
self.sd_identifier.add_stream_downloader_factory(LBRYFileStreamType, downloader_factory)
|
self.sd_identifier.add_stream_downloader_factory(LBRYFileStreamType, downloader_factory)
|
||||||
|
|
||||||
def _start_lbry_files(self):
|
def _start_lbry_files(self):
|
||||||
|
|
|
@ -1,15 +1,12 @@
|
||||||
from lbrynet.core.StreamDescriptor import BlobStreamDescriptorWriter
|
from lbrynet.core.StreamDescriptor import BlobStreamDescriptorWriter
|
||||||
from lbrynet.lbrylive.StreamDescriptor import get_sd_info, LiveStreamType, LBRYLiveStreamDescriptorValidator
|
from lbrynet.lbrylive.StreamDescriptor import get_sd_info
|
||||||
from lbrynet.cryptstream.CryptStreamCreator import CryptStreamCreator
|
from lbrynet.cryptstream.CryptStreamCreator import CryptStreamCreator
|
||||||
from lbrynet.lbrylive.LiveBlob import LiveStreamBlobMaker
|
from lbrynet.lbrylive.LiveBlob import LiveStreamBlobMaker
|
||||||
from lbrynet.lbrylive.PaymentRateManager import BaseLiveStreamPaymentRateManager
|
|
||||||
from lbrynet.core.cryptoutils import get_lbry_hash_obj, get_pub_key, sign_with_pass_phrase
|
from lbrynet.core.cryptoutils import get_lbry_hash_obj, get_pub_key, sign_with_pass_phrase
|
||||||
from Crypto import Random
|
from Crypto import Random
|
||||||
import binascii
|
import binascii
|
||||||
import logging
|
import logging
|
||||||
from lbrynet.conf import CRYPTSD_FILE_EXTENSION
|
from lbrynet.conf import CRYPTSD_FILE_EXTENSION
|
||||||
from lbrynet.conf import MIN_BLOB_INFO_PAYMENT_RATE
|
|
||||||
from lbrynet.lbrylive.client.LiveStreamDownloader import FullLiveStreamDownloaderFactory
|
|
||||||
from twisted.internet import interfaces, defer
|
from twisted.internet import interfaces, defer
|
||||||
from twisted.protocols.basic import FileSender
|
from twisted.protocols.basic import FileSender
|
||||||
from zope.interface import implements
|
from zope.interface import implements
|
||||||
|
@ -173,17 +170,4 @@ class StdinStreamProducer(object):
|
||||||
self.consumer.write(data)
|
self.consumer.write(data)
|
||||||
|
|
||||||
def childConnectionLost(self, fd, reason):
|
def childConnectionLost(self, fd, reason):
|
||||||
self.stopProducing()
|
self.stopProducing()
|
||||||
|
|
||||||
|
|
||||||
def add_live_stream_to_sd_identifier(session, stream_info_manager, sd_identifier):
|
|
||||||
downloader_factory = FullLiveStreamDownloaderFactory(session.peer_finder,
|
|
||||||
session.rate_limiter,
|
|
||||||
session.blob_manager,
|
|
||||||
stream_info_manager,
|
|
||||||
session.wallet,
|
|
||||||
BaseLiveStreamPaymentRateManager(
|
|
||||||
MIN_BLOB_INFO_PAYMENT_RATE
|
|
||||||
))
|
|
||||||
sd_identifier.add_stream_info_validator(LiveStreamType, LBRYLiveStreamDescriptorValidator)
|
|
||||||
sd_identifier.add_stream_downloader_factory(LiveStreamType, downloader_factory)
|
|
|
@ -1,5 +1,4 @@
|
||||||
import binascii
|
import binascii
|
||||||
from lbrynet.core.DownloadOption import DownloadOption
|
|
||||||
from lbrynet.cryptstream.client.CryptStreamDownloader import CryptStreamDownloader
|
from lbrynet.cryptstream.client.CryptStreamDownloader import CryptStreamDownloader
|
||||||
from zope.interface import implements
|
from zope.interface import implements
|
||||||
from lbrynet.lbrylive.client.LiveStreamMetadataHandler import LiveStreamMetadataHandler
|
from lbrynet.lbrylive.client.LiveStreamMetadataHandler import LiveStreamMetadataHandler
|
||||||
|
@ -9,6 +8,9 @@ from lbrynet.lbrylive.StreamDescriptor import save_sd_info
|
||||||
from lbrynet.lbrylive.PaymentRateManager import LiveStreamPaymentRateManager
|
from lbrynet.lbrylive.PaymentRateManager import LiveStreamPaymentRateManager
|
||||||
from twisted.internet import defer, threads # , process
|
from twisted.internet import defer, threads # , process
|
||||||
from lbrynet.interfaces import IStreamDownloaderFactory
|
from lbrynet.interfaces import IStreamDownloaderFactory
|
||||||
|
from lbrynet.lbrylive.PaymentRateManager import BaseLiveStreamPaymentRateManager
|
||||||
|
from lbrynet.conf import MIN_BLOB_INFO_PAYMENT_RATE
|
||||||
|
from lbrynet.lbrylive.StreamDescriptor import LiveStreamType
|
||||||
|
|
||||||
|
|
||||||
class LiveStreamDownloader(CryptStreamDownloader):
|
class LiveStreamDownloader(CryptStreamDownloader):
|
||||||
|
@ -138,28 +140,8 @@ class FullLiveStreamDownloaderFactory(object):
|
||||||
self.wallet = wallet
|
self.wallet = wallet
|
||||||
self.default_payment_rate_manager = default_payment_rate_manager
|
self.default_payment_rate_manager = default_payment_rate_manager
|
||||||
|
|
||||||
def get_downloader_options(self, sd_validator, payment_rate_manager):
|
def can_download(self, sd_validator):
|
||||||
options = [
|
return True
|
||||||
DownloadOption(
|
|
||||||
[float, None],
|
|
||||||
"rate which will be paid for data (None means use application default)",
|
|
||||||
"data payment rate",
|
|
||||||
None
|
|
||||||
),
|
|
||||||
DownloadOption(
|
|
||||||
[float, None],
|
|
||||||
"rate which will be paid for metadata (None means use application default)",
|
|
||||||
"metadata payment rate",
|
|
||||||
None
|
|
||||||
),
|
|
||||||
DownloadOption(
|
|
||||||
[bool],
|
|
||||||
"allow reuploading data downloaded for this file",
|
|
||||||
"allow upload",
|
|
||||||
True
|
|
||||||
),
|
|
||||||
]
|
|
||||||
return options
|
|
||||||
|
|
||||||
def make_downloader(self, sd_validator, options, payment_rate_manager):
|
def make_downloader(self, sd_validator, options, payment_rate_manager):
|
||||||
# TODO: check options for payment rate manager parameters
|
# TODO: check options for payment rate manager parameters
|
||||||
|
@ -177,4 +159,15 @@ class FullLiveStreamDownloaderFactory(object):
|
||||||
return d
|
return d
|
||||||
|
|
||||||
d.addCallback(create_downloader)
|
d.addCallback(create_downloader)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
def add_full_live_stream_downloader_to_sd_identifier(session, stream_info_manager, sd_identifier,
|
||||||
|
base_live_stream_payment_rate_manager):
|
||||||
|
downloader_factory = FullLiveStreamDownloaderFactory(session.peer_finder,
|
||||||
|
session.rate_limiter,
|
||||||
|
session.blob_manager,
|
||||||
|
stream_info_manager,
|
||||||
|
session.wallet,
|
||||||
|
base_live_stream_payment_rate_manager)
|
||||||
|
sd_identifier.add_stream_downloader_factory(LiveStreamType, downloader_factory)
|
73
lbrynet/lbrylive/client/LiveStreamOptions.py
Normal file
73
lbrynet/lbrylive/client/LiveStreamOptions.py
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
from lbrynet.lbrylive.StreamDescriptor import LiveStreamType, LBRYLiveStreamDescriptorValidator
|
||||||
|
from lbrynet.core.DownloadOption import DownloadOption, DownloadChoice
|
||||||
|
|
||||||
|
|
||||||
|
def add_live_stream_to_sd_identifier(sd_identifier, base_live_stream_payment_rate_manager):
|
||||||
|
sd_identifier.add_stream_type(LiveStreamType, LBRYLiveStreamDescriptorValidator,
|
||||||
|
LiveStreamOptions(base_live_stream_payment_rate_manager))
|
||||||
|
|
||||||
|
|
||||||
|
class LiveStreamOptions(object):
|
||||||
|
def __init__(self, base_live_stream_payment_rate_manager):
|
||||||
|
self.base_live_stream_prm = base_live_stream_payment_rate_manager
|
||||||
|
|
||||||
|
def get_downloader_options(self, sd_validator, payment_rate_manager):
|
||||||
|
prm = payment_rate_manager
|
||||||
|
|
||||||
|
def get_default_data_rate_description():
|
||||||
|
if prm.min_blob_data_payment_rate is None:
|
||||||
|
return "Application default (%s LBC/MB)" % str(prm.base.min_blob_data_payment_rate)
|
||||||
|
else:
|
||||||
|
return "%f LBC/MB" % prm.min_blob_data_payment_rate
|
||||||
|
|
||||||
|
options = [
|
||||||
|
DownloadOption(
|
||||||
|
[
|
||||||
|
DownloadChoice(None,
|
||||||
|
"No change",
|
||||||
|
"No change"),
|
||||||
|
DownloadChoice(None,
|
||||||
|
"Application default (%s LBC/MB)" % str(prm.base.min_blob_data_payment_rate),
|
||||||
|
"Default (%s LBC/MB)" % str(prm.base.min_blob_data_payment_rate)),
|
||||||
|
DownloadChoice(float,
|
||||||
|
"Rate in LBC/MB",
|
||||||
|
"Rate in LBC/MB")
|
||||||
|
],
|
||||||
|
"rate which will be paid for data",
|
||||||
|
"data payment rate",
|
||||||
|
prm.min_blob_data_payment_rate,
|
||||||
|
get_default_data_rate_description()
|
||||||
|
),
|
||||||
|
DownloadOption(
|
||||||
|
[
|
||||||
|
DownloadChoice(None,
|
||||||
|
"No change",
|
||||||
|
"No change"),
|
||||||
|
DownloadChoice(None,
|
||||||
|
"Application default (%s LBC/MB)" % str(self.base_live_stream_prm.min_live_blob_info_payment_rate),
|
||||||
|
"Default (%s LBC/MB)" % str(self.base_live_stream_prm.min_live_blob_info_payment_rate)),
|
||||||
|
DownloadChoice(float,
|
||||||
|
"Rate in LBC/MB",
|
||||||
|
"Rate in LBC/MB")
|
||||||
|
],
|
||||||
|
"rate which will be paid for metadata",
|
||||||
|
"metadata payment rate",
|
||||||
|
None,
|
||||||
|
"Application default (%s LBC/MB)" % str(self.base_live_stream_prm.min_live_blob_info_payment_rate)
|
||||||
|
),
|
||||||
|
DownloadOption(
|
||||||
|
[
|
||||||
|
DownloadChoice(True,
|
||||||
|
"Allow reuploading data downloaded for this file",
|
||||||
|
"Allow reuploading"),
|
||||||
|
DownloadChoice(False,
|
||||||
|
"Disallow reuploading data downloaded for this file",
|
||||||
|
"Disallow reuploading")
|
||||||
|
],
|
||||||
|
"allow reuploading data downloaded for this file",
|
||||||
|
"allow upload",
|
||||||
|
True,
|
||||||
|
"Allow"
|
||||||
|
),
|
||||||
|
]
|
||||||
|
return options
|
|
@ -13,6 +13,10 @@ class InvalidChoiceError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidValueError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class ControlHandlerFactory(object):
|
class ControlHandlerFactory(object):
|
||||||
implements(IControlHandlerFactory)
|
implements(IControlHandlerFactory)
|
||||||
|
|
||||||
|
@ -235,9 +239,11 @@ class AddStream(ControlHandler):
|
||||||
self.factories = None
|
self.factories = None
|
||||||
self.factory = None
|
self.factory = None
|
||||||
self.info_validator = None
|
self.info_validator = None
|
||||||
|
self.options = None
|
||||||
self.options_left = []
|
self.options_left = []
|
||||||
self.options_chosen = []
|
self.options_chosen = []
|
||||||
self.current_option = None
|
self.current_option = None
|
||||||
|
self.current_choice = None
|
||||||
self.downloader = None
|
self.downloader = None
|
||||||
self.got_options_response = False
|
self.got_options_response = False
|
||||||
self.loading_failed = False
|
self.loading_failed = False
|
||||||
|
@ -274,18 +280,31 @@ class AddStream(ControlHandler):
|
||||||
return False, defer.succeed(self._show_factory_choices())
|
return False, defer.succeed(self._show_factory_choices())
|
||||||
if self.got_options_response is False:
|
if self.got_options_response is False:
|
||||||
self.got_options_response = True
|
self.got_options_response = True
|
||||||
if line == 'y' or line == 'Y':
|
if line == 'y' or line == 'Y' and self.options_left:
|
||||||
if self.options_left:
|
return False, defer.succeed(self._get_next_option_prompt())
|
||||||
return False, defer.succeed(self._get_next_option_prompt())
|
else:
|
||||||
self.options_chosen = [option.default for option in self.options_left]
|
self.options_chosen = [option.default_value for option in self.options_left]
|
||||||
self.options_left = []
|
self.options_left = []
|
||||||
return False, defer.succeed(self.line_prompt3)
|
return False, defer.succeed(self.line_prompt3)
|
||||||
if self.current_option is not None:
|
if self.current_option is not None:
|
||||||
try:
|
if self.current_choice is None:
|
||||||
choice = self._get_choice_from_input(line)
|
try:
|
||||||
except InvalidChoiceError:
|
self.current_choice = self._get_choice_from_input(line)
|
||||||
return False, defer.succeed(self._get_next_option_prompt(invalid_response=True))
|
except InvalidChoiceError:
|
||||||
self.options_chosen.append(choice)
|
return False, defer.succeed(self._get_next_option_prompt(invalid_choice=True))
|
||||||
|
choice = self.current_option.option_types[self.current_choice]
|
||||||
|
if choice.value == float or choice.value == bool:
|
||||||
|
return False, defer.succeed(self._get_choice_value_prompt())
|
||||||
|
else:
|
||||||
|
value = choice.value
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
value = self._get_value_for_choice(line)
|
||||||
|
except InvalidValueError:
|
||||||
|
return False, defer.succeed(self._get_choice_value_prompt(invalid_value=True))
|
||||||
|
self.options_chosen.append(value)
|
||||||
|
self.current_choice = None
|
||||||
|
self.current_option = None
|
||||||
self.options_left = self.options_left[1:]
|
self.options_left = self.options_left[1:]
|
||||||
if self.options_left:
|
if self.options_left:
|
||||||
return False, defer.succeed(self._get_next_option_prompt())
|
return False, defer.succeed(self._get_next_option_prompt())
|
||||||
|
@ -299,23 +318,13 @@ class AddStream(ControlHandler):
|
||||||
return True, d
|
return True, d
|
||||||
|
|
||||||
def _get_choice_from_input(self, line):
|
def _get_choice_from_input(self, line):
|
||||||
if line == "":
|
try:
|
||||||
return self.current_option.default
|
choice_num = int(line)
|
||||||
for option_type in self.current_option.option_types:
|
except ValueError:
|
||||||
if option_type == float:
|
raise InvalidChoiceError()
|
||||||
try:
|
if 0 <= choice_num < len(self.current_option.option_types):
|
||||||
return float(line)
|
return choice_num
|
||||||
except ValueError:
|
raise InvalidChoiceError()
|
||||||
pass
|
|
||||||
if option_type is None:
|
|
||||||
if line.lower() == "none":
|
|
||||||
return None
|
|
||||||
if option_type == bool:
|
|
||||||
if line.lower() == "true" or line.lower() == "t":
|
|
||||||
return True
|
|
||||||
if line.lower() == "false" or line.lower() == "f":
|
|
||||||
return False
|
|
||||||
raise InvalidChoiceError(line)
|
|
||||||
|
|
||||||
def _load_info_and_factories(self, sd_file):
|
def _load_info_and_factories(self, sd_file):
|
||||||
return defer.fail(NotImplementedError())
|
return defer.fail(NotImplementedError())
|
||||||
|
@ -333,7 +342,7 @@ class AddStream(ControlHandler):
|
||||||
|
|
||||||
def _choose_factory(self, info_and_factories):
|
def _choose_factory(self, info_and_factories):
|
||||||
self.loading_info_and_factories_deferred = None
|
self.loading_info_and_factories_deferred = None
|
||||||
self.info_validator, self.factories = info_and_factories
|
self.info_validator, self.options, self.factories = info_and_factories
|
||||||
if len(self.factories) == 1:
|
if len(self.factories) == 1:
|
||||||
self.factory = self.factories[0]
|
self.factory = self.factories[0]
|
||||||
return self._show_info_and_options()
|
return self._show_info_and_options()
|
||||||
|
@ -346,38 +355,71 @@ class AddStream(ControlHandler):
|
||||||
return str(prompt)
|
return str(prompt)
|
||||||
|
|
||||||
def _show_info_and_options(self):
|
def _show_info_and_options(self):
|
||||||
self.options_left = self.factory.get_downloader_options(self.info_validator,
|
self.options_left = self.options.get_downloader_options(self.info_validator,
|
||||||
self.payment_rate_manager)
|
self.payment_rate_manager)
|
||||||
prompt = "Stream info:\n"
|
prompt = "Stream info:\n"
|
||||||
for info_line in self.info_validator.info_to_show():
|
for info_line in self.info_validator.info_to_show():
|
||||||
prompt += info_line[0] + ": " + info_line[1] + "\n"
|
prompt += info_line[0] + ": " + info_line[1] + "\n"
|
||||||
prompt += "\nOptions:\n"
|
prompt += "\nOptions:\n"
|
||||||
for option in self.options_left:
|
for option in self.options_left:
|
||||||
prompt += option.long_description + ": " + str(option.default) + "\n"
|
prompt += option.long_description + ": " + str(option.default_value_description) + "\n"
|
||||||
prompt += "\nModify options? (y/n)"
|
prompt += "\nModify options? (y/n)"
|
||||||
return str(prompt)
|
return str(prompt)
|
||||||
|
|
||||||
def _get_option_type_description(self, option_type):
|
def _get_list_of_option_types(self):
|
||||||
if option_type == float:
|
options_string = ""
|
||||||
return "floating point number (e.g. 1.0)"
|
for i, option_type in enumerate(self.current_option.option_types):
|
||||||
if option_type == bool:
|
options_string += "[%s] %s\n" % (str(i), option_type.long_description)
|
||||||
return "True or False"
|
options_string += "Enter choice:"
|
||||||
if option_type is None:
|
return options_string
|
||||||
return "None"
|
|
||||||
|
|
||||||
def _get_next_option_prompt(self, invalid_response=False):
|
def _get_choice_value_prompt(self, invalid_value=False):
|
||||||
assert len(self.options_left), "Something went wrong. There were no options left"
|
choice = self.current_option.option_types[self.current_choice]
|
||||||
choice = self.options_left[0]
|
|
||||||
choice_string = ""
|
choice_string = ""
|
||||||
if invalid_response is True:
|
if invalid_value is True:
|
||||||
|
"Invalid value entered. Try again.\n"
|
||||||
|
if choice.short_description is not None:
|
||||||
|
choice_string += choice.short_description + "\n"
|
||||||
|
if choice.value == float:
|
||||||
|
choice_string += "Enter floating point number (e.g. 1.0):"
|
||||||
|
elif choice.value == bool:
|
||||||
|
true_string = "Yes"
|
||||||
|
false_string = "No"
|
||||||
|
if choice.bool_options_description is not None:
|
||||||
|
true_string, false_string = choice.bool_options_description
|
||||||
|
choice_string += "[0] %s\n[1] %s\nEnter choice:" % (true_string, false_string)
|
||||||
|
else:
|
||||||
|
NotImplementedError()
|
||||||
|
return choice_string
|
||||||
|
|
||||||
|
def _get_value_for_choice(self, input):
|
||||||
|
choice = self.current_option.option_types[self.current_choice]
|
||||||
|
if choice.value == float:
|
||||||
|
try:
|
||||||
|
return float(input)
|
||||||
|
except ValueError:
|
||||||
|
raise InvalidValueError()
|
||||||
|
elif choice.value == bool:
|
||||||
|
if input == "0":
|
||||||
|
return True
|
||||||
|
elif input == "1":
|
||||||
|
return False
|
||||||
|
raise InvalidValueError()
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def _get_next_option_prompt(self, invalid_choice=False):
|
||||||
|
assert len(self.options_left), "Something went wrong. There were no options left"
|
||||||
|
self.current_option = self.options_left[0]
|
||||||
|
choice_string = ""
|
||||||
|
if invalid_choice is True:
|
||||||
choice_string += "Invalid response entered. Try again.\n"
|
choice_string += "Invalid response entered. Try again.\n"
|
||||||
choice_string += choice.long_description + "\n"
|
|
||||||
choice_string += "Valid inputs:\n"
|
choice_string += self.current_option.long_description + "\n"
|
||||||
for option_type in choice.option_types:
|
if len(self.current_option.option_types) > 1:
|
||||||
choice_string += "\t" + self._get_option_type_description(option_type) + "\n"
|
choice_string += self._get_list_of_option_types()
|
||||||
choice_string += "Leave blank for default (" + str(choice.default) + ")\n"
|
elif len(self.current_option.option_types) == 1:
|
||||||
choice_string += "Enter choice:"
|
self.current_choice = 0
|
||||||
self.current_option = choice
|
choice_string += self._get_choice_value_prompt()
|
||||||
return choice_string
|
return choice_string
|
||||||
|
|
||||||
def _start_download(self):
|
def _start_download(self):
|
||||||
|
|
|
@ -15,6 +15,7 @@ from lbrynet.core.server.BlobAvailabilityHandler import BlobAvailabilityHandlerF
|
||||||
from lbrynet.core.server.BlobRequestHandler import BlobRequestHandlerFactory
|
from lbrynet.core.server.BlobRequestHandler import BlobRequestHandlerFactory
|
||||||
from lbrynet.core.server.ServerProtocol import ServerProtocolFactory
|
from lbrynet.core.server.ServerProtocol import ServerProtocolFactory
|
||||||
from lbrynet.core.PTCWallet import PTCWallet
|
from lbrynet.core.PTCWallet import PTCWallet
|
||||||
|
from lbrynet.lbryfile.client.LBRYFileOptions import add_lbry_file_to_sd_identifier
|
||||||
from lbrynet.lbryfile.client.LBRYFileDownloader import LBRYFileOpenerFactory
|
from lbrynet.lbryfile.client.LBRYFileDownloader import LBRYFileOpenerFactory
|
||||||
from lbrynet.lbryfile.StreamDescriptor import LBRYFileStreamType
|
from lbrynet.lbryfile.StreamDescriptor import LBRYFileStreamType
|
||||||
from lbrynet.lbryfile.LBRYFileMetadataManager import DBLBRYFileMetadataManager, TempLBRYFileMetadataManager
|
from lbrynet.lbryfile.LBRYFileMetadataManager import DBLBRYFileMetadataManager, TempLBRYFileMetadataManager
|
||||||
|
@ -77,6 +78,7 @@ class LBRYConsole():
|
||||||
d = threads.deferToThread(self._create_directory)
|
d = threads.deferToThread(self._create_directory)
|
||||||
d.addCallback(lambda _: self._get_settings())
|
d.addCallback(lambda _: self._get_settings())
|
||||||
d.addCallback(lambda _: self._get_session())
|
d.addCallback(lambda _: self._get_session())
|
||||||
|
d.addCallback(lambda _: add_lbry_file_to_sd_identifier(self.sd_identifier))
|
||||||
d.addCallback(lambda _: self._setup_lbry_file_manager())
|
d.addCallback(lambda _: self._setup_lbry_file_manager())
|
||||||
d.addCallback(lambda _: self._setup_lbry_file_opener())
|
d.addCallback(lambda _: self._setup_lbry_file_opener())
|
||||||
d.addCallback(lambda _: self._setup_control_handlers())
|
d.addCallback(lambda _: self._setup_control_handlers())
|
||||||
|
|
|
@ -17,7 +17,8 @@ from lbrynet.core.StreamDescriptor import StreamDescriptorIdentifier
|
||||||
from lbrynet.core.PaymentRateManager import PaymentRateManager
|
from lbrynet.core.PaymentRateManager import PaymentRateManager
|
||||||
from lbrynet.lbryfile.LBRYFileMetadataManager import TempLBRYFileMetadataManager
|
from lbrynet.lbryfile.LBRYFileMetadataManager import TempLBRYFileMetadataManager
|
||||||
from lbrynet.core import StreamDescriptor
|
from lbrynet.core import StreamDescriptor
|
||||||
from lbrynet.lbryfile.StreamDescriptor import LBRYFileStreamType, LBRYFileStreamDescriptorValidator
|
from lbrynet.lbryfile.client.LBRYFileOptions import add_lbry_file_to_sd_identifier
|
||||||
|
from lbrynet.lbryfile.StreamDescriptor import LBRYFileStreamType
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
|
|
||||||
|
@ -101,7 +102,7 @@ class LBRYDownloader(object):
|
||||||
return defer.succeed(True)
|
return defer.succeed(True)
|
||||||
|
|
||||||
def _setup_stream_identifier(self):
|
def _setup_stream_identifier(self):
|
||||||
self.sd_identifier.add_stream_info_validator(LBRYFileStreamType, LBRYFileStreamDescriptorValidator)
|
add_lbry_file_to_sd_identifier(self.sd_identifier)
|
||||||
file_saver_factory = LBRYFileSaverFactory(self.session.peer_finder, self.session.rate_limiter,
|
file_saver_factory = LBRYFileSaverFactory(self.session.peer_finder, self.session.rate_limiter,
|
||||||
self.session.blob_manager, self.stream_info_manager,
|
self.session.blob_manager, self.stream_info_manager,
|
||||||
self.session.wallet, self.download_directory)
|
self.session.wallet, self.download_directory)
|
||||||
|
@ -184,7 +185,7 @@ class LBRYDownloader(object):
|
||||||
return stream_name, stream_size
|
return stream_name, stream_size
|
||||||
|
|
||||||
def choose_download_factory(info_and_factories):
|
def choose_download_factory(info_and_factories):
|
||||||
info_validator, factories = info_and_factories
|
info_validator, options, factories = info_and_factories
|
||||||
stream_name, stream_size = get_info_from_validator(info_validator)
|
stream_name, stream_size = get_info_from_validator(info_validator)
|
||||||
if isinstance(stream_size, (int, long)):
|
if isinstance(stream_size, (int, long)):
|
||||||
price = payment_rate_manager.get_effective_min_blob_data_payment_rate()
|
price = payment_rate_manager.get_effective_min_blob_data_payment_rate()
|
||||||
|
@ -192,26 +193,30 @@ class LBRYDownloader(object):
|
||||||
else:
|
else:
|
||||||
estimated_cost = "unknown"
|
estimated_cost = "unknown"
|
||||||
|
|
||||||
stream_frame.show_stream_metadata(stream_name, stream_size, estimated_cost)
|
stream_frame.show_stream_metadata(stream_name, stream_size)
|
||||||
|
|
||||||
|
available_options = options.get_downloader_options(info_validator, payment_rate_manager)
|
||||||
|
|
||||||
|
stream_frame.show_download_options(available_options)
|
||||||
|
|
||||||
get_downloader_d = defer.Deferred()
|
get_downloader_d = defer.Deferred()
|
||||||
|
|
||||||
def create_downloader(f):
|
def create_downloader(f, chosen_options):
|
||||||
|
|
||||||
def fire_get_downloader_d(downloader):
|
def fire_get_downloader_d(downloader):
|
||||||
if not get_downloader_d.called:
|
if not get_downloader_d.called:
|
||||||
get_downloader_d.callback(downloader)
|
get_downloader_d.callback(downloader)
|
||||||
|
|
||||||
stream_frame.disable_download_buttons()
|
stream_frame.disable_download_buttons()
|
||||||
download_options = [o.default for o in f.get_downloader_options(info_validator, payment_rate_manager)]
|
d = f.make_downloader(info_validator, chosen_options,
|
||||||
d = f.make_downloader(info_validator, download_options,
|
|
||||||
payment_rate_manager)
|
payment_rate_manager)
|
||||||
d.addCallback(fire_get_downloader_d)
|
d.addCallback(fire_get_downloader_d)
|
||||||
|
|
||||||
for factory in factories:
|
for factory in factories:
|
||||||
|
|
||||||
def choose_factory(f=factory):
|
def choose_factory(f=factory):
|
||||||
create_downloader(f)
|
chosen_options = stream_frame.get_chosen_options()
|
||||||
|
create_downloader(f, chosen_options)
|
||||||
|
|
||||||
stream_frame.add_download_factory(factory, choose_factory)
|
stream_frame.add_download_factory(factory, choose_factory)
|
||||||
|
|
||||||
|
@ -301,9 +306,9 @@ class StreamFrame(object):
|
||||||
self.uri_label.grid(row=0, column=0, sticky=tk.W)
|
self.uri_label.grid(row=0, column=0, sticky=tk.W)
|
||||||
|
|
||||||
if os.name == "nt":
|
if os.name == "nt":
|
||||||
close_cursor = ""
|
self.button_cursor = ""
|
||||||
else:
|
else:
|
||||||
close_cursor = "hand1"
|
self.button_cursor = "hand1"
|
||||||
|
|
||||||
close_file_name = "close2.gif"
|
close_file_name = "close2.gif"
|
||||||
try:
|
try:
|
||||||
|
@ -316,7 +321,7 @@ class StreamFrame(object):
|
||||||
file=close_file
|
file=close_file
|
||||||
)
|
)
|
||||||
self.close_button = ttk.Button(
|
self.close_button = ttk.Button(
|
||||||
self.stream_frame_header, command=self.cancel, style="Stop.TButton", cursor=close_cursor
|
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.config(image=self.close_picture)
|
||||||
self.close_button.grid(row=0, column=1, sticky=tk.E + tk.N)
|
self.close_button.grid(row=0, column=1, sticky=tk.E + tk.N)
|
||||||
|
@ -334,26 +339,50 @@ class StreamFrame(object):
|
||||||
|
|
||||||
self.stream_frame_body.grid_columnconfigure(0, weight=1)
|
self.stream_frame_body.grid_columnconfigure(0, weight=1)
|
||||||
|
|
||||||
self.info_frame = ttk.Frame(self.stream_frame_body, style="D.TFrame")
|
self.metadata_frame = ttk.Frame(self.stream_frame_body, style="D.TFrame")
|
||||||
self.info_frame.grid(sticky=tk.W + tk.E, row=1)
|
self.metadata_frame.grid(sticky=tk.W + tk.E, row=1)
|
||||||
self.info_frame.grid_columnconfigure(0, weight=1)
|
|
||||||
|
|
||||||
self.metadata_frame = ttk.Frame(self.info_frame, style="E.TFrame")
|
|
||||||
self.metadata_frame.grid(sticky=tk.W + tk.E)
|
|
||||||
self.metadata_frame.grid_columnconfigure(0, weight=1)
|
self.metadata_frame.grid_columnconfigure(0, weight=1)
|
||||||
|
|
||||||
self.outer_button_frame = ttk.Frame(self.stream_frame_body, style="D.TFrame")
|
self.options_frame = ttk.Frame(self.stream_frame_body, style="D.TFrame")
|
||||||
self.outer_button_frame.grid(sticky=tk.W + tk.E, row=2)
|
|
||||||
|
|
||||||
self.button_frame = ttk.Frame(self.outer_button_frame, style="E.TFrame")
|
self.outer_button_frame = ttk.Frame(self.stream_frame_body, style="D.TFrame")
|
||||||
self.button_frame.pack(side=tk.TOP)
|
self.outer_button_frame.grid(sticky=tk.W + tk.E, row=4)
|
||||||
|
|
||||||
|
show_options_picture_file_name = "show_options.gif"
|
||||||
|
try:
|
||||||
|
show_options_picture_file = os.path.join(os.path.dirname(__file__),
|
||||||
|
show_options_picture_file_name)
|
||||||
|
except NameError:
|
||||||
|
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)
|
||||||
|
|
||||||
|
self.show_options_picture = tk.PhotoImage(
|
||||||
|
file=show_options_picture_file
|
||||||
|
)
|
||||||
|
|
||||||
|
hide_options_picture_file_name = "hide_options.gif"
|
||||||
|
try:
|
||||||
|
hide_options_picture_file = os.path.join(os.path.dirname(__file__),
|
||||||
|
hide_options_picture_file_name)
|
||||||
|
except NameError:
|
||||||
|
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)
|
||||||
|
|
||||||
|
self.hide_options_picture = tk.PhotoImage(
|
||||||
|
file=hide_options_picture_file
|
||||||
|
)
|
||||||
|
|
||||||
|
self.show_options_button = None
|
||||||
|
|
||||||
self.status_label = None
|
self.status_label = None
|
||||||
self.name_label = None
|
self.name_label = None
|
||||||
self.bytes_downloaded_label = None
|
self.bytes_downloaded_label = None
|
||||||
self.bytes_outputted_label = None
|
self.bytes_outputted_label = None
|
||||||
|
self.button_frame = None
|
||||||
self.download_buttons = []
|
self.download_buttons = []
|
||||||
|
self.option_frames = []
|
||||||
self.name_font = None
|
self.name_font = None
|
||||||
self.description_label = None
|
self.description_label = None
|
||||||
self.file_name_frame = None
|
self.file_name_frame = None
|
||||||
|
@ -416,7 +445,7 @@ class StreamFrame(object):
|
||||||
return "%.1f %s" % (round((stream_size * 1.0 / factor), 1), units)
|
return "%.1f %s" % (round((stream_size * 1.0 / factor), 1), units)
|
||||||
return stream_size
|
return stream_size
|
||||||
|
|
||||||
def show_stream_metadata(self, stream_name, stream_size, estimated_cost):
|
def show_stream_metadata(self, stream_name, stream_size):
|
||||||
if self.status_label is not None:
|
if self.status_label is not None:
|
||||||
self.status_label.destroy()
|
self.status_label.destroy()
|
||||||
|
|
||||||
|
@ -436,19 +465,6 @@ class StreamFrame(object):
|
||||||
)
|
)
|
||||||
file_name_label.grid(row=0, column=3)
|
file_name_label.grid(row=0, column=3)
|
||||||
|
|
||||||
self.outer_button_frame = ttk.Frame(self.stream_frame_body, style="D.TFrame")
|
|
||||||
self.outer_button_frame.grid(sticky=tk.W + tk.E, row=2)
|
|
||||||
|
|
||||||
self.cost_frame = ttk.Frame(self.outer_button_frame, style="F.TFrame")
|
|
||||||
self.cost_frame.grid(row=0, column=0, sticky=tk.W+tk.N, pady=(0, 12))
|
|
||||||
|
|
||||||
self.cost_label = ttk.Label(
|
|
||||||
self.cost_frame,
|
|
||||||
text=locale.format_string("%.2f LBC", (round(estimated_cost, 2),), grouping=True),
|
|
||||||
foreground="red"
|
|
||||||
)
|
|
||||||
self.cost_label.grid(row=0, column=1, padx=(1, 0))
|
|
||||||
|
|
||||||
self.button_frame = ttk.Frame(self.outer_button_frame, style="E.TFrame")
|
self.button_frame = ttk.Frame(self.outer_button_frame, style="E.TFrame")
|
||||||
self.button_frame.grid(row=0, column=1)
|
self.button_frame.grid(row=0, column=1)
|
||||||
|
|
||||||
|
@ -457,13 +473,9 @@ class StreamFrame(object):
|
||||||
self.outer_button_frame.grid_columnconfigure(2, weight=1, uniform="buttons")
|
self.outer_button_frame.grid_columnconfigure(2, weight=1, uniform="buttons")
|
||||||
|
|
||||||
def add_download_factory(self, factory, download_func):
|
def add_download_factory(self, factory, download_func):
|
||||||
if os.name == "nt":
|
|
||||||
button_cursor = ""
|
|
||||||
else:
|
|
||||||
button_cursor = "hand1"
|
|
||||||
download_button = ttk.Button(
|
download_button = ttk.Button(
|
||||||
self.button_frame, text=factory.get_description(), command=download_func,
|
self.button_frame, text=factory.get_description(), command=download_func,
|
||||||
style='LBRY.TButton', cursor=button_cursor
|
style='LBRY.TButton', cursor=self.button_cursor
|
||||||
)
|
)
|
||||||
self.download_buttons.append(download_button)
|
self.download_buttons.append(download_button)
|
||||||
download_button.grid(row=0, column=len(self.download_buttons) - 1, padx=5, pady=(1, 2))
|
download_button.grid(row=0, column=len(self.download_buttons) - 1, padx=5, pady=(1, 2))
|
||||||
|
@ -477,11 +489,160 @@ class StreamFrame(object):
|
||||||
download_button.destroy()
|
download_button.destroy()
|
||||||
self.download_buttons = []
|
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, bytes_left_to_output, points_paid,
|
def show_progress(self, total_bytes, bytes_left_to_download, bytes_left_to_output, points_paid,
|
||||||
points_remaining):
|
points_remaining):
|
||||||
if self.bytes_outputted_label is None:
|
if self.bytes_outputted_label is None:
|
||||||
self.remove_download_buttons()
|
self.remove_download_buttons()
|
||||||
self.button_frame.destroy()
|
self.button_frame.destroy()
|
||||||
|
for option, frame in self.option_frames:
|
||||||
|
frame.destroy()
|
||||||
|
self.options_frame.destroy()
|
||||||
|
self.show_options_button.destroy()
|
||||||
|
|
||||||
|
self.cost_frame = ttk.Frame(self.outer_button_frame, style="F.TFrame")
|
||||||
|
self.cost_frame.grid(row=0, column=0, sticky=tk.W+tk.N, pady=(0, 12))
|
||||||
|
|
||||||
|
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="")
|
self.outer_button_frame.grid_columnconfigure(2, weight=0, uniform="")
|
||||||
|
|
||||||
self.bytes_outputted_label = ttk.Label(
|
self.bytes_outputted_label = ttk.Label(
|
||||||
|
@ -667,6 +828,7 @@ class App(object):
|
||||||
ttk.Style().configure("Lookup.LBRY.TButton", padding=lookup_button_padding)
|
ttk.Style().configure("Lookup.LBRY.TButton", padding=lookup_button_padding)
|
||||||
ttk.Style().configure("Stop.TButton", padding=1, background="#FFFFFF", relief="flat", borderwidth=0)
|
ttk.Style().configure("Stop.TButton", padding=1, background="#FFFFFF", relief="flat", borderwidth=0)
|
||||||
ttk.Style().configure("TEntry", padding=11)
|
ttk.Style().configure("TEntry", padding=11)
|
||||||
|
ttk.Style().configure("Float.TEntry", padding=2)
|
||||||
#ttk.Style().configure("A.TFrame", background="red")
|
#ttk.Style().configure("A.TFrame", background="red")
|
||||||
#ttk.Style().configure("B.TFrame", background="green")
|
#ttk.Style().configure("B.TFrame", background="green")
|
||||||
#ttk.Style().configure("B2.TFrame", background="#80FF80")
|
#ttk.Style().configure("B2.TFrame", background="#80FF80")
|
||||||
|
@ -674,6 +836,8 @@ class App(object):
|
||||||
#ttk.Style().configure("D.TFrame", background="blue")
|
#ttk.Style().configure("D.TFrame", background="blue")
|
||||||
#ttk.Style().configure("E.TFrame", background="yellow")
|
#ttk.Style().configure("E.TFrame", background="yellow")
|
||||||
#ttk.Style().configure("F.TFrame", background="#808080")
|
#ttk.Style().configure("F.TFrame", background="#808080")
|
||||||
|
#ttk.Style().configure("G.TFrame", background="#FF80FF")
|
||||||
|
#ttk.Style().configure("H.TFrame", background="#0080FF")
|
||||||
#ttk.Style().configure("LBRY.TProgressbar", background="#104639", orient="horizontal", thickness=5)
|
#ttk.Style().configure("LBRY.TProgressbar", background="#104639", orient="horizontal", thickness=5)
|
||||||
#ttk.Style().configure("LBRY.TProgressbar")
|
#ttk.Style().configure("LBRY.TProgressbar")
|
||||||
#ttk.Style().layout("Horizontal.LBRY.TProgressbar", ttk.Style().layout("Horizontal.TProgressbar"))
|
#ttk.Style().layout("Horizontal.LBRY.TProgressbar", ttk.Style().layout("Horizontal.TProgressbar"))
|
||||||
|
|
BIN
lbrynet/lbrynet_downloader_gui/hide_options.gif
Normal file
BIN
lbrynet/lbrynet_downloader_gui/hide_options.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 174 B |
BIN
lbrynet/lbrynet_downloader_gui/show_options.gif
Normal file
BIN
lbrynet/lbrynet_downloader_gui/show_options.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 155 B |
2
setup.py
2
setup.py
|
@ -36,6 +36,8 @@ setup(name='lbrynet',
|
||||||
'lbrynet/lbrynet_downloader_gui/lbry-dark-icon.xbm',
|
'lbrynet/lbrynet_downloader_gui/lbry-dark-icon.xbm',
|
||||||
'lbrynet/lbrynet_downloader_gui/lbry-dark-icon.ico',
|
'lbrynet/lbrynet_downloader_gui/lbry-dark-icon.ico',
|
||||||
'lbrynet/lbrynet_downloader_gui/drop_down.gif',
|
'lbrynet/lbrynet_downloader_gui/drop_down.gif',
|
||||||
|
'lbrynet/lbrynet_downloader_gui/show_options.gif',
|
||||||
|
'lbrynet/lbrynet_downloader_gui/hide_options.gif',
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
|
@ -9,7 +9,7 @@ from Crypto import Random
|
||||||
from Crypto.Hash import MD5
|
from Crypto.Hash import MD5
|
||||||
from lbrynet.conf import MIN_BLOB_DATA_PAYMENT_RATE
|
from lbrynet.conf import MIN_BLOB_DATA_PAYMENT_RATE
|
||||||
from lbrynet.conf import MIN_BLOB_INFO_PAYMENT_RATE
|
from lbrynet.conf import MIN_BLOB_INFO_PAYMENT_RATE
|
||||||
from lbrynet.lbrylive.LiveStreamCreator import FileLiveStreamCreator, add_live_stream_to_sd_identifier
|
from lbrynet.lbrylive.LiveStreamCreator import FileLiveStreamCreator
|
||||||
from lbrynet.lbrylive.PaymentRateManager import BaseLiveStreamPaymentRateManager
|
from lbrynet.lbrylive.PaymentRateManager import BaseLiveStreamPaymentRateManager
|
||||||
from lbrynet.lbrylive.PaymentRateManager import LiveStreamPaymentRateManager
|
from lbrynet.lbrylive.PaymentRateManager import LiveStreamPaymentRateManager
|
||||||
from lbrynet.lbrylive.LiveStreamMetadataManager import DBLiveStreamMetadataManager
|
from lbrynet.lbrylive.LiveStreamMetadataManager import DBLiveStreamMetadataManager
|
||||||
|
@ -24,6 +24,7 @@ from lbrynet.core.StreamDescriptor import BlobStreamDescriptorWriter
|
||||||
from lbrynet.core.StreamDescriptor import StreamDescriptorIdentifier
|
from lbrynet.core.StreamDescriptor import StreamDescriptorIdentifier
|
||||||
from lbrynet.core.StreamDescriptor import download_sd_blob
|
from lbrynet.core.StreamDescriptor import download_sd_blob
|
||||||
from lbrynet.lbryfilemanager.LBRYFileCreator import create_lbry_file
|
from lbrynet.lbryfilemanager.LBRYFileCreator import create_lbry_file
|
||||||
|
from lbrynet.lbryfile.client.LBRYFileOptions import add_lbry_file_to_sd_identifier
|
||||||
from lbrynet.lbryfile.StreamDescriptor import get_sd_info
|
from lbrynet.lbryfile.StreamDescriptor import get_sd_info
|
||||||
from twisted.internet import defer, threads, task
|
from twisted.internet import defer, threads, task
|
||||||
from twisted.trial.unittest import TestCase
|
from twisted.trial.unittest import TestCase
|
||||||
|
@ -35,6 +36,8 @@ from lbrynet.core.server.BlobAvailabilityHandler import BlobAvailabilityHandlerF
|
||||||
from lbrynet.core.server.BlobRequestHandler import BlobRequestHandlerFactory
|
from lbrynet.core.server.BlobRequestHandler import BlobRequestHandlerFactory
|
||||||
from lbrynet.core.server.ServerProtocol import ServerProtocolFactory
|
from lbrynet.core.server.ServerProtocol import ServerProtocolFactory
|
||||||
from lbrynet.lbrylive.server.LiveBlobInfoQueryHandler import CryptBlobInfoQueryHandlerFactory
|
from lbrynet.lbrylive.server.LiveBlobInfoQueryHandler import CryptBlobInfoQueryHandlerFactory
|
||||||
|
from lbrynet.lbrylive.client.LiveStreamOptions import add_live_stream_to_sd_identifier
|
||||||
|
from lbrynet.lbrylive.client.LiveStreamDownloader import add_full_live_stream_downloader_to_sd_identifier
|
||||||
|
|
||||||
|
|
||||||
log_format = "%(funcName)s(): %(message)s"
|
log_format = "%(funcName)s(): %(message)s"
|
||||||
|
@ -248,6 +251,7 @@ def start_lbry_uploader(sd_hash_queue, kill_event, dead_event):
|
||||||
def start_all():
|
def start_all():
|
||||||
|
|
||||||
d = session.setup()
|
d = session.setup()
|
||||||
|
d.addCallback(lambda _: add_lbry_file_to_sd_identifier(sd_identifier))
|
||||||
d.addCallback(lambda _: lbry_file_manager.setup())
|
d.addCallback(lambda _: lbry_file_manager.setup())
|
||||||
d.addCallback(lambda _: start_server())
|
d.addCallback(lambda _: start_server())
|
||||||
d.addCallback(lambda _: create_stream())
|
d.addCallback(lambda _: create_stream())
|
||||||
|
@ -437,7 +441,12 @@ def start_live_server(sd_hash_queue, kill_event, dead_event):
|
||||||
return d
|
return d
|
||||||
|
|
||||||
def enable_live_stream():
|
def enable_live_stream():
|
||||||
return add_live_stream_to_sd_identifier(session, stream_info_manager, sd_identifier)
|
base_live_stream_payment_rate_manager = BaseLiveStreamPaymentRateManager(
|
||||||
|
MIN_BLOB_INFO_PAYMENT_RATE
|
||||||
|
)
|
||||||
|
add_live_stream_to_sd_identifier(sd_identifier, base_live_stream_payment_rate_manager)
|
||||||
|
add_full_live_stream_downloader_to_sd_identifier(session, stream_info_manager, sd_identifier,
|
||||||
|
base_live_stream_payment_rate_manager)
|
||||||
|
|
||||||
def run_server():
|
def run_server():
|
||||||
d = session.setup()
|
d = session.setup()
|
||||||
|
@ -670,9 +679,9 @@ class TestTransfer(TestCase):
|
||||||
self.lbry_file_manager = LBRYFileManager(self.session, self.stream_info_manager, sd_identifier)
|
self.lbry_file_manager = LBRYFileManager(self.session, self.stream_info_manager, sd_identifier)
|
||||||
|
|
||||||
def make_downloader(info_and_factories, prm):
|
def make_downloader(info_and_factories, prm):
|
||||||
info_validator, factories = info_and_factories
|
info_validator, options, factories = info_and_factories
|
||||||
options = [o.default for o in factories[0].get_downloader_options(info_validator, prm)]
|
chosen_options = [o.default_value for o in options.get_downloader_options(info_validator, prm)]
|
||||||
return factories[0].make_downloader(info_validator, options, prm)
|
return factories[0].make_downloader(info_validator, chosen_options, prm)
|
||||||
|
|
||||||
def download_file(sd_hash):
|
def download_file(sd_hash):
|
||||||
prm = PaymentRateManager(self.session.base_payment_rate_manager)
|
prm = PaymentRateManager(self.session.base_payment_rate_manager)
|
||||||
|
@ -693,6 +702,7 @@ class TestTransfer(TestCase):
|
||||||
logging.debug("Starting the transfer")
|
logging.debug("Starting the transfer")
|
||||||
|
|
||||||
d = self.session.setup()
|
d = self.session.setup()
|
||||||
|
d.addCallback(lambda _: add_lbry_file_to_sd_identifier(sd_identifier))
|
||||||
d.addCallback(lambda _: self.lbry_file_manager.setup())
|
d.addCallback(lambda _: self.lbry_file_manager.setup())
|
||||||
d.addCallback(lambda _: download_file(sd_hash))
|
d.addCallback(lambda _: download_file(sd_hash))
|
||||||
d.addCallback(lambda _: check_md5_sum())
|
d.addCallback(lambda _: check_md5_sum())
|
||||||
|
@ -750,9 +760,9 @@ class TestTransfer(TestCase):
|
||||||
d = self.wait_for_hash_from_queue(sd_hash_queue)
|
d = self.wait_for_hash_from_queue(sd_hash_queue)
|
||||||
|
|
||||||
def create_downloader(info_and_factories, prm):
|
def create_downloader(info_and_factories, prm):
|
||||||
info_validator, factories = info_and_factories
|
info_validator, options, factories = info_and_factories
|
||||||
options = [o.default for o in factories[0].get_downloader_options(info_validator, prm)]
|
chosen_options = [o.default_value for o in options.get_downloader_options(info_validator, prm)]
|
||||||
return factories[0].make_downloader(info_validator, options, prm)
|
return factories[0].make_downloader(info_validator, chosen_options, prm)
|
||||||
|
|
||||||
def start_lbry_file(lbry_file):
|
def start_lbry_file(lbry_file):
|
||||||
lbry_file = lbry_file
|
lbry_file = lbry_file
|
||||||
|
@ -776,7 +786,14 @@ class TestTransfer(TestCase):
|
||||||
return d
|
return d
|
||||||
|
|
||||||
def enable_live_stream():
|
def enable_live_stream():
|
||||||
return add_live_stream_to_sd_identifier(self.session, self.stream_info_manager, sd_identifier)
|
base_live_stream_payment_rate_manager = BaseLiveStreamPaymentRateManager(
|
||||||
|
MIN_BLOB_INFO_PAYMENT_RATE
|
||||||
|
)
|
||||||
|
add_live_stream_to_sd_identifier(sd_identifier,
|
||||||
|
base_live_stream_payment_rate_manager)
|
||||||
|
add_full_live_stream_downloader_to_sd_identifier(self.session, self.stream_info_manager,
|
||||||
|
sd_identifier,
|
||||||
|
base_live_stream_payment_rate_manager)
|
||||||
|
|
||||||
d.addCallback(do_download)
|
d.addCallback(do_download)
|
||||||
|
|
||||||
|
@ -941,6 +958,7 @@ class TestStreamify(TestCase):
|
||||||
|
|
||||||
d = self.session.setup()
|
d = self.session.setup()
|
||||||
d.addCallback(lambda _: self.stream_info_manager.setup())
|
d.addCallback(lambda _: self.stream_info_manager.setup())
|
||||||
|
d.addCallback(lambda _: add_lbry_file_to_sd_identifier(sd_identifier))
|
||||||
d.addCallback(lambda _: self.lbry_file_manager.setup())
|
d.addCallback(lambda _: self.lbry_file_manager.setup())
|
||||||
|
|
||||||
def verify_equal(sd_info):
|
def verify_equal(sd_info):
|
||||||
|
@ -1017,6 +1035,7 @@ class TestStreamify(TestCase):
|
||||||
|
|
||||||
d = self.session.setup()
|
d = self.session.setup()
|
||||||
d.addCallback(lambda _: self.stream_info_manager.setup())
|
d.addCallback(lambda _: self.stream_info_manager.setup())
|
||||||
|
d.addCallback(lambda _: add_lbry_file_to_sd_identifier(sd_identifier))
|
||||||
d.addCallback(lambda _: self.lbry_file_manager.setup())
|
d.addCallback(lambda _: self.lbry_file_manager.setup())
|
||||||
d.addCallback(lambda _: create_stream())
|
d.addCallback(lambda _: create_stream())
|
||||||
d.addCallback(combine_stream)
|
d.addCallback(combine_stream)
|
||||||
|
|
Loading…
Reference in a new issue