|
@ -4,5 +4,5 @@ log = logging.getLogger(__name__)
|
|||
logging.getLogger(__name__).addHandler(logging.NullHandler())
|
||||
log.setLevel(logging.ERROR)
|
||||
|
||||
version = (0, 2, 5)
|
||||
version = (0, 3, 0)
|
||||
__version__ = ".".join([str(x) for x in version])
|
||||
|
|
|
@ -17,9 +17,9 @@ MIN_VALUABLE_BLOB_HASH_PAYMENT_RATE = .05 # points/1000 infos
|
|||
MAX_CONNECTIONS_PER_STREAM = 5
|
||||
|
||||
KNOWN_DHT_NODES = [('104.236.42.182', 4000),
|
||||
('lbryum1.lbry.io', 4444),
|
||||
('lbryum2.lbry.io', 4444),
|
||||
('lbryum3.lbry.io', 4444)]
|
||||
('lbrynet1.lbry.io', 4444),
|
||||
('lbrynet2.lbry.io', 4444),
|
||||
('lbrynet3.lbry.io', 4444)]
|
||||
|
||||
POINTTRADER_SERVER = 'http://ec2-54-187-192-68.us-west-2.compute.amazonaws.com:2424'
|
||||
#POINTTRADER_SERVER = 'http://127.0.0.1:2424'
|
||||
|
@ -35,10 +35,10 @@ API_PORT = 5279
|
|||
ICON_PATH = "app.icns"
|
||||
APP_NAME = "LBRY"
|
||||
API_CONNECTION_STRING = "http://%s:%i/%s" % (API_INTERFACE, API_PORT, API_ADDRESS)
|
||||
UI_ADDRESS = "http://" + API_INTERFACE + ":" + str(API_PORT)
|
||||
UI_ADDRESS = "http://%s:%i" % (API_INTERFACE, API_PORT)
|
||||
PROTOCOL_PREFIX = "lbry"
|
||||
|
||||
DEFAULT_WALLET = "lbryum"
|
||||
DEFAULT_WALLET = "lbrycrd"
|
||||
WALLET_TYPES = ["lbryum", "lbrycrd"]
|
||||
DEFAULT_TIMEOUT = 30
|
||||
DEFAULT_MAX_SEARCH_RESULTS = 25
|
||||
|
@ -46,3 +46,7 @@ DEFAULT_MAX_KEY_FEE = 100.0
|
|||
DEFAULT_SEARCH_TIMEOUT = 3.0
|
||||
DEFAULT_CACHE_TIME = 3600
|
||||
DEFAULT_UI_BRANCH = "master"
|
||||
|
||||
SOURCE_TYPES = ['lbry_sd_hash', 'url', 'btih']
|
||||
BASE_METADATA_FIELDS = ['title', 'description', 'author', 'language', 'license', 'content-type']
|
||||
OPTIONAL_METADATA_FIELDS = ['thumbnail', 'preview', 'fee', 'contact', 'pubkey']
|
|
@ -4,6 +4,7 @@ from lbrynet.core.client.ClientRequest import ClientRequest
|
|||
from lbrynet.core.Error import UnknownNameError, InvalidStreamInfoError, RequestCanceledError
|
||||
from lbrynet.core.Error import InsufficientFundsError
|
||||
from lbrynet.core.sqlite_helpers import rerun_if_locked
|
||||
from lbrynet.conf import BASE_METADATA_FIELDS, SOURCE_TYPES, OPTIONAL_METADATA_FIELDS
|
||||
|
||||
from lbryum import SimpleConfig, Network
|
||||
from lbryum.bitcoin import COIN, TYPE_ADDRESS
|
||||
|
@ -318,68 +319,51 @@ class LBRYWallet(object):
|
|||
r_dict = {}
|
||||
if 'value' in result:
|
||||
value = result['value']
|
||||
|
||||
try:
|
||||
value_dict = json.loads(value)
|
||||
except (ValueError, TypeError):
|
||||
return Failure(InvalidStreamInfoError(name))
|
||||
known_fields = ['stream_hash', 'name', 'description', 'key_fee', 'key_fee_address', 'thumbnail',
|
||||
'content_license', 'sources', 'fee', 'author']
|
||||
known_sources = ['lbry_sd_hash', 'btih', 'url']
|
||||
known_fee_types = {'LBC': ['amount', 'address']}
|
||||
for field in known_fields:
|
||||
if field in value_dict:
|
||||
if field == 'sources':
|
||||
for source in known_sources:
|
||||
if source in value_dict[field]:
|
||||
if source == 'lbry_sd_hash':
|
||||
r_dict['stream_hash'] = value_dict[field][source]
|
||||
else:
|
||||
r_dict[source] = value_dict[field][source]
|
||||
elif field == 'fee':
|
||||
fee = value_dict['fee']
|
||||
if 'type' in fee:
|
||||
if fee['type'] in known_fee_types:
|
||||
fee_fields = known_fee_types[fee['type']]
|
||||
if all([f in fee for f in fee_fields]):
|
||||
r_dict['key_fee'] = fee['amount']
|
||||
r_dict['key_fee_address'] = fee['address']
|
||||
else:
|
||||
for f in ['key_fee', 'key_fee_address']:
|
||||
if f in r_dict:
|
||||
del r_dict[f]
|
||||
else:
|
||||
r_dict[field] = value_dict[field]
|
||||
if 'stream_hash' in r_dict and 'txid' in result:
|
||||
d = self._save_name_metadata(name, r_dict['stream_hash'], str(result['txid']))
|
||||
else:
|
||||
d = defer.succeed(True)
|
||||
r_dict['sources'] = value_dict['sources']
|
||||
for field in BASE_METADATA_FIELDS:
|
||||
r_dict[field] = value_dict[field]
|
||||
for field in value_dict:
|
||||
if field in OPTIONAL_METADATA_FIELDS:
|
||||
r_dict[field] = value_dict[field]
|
||||
|
||||
if 'txid' in result:
|
||||
d = self._save_name_metadata(name, r_dict['sources']['lbry_sd_hash'], str(result['txid']))
|
||||
d.addCallback(lambda _: r_dict)
|
||||
return d
|
||||
elif 'error' in result:
|
||||
log.warning("Got an error looking up a name: %s", result['error'])
|
||||
return Failure(UnknownNameError(name))
|
||||
return Failure(UnknownNameError(name))
|
||||
else:
|
||||
log.warning("Got an error looking up a name: %s", json.dumps(result))
|
||||
return Failure(UnknownNameError(name))
|
||||
|
||||
def claim_name(self, name, sd_hash, amount, description=None, key_fee=None,
|
||||
key_fee_address=None, thumbnail=None, content_license=None, author=None, sources=None):
|
||||
value = {"sources": {'lbry_sd_hash': sd_hash}}
|
||||
if description is not None:
|
||||
value['description'] = description
|
||||
if key_fee is not None and key_fee_address is not None:
|
||||
value['fee'] = {'type': 'LBC', 'amount': key_fee, 'address': key_fee_address}
|
||||
if thumbnail is not None:
|
||||
value['thumbnail'] = thumbnail
|
||||
if content_license is not None:
|
||||
value['content_license'] = content_license
|
||||
if author is not None:
|
||||
value['author'] = author
|
||||
if isinstance(sources, dict):
|
||||
sources['lbry_sd_hash'] = sd_hash
|
||||
value['sources'] = sources
|
||||
def claim_name(self, name, bid, sources, metadata, fee=None):
|
||||
value = {'sources': {}}
|
||||
for k in SOURCE_TYPES:
|
||||
if k in sources:
|
||||
value['sources'][k] = sources[k]
|
||||
if value['sources'] == {}:
|
||||
return defer.fail("No source given")
|
||||
for k in BASE_METADATA_FIELDS:
|
||||
if k not in metadata:
|
||||
return defer.fail("Missing required field '%s'" % k)
|
||||
value[k] = metadata[k]
|
||||
for k in metadata:
|
||||
if k not in BASE_METADATA_FIELDS:
|
||||
value[k] = metadata[k]
|
||||
if fee is not None:
|
||||
if "LBC" in fee:
|
||||
value['fee'] = {'LBC': {'amount': fee['LBC']['amount'], 'address': fee['LBC']['address']}}
|
||||
|
||||
d = self._send_name_claim(name, json.dumps(value), amount)
|
||||
d = self._send_name_claim(name, json.dumps(value), bid)
|
||||
|
||||
def _save_metadata(txid):
|
||||
d = self._save_name_metadata(name, sd_hash, txid)
|
||||
d = self._save_name_metadata(name, value['sources']['lbry_sd_hash'], txid)
|
||||
d.addCallback(lambda _: txid)
|
||||
return d
|
||||
|
||||
|
@ -409,7 +393,7 @@ class LBRYWallet(object):
|
|||
def abandon(results):
|
||||
if results[0][0] and results[1][0]:
|
||||
address = results[0][1]
|
||||
amount = results[1][1]
|
||||
amount = float(results[1][1])
|
||||
return self._send_abandon(txid, address, amount)
|
||||
elif results[0][0] is False:
|
||||
return defer.fail(Failure(ValueError("Couldn't get a new address")))
|
||||
|
@ -424,8 +408,11 @@ class LBRYWallet(object):
|
|||
d.addCallback(self._get_decoded_tx)
|
||||
return d
|
||||
|
||||
# def update_name(self, name_value):
|
||||
# return self._update_name(name_value)
|
||||
def update_name(self, name, value, amount):
|
||||
d = self._get_value_for_name(name)
|
||||
d.addCallback(lambda r: (self._update_name(r['txid'], json.dumps(value), amount), r['txid']))
|
||||
d.addCallback(lambda (new_txid, old_txid): self._update_name_metadata(name, value['sources']['lbry_sd_hash'], old_txid, new_txid))
|
||||
return d
|
||||
|
||||
def get_name_and_validity_for_sd_hash(self, sd_hash):
|
||||
d = self._get_claim_metadata_for_sd_hash(sd_hash)
|
||||
|
@ -541,6 +528,12 @@ class LBRYWallet(object):
|
|||
|
||||
return d
|
||||
|
||||
def _update_name_metadata(self, name, sd_hash, old_txid, new_txid):
|
||||
d = self.db.runQuery("delete * from name_metadata where txid=? and sd_hash=?", (old_txid, sd_hash))
|
||||
d.addCallback(lambda _: self.db.runQuery("insert into name_metadata values (?, ?, ?)", (name, new_txid, sd_hash)))
|
||||
d.addCallback(lambda _: new_txid)
|
||||
return d
|
||||
|
||||
def _get_claim_metadata_for_sd_hash(self, sd_hash):
|
||||
d = self.db.runQuery("select name, txid from name_metadata where sd_hash=?", (sd_hash,))
|
||||
d.addCallback(lambda r: r[0] if len(r) else None)
|
||||
|
@ -581,6 +574,9 @@ class LBRYWallet(object):
|
|||
def _send_abandon(self, txid, address, amount):
|
||||
return defer.fail(NotImplementedError())
|
||||
|
||||
def _update_name(self, txid, value, amount):
|
||||
return defer.fail(NotImplementedError())
|
||||
|
||||
def _do_send_many(self, payments_to_send):
|
||||
return defer.fail(NotImplementedError())
|
||||
|
||||
|
@ -634,7 +630,7 @@ class LBRYcrdWallet(LBRYWallet):
|
|||
def _get_rpc_conf(self):
|
||||
settings = {"username": "rpcuser",
|
||||
"password": "rpcpassword",
|
||||
"rpc_port": 8332}
|
||||
"rpc_port": 9245}
|
||||
if os.path.exists(self.wallet_conf):
|
||||
conf = open(self.wallet_conf)
|
||||
for l in conf:
|
||||
|
@ -713,6 +709,9 @@ class LBRYcrdWallet(LBRYWallet):
|
|||
def _send_abandon(self, txid, address, amount):
|
||||
return threads.deferToThread(self._send_abandon_rpc, txid, address, amount)
|
||||
|
||||
def _update_name(self, txid, value, amount):
|
||||
return threads.deferToThread(self._update_name_rpc, txid, value, amount)
|
||||
|
||||
def get_claims_from_tx(self, txid):
|
||||
return threads.deferToThread(self._get_claims_from_tx_rpc, txid)
|
||||
|
||||
|
@ -826,7 +825,7 @@ class LBRYcrdWallet(LBRYWallet):
|
|||
@_catch_connection_error
|
||||
def _send_abandon_rpc(self, txid, address, amount):
|
||||
rpc_conn = self._get_rpc_conn()
|
||||
return rpc_conn.abandonname(txid, address, amount)
|
||||
return rpc_conn.abandonclaim(txid, address, amount)
|
||||
|
||||
@_catch_connection_error
|
||||
def _get_blockchain_info_rpc(self):
|
||||
|
@ -846,7 +845,7 @@ class LBRYcrdWallet(LBRYWallet):
|
|||
@_catch_connection_error
|
||||
def _get_nametrie_rpc(self):
|
||||
rpc_conn = self._get_rpc_conn()
|
||||
return rpc_conn.getnametrie()
|
||||
return rpc_conn.getclaimtrie()
|
||||
|
||||
@_catch_connection_error
|
||||
def _get_wallet_balance_rpc(self):
|
||||
|
@ -863,9 +862,9 @@ class LBRYcrdWallet(LBRYWallet):
|
|||
rpc_conn = self._get_rpc_conn()
|
||||
return rpc_conn.getvalueforname(name)
|
||||
|
||||
# def _update_name_rpc(self, name_value):
|
||||
# rpc_conn = self._get_rpc_conn()
|
||||
# return rpc_conn.updatename(name_value)
|
||||
def _update_name_rpc(self, txid, value, amount):
|
||||
rpc_conn = self._get_rpc_conn()
|
||||
return rpc_conn.updateclaim(txid, value, amount)
|
||||
|
||||
@_catch_connection_error
|
||||
def _send_name_claim_rpc(self, name, value, amount):
|
|
@ -12,7 +12,7 @@ from lbrynet.pointtraderclient import pointtraderclient
|
|||
from twisted.internet import defer, threads
|
||||
from zope.interface import implements
|
||||
from twisted.python.failure import Failure
|
||||
from lbrynet.core.LBRYcrdWallet import ReservedPoints
|
||||
from lbrynet.core.LBRYWallet import ReservedPoints
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
|
|
@ -43,7 +43,7 @@ from lbrynet.lbrynet_console.ControlHandlers import ShowServerStatusFactory, Mod
|
|||
from lbrynet.lbrynet_console.ControlHandlers import ModifyLBRYFileOptionsChooserFactory, StatusFactory
|
||||
from lbrynet.lbrynet_console.ControlHandlers import PeerStatsAndSettingsChooserFactory, PublishFactory
|
||||
from lbrynet.lbrynet_console.ControlHandlers import BlockchainStatusFactory
|
||||
from lbrynet.core.LBRYcrdWallet import LBRYcrdWallet, LBRYumWallet
|
||||
from lbrynet.core.LBRYWallet import LBRYcrdWallet, LBRYumWallet
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
|
|
@ -24,7 +24,7 @@ from appdirs import user_data_dir
|
|||
from urllib2 import urlopen
|
||||
|
||||
from lbrynet import __version__ as lbrynet_version
|
||||
from lbryum.version import ELECTRUM_VERSION as lbryum_version
|
||||
from lbryum.version import LBRYUM_VERSION as lbryum_version
|
||||
from lbrynet.core.PaymentRateManager import PaymentRateManager
|
||||
from lbrynet.core.server.BlobAvailabilityHandler import BlobAvailabilityHandlerFactory
|
||||
from lbrynet.core.server.BlobRequestHandler import BlobRequestHandlerFactory
|
||||
|
@ -39,15 +39,16 @@ from lbrynet.lbrynet_daemon.LBRYPublisher import Publisher
|
|||
from lbrynet.core.utils import generate_id
|
||||
from lbrynet.lbrynet_console.LBRYSettings import LBRYSettings
|
||||
from lbrynet.conf import MIN_BLOB_DATA_PAYMENT_RATE, DEFAULT_MAX_SEARCH_RESULTS, KNOWN_DHT_NODES, DEFAULT_MAX_KEY_FEE, \
|
||||
DEFAULT_WALLET, DEFAULT_SEARCH_TIMEOUT, DEFAULT_CACHE_TIME, DEFAULT_UI_BRANCH, LOG_POST_URL, LOG_FILE_NAME
|
||||
DEFAULT_WALLET, DEFAULT_SEARCH_TIMEOUT, DEFAULT_CACHE_TIME, DEFAULT_UI_BRANCH, LOG_POST_URL, LOG_FILE_NAME, \
|
||||
BASE_METADATA_FIELDS, OPTIONAL_METADATA_FIELDS, SOURCE_TYPES
|
||||
from lbrynet.conf import DEFAULT_TIMEOUT, WALLET_TYPES
|
||||
from lbrynet.core.StreamDescriptor import StreamDescriptorIdentifier, download_sd_blob
|
||||
from lbrynet.core.Session import LBRYSession
|
||||
from lbrynet.core.PTCWallet import PTCWallet
|
||||
from lbrynet.core.LBRYcrdWallet import LBRYcrdWallet, LBRYumWallet
|
||||
from lbrynet.core.LBRYWallet import LBRYcrdWallet, LBRYumWallet
|
||||
from lbrynet.lbryfilemanager.LBRYFileManager import LBRYFileManager
|
||||
from lbrynet.lbryfile.LBRYFileMetadataManager import DBLBRYFileMetadataManager, TempLBRYFileMetadataManager
|
||||
from lbryum import LOG_PATH as lbryum_log
|
||||
# from lbryum import LOG_PATH as lbryum_log
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
@ -67,12 +68,13 @@ handler = logging.handlers.RotatingFileHandler(lbrynet_log, maxBytes=2097152, ba
|
|||
log.addHandler(handler)
|
||||
log.setLevel(logging.INFO)
|
||||
|
||||
if os.path.isfile(lbryum_log):
|
||||
f = open(lbryum_log, 'r')
|
||||
PREVIOUS_LBRYUM_LOG = len(f.read())
|
||||
f.close()
|
||||
else:
|
||||
PREVIOUS_LBRYUM_LOG = 0
|
||||
# if os.path.isfile(lbryum_log):
|
||||
# f = open(lbryum_log, 'r')
|
||||
# PREVIOUS_LBRYUM_LOG = len(f.read())
|
||||
# f.close()
|
||||
# else:
|
||||
# PREVIOUS_LBRYUM_LOG = 0
|
||||
|
||||
if os.path.isfile(lbrynet_log):
|
||||
f = open(lbrynet_log, 'r')
|
||||
PREVIOUS_LBRYNET_LOG = len(f.read())
|
||||
|
@ -141,7 +143,7 @@ class LBRYDaemon(jsonrpc.JSONRPC):
|
|||
|
||||
isLeaf = True
|
||||
|
||||
def __init__(self, root, wallet_type=None):
|
||||
def __init__(self, root, wallet_type="lbrycrd"):
|
||||
jsonrpc.JSONRPC.__init__(self)
|
||||
reactor.addSystemEventTrigger('before', 'shutdown', self._shutdown)
|
||||
|
||||
|
@ -397,11 +399,8 @@ class LBRYDaemon(jsonrpc.JSONRPC):
|
|||
|
||||
def setup(self, branch=DEFAULT_UI_BRANCH, user_specified=False, branch_specified=False):
|
||||
def _log_starting_vals():
|
||||
d = self._get_lbry_files()
|
||||
d.addCallback(lambda r: json.dumps([d[1] for d in r]))
|
||||
d.addCallback(lambda r: log.info("LBRY Files: " + r))
|
||||
d.addCallback(lambda _: log.info("Starting balance: " + str(self.session.wallet.wallet_balance)))
|
||||
return d
|
||||
log.info("Starting balance: " + str(self.session.wallet.wallet_balance))
|
||||
return defer.succeed(None)
|
||||
|
||||
def _announce_startup():
|
||||
def _wait_for_credits():
|
||||
|
@ -428,11 +427,12 @@ class LBRYDaemon(jsonrpc.JSONRPC):
|
|||
else:
|
||||
d = defer.succeed(None)
|
||||
|
||||
if float(self.session.wallet.wallet_balance) == 0.0:
|
||||
d.addCallback(lambda _: self._check_first_run())
|
||||
d.addCallback(self._show_first_run_result)
|
||||
# if float(self.session.wallet.wallet_balance) == 0.0:
|
||||
# d.addCallback(lambda _: self._check_first_run())
|
||||
# d.addCallback(self._show_first_run_result)
|
||||
|
||||
d.addCallback(lambda _: _wait_for_credits() if self.requested_first_run_credits else _announce())
|
||||
# d.addCallback(lambda _: _wait_for_credits() if self.requested_first_run_credits else _announce())
|
||||
d.addCallback(lambda _: _announce())
|
||||
return d
|
||||
|
||||
log.info("[" + str(datetime.now()) + "] Starting lbrynet-daemon")
|
||||
|
@ -516,7 +516,7 @@ class LBRYDaemon(jsonrpc.JSONRPC):
|
|||
try:
|
||||
r = urlopen("https://raw.githubusercontent.com/lbryio/lbryum/master/lib/version.py").read().split('\n')
|
||||
version = next(line.split("=")[1].split("#")[0].replace(" ", "")
|
||||
for line in r if "ELECTRUM_VERSION" in line)
|
||||
for line in r if "LBRYUM_VERSION" in line)
|
||||
version = version.replace("'", "")
|
||||
log.info("remote lbryum " + str(version) + " > local lbryum " + str(lbryum_version) + " = " + str(
|
||||
version > lbryum_version))
|
||||
|
@ -634,11 +634,11 @@ class LBRYDaemon(jsonrpc.JSONRPC):
|
|||
|
||||
def _upload_log(self, log_type=None, exclude_previous=False, force=False):
|
||||
if self.upload_log or force:
|
||||
for lm, lp in [('lbrynet', lbrynet_log), ('lbryum', lbryum_log)]:
|
||||
for lm, lp in [('lbrynet', lbrynet_log)]: #, ('lbryum', lbryum_log)]:
|
||||
if os.path.isfile(lp):
|
||||
if exclude_previous:
|
||||
f = open(lp, "r")
|
||||
f.seek(PREVIOUS_LBRYNET_LOG if lm == 'lbrynet' else PREVIOUS_LBRYUM_LOG)
|
||||
f.seek(PREVIOUS_LBRYNET_LOG) # if lm == 'lbrynet' else PREVIOUS_LBRYUM_LOG)
|
||||
log_contents = f.read()
|
||||
f.close()
|
||||
else:
|
||||
|
@ -1038,12 +1038,15 @@ class LBRYDaemon(jsonrpc.JSONRPC):
|
|||
|
||||
def _get_stream(stream_info):
|
||||
def _wait_for_write():
|
||||
if os.path.isfile(os.path.join(self.download_directory, self.streams[name].downloader.file_name)):
|
||||
written_file = file(os.path.join(self.download_directory, self.streams[name].downloader.file_name))
|
||||
written_file.seek(0, os.SEEK_END)
|
||||
written_bytes = written_file.tell()
|
||||
written_file.close()
|
||||
else:
|
||||
try:
|
||||
if os.path.isfile(os.path.join(self.download_directory, self.streams[name].downloader.file_name)):
|
||||
written_file = file(os.path.join(self.download_directory, self.streams[name].downloader.file_name))
|
||||
written_file.seek(0, os.SEEK_END)
|
||||
written_bytes = written_file.tell()
|
||||
written_file.close()
|
||||
else:
|
||||
written_bytes = False
|
||||
except:
|
||||
written_bytes = False
|
||||
|
||||
if not written_bytes:
|
||||
|
@ -1151,12 +1154,11 @@ class LBRYDaemon(jsonrpc.JSONRPC):
|
|||
|
||||
def _add_key_fee(data_cost):
|
||||
d = self._resolve_name(name)
|
||||
d.addCallback(lambda info: data_cost + info['key_fee'] if 'key_fee' in info.keys() else data_cost)
|
||||
d.addCallback(lambda info: data_cost if 'fee' not in info else data_cost + info['fee']['LBC']['amount'])
|
||||
return d
|
||||
|
||||
d = self._resolve_name(name)
|
||||
d.addCallback(lambda info: info['stream_hash'] if isinstance(info['stream_hash'], str)
|
||||
else info['stream_hash']['sd_hash'])
|
||||
d.addCallback(lambda info: info['sources']['lbry_sd_hash'])
|
||||
d.addCallback(lambda sd_hash: download_sd_blob(self.session, sd_hash,
|
||||
self.blob_request_payment_rate_manager))
|
||||
d.addCallback(self.sd_identifier.get_metadata_for_sd_blob)
|
||||
|
@ -1170,10 +1172,7 @@ class LBRYDaemon(jsonrpc.JSONRPC):
|
|||
|
||||
def _get_lbry_file_by_uri(self, name):
|
||||
def _get_file(stream_info):
|
||||
if isinstance(stream_info['stream_hash'], str) or isinstance(stream_info['stream_hash'], unicode):
|
||||
sd = stream_info['stream_hash']
|
||||
elif isinstance(stream_info['stream_hash'], dict):
|
||||
sd = stream_info['stream_hash']['sd_hash']
|
||||
sd = stream_info['sources']['lbry_sd_hash']
|
||||
|
||||
for l in self.lbry_file_manager.lbry_files:
|
||||
if l.sd_hash == sd:
|
||||
|
@ -1791,15 +1790,13 @@ class LBRYDaemon(jsonrpc.JSONRPC):
|
|||
for r in results:
|
||||
t = {}
|
||||
t.update(r[0])
|
||||
if 'name' in r[1].keys():
|
||||
r[1]['stream_name'] = r[1]['name']
|
||||
del r[1]['name']
|
||||
if not 'thumbnail' in r[1].keys():
|
||||
r[1]['thumbnail'] = "img/Free-speech-flag.svg"
|
||||
t.update(r[1])
|
||||
t['cost_est'] = r[2]
|
||||
if not 'thumbnail' in t.keys():
|
||||
t['thumbnail'] = "img/Free-speech-flag.svg"
|
||||
consolidated_results.append(t)
|
||||
# log.info(str(t))
|
||||
|
||||
return consolidated_results
|
||||
|
||||
log.info('[' + str(datetime.now()) + '] Search nametrie: ' + search)
|
||||
|
@ -1845,46 +1842,30 @@ class LBRYDaemon(jsonrpc.JSONRPC):
|
|||
|
||||
def jsonrpc_publish(self, p):
|
||||
"""
|
||||
Make a new name claim
|
||||
Make a new name claim and publish associated data to lbrynet
|
||||
|
||||
Args:
|
||||
'name': name to be claimed, string
|
||||
'file_path': path to file to be associated with name, string
|
||||
'bid': amount of credits to commit in this claim, float
|
||||
optional 'author': author, string
|
||||
optional 'title': title, description
|
||||
optional 'description': content description, string
|
||||
optional 'thumbnail': thumbnail image url
|
||||
optional 'key_fee': key fee to be paid to publisher, float (default 0.0)
|
||||
optional 'key_fee_address': address for key fee to be sent to, string (defaults on new address)
|
||||
optional 'content_license': content license string
|
||||
optional 'sources': alternative sources dict, keys 'lbry_sd_hash', 'btih', 'url'
|
||||
'metadata': metadata dictionary
|
||||
optional 'fee'
|
||||
Returns:
|
||||
Confirmation message
|
||||
Claim txid
|
||||
"""
|
||||
|
||||
metadata_fields = ["name", "file_path", "bid", "author", "title",
|
||||
"description", "thumbnail", "key_fee", "key_fee_address",
|
||||
"content_license", "sources"]
|
||||
|
||||
for k in metadata_fields:
|
||||
if k not in p.keys():
|
||||
p[k] = None
|
||||
# start(self, name, file_path, bid, metadata, fee=None, sources=None):
|
||||
name = p['name']
|
||||
bid = p['bid']
|
||||
file_path = p['file_path']
|
||||
metadata = p['metadata']
|
||||
if 'fee' in p:
|
||||
fee = p['fee']
|
||||
else:
|
||||
fee = None
|
||||
|
||||
pub = Publisher(self.session, self.lbry_file_manager, self.session.wallet)
|
||||
|
||||
d = pub.start(p['name'],
|
||||
p['file_path'],
|
||||
p['bid'],
|
||||
title=p['title'],
|
||||
description=p['description'],
|
||||
thumbnail=p['thumbnail'],
|
||||
key_fee=p['key_fee'],
|
||||
key_fee_address=p['key_fee_address'],
|
||||
content_license=p['content_license'],
|
||||
author=p['author'],
|
||||
sources=p['sources'])
|
||||
|
||||
d = pub.start(name, file_path, bid, metadata, fee)
|
||||
d.addCallbacks(lambda msg: self._render_response(msg, OK_CODE),
|
||||
lambda err: self._render_response(err.getTraceback(), BAD_REQUEST))
|
||||
|
||||
|
@ -2149,25 +2130,26 @@ class LBRYDaemon(jsonrpc.JSONRPC):
|
|||
d.addCallback(lambda r: self._render_response(r, OK_CODE))
|
||||
return d
|
||||
|
||||
# def jsonrpc_update_name(self, metadata):
|
||||
# def _disp(x):
|
||||
# print x
|
||||
# return x
|
||||
#
|
||||
# metadata = json.loads(metadata)
|
||||
#
|
||||
# required = ['name', 'file_path', 'bid']
|
||||
#
|
||||
# for r in required:
|
||||
# if not r in metadata.keys():
|
||||
# return defer.fail()
|
||||
#
|
||||
# d = defer.Deferred()
|
||||
# d.addCallback(lambda _: self.session.wallet.update_name(metadata))
|
||||
# d.addCallback(_disp)
|
||||
# d.callback(None)
|
||||
#
|
||||
# return d
|
||||
def jsonrpc_update_name(self, p):
|
||||
"""
|
||||
Update name claim
|
||||
|
||||
Args:
|
||||
'name': the uri of the claim to be updated
|
||||
'metadata': new metadata dict
|
||||
'amount': bid amount of updated claim
|
||||
Returns:
|
||||
txid
|
||||
"""
|
||||
|
||||
name = p['name']
|
||||
metadata = p['metadata'] if isinstance(p['metadata'], dict) else json.loads(p['metadata'])
|
||||
amount = p['amount']
|
||||
|
||||
d = self.session.wallet.update_name(name, metadata, amount)
|
||||
d.addCallback(lambda r: self._render_response(r, OK_CODE))
|
||||
|
||||
return d
|
||||
|
||||
def jsonrpc_log(self, p):
|
||||
"""
|
||||
|
@ -2260,4 +2242,4 @@ class LBRYDaemon(jsonrpc.JSONRPC):
|
|||
d = threads.deferToThread(subprocess.Popen, ['xdg-open', '-R', path])
|
||||
|
||||
d.addCallback(lambda _: self._render_response(True, OK_CODE))
|
||||
return d
|
||||
return d
|
||||
|
|
|
@ -183,7 +183,7 @@ class HostedLBRYFile(resource.Resource):
|
|||
class LBRYDaemonServer(object):
|
||||
def _setup_server(self, wallet):
|
||||
self.root = LBRYindex(os.path.join(os.path.join(data_dir, "lbry-ui"), "active"))
|
||||
self._api = LBRYDaemon(self.root, wallet_type=wallet)
|
||||
self._api = LBRYDaemon(self.root, wallet_type="lbrycrd")
|
||||
self.root.putChild("view", HostedLBRYFile(self._api))
|
||||
self.root.putChild(API_ADDRESS, self._api)
|
||||
return defer.succeed(True)
|
||||
|
|
|
@ -42,15 +42,14 @@ log.addHandler(handler)
|
|||
log.setLevel(logging.INFO)
|
||||
|
||||
class GetStream(object):
|
||||
def __init__(self, sd_identifier, session, wallet, lbry_file_manager, max_key_fee, pay_key=True, data_rate=0.5,
|
||||
timeout=DEFAULT_TIMEOUT, download_directory=None, file_name=None):
|
||||
def __init__(self, sd_identifier, session, wallet, lbry_file_manager, max_key_fee, data_rate=0.5,
|
||||
timeout=DEFAULT_TIMEOUT, download_directory=None, file_name=None):
|
||||
self.wallet = wallet
|
||||
self.resolved_name = None
|
||||
self.description = None
|
||||
self.key_fee = None
|
||||
self.key_fee_address = None
|
||||
self.data_rate = data_rate
|
||||
self.pay_key = pay_key
|
||||
self.name = None
|
||||
self.file_name = file_name
|
||||
self.session = session
|
||||
|
@ -79,7 +78,7 @@ class GetStream(object):
|
|||
self.finished.callback((self.stream_hash, self.download_path))
|
||||
|
||||
elif self.timeout_counter >= self.timeout:
|
||||
log.info("Timeout downloading lbry://" + self.resolved_name + ", " + str(self.stream_info))
|
||||
log.info("Timeout downloading lbry://%s" % self.resolved_name)
|
||||
self.checker.stop()
|
||||
self.d.cancel()
|
||||
self.code = STREAM_STAGES[4]
|
||||
|
@ -88,28 +87,24 @@ class GetStream(object):
|
|||
def start(self, stream_info, name):
|
||||
self.resolved_name = name
|
||||
self.stream_info = stream_info
|
||||
if 'stream_hash' in self.stream_info.keys():
|
||||
self.stream_hash = self.stream_info['stream_hash']
|
||||
elif 'sources' in self.stream_info.keys():
|
||||
if 'sources' in self.stream_info:
|
||||
self.stream_hash = self.stream_info['sources']['lbry_sd_hash']
|
||||
else:
|
||||
raise InvalidStreamInfoError(self.stream_info)
|
||||
if 'description' in self.stream_info.keys():
|
||||
if 'description' in self.stream_info:
|
||||
self.description = self.stream_info['description']
|
||||
if 'key_fee' in self.stream_info.keys():
|
||||
self.key_fee = float(self.stream_info['key_fee'])
|
||||
if 'key_fee_address' in self.stream_info.keys():
|
||||
self.key_fee_address = self.stream_info['key_fee_address']
|
||||
if 'fee' in self.stream_info:
|
||||
if 'LBC' in self.stream_info['fee']:
|
||||
self.key_fee = float(self.stream_info['fee']['LBC']['amount'])
|
||||
self.key_fee_address = self.stream_info['fee']['LBC']['address']
|
||||
else:
|
||||
self.key_fee_address = None
|
||||
else:
|
||||
self.key_fee = None
|
||||
self.key_fee_address = None
|
||||
if self.key_fee > self.max_key_fee:
|
||||
if self.pay_key:
|
||||
log.info("Key fee (" + str(self.key_fee) + ") above limit of " + str(
|
||||
self.max_key_fee) + ", didn't download lbry://" + str(self.resolved_name))
|
||||
return defer.fail(None)
|
||||
log.info("Key fee %f above limit of %f didn't download lbry://%s" % (self.key_fee, self.max_key_fee, self.resolved_name))
|
||||
return defer.fail(None)
|
||||
else:
|
||||
pass
|
||||
|
||||
|
@ -117,6 +112,7 @@ class GetStream(object):
|
|||
self.timeout_counter = self.timeout * 2
|
||||
|
||||
def _set_status(x, status):
|
||||
log.info("Download lbry://%s status changed to %s" % (self.resolved_name, status))
|
||||
self.code = next(s for s in STREAM_STAGES if s[0] == status)
|
||||
return x
|
||||
|
||||
|
@ -126,9 +122,8 @@ class GetStream(object):
|
|||
self.d.addCallback(lambda _: download_sd_blob(self.session, self.stream_hash, self.payment_rate_manager))
|
||||
self.d.addCallback(self.sd_identifier.get_metadata_for_sd_blob)
|
||||
self.d.addCallback(lambda r: _set_status(r, DOWNLOAD_RUNNING_CODE))
|
||||
self.d.addCallback(lambda metadata: (
|
||||
next(factory for factory in metadata.factories if isinstance(factory, ManagedLBRYFileDownloaderFactory)),
|
||||
metadata))
|
||||
self.d.addCallback(lambda metadata: (next(factory for factory in metadata.factories if isinstance(factory, ManagedLBRYFileDownloaderFactory)),
|
||||
metadata))
|
||||
self.d.addCallback(lambda (factory, metadata): factory.make_downloader(metadata,
|
||||
[self.data_rate, True],
|
||||
self.payment_rate_manager,
|
||||
|
@ -145,15 +140,13 @@ class GetStream(object):
|
|||
reserved_points = self.wallet.reserve_points(self.key_fee_address, self.key_fee)
|
||||
if reserved_points is None:
|
||||
return defer.fail(InsufficientFundsError())
|
||||
log.info("Key fee: " + str(self.key_fee) + " | " + str(self.key_fee_address))
|
||||
log.info("Key fee: %f --> %s" % (self.key_fee, self.key_fee_address))
|
||||
return self.wallet.send_points_to_address(reserved_points, self.key_fee)
|
||||
return defer.succeed(None)
|
||||
|
||||
if self.pay_key:
|
||||
d = _pay_key_fee()
|
||||
else:
|
||||
d = defer.Deferred()
|
||||
d = _pay_key_fee()
|
||||
self.downloader = downloader
|
||||
self.download_path = os.path.join(downloader.download_directory, downloader.file_name)
|
||||
d.addCallback(lambda _: log.info("[" + str(datetime.now()) + "] Downloading " + str(self.stream_hash) + " --> " + str(self.download_path)))
|
||||
d.addCallback(lambda _: log.info("[%s] Downloading %s --> %s" % (datetime.now(), self.stream_hash, self.downloader.file_name)))
|
||||
d.addCallback(lambda _: self.downloader.start())
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import logging
|
||||
import mimetypes
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
@ -36,42 +37,27 @@ class Publisher(object):
|
|||
self.received_file_name = False
|
||||
self.file_path = None
|
||||
self.file_name = None
|
||||
self.thumbnail = None
|
||||
self.title = None
|
||||
self.publish_name = None
|
||||
self.bid_amount = None
|
||||
self.key_fee = None
|
||||
self.key_fee_address = None
|
||||
self.key_fee_address_chosen = False
|
||||
self.description = None
|
||||
self.verified = False
|
||||
self.lbry_file = None
|
||||
self.sd_hash = None
|
||||
self.tx_hash = None
|
||||
self.content_license = None
|
||||
self.author = None
|
||||
self.sources = None
|
||||
self.txid = None
|
||||
self.sources = {}
|
||||
self.fee = None
|
||||
|
||||
def start(self, name, file_path, bid, title=None, description=None, thumbnail=None,
|
||||
key_fee=None, key_fee_address=None, content_license=None, author=None, sources=None):
|
||||
def start(self, name, file_path, bid, metadata, fee=None, sources={}):
|
||||
|
||||
def _show_result():
|
||||
message = "[" + str(datetime.now()) + "] Published " + self.file_name + " --> lbry://" + \
|
||||
str(self.publish_name) + " with txid: " + str(self.tx_hash)
|
||||
|
||||
message = "[%s] Published %s --> lbry://%s txid: %s" % (datetime.now(), self.file_name, self.publish_name, self.txid)
|
||||
log.info(message)
|
||||
return defer.succeed(self.tx_hash)
|
||||
return defer.succeed(self.txid)
|
||||
|
||||
self.publish_name = name
|
||||
self.file_path = file_path
|
||||
self.bid_amount = bid
|
||||
self.title = title
|
||||
self.description = description
|
||||
self.thumbnail = thumbnail
|
||||
self.key_fee = key_fee
|
||||
self.key_fee_address = key_fee_address
|
||||
self.content_license = content_license
|
||||
self.author = author
|
||||
self.sources = sources
|
||||
self.fee = fee
|
||||
self.metadata = metadata
|
||||
|
||||
d = self._check_file_path(self.file_path)
|
||||
d.addCallback(lambda _: create_lbry_file(self.session, self.lbry_file_manager,
|
||||
|
@ -118,20 +104,21 @@ class Publisher(object):
|
|||
self.lbry_file.stream_hash)
|
||||
|
||||
def set_sd_hash(sd_hash):
|
||||
self.sd_hash = sd_hash
|
||||
self.sources['lbry_sd_hash'] = sd_hash
|
||||
|
||||
d.addCallback(set_sd_hash)
|
||||
return d
|
||||
|
||||
def _claim_name(self):
|
||||
d = self.wallet.claim_name(self.publish_name, self.sd_hash, self.bid_amount,
|
||||
description=self.description, key_fee=self.key_fee,
|
||||
key_fee_address=self.key_fee_address, thumbnail=self.thumbnail,
|
||||
content_license=self.content_license, author=self.author,
|
||||
sources=self.sources)
|
||||
|
||||
def set_tx_hash(tx_hash):
|
||||
self.tx_hash = tx_hash
|
||||
self.metadata['content-type'] = mimetypes.guess_type(os.path.join(self.lbry_file.download_directory,
|
||||
self.lbry_file.file_name))[0]
|
||||
d = self.wallet.claim_name(self.publish_name,
|
||||
self.bid_amount,
|
||||
self.sources,
|
||||
self.metadata,
|
||||
fee=self.fee)
|
||||
def set_tx_hash(txid):
|
||||
self.txid = txid
|
||||
|
||||
d.addCallback(set_tx_hash)
|
||||
return d
|
||||
|
@ -140,6 +127,7 @@ class Publisher(object):
|
|||
log.info(err.getTraceback())
|
||||
message = "An error occurred publishing %s to %s. Error: %s."
|
||||
if err.check(InsufficientFundsError):
|
||||
d = defer.succeed(True)
|
||||
error_message = "Insufficient funds"
|
||||
else:
|
||||
d = defer.succeed(True)
|
||||
|
|
|
@ -10,7 +10,7 @@ from twisted.web import static
|
|||
from twisted.internet import defer
|
||||
from lbrynet.conf import DEFAULT_UI_BRANCH, LOG_FILE_NAME
|
||||
from lbrynet import __version__ as lbrynet_version
|
||||
from lbryum.version import ELECTRUM_VERSION as lbryum_version
|
||||
from lbryum.version import LBRYUM_VERSION as lbryum_version
|
||||
from zipfile import ZipFile
|
||||
from appdirs import user_data_dir
|
||||
|
||||
|
|
|
@ -1,352 +0,0 @@
|
|||
import Tkinter as tk
|
||||
import logging
|
||||
import sys
|
||||
import tkFont
|
||||
import tkMessageBox
|
||||
import ttk
|
||||
from lbrynet.lbrynet_gui.LBRYGui import LBRYDownloader
|
||||
from lbrynet.lbrynet_gui.StreamFrame import StreamFrame
|
||||
import locale
|
||||
import os
|
||||
from twisted.internet import defer, reactor, tksupport, task
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DownloaderApp(object):
|
||||
def __init__(self):
|
||||
self.master = None
|
||||
self.downloader = None
|
||||
self.wallet_balance_check = None
|
||||
self.streams_frame = None
|
||||
|
||||
def start(self):
|
||||
|
||||
d = defer.maybeDeferred(self._start_root)
|
||||
d.addCallback(lambda _: self._draw_main())
|
||||
d.addCallback(lambda _: self._start_downloader())
|
||||
d.addCallback(lambda _: self._start_checking_wallet_balance())
|
||||
d.addCallback(lambda _: self._enable_lookup())
|
||||
|
||||
def show_error_and_stop(err):
|
||||
log.error(err.getErrorMessage())
|
||||
tkMessageBox.showerror(title="Start Error", message=err.getErrorMessage())
|
||||
return self.stop()
|
||||
|
||||
d.addErrback(show_error_and_stop)
|
||||
return d
|
||||
|
||||
def stop(self):
|
||||
|
||||
def log_error(err):
|
||||
log.error(err.getErrorMessage())
|
||||
|
||||
if self.downloader is not None:
|
||||
d = self.downloader.stop()
|
||||
else:
|
||||
d = defer.succeed(True)
|
||||
d.addErrback(log_error)
|
||||
d.addCallback(lambda _: self._stop_checking_wallet_balance())
|
||||
d.addErrback(log_error)
|
||||
d.addCallback(lambda _: reactor.stop())
|
||||
d.addErrback(log_error)
|
||||
return d
|
||||
|
||||
def _start_root(self):
|
||||
if os.name == "nt":
|
||||
button_foreground = "#104639"
|
||||
lookup_button_padding = 10
|
||||
else:
|
||||
button_foreground = "#FFFFFF"
|
||||
lookup_button_padding = 11
|
||||
|
||||
root = tk.Tk()
|
||||
root.resizable(0, 0)
|
||||
root.wm_title("LBRY")
|
||||
|
||||
tksupport.install(root)
|
||||
|
||||
if os.name == "nt":
|
||||
root.iconbitmap(os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])),
|
||||
"lbry-dark-icon.ico"))
|
||||
else:
|
||||
root.wm_iconbitmap("@" + os.path.join(os.path.dirname(__file__), "lbry-dark-icon.xbm"))
|
||||
|
||||
root.button_font = tkFont.Font(size=9)
|
||||
|
||||
ttk.Style().configure(".", background="#FFFFFF")
|
||||
ttk.Style().configure("LBRY.TButton", background="#104639", foreground=button_foreground,
|
||||
borderwidth=1, relief="solid", font=root.button_font)
|
||||
ttk.Style().map("LBRY.TButton",
|
||||
background=[('pressed', "#104639"),
|
||||
('active', "#104639")])
|
||||
#ttk.Style().configure("LBRY.TButton.border", background="#808080")
|
||||
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("TEntry", padding=11)
|
||||
ttk.Style().configure("Float.TEntry", padding=2)
|
||||
#ttk.Style().configure("A.TFrame", background="red")
|
||||
#ttk.Style().configure("B.TFrame", background="green")
|
||||
#ttk.Style().configure("B2.TFrame", background="#80FF80")
|
||||
#ttk.Style().configure("C.TFrame", background="orange")
|
||||
#ttk.Style().configure("D.TFrame", background="blue")
|
||||
#ttk.Style().configure("E.TFrame", background="yellow")
|
||||
#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")
|
||||
#ttk.Style().layout("Horizontal.LBRY.TProgressbar", ttk.Style().layout("Horizontal.TProgressbar"))
|
||||
|
||||
root.configure(background="#FFFFFF")
|
||||
|
||||
root.protocol("WM_DELETE_WINDOW", self.stop)
|
||||
|
||||
self.master = root
|
||||
|
||||
def _draw_main(self):
|
||||
self.frame = ttk.Frame(self.master, style="A.TFrame")
|
||||
self.frame.grid(padx=20, pady=20)
|
||||
|
||||
logo_file_name = "lbry-dark-242x80.gif"
|
||||
if os.name == "nt":
|
||||
logo_file = os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])), logo_file_name)
|
||||
else:
|
||||
logo_file = os.path.join(os.path.dirname(__file__), logo_file_name)
|
||||
|
||||
self.logo_picture = tk.PhotoImage(file=logo_file)
|
||||
|
||||
self.logo_frame = ttk.Frame(self.frame, style="B.TFrame")
|
||||
self.logo_frame.grid(pady=5, sticky=tk.W + tk.E)
|
||||
|
||||
self.dummy_frame = ttk.Frame(self.logo_frame, style="C.TFrame") # keeps the logo in the middle
|
||||
self.dummy_frame.grid(row=0, column=1, padx=5)
|
||||
|
||||
self.logo_label = ttk.Label(self.logo_frame, image=self.logo_picture)
|
||||
self.logo_label.grid(row=0, column=1, padx=5)
|
||||
|
||||
self.wallet_balance_frame = ttk.Frame(self.logo_frame, style="C.TFrame")
|
||||
self.wallet_balance_frame.grid(sticky=tk.E + tk.N, row=0, column=2)
|
||||
|
||||
self.logo_frame.grid_columnconfigure(0, weight=1, uniform="a")
|
||||
self.logo_frame.grid_columnconfigure(1, weight=2, uniform="b")
|
||||
self.logo_frame.grid_columnconfigure(2, weight=1, uniform="a")
|
||||
|
||||
self.wallet_balance = ttk.Label(
|
||||
self.wallet_balance_frame,
|
||||
text=" -- LBC"
|
||||
)
|
||||
self.wallet_balance.grid(row=0, column=0)
|
||||
|
||||
dropdown_file_name = "drop_down.gif"
|
||||
if os.name == "nt":
|
||||
dropdown_file = os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])),
|
||||
dropdown_file_name)
|
||||
else:
|
||||
dropdown_file = os.path.join(os.path.dirname(__file__), dropdown_file_name)
|
||||
|
||||
self.dropdown_picture = tk.PhotoImage(
|
||||
file=dropdown_file
|
||||
)
|
||||
|
||||
def get_new_address():
|
||||
def show_address(address):
|
||||
w = AddressWindow(self.master, address)
|
||||
w.show()
|
||||
d = defer.maybeDeferred(self.downloader.get_new_address)
|
||||
d.addCallback(show_address)
|
||||
|
||||
def show_error(err):
|
||||
tkMessageBox.showerror(title="Failed to get new address", message=err.getErrorMessage())
|
||||
|
||||
d.addErrback(show_error)
|
||||
|
||||
self.wallet_menu = tk.Menu(
|
||||
self.master, tearoff=0
|
||||
)
|
||||
self.wallet_menu.add_command(label="Get new LBRYcrd address", command=get_new_address)
|
||||
|
||||
if os.name == "nt":
|
||||
button_cursor = ""
|
||||
else:
|
||||
button_cursor = "hand1"
|
||||
|
||||
self.wallet_menu_button = ttk.Button(self.wallet_balance_frame, image=self.dropdown_picture,
|
||||
style="Stop.TButton", cursor=button_cursor)
|
||||
self.wallet_menu_button.grid(row=0, column=1, padx=(5, 0))
|
||||
|
||||
def popup_wallet(event):
|
||||
self.wallet_menu.tk_popup(event.x_root, event.y_root)
|
||||
|
||||
self.wallet_menu_button.bind("<Button-1>", popup_wallet)
|
||||
|
||||
self.uri_frame = ttk.Frame(self.frame, style="B.TFrame")
|
||||
self.uri_frame.grid()
|
||||
|
||||
self.uri_label = ttk.Label(
|
||||
self.uri_frame, text="lbry://"
|
||||
)
|
||||
self.uri_label.grid(row=0, column=0, sticky=tk.E, pady=2)
|
||||
|
||||
self.entry_font = tkFont.Font(size=11)
|
||||
|
||||
self.uri_entry = ttk.Entry(self.uri_frame, width=50, foreground="#222222", font=self.entry_font,
|
||||
state=tk.DISABLED)
|
||||
self.uri_entry.grid(row=0, column=1, padx=2, pady=2)
|
||||
|
||||
def copy_command():
|
||||
self.uri_entry.event_generate('<Control-c>')
|
||||
|
||||
def cut_command():
|
||||
self.uri_entry.event_generate('<Control-x>')
|
||||
|
||||
def paste_command():
|
||||
self.uri_entry.event_generate('<Control-v>')
|
||||
|
||||
def popup_uri(event):
|
||||
selection_menu = tk.Menu(
|
||||
self.master, tearoff=0
|
||||
)
|
||||
if self.uri_entry.selection_present():
|
||||
selection_menu.add_command(label=" Cut ", command=cut_command)
|
||||
selection_menu.add_command(label=" Copy ", command=copy_command)
|
||||
selection_menu.add_command(label=" Paste ", command=paste_command)
|
||||
selection_menu.tk_popup(event.x_root, event.y_root)
|
||||
|
||||
self.uri_entry.bind("<Button-3>", popup_uri)
|
||||
|
||||
self.uri_button = ttk.Button(
|
||||
self.uri_frame, text="Go", command=self._open_stream,
|
||||
style='Lookup.LBRY.TButton', cursor=button_cursor
|
||||
)
|
||||
self.uri_button.grid(row=0, column=2, pady=2, padx=0)
|
||||
|
||||
def _start_downloader(self):
|
||||
self.downloader = LBRYDownloader()
|
||||
d = self.downloader.start()
|
||||
d.addCallback(lambda _: self.downloader.check_first_run())
|
||||
d.addCallback(self._show_welcome_message)
|
||||
return d
|
||||
|
||||
def _show_welcome_message(self, points_sent):
|
||||
if points_sent != 0.0:
|
||||
w = WelcomeWindow(self.master, points_sent)
|
||||
w.show()
|
||||
|
||||
def stream_removed(self):
|
||||
if self.streams_frame is not None:
|
||||
if len(self.streams_frame.winfo_children()) == 0:
|
||||
self.streams_frame.destroy()
|
||||
self.streams_frame = None
|
||||
|
||||
def _start_checking_wallet_balance(self):
|
||||
|
||||
def set_balance(balance):
|
||||
self.wallet_balance.configure(text=locale.format_string("%.2f LBC", (round(balance, 2),),
|
||||
grouping=True))
|
||||
|
||||
def update_balance():
|
||||
balance = self.downloader.session.wallet.get_available_balance()
|
||||
set_balance(balance)
|
||||
|
||||
def start_looping_call():
|
||||
self.wallet_balance_check = task.LoopingCall(update_balance)
|
||||
self.wallet_balance_check.start(5)
|
||||
|
||||
d = self.downloader.session.wallet.get_balance()
|
||||
d.addCallback(set_balance)
|
||||
d.addCallback(lambda _: start_looping_call())
|
||||
|
||||
def _stop_checking_wallet_balance(self):
|
||||
if self.wallet_balance_check is not None:
|
||||
self.wallet_balance_check.stop()
|
||||
|
||||
def _enable_lookup(self):
|
||||
self.uri_entry.bind('<Return>', self._open_stream)
|
||||
self.uri_entry.config(state=tk.NORMAL)
|
||||
|
||||
def _open_stream(self, event=None):
|
||||
if self.streams_frame is None:
|
||||
self.streams_frame = ttk.Frame(self.frame, style="B2.TFrame")
|
||||
self.streams_frame.grid(sticky=tk.E + tk.W)
|
||||
uri = self.uri_entry.get()
|
||||
self.uri_entry.delete(0, tk.END)
|
||||
stream_frame = StreamFrame(self, "lbry://" + uri)
|
||||
|
||||
self.downloader.download_stream(stream_frame, uri)
|
||||
|
||||
|
||||
class WelcomeWindow(object):
|
||||
def __init__(self, root, points_sent):
|
||||
self.root = root
|
||||
self.points_sent = points_sent
|
||||
|
||||
def show(self):
|
||||
window = tk.Toplevel(self.root, background="#FFFFFF")
|
||||
window.transient(self.root)
|
||||
window.wm_title("Welcome to LBRY")
|
||||
window.protocol("WM_DELETE_WINDOW", window.destroy)
|
||||
window.resizable(0, 0)
|
||||
|
||||
text_box = tk.Text(window, width=45, height=3, relief=tk.FLAT, borderwidth=0,
|
||||
highlightthickness=0)
|
||||
|
||||
points_string = locale.format_string("%.2f LBC", (round(self.points_sent, 2),),
|
||||
grouping=True)
|
||||
|
||||
text_box.insert(tk.END, "Thank you for using LBRY! You have been\n"
|
||||
"given %s for free because we love\n"
|
||||
"you. Please give them 60 seconds to show up." % points_string)
|
||||
text_box.grid(row=0, padx=10, pady=5, columnspan=2)
|
||||
text_box.config(state='normal')
|
||||
|
||||
window.focus_set()
|
||||
|
||||
|
||||
class AddressWindow(object):
|
||||
def __init__(self, root, address):
|
||||
self.root = root
|
||||
self.address = address
|
||||
|
||||
def show(self):
|
||||
window = tk.Toplevel(self.root, background="#FFFFFF")
|
||||
window.transient(self.root)
|
||||
window.wm_title("New address")
|
||||
window.protocol("WM_DELETE_WINDOW", window.destroy)
|
||||
window.resizable(0, 0)
|
||||
|
||||
text_box = tk.Text(window, width=35, height=1, relief=tk.FLAT, borderwidth=0,
|
||||
highlightthickness=0)
|
||||
text_box.insert(tk.END, self.address)
|
||||
text_box.grid(row=0, padx=10, pady=5, columnspan=2)
|
||||
text_box.config(state='normal')
|
||||
|
||||
def copy_to_clipboard():
|
||||
self.root.clipboard_clear()
|
||||
self.root.clipboard_append(text_box.get('1.0', 'end-1c'))
|
||||
|
||||
def copy_command():
|
||||
text_box.event_generate("<Control-c>")
|
||||
|
||||
copy_menu = tk.Menu(
|
||||
self.root, tearoff=0
|
||||
)
|
||||
copy_menu.add_command(label=" Copy ", command=copy_command)
|
||||
|
||||
def popup(event):
|
||||
if text_box.tag_ranges("sel"):
|
||||
copy_menu.tk_popup(event.x_root, event.y_root)
|
||||
|
||||
text_box.bind("<Button-3>", popup)
|
||||
|
||||
copy_button = ttk.Button(
|
||||
window, text="Copy", command=copy_to_clipboard, style="LBRY.TButton"
|
||||
)
|
||||
copy_button.grid(row=1, column=0, pady=(0, 5), padx=5, sticky=tk.E)
|
||||
|
||||
done_button = ttk.Button(
|
||||
window, text="OK", command=window.destroy, style="LBRY.TButton"
|
||||
)
|
||||
done_button.grid(row=1, column=1, pady=(0, 5), padx=5, sticky=tk.W)
|
||||
window.focus_set()
|
|
@ -1,393 +0,0 @@
|
|||
Attribution 4.0 International
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons Corporation ("Creative Commons") is not a law firm and
|
||||
does not provide legal services or legal advice. Distribution of
|
||||
Creative Commons public licenses does not create a lawyer-client or
|
||||
other relationship. Creative Commons makes its licenses and related
|
||||
information available on an "as-is" basis. Creative Commons gives no
|
||||
warranties regarding its licenses, any material licensed under their
|
||||
terms and conditions, or any related information. Creative Commons
|
||||
disclaims all liability for damages resulting from their use to the
|
||||
fullest extent possible.
|
||||
|
||||
Using Creative Commons Public Licenses
|
||||
|
||||
Creative Commons public licenses provide a standard set of terms and
|
||||
conditions that creators and other rights holders may use to share
|
||||
original works of authorship and other material subject to copyright
|
||||
and certain other rights specified in the public license below. The
|
||||
following considerations are for informational purposes only, are not
|
||||
exhaustive, and do not form part of our licenses.
|
||||
|
||||
Considerations for licensors: Our public licenses are
|
||||
intended for use by those authorized to give the public
|
||||
permission to use material in ways otherwise restricted by
|
||||
copyright and certain other rights. Our licenses are
|
||||
irrevocable. Licensors should read and understand the terms
|
||||
and conditions of the license they choose before applying it.
|
||||
Licensors should also secure all rights necessary before
|
||||
applying our licenses so that the public can reuse the
|
||||
material as expected. Licensors should clearly mark any
|
||||
material not subject to the license. This includes other CC-
|
||||
licensed material, or material used under an exception or
|
||||
limitation to copyright. More considerations for licensors:
|
||||
wiki.creativecommons.org/Considerations_for_licensors
|
||||
|
||||
Considerations for the public: By using one of our public
|
||||
licenses, a licensor grants the public permission to use the
|
||||
licensed material under specified terms and conditions. If
|
||||
the licensor's permission is not necessary for any reason--for
|
||||
example, because of any applicable exception or limitation to
|
||||
copyright--then that use is not regulated by the license. Our
|
||||
licenses grant only permissions under copyright and certain
|
||||
other rights that a licensor has authority to grant. Use of
|
||||
the licensed material may still be restricted for other
|
||||
reasons, including because others have copyright or other
|
||||
rights in the material. A licensor may make special requests,
|
||||
such as asking that all changes be marked or described.
|
||||
Although not required by our licenses, you are encouraged to
|
||||
respect those requests where reasonable. More_considerations
|
||||
for the public:
|
||||
wiki.creativecommons.org/Considerations_for_licensees
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons Attribution 4.0 International Public License
|
||||
|
||||
By exercising the Licensed Rights (defined below), You accept and agree
|
||||
to be bound by the terms and conditions of this Creative Commons
|
||||
Attribution 4.0 International Public License ("Public License"). To the
|
||||
extent this Public License may be interpreted as a contract, You are
|
||||
granted the Licensed Rights in consideration of Your acceptance of
|
||||
these terms and conditions, and the Licensor grants You such rights in
|
||||
consideration of benefits the Licensor receives from making the
|
||||
Licensed Material available under these terms and conditions.
|
||||
|
||||
|
||||
Section 1 -- Definitions.
|
||||
|
||||
a. Adapted Material means material subject to Copyright and Similar
|
||||
Rights that is derived from or based upon the Licensed Material
|
||||
and in which the Licensed Material is translated, altered,
|
||||
arranged, transformed, or otherwise modified in a manner requiring
|
||||
permission under the Copyright and Similar Rights held by the
|
||||
Licensor. For purposes of this Public License, where the Licensed
|
||||
Material is a musical work, performance, or sound recording,
|
||||
Adapted Material is always produced where the Licensed Material is
|
||||
synched in timed relation with a moving image.
|
||||
|
||||
b. Adapter's License means the license You apply to Your Copyright
|
||||
and Similar Rights in Your contributions to Adapted Material in
|
||||
accordance with the terms and conditions of this Public License.
|
||||
|
||||
c. Copyright and Similar Rights means copyright and/or similar rights
|
||||
closely related to copyright including, without limitation,
|
||||
performance, broadcast, sound recording, and Sui Generis Database
|
||||
Rights, without regard to how the rights are labeled or
|
||||
categorized. For purposes of this Public License, the rights
|
||||
specified in Section 2(b)(1)-(2) are not Copyright and Similar
|
||||
Rights.
|
||||
|
||||
d. Effective Technological Measures means those measures that, in the
|
||||
absence of proper authority, may not be circumvented under laws
|
||||
fulfilling obligations under Article 11 of the WIPO Copyright
|
||||
Treaty adopted on December 20, 1996, and/or similar international
|
||||
agreements.
|
||||
|
||||
e. Exceptions and Limitations means fair use, fair dealing, and/or
|
||||
any other exception or limitation to Copyright and Similar Rights
|
||||
that applies to Your use of the Licensed Material.
|
||||
|
||||
f. Licensed Material means the artistic or literary work, database,
|
||||
or other material to which the Licensor applied this Public
|
||||
License.
|
||||
|
||||
g. Licensed Rights means the rights granted to You subject to the
|
||||
terms and conditions of this Public License, which are limited to
|
||||
all Copyright and Similar Rights that apply to Your use of the
|
||||
Licensed Material and that the Licensor has authority to license.
|
||||
|
||||
h. Licensor means the individual(s) or entity(ies) granting rights
|
||||
under this Public License.
|
||||
|
||||
i. Share means to provide material to the public by any means or
|
||||
process that requires permission under the Licensed Rights, such
|
||||
as reproduction, public display, public performance, distribution,
|
||||
dissemination, communication, or importation, and to make material
|
||||
available to the public including in ways that members of the
|
||||
public may access the material from a place and at a time
|
||||
individually chosen by them.
|
||||
|
||||
j. Sui Generis Database Rights means rights other than copyright
|
||||
resulting from Directive 96/9/EC of the European Parliament and of
|
||||
the Council of 11 March 1996 on the legal protection of databases,
|
||||
as amended and/or succeeded, as well as other essentially
|
||||
equivalent rights anywhere in the world.
|
||||
|
||||
k. You means the individual or entity exercising the Licensed Rights
|
||||
under this Public License. Your has a corresponding meaning.
|
||||
|
||||
|
||||
Section 2 -- Scope.
|
||||
|
||||
a. License grant.
|
||||
|
||||
1. Subject to the terms and conditions of this Public License,
|
||||
the Licensor hereby grants You a worldwide, royalty-free,
|
||||
non-sublicensable, non-exclusive, irrevocable license to
|
||||
exercise the Licensed Rights in the Licensed Material to:
|
||||
|
||||
a. reproduce and Share the Licensed Material, in whole or
|
||||
in part; and
|
||||
|
||||
b. produce, reproduce, and Share Adapted Material.
|
||||
|
||||
2. Exceptions and Limitations. For the avoidance of doubt, where
|
||||
Exceptions and Limitations apply to Your use, this Public
|
||||
License does not apply, and You do not need to comply with
|
||||
its terms and conditions.
|
||||
|
||||
3. Term. The term of this Public License is specified in Section
|
||||
6(a).
|
||||
|
||||
4. Media and formats; technical modifications allowed. The
|
||||
Licensor authorizes You to exercise the Licensed Rights in
|
||||
all media and formats whether now known or hereafter created,
|
||||
and to make technical modifications necessary to do so. The
|
||||
Licensor waives and/or agrees not to assert any right or
|
||||
authority to forbid You from making technical modifications
|
||||
necessary to exercise the Licensed Rights, including
|
||||
technical modifications necessary to circumvent Effective
|
||||
Technological Measures. For purposes of this Public License,
|
||||
simply making modifications authorized by this Section 2(a)
|
||||
(4) never produces Adapted Material.
|
||||
|
||||
5. Downstream recipients.
|
||||
|
||||
a. Offer from the Licensor -- Licensed Material. Every
|
||||
recipient of the Licensed Material automatically
|
||||
receives an offer from the Licensor to exercise the
|
||||
Licensed Rights under the terms and conditions of this
|
||||
Public License.
|
||||
|
||||
b. No downstream restrictions. You may not offer or impose
|
||||
any additional or different terms or conditions on, or
|
||||
apply any Effective Technological Measures to, the
|
||||
Licensed Material if doing so restricts exercise of the
|
||||
Licensed Rights by any recipient of the Licensed
|
||||
Material.
|
||||
|
||||
6. No endorsement. Nothing in this Public License constitutes or
|
||||
may be construed as permission to assert or imply that You
|
||||
are, or that Your use of the Licensed Material is, connected
|
||||
with, or sponsored, endorsed, or granted official status by,
|
||||
the Licensor or others designated to receive attribution as
|
||||
provided in Section 3(a)(1)(A)(i).
|
||||
|
||||
b. Other rights.
|
||||
|
||||
1. Moral rights, such as the right of integrity, are not
|
||||
licensed under this Public License, nor are publicity,
|
||||
privacy, and/or other similar personality rights; however, to
|
||||
the extent possible, the Licensor waives and/or agrees not to
|
||||
assert any such rights held by the Licensor to the limited
|
||||
extent necessary to allow You to exercise the Licensed
|
||||
Rights, but not otherwise.
|
||||
|
||||
2. Patent and trademark rights are not licensed under this
|
||||
Public License.
|
||||
|
||||
3. To the extent possible, the Licensor waives any right to
|
||||
collect royalties from You for the exercise of the Licensed
|
||||
Rights, whether directly or through a collecting society
|
||||
under any voluntary or waivable statutory or compulsory
|
||||
licensing scheme. In all other cases the Licensor expressly
|
||||
reserves any right to collect such royalties.
|
||||
|
||||
|
||||
Section 3 -- License Conditions.
|
||||
|
||||
Your exercise of the Licensed Rights is expressly made subject to the
|
||||
following conditions.
|
||||
|
||||
a. Attribution.
|
||||
|
||||
1. If You Share the Licensed Material (including in modified
|
||||
form), You must:
|
||||
|
||||
a. retain the following if it is supplied by the Licensor
|
||||
with the Licensed Material:
|
||||
|
||||
i. identification of the creator(s) of the Licensed
|
||||
Material and any others designated to receive
|
||||
attribution, in any reasonable manner requested by
|
||||
the Licensor (including by pseudonym if
|
||||
designated);
|
||||
|
||||
ii. a copyright notice;
|
||||
|
||||
iii. a notice that refers to this Public License;
|
||||
|
||||
iv. a notice that refers to the disclaimer of
|
||||
warranties;
|
||||
|
||||
v. a URI or hyperlink to the Licensed Material to the
|
||||
extent reasonably practicable;
|
||||
|
||||
b. indicate if You modified the Licensed Material and
|
||||
retain an indication of any previous modifications; and
|
||||
|
||||
c. indicate the Licensed Material is licensed under this
|
||||
Public License, and include the text of, or the URI or
|
||||
hyperlink to, this Public License.
|
||||
|
||||
2. You may satisfy the conditions in Section 3(a)(1) in any
|
||||
reasonable manner based on the medium, means, and context in
|
||||
which You Share the Licensed Material. For example, it may be
|
||||
reasonable to satisfy the conditions by providing a URI or
|
||||
hyperlink to a resource that includes the required
|
||||
information.
|
||||
|
||||
3. If requested by the Licensor, You must remove any of the
|
||||
information required by Section 3(a)(1)(A) to the extent
|
||||
reasonably practicable.
|
||||
|
||||
4. If You Share Adapted Material You produce, the Adapter's
|
||||
License You apply must not prevent recipients of the Adapted
|
||||
Material from complying with this Public License.
|
||||
|
||||
|
||||
Section 4 -- Sui Generis Database Rights.
|
||||
|
||||
Where the Licensed Rights include Sui Generis Database Rights that
|
||||
apply to Your use of the Licensed Material:
|
||||
|
||||
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
|
||||
to extract, reuse, reproduce, and Share all or a substantial
|
||||
portion of the contents of the database;
|
||||
|
||||
b. if You include all or a substantial portion of the database
|
||||
contents in a database in which You have Sui Generis Database
|
||||
Rights, then the database in which You have Sui Generis Database
|
||||
Rights (but not its individual contents) is Adapted Material; and
|
||||
|
||||
c. You must comply with the conditions in Section 3(a) if You Share
|
||||
all or a substantial portion of the contents of the database.
|
||||
|
||||
For the avoidance of doubt, this Section 4 supplements and does not
|
||||
replace Your obligations under this Public License where the Licensed
|
||||
Rights include other Copyright and Similar Rights.
|
||||
|
||||
|
||||
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
|
||||
|
||||
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
|
||||
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
|
||||
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
|
||||
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
|
||||
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
|
||||
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
|
||||
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
|
||||
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
|
||||
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
|
||||
|
||||
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
|
||||
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
|
||||
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
|
||||
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
|
||||
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
|
||||
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
|
||||
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
|
||||
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
|
||||
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
|
||||
|
||||
c. The disclaimer of warranties and limitation of liability provided
|
||||
above shall be interpreted in a manner that, to the extent
|
||||
possible, most closely approximates an absolute disclaimer and
|
||||
waiver of all liability.
|
||||
|
||||
|
||||
Section 6 -- Term and Termination.
|
||||
|
||||
a. This Public License applies for the term of the Copyright and
|
||||
Similar Rights licensed here. However, if You fail to comply with
|
||||
this Public License, then Your rights under this Public License
|
||||
terminate automatically.
|
||||
|
||||
b. Where Your right to use the Licensed Material has terminated under
|
||||
Section 6(a), it reinstates:
|
||||
|
||||
1. automatically as of the date the violation is cured, provided
|
||||
it is cured within 30 days of Your discovery of the
|
||||
violation; or
|
||||
|
||||
2. upon express reinstatement by the Licensor.
|
||||
|
||||
For the avoidance of doubt, this Section 6(b) does not affect any
|
||||
right the Licensor may have to seek remedies for Your violations
|
||||
of this Public License.
|
||||
|
||||
c. For the avoidance of doubt, the Licensor may also offer the
|
||||
Licensed Material under separate terms or conditions or stop
|
||||
distributing the Licensed Material at any time; however, doing so
|
||||
will not terminate this Public License.
|
||||
|
||||
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
|
||||
License.
|
||||
|
||||
|
||||
Section 7 -- Other Terms and Conditions.
|
||||
|
||||
a. The Licensor shall not be bound by any additional or different
|
||||
terms or conditions communicated by You unless expressly agreed.
|
||||
|
||||
b. Any arrangements, understandings, or agreements regarding the
|
||||
Licensed Material not stated herein are separate from and
|
||||
independent of the terms and conditions of this Public License.
|
||||
|
||||
|
||||
Section 8 -- Interpretation.
|
||||
|
||||
a. For the avoidance of doubt, this Public License does not, and
|
||||
shall not be interpreted to, reduce, limit, restrict, or impose
|
||||
conditions on any use of the Licensed Material that could lawfully
|
||||
be made without permission under this Public License.
|
||||
|
||||
b. To the extent possible, if any provision of this Public License is
|
||||
deemed unenforceable, it shall be automatically reformed to the
|
||||
minimum extent necessary to make it enforceable. If the provision
|
||||
cannot be reformed, it shall be severed from this Public License
|
||||
without affecting the enforceability of the remaining terms and
|
||||
conditions.
|
||||
|
||||
c. No term or condition of this Public License will be waived and no
|
||||
failure to comply consented to unless expressly agreed to by the
|
||||
Licensor.
|
||||
|
||||
d. Nothing in this Public License constitutes or may be interpreted
|
||||
as a limitation upon, or waiver of, any privileges and immunities
|
||||
that apply to the Licensor or You, including from the legal
|
||||
processes of any jurisdiction or authority.
|
||||
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons is not a party to its public licenses.
|
||||
Notwithstanding, Creative Commons may elect to apply one of its public
|
||||
licenses to material it publishes and in those instances will be
|
||||
considered the "Licensor." Except for the limited purpose of indicating
|
||||
that material is shared under a Creative Commons public license or as
|
||||
otherwise permitted by the Creative Commons policies published at
|
||||
creativecommons.org/policies, Creative Commons does not authorize the
|
||||
use of the trademark "Creative Commons" or any other trademark or logo
|
||||
of Creative Commons without its prior written consent including,
|
||||
without limitation, in connection with any unauthorized modifications
|
||||
to any of its public licenses or any other arrangements,
|
||||
understandings, or agreements concerning use of licensed material. For
|
||||
the avoidance of doubt, this paragraph does not form part of the public
|
||||
licenses.
|
||||
|
||||
Creative Commons may be contacted at creativecommons.org.
|
|
@ -1,571 +0,0 @@
|
|||
import binascii
|
||||
import logging
|
||||
import tkMessageBox
|
||||
from Crypto import Random
|
||||
from lbrynet.conf import MIN_BLOB_DATA_PAYMENT_RATE
|
||||
from lbrynet.core import StreamDescriptor
|
||||
from lbrynet.core.Error import UnknownNameError, UnknownStreamTypeError, InvalidStreamDescriptorError
|
||||
from lbrynet.core.Error import InvalidStreamInfoError
|
||||
from lbrynet.core.LBRYcrdWallet import LBRYcrdWallet
|
||||
from lbrynet.core.PaymentRateManager import PaymentRateManager
|
||||
from lbrynet.core.Session import LBRYSession
|
||||
from lbrynet.core.StreamDescriptor import StreamDescriptorIdentifier
|
||||
from lbrynet.core.server.BlobAvailabilityHandler import BlobAvailabilityHandlerFactory
|
||||
from lbrynet.core.server.BlobRequestHandler import BlobRequestHandlerFactory
|
||||
from lbrynet.core.server.ServerProtocol import ServerProtocolFactory
|
||||
from lbrynet.lbryfile.LBRYFileMetadataManager import TempLBRYFileMetadataManager
|
||||
from lbrynet.lbryfile.StreamDescriptor import LBRYFileStreamType
|
||||
from lbrynet.lbryfile.client.LBRYFileDownloader import LBRYFileSaverFactory, LBRYFileOpenerFactory
|
||||
from lbrynet.lbryfile.client.LBRYFileOptions import add_lbry_file_to_sd_identifier
|
||||
import os
|
||||
import requests
|
||||
import shutil
|
||||
import sys
|
||||
from twisted.internet import threads, defer, task
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class LBRYDownloader(object):
|
||||
def __init__(self):
|
||||
self.session = None
|
||||
self.known_dht_nodes = [('104.236.42.182', 4000)]
|
||||
self.db_dir = os.path.join(os.path.expanduser("~"), ".lbrydownloader")
|
||||
self.blobfile_dir = os.path.join(self.db_dir, "blobfiles")
|
||||
self.peer_port = 3333
|
||||
self.dht_node_port = 4444
|
||||
self.run_server = True
|
||||
self.first_run = False
|
||||
self.current_db_revision = 1
|
||||
if os.name == "nt":
|
||||
from lbrynet.winhelpers.knownpaths import get_path, FOLDERID, UserHandle
|
||||
self.download_directory = get_path(FOLDERID.Downloads, UserHandle.current)
|
||||
self.wallet_dir = os.path.join(get_path(FOLDERID.RoamingAppData, UserHandle.current), "lbrycrd")
|
||||
else:
|
||||
if sys.platform == 'darwin':
|
||||
self.download_directory = os.path.join(os.path.expanduser("~"), "Downloads")
|
||||
self.wallet_dir = os.path.join(os.path.expanduser("~"), "Library/Application Support/lbrycrd")
|
||||
else:
|
||||
self.download_directory = os.getcwd()
|
||||
self.wallet_dir = os.path.join(os.path.expanduser("~"), ".lbrycrd")
|
||||
self.wallet_conf = os.path.join(self.wallet_dir, "lbrycrd.conf")
|
||||
self.wallet_user = None
|
||||
self.wallet_password = None
|
||||
self.sd_identifier = StreamDescriptorIdentifier()
|
||||
self.wallet_rpc_port = 8332
|
||||
self.download_deferreds = []
|
||||
self.stream_frames = []
|
||||
self.default_blob_data_payment_rate = MIN_BLOB_DATA_PAYMENT_RATE
|
||||
self.use_upnp = True
|
||||
self.start_lbrycrdd = True
|
||||
if os.name == "nt":
|
||||
self.lbrycrdd_path = "lbrycrdd.exe"
|
||||
else:
|
||||
self.lbrycrdd_path = None
|
||||
self.default_lbrycrdd_path = "./lbrycrdd"
|
||||
self.delete_blobs_on_remove = True
|
||||
self.blob_request_payment_rate_manager = None
|
||||
|
||||
def start(self):
|
||||
d = self._load_conf_options()
|
||||
d.addCallback(lambda _: threads.deferToThread(self._create_directory))
|
||||
d.addCallback(lambda _: self._check_db_migration())
|
||||
d.addCallback(lambda _: self._get_session())
|
||||
d.addCallback(lambda _: self._setup_stream_info_manager())
|
||||
d.addCallback(lambda _: self._setup_stream_identifier())
|
||||
d.addCallback(lambda _: self.start_server())
|
||||
return d
|
||||
|
||||
def stop(self):
|
||||
dl = defer.DeferredList(self.download_deferreds)
|
||||
for stream_frame in self.stream_frames:
|
||||
stream_frame.cancel_func()
|
||||
if self.session is not None:
|
||||
dl.addBoth(lambda _: self.stop_server())
|
||||
dl.addBoth(lambda _: self.session.shut_down())
|
||||
return dl
|
||||
|
||||
def get_new_address(self):
|
||||
return self.session.wallet.get_new_address()
|
||||
|
||||
def _check_db_migration(self):
|
||||
old_revision = 0
|
||||
db_revision_file = os.path.join(self.db_dir, "db_revision")
|
||||
if os.path.exists(db_revision_file):
|
||||
old_revision = int(open(db_revision_file).read().strip())
|
||||
if old_revision < self.current_db_revision:
|
||||
if os.name == "nt":
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
def run_migrator():
|
||||
migrator_exe = os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])),
|
||||
"dbmigrator", "migrator.exe")
|
||||
print "trying to find the migrator at", migrator_exe
|
||||
si = subprocess.STARTUPINFO
|
||||
si.dwFlags = subprocess.STARTF_USESHOWWINDOW
|
||||
si.wShowWindow = subprocess.SW_HIDE
|
||||
print "trying to run the migrator"
|
||||
migrator_proc = subprocess.Popen([migrator_exe, self.db_dir, str(old_revision),
|
||||
str(self.current_db_revision)], startupinfo=si)
|
||||
print "started the migrator"
|
||||
migrator_proc.wait()
|
||||
print "migrator has returned"
|
||||
|
||||
return threads.deferToThread(run_migrator)
|
||||
else:
|
||||
from lbrynet.db_migrator import dbmigrator
|
||||
return threads.deferToThread(dbmigrator.migrate_db, self.db_dir, old_revision,
|
||||
self.current_db_revision)
|
||||
return defer.succeed(True)
|
||||
|
||||
def _load_conf_options(self):
|
||||
|
||||
def get_lbrycrdd_path_conf_file():
|
||||
if os.name == "nt":
|
||||
return ""
|
||||
lbrycrdd_path_conf_path = os.path.join(os.path.expanduser("~"), ".lbrycrddpath.conf")
|
||||
if not os.path.exists(lbrycrdd_path_conf_path):
|
||||
return ""
|
||||
lbrycrdd_path_conf = open(lbrycrdd_path_conf_path)
|
||||
lines = lbrycrdd_path_conf.readlines()
|
||||
return lines
|
||||
|
||||
d = threads.deferToThread(get_lbrycrdd_path_conf_file)
|
||||
|
||||
def load_lbrycrdd_path(conf):
|
||||
for line in conf:
|
||||
if len(line.strip()) and line.strip()[0] != "#":
|
||||
self.lbrycrdd_path = line.strip()
|
||||
|
||||
d.addCallback(load_lbrycrdd_path)
|
||||
|
||||
def get_configuration_file():
|
||||
if os.name == "nt":
|
||||
lbry_conf_path = "lbry.conf"
|
||||
if not os.path.exists(lbry_conf_path):
|
||||
log.debug("Could not read lbry.conf")
|
||||
return ""
|
||||
else:
|
||||
lbry_conf_path = os.path.join(os.path.expanduser("~"), ".lbrynetgui.conf")
|
||||
if not os.path.exists(lbry_conf_path):
|
||||
clean_conf_path = os.path.join(os.path.dirname(__file__), "lbry.conf")
|
||||
shutil.copy(clean_conf_path, lbry_conf_path)
|
||||
lbry_conf = open(lbry_conf_path)
|
||||
log.debug("Loading configuration options from %s", lbry_conf_path)
|
||||
lines = lbry_conf.readlines()
|
||||
log.debug("%s file contents:\n%s", lbry_conf_path, str(lines))
|
||||
return lines
|
||||
|
||||
d.addCallback(lambda _: threads.deferToThread(get_configuration_file))
|
||||
|
||||
def load_configuration_file(conf):
|
||||
for line in conf:
|
||||
if len(line.strip()) and line.strip()[0] != "#":
|
||||
try:
|
||||
field_name, field_value = map(lambda x: x.strip(), line.strip().split("=", 1))
|
||||
field_name = field_name.lower()
|
||||
except ValueError:
|
||||
raise ValueError("Invalid configuration line: %s" % line)
|
||||
if field_name == "known_dht_nodes":
|
||||
known_nodes = []
|
||||
nodes = field_value.split(",")
|
||||
for n in nodes:
|
||||
if n.strip():
|
||||
try:
|
||||
ip_address, port_string = map(lambda x: x.strip(), n.split(":"))
|
||||
ip_numbers = ip_address.split(".")
|
||||
assert len(ip_numbers) == 4
|
||||
for ip_num in ip_numbers:
|
||||
num = int(ip_num)
|
||||
assert 0 <= num <= 255
|
||||
known_nodes.append((ip_address, int(port_string)))
|
||||
except (ValueError, AssertionError):
|
||||
raise ValueError("Expected known nodes in format 192.168.1.1:4000,192.168.1.2:4001. Got %s" % str(field_value))
|
||||
log.debug("Setting known_dht_nodes to %s", str(known_nodes))
|
||||
self.known_dht_nodes = known_nodes
|
||||
elif field_name == "run_server":
|
||||
if field_value.lower() == "true":
|
||||
run_server = True
|
||||
elif field_value.lower() == "false":
|
||||
run_server = False
|
||||
else:
|
||||
raise ValueError("run_server must be set to True or False. Got %s" % field_value)
|
||||
log.debug("Setting run_server to %s", str(run_server))
|
||||
self.run_server = run_server
|
||||
elif field_name == "data_dir":
|
||||
log.debug("Setting data_dir to %s", str(field_value))
|
||||
self.db_dir = field_value
|
||||
self.blobfile_dir = os.path.join(self.db_dir, "blobfiles")
|
||||
elif field_name == "wallet_dir":
|
||||
log.debug("Setting wallet_dir to %s", str(field_value))
|
||||
self.wallet_dir = field_value
|
||||
elif field_name == "wallet_conf":
|
||||
log.debug("Setting wallet_conf to %s", str(field_value))
|
||||
self.wallet_conf = field_value
|
||||
elif field_name == "peer_port":
|
||||
try:
|
||||
peer_port = int(field_value)
|
||||
assert 0 <= peer_port <= 65535
|
||||
log.debug("Setting peer_port to %s", str(peer_port))
|
||||
self.peer_port = peer_port
|
||||
except (ValueError, AssertionError):
|
||||
raise ValueError("peer_port must be set to an integer between 1 and 65535. Got %s" % field_value)
|
||||
elif field_name == "dht_port":
|
||||
try:
|
||||
dht_port = int(field_value)
|
||||
assert 0 <= dht_port <= 65535
|
||||
log.debug("Setting dht_node_port to %s", str(dht_port))
|
||||
self.dht_node_port = dht_port
|
||||
except (ValueError, AssertionError):
|
||||
raise ValueError("dht_port must be set to an integer between 1 and 65535. Got %s" % field_value)
|
||||
elif field_name == "use_upnp":
|
||||
if field_value.lower() == "true":
|
||||
use_upnp = True
|
||||
elif field_value.lower() == "false":
|
||||
use_upnp = False
|
||||
else:
|
||||
raise ValueError("use_upnp must be set to True or False. Got %s" % str(field_value))
|
||||
log.debug("Setting use_upnp to %s", str(use_upnp))
|
||||
self.use_upnp = use_upnp
|
||||
elif field_name == "default_blob_data_payment_rate":
|
||||
try:
|
||||
rate = float(field_value)
|
||||
assert rate >= 0.0
|
||||
log.debug("Setting default_blob_data_payment_rate to %s", str(rate))
|
||||
self.default_blob_data_payment_rate = rate
|
||||
except (ValueError, AssertionError):
|
||||
raise ValueError("default_blob_data_payment_rate must be a positive floating point number, e.g. 0.5. Got %s" % str(field_value))
|
||||
elif field_name == "start_lbrycrdd":
|
||||
if field_value.lower() == "true":
|
||||
start_lbrycrdd = True
|
||||
elif field_value.lower() == "false":
|
||||
start_lbrycrdd = False
|
||||
else:
|
||||
raise ValueError("start_lbrycrdd must be set to True or False. Got %s" % field_value)
|
||||
log.debug("Setting start_lbrycrdd to %s", str(start_lbrycrdd))
|
||||
self.start_lbrycrdd = start_lbrycrdd
|
||||
elif field_name == "lbrycrdd_path":
|
||||
self.lbrycrdd_path = field_value
|
||||
elif field_name == "download_directory":
|
||||
log.debug("Setting download_directory to %s", str(field_value))
|
||||
self.download_directory = field_value
|
||||
elif field_name == "delete_blobs_on_stream_remove":
|
||||
if field_value.lower() == "true":
|
||||
self.delete_blobs_on_remove = True
|
||||
elif field_value.lower() == "false":
|
||||
self.delete_blobs_on_remove = False
|
||||
else:
|
||||
raise ValueError("delete_blobs_on_stream_remove must be set to True or False")
|
||||
else:
|
||||
log.warning("Got unknown configuration field: %s", field_name)
|
||||
|
||||
d.addCallback(load_configuration_file)
|
||||
return d
|
||||
|
||||
def _create_directory(self):
|
||||
if not os.path.exists(self.db_dir):
|
||||
os.makedirs(self.db_dir)
|
||||
db_revision = open(os.path.join(self.db_dir, "db_revision"), mode='w')
|
||||
db_revision.write(str(self.current_db_revision))
|
||||
db_revision.close()
|
||||
log.debug("Created the configuration directory: %s", str(self.db_dir))
|
||||
if not os.path.exists(self.blobfile_dir):
|
||||
os.makedirs(self.blobfile_dir)
|
||||
log.debug("Created the data directory: %s", str(self.blobfile_dir))
|
||||
if os.name == "nt":
|
||||
if not os.path.exists(self.wallet_dir):
|
||||
os.makedirs(self.wallet_dir)
|
||||
if not os.path.exists(self.wallet_conf):
|
||||
lbrycrd_conf = open(self.wallet_conf, mode='w')
|
||||
self.wallet_user = "rpcuser"
|
||||
lbrycrd_conf.write("rpcuser=%s\n" % self.wallet_user)
|
||||
self.wallet_password = binascii.hexlify(Random.new().read(20))
|
||||
lbrycrd_conf.write("rpcpassword=%s\n" % self.wallet_password)
|
||||
lbrycrd_conf.write("server=1\n")
|
||||
lbrycrd_conf.close()
|
||||
else:
|
||||
lbrycrd_conf = open(self.wallet_conf)
|
||||
for l in lbrycrd_conf:
|
||||
if l.startswith("rpcuser="):
|
||||
self.wallet_user = l[8:].rstrip('\n')
|
||||
if l.startswith("rpcpassword="):
|
||||
self.wallet_password = l[12:].rstrip('\n')
|
||||
if l.startswith("rpcport="):
|
||||
self.wallet_rpc_port = int(l[8:-1].rstrip('\n'))
|
||||
|
||||
def _get_session(self):
|
||||
lbrycrdd_path = None
|
||||
if self.start_lbrycrdd is True:
|
||||
lbrycrdd_path = self.lbrycrdd_path
|
||||
if not lbrycrdd_path:
|
||||
lbrycrdd_path = self.default_lbrycrdd_path
|
||||
|
||||
if sys.platform == 'darwin':
|
||||
os.chdir("/Applications/LBRY.app/Contents/Resources")
|
||||
|
||||
wallet = LBRYcrdWallet(self.db_dir, wallet_dir=self.wallet_dir, wallet_conf=self.wallet_conf,
|
||||
lbrycrdd_path=lbrycrdd_path)
|
||||
|
||||
peer_port = None
|
||||
if self.run_server:
|
||||
peer_port = self.peer_port
|
||||
self.session = LBRYSession(self.default_blob_data_payment_rate, db_dir=self.db_dir,
|
||||
blob_dir=self.blobfile_dir, use_upnp=self.use_upnp, wallet=wallet,
|
||||
known_dht_nodes=self.known_dht_nodes, dht_node_port=self.dht_node_port,
|
||||
peer_port=peer_port)
|
||||
return self.session.setup()
|
||||
|
||||
def _setup_stream_info_manager(self):
|
||||
self.stream_info_manager = TempLBRYFileMetadataManager()
|
||||
return defer.succeed(True)
|
||||
|
||||
def start_server(self):
|
||||
|
||||
if self.run_server:
|
||||
self.blob_request_payment_rate_manager = PaymentRateManager(
|
||||
self.session.base_payment_rate_manager,
|
||||
self.default_blob_data_payment_rate
|
||||
)
|
||||
handlers = [
|
||||
BlobAvailabilityHandlerFactory(self.session.blob_manager),
|
||||
self.session.wallet.get_wallet_info_query_handler_factory(),
|
||||
BlobRequestHandlerFactory(self.session.blob_manager, self.session.wallet,
|
||||
self.blob_request_payment_rate_manager)
|
||||
]
|
||||
|
||||
server_factory = ServerProtocolFactory(self.session.rate_limiter,
|
||||
handlers,
|
||||
self.session.peer_manager)
|
||||
from twisted.internet import reactor
|
||||
self.lbry_server_port = reactor.listenTCP(self.peer_port, server_factory)
|
||||
|
||||
return defer.succeed(True)
|
||||
|
||||
def stop_server(self):
|
||||
if self.lbry_server_port is not None:
|
||||
self.lbry_server_port, p = None, self.lbry_server_port
|
||||
return defer.maybeDeferred(p.stopListening)
|
||||
else:
|
||||
return defer.succeed(True)
|
||||
|
||||
def _setup_stream_identifier(self):
|
||||
add_lbry_file_to_sd_identifier(self.sd_identifier)
|
||||
file_saver_factory = LBRYFileSaverFactory(self.session.peer_finder, self.session.rate_limiter,
|
||||
self.session.blob_manager, self.stream_info_manager,
|
||||
self.session.wallet, self.download_directory)
|
||||
self.sd_identifier.add_stream_downloader_factory(LBRYFileStreamType, file_saver_factory)
|
||||
file_opener_factory = LBRYFileOpenerFactory(self.session.peer_finder, self.session.rate_limiter,
|
||||
self.session.blob_manager, self.stream_info_manager,
|
||||
self.session.wallet)
|
||||
self.sd_identifier.add_stream_downloader_factory(LBRYFileStreamType, file_opener_factory)
|
||||
|
||||
def check_first_run(self):
|
||||
d = self.session.wallet.is_first_run()
|
||||
d.addCallback(lambda is_first_run: self._do_first_run() if is_first_run else 0.0)
|
||||
return d
|
||||
|
||||
def _do_first_run(self):
|
||||
d = self.session.wallet.get_new_address()
|
||||
|
||||
def send_request(url, data):
|
||||
r = requests.post(url, json=data)
|
||||
if r.status_code == 200:
|
||||
return r.json()['credits_sent']
|
||||
return 0.0
|
||||
|
||||
def log_error(err):
|
||||
log.warning("unable to request free credits. %s", err.getErrorMessage())
|
||||
return 0.0
|
||||
|
||||
def request_credits(address):
|
||||
url = "http://credreq.lbry.io/requestcredits"
|
||||
data = {"address": address}
|
||||
d = threads.deferToThread(send_request, url, data)
|
||||
d.addErrback(log_error)
|
||||
return d
|
||||
|
||||
d.addCallback(request_credits)
|
||||
return d
|
||||
|
||||
def _resolve_name(self, uri):
|
||||
return self.session.wallet.get_stream_info_for_name(uri)
|
||||
|
||||
def download_stream(self, stream_frame, uri):
|
||||
resolve_d = self._resolve_name(uri)
|
||||
|
||||
stream_frame.show_metadata_status("resolving name...")
|
||||
|
||||
stream_frame.cancel_func = resolve_d.cancel
|
||||
payment_rate_manager = PaymentRateManager(self.session.base_payment_rate_manager)
|
||||
|
||||
def update_stream_name(value):
|
||||
if 'name' in value:
|
||||
stream_frame.show_name(value['name'])
|
||||
if 'description' in value:
|
||||
stream_frame.show_description(value['description'])
|
||||
if 'thumbnail' in value:
|
||||
stream_frame.show_thumbnail(value['thumbnail'])
|
||||
return value
|
||||
|
||||
def get_sd_hash(value):
|
||||
if 'stream_hash' in value:
|
||||
return value['stream_hash']
|
||||
raise UnknownNameError(uri)
|
||||
|
||||
def get_sd_blob(sd_hash):
|
||||
stream_frame.show_metadata_status("name resolved, fetching metadata...")
|
||||
get_sd_d = StreamDescriptor.download_sd_blob(self.session, sd_hash,
|
||||
payment_rate_manager)
|
||||
get_sd_d.addCallback(self.sd_identifier.get_metadata_for_sd_blob)
|
||||
get_sd_d.addCallbacks(choose_download_factory, bad_sd_blob)
|
||||
return get_sd_d
|
||||
|
||||
def get_info_from_validator(info_validator):
|
||||
stream_name = None
|
||||
stream_size = None
|
||||
for field, val in info_validator.info_to_show():
|
||||
if field == "suggested_file_name":
|
||||
stream_name = val
|
||||
elif field == "stream_name" and stream_name is None:
|
||||
stream_name = val
|
||||
elif field == "stream_size":
|
||||
stream_size = int(val)
|
||||
if stream_size is None:
|
||||
stream_size = "unknown"
|
||||
if stream_name is None:
|
||||
stream_name = "unknown"
|
||||
return stream_name, stream_size
|
||||
|
||||
def choose_download_factory(metadata):
|
||||
#info_validator, options, factories = info_and_factories
|
||||
stream_name, stream_size = get_info_from_validator(metadata.validator)
|
||||
if isinstance(stream_size, (int, long)):
|
||||
price = payment_rate_manager.get_effective_min_blob_data_payment_rate()
|
||||
estimated_cost = stream_size * 1.0 / 2**20 * price
|
||||
else:
|
||||
estimated_cost = "unknown"
|
||||
|
||||
stream_frame.show_stream_metadata(stream_name, stream_size, estimated_cost)
|
||||
|
||||
available_options = metadata.options.get_downloader_options(metadata.validator,
|
||||
payment_rate_manager)
|
||||
|
||||
stream_frame.show_download_options(available_options)
|
||||
|
||||
get_downloader_d = defer.Deferred()
|
||||
|
||||
def create_downloader(f, chosen_options):
|
||||
|
||||
def fire_get_downloader_d(downloader):
|
||||
if not get_downloader_d.called:
|
||||
get_downloader_d.callback(downloader)
|
||||
|
||||
stream_frame.disable_download_buttons()
|
||||
d = f.make_downloader(metadata, chosen_options,
|
||||
payment_rate_manager)
|
||||
d.addCallback(fire_get_downloader_d)
|
||||
|
||||
for factory in metadata.factories:
|
||||
|
||||
def choose_factory(f=factory):
|
||||
chosen_options = stream_frame.get_chosen_options()
|
||||
create_downloader(f, chosen_options)
|
||||
|
||||
stream_frame.add_download_factory(factory, choose_factory)
|
||||
|
||||
get_downloader_d.addCallback(start_download)
|
||||
|
||||
return get_downloader_d
|
||||
|
||||
def show_stream_status(downloader):
|
||||
total_bytes = downloader.get_total_bytes_cached()
|
||||
bytes_left_to_download = downloader.get_bytes_left_to_download()
|
||||
points_paid = payment_rate_manager.points_paid
|
||||
payment_rate = payment_rate_manager.get_effective_min_blob_data_payment_rate()
|
||||
points_remaining = 1.0 * bytes_left_to_download * payment_rate / 2**20
|
||||
stream_frame.show_progress(total_bytes, bytes_left_to_download,
|
||||
points_paid, points_remaining)
|
||||
|
||||
def show_finished(arg, downloader):
|
||||
show_stream_status(downloader)
|
||||
stream_frame.show_download_done(payment_rate_manager.points_paid)
|
||||
return arg
|
||||
|
||||
def start_download(downloader):
|
||||
stream_frame.stream_hash = downloader.stream_hash
|
||||
l = task.LoopingCall(show_stream_status, downloader)
|
||||
l.start(1)
|
||||
d = downloader.start()
|
||||
stream_frame.cancel_func = downloader.stop
|
||||
|
||||
def stop_looping_call(arg):
|
||||
l.stop()
|
||||
stream_frame.cancel_func = resolve_d.cancel
|
||||
return arg
|
||||
|
||||
d.addBoth(stop_looping_call)
|
||||
d.addCallback(show_finished, downloader)
|
||||
return d
|
||||
|
||||
def lookup_failed(err):
|
||||
stream_frame.show_metadata_status("name lookup failed")
|
||||
return err
|
||||
|
||||
def bad_sd_blob(err):
|
||||
stream_frame.show_metadata_status("Unknown type or badly formed metadata")
|
||||
return err
|
||||
|
||||
resolve_d.addCallback(update_stream_name)
|
||||
resolve_d.addCallback(get_sd_hash)
|
||||
resolve_d.addCallbacks(get_sd_blob, lookup_failed)
|
||||
|
||||
def show_err(err):
|
||||
tkMessageBox.showerror(title="Download Error", message=err.getErrorMessage())
|
||||
log.error(err.getErrorMessage())
|
||||
stream_frame.show_download_done(payment_rate_manager.points_paid)
|
||||
|
||||
resolve_d.addErrback(lambda err: err.trap(defer.CancelledError, UnknownNameError,
|
||||
UnknownStreamTypeError, InvalidStreamDescriptorError,
|
||||
InvalidStreamInfoError))
|
||||
resolve_d.addErrback(show_err)
|
||||
|
||||
def delete_associated_blobs():
|
||||
if stream_frame.stream_hash is None or self.delete_blobs_on_remove is False:
|
||||
return defer.succeed(True)
|
||||
d1 = self.stream_info_manager.get_blobs_for_stream(stream_frame.stream_hash)
|
||||
|
||||
def get_blob_hashes(blob_infos):
|
||||
return [b[0] for b in blob_infos if b[0] is not None]
|
||||
|
||||
d1.addCallback(get_blob_hashes)
|
||||
d2 = self.stream_info_manager.get_sd_blob_hashes_for_stream(stream_frame.stream_hash)
|
||||
|
||||
def combine_blob_hashes(results):
|
||||
blob_hashes = []
|
||||
for success, result in results:
|
||||
if success is True:
|
||||
blob_hashes.extend(result)
|
||||
return blob_hashes
|
||||
|
||||
def delete_blobs(blob_hashes):
|
||||
return self.session.blob_manager.delete_blobs(blob_hashes)
|
||||
|
||||
dl = defer.DeferredList([d1, d2], fireOnOneErrback=True)
|
||||
dl.addCallback(combine_blob_hashes)
|
||||
dl.addCallback(delete_blobs)
|
||||
return dl
|
||||
|
||||
resolve_d.addCallback(lambda _: delete_associated_blobs())
|
||||
self._add_download_deferred(resolve_d, stream_frame)
|
||||
|
||||
def _add_download_deferred(self, d, stream_frame):
|
||||
self.download_deferreds.append(d)
|
||||
self.stream_frames.append(stream_frame)
|
||||
|
||||
def remove_from_list():
|
||||
self.download_deferreds.remove(d)
|
||||
self.stream_frames.remove(stream_frame)
|
||||
|
||||
d.addBoth(lambda _: remove_from_list())
|
|
@ -1,463 +0,0 @@
|
|||
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])), 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=16)
|
||||
self.name_frame.grid_columnconfigure(1, 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.name_text = None
|
||||
self.estimated_cost_frame = None
|
||||
self.bytes_downloaded_label = None
|
||||
self.button_frame = None
|
||||
self.download_buttons = []
|
||||
self.option_frames = []
|
||||
self.name_font = None
|
||||
self.description_text = 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() # pylint: disable=not-callable
|
||||
self.stream_frame.destroy()
|
||||
self.app.stream_removed()
|
||||
|
||||
def _resize_text(self, text_widget):
|
||||
actual_height = text_widget.tk.call(text_widget._w, "count", "-displaylines", "0.0", "end")
|
||||
text_widget.config(height=int(actual_height))
|
||||
|
||||
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)
|
||||
self.name_text = tk.Text(
|
||||
self.name_frame, font=self.name_font, wrap=tk.WORD, relief=tk.FLAT, borderwidth=0,
|
||||
highlightthickness=0, width=1, height=1
|
||||
)
|
||||
self.name_text.insert(tk.INSERT, name)
|
||||
self.name_text.config(state=tk.DISABLED)
|
||||
self.name_text.grid(row=0, column=0, sticky=tk.W+tk.E+tk.N+tk.S)
|
||||
self.name_text.update()
|
||||
self._resize_text(self.name_text)
|
||||
|
||||
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)
|
||||
self.description_text = tk.Text(
|
||||
self.name_frame, wrap=tk.WORD, relief=tk.FLAT, borderwidth=0,
|
||||
highlightthickness=0, width=1, height=1
|
||||
)
|
||||
self.description_text.insert(tk.INSERT, description)
|
||||
self.description_text.config(state=tk.DISABLED)
|
||||
self.description_text.grid(row=1, column=0, sticky=tk.W+tk.E+tk.N+tk.S)
|
||||
self.description_text.update()
|
||||
self._resize_text(self.description_text)
|
||||
|
||||
def show_thumbnail(self, url=None):
|
||||
thumbnail = None
|
||||
if url is not None:
|
||||
import urllib2
|
||||
import base64
|
||||
response = urllib2.urlopen(url)
|
||||
thumbnail_data = base64.b64encode(response.read())
|
||||
thumbnail = tk.PhotoImage(data=thumbnail_data)
|
||||
current_width = thumbnail.width()
|
||||
current_height = thumbnail.height()
|
||||
max_width = 130
|
||||
max_height = 90
|
||||
scale_ratio = max(1.0 * current_width / max_width, 1.0 * current_height / max_height)
|
||||
if scale_ratio < 1:
|
||||
scale_ratio = 1
|
||||
else:
|
||||
scale_ratio = int(scale_ratio + 1)
|
||||
thumbnail = thumbnail.subsample(scale_ratio)
|
||||
if thumbnail is not None:
|
||||
label = ttk.Label(self.name_frame, image=thumbnail)
|
||||
label.safekeeping = thumbnail
|
||||
label.grid(row=0, column=1, rowspan=2, sticky=tk.E+tk.N+tk.W+tk.S)
|
||||
label.update()
|
||||
self.description_text.update()
|
||||
self.name_text.update()
|
||||
self._resize_text(self.description_text)
|
||||
self._resize_text(self.name_text)
|
||||
|
||||
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, stream_cost):
|
||||
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.estimated_cost_frame = ttk.Frame(self.metadata_frame, style="F.TFrame")
|
||||
self.estimated_cost_frame.grid(row=1, column=0, sticky=tk.W)
|
||||
|
||||
estimated_cost_label = ttk.Label(
|
||||
self.estimated_cost_frame,
|
||||
text=locale.format_string("%.2f LBC",
|
||||
(round(stream_cost, 2)), grouping=True),
|
||||
foreground="red"
|
||||
)
|
||||
estimated_cost_label.grid(row=1, column=2)
|
||||
|
||||
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()
|
||||
self.estimated_cost_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, 4))
|
||||
|
||||
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))
|
|
@ -1 +0,0 @@
|
|||
"""A gui application for downloading LBRY files from LBRYnet"""
|
Before Width: | Height: | Size: 188 B |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 195 B |
Before Width: | Height: | Size: 72 B |
|
@ -1,33 +0,0 @@
|
|||
import logging
|
||||
import sys
|
||||
|
||||
from lbrynet.lbrynet_gui.GuiApp import DownloaderApp
|
||||
from twisted.internet import reactor, task
|
||||
import locale
|
||||
|
||||
|
||||
def start_gui():
|
||||
|
||||
log_format = "(%(asctime)s)[%(filename)s:%(lineno)s] %(funcName)s(): %(message)s"
|
||||
formatter = logging.Formatter(log_format)
|
||||
|
||||
logger = logging.getLogger()
|
||||
logger.setLevel(logging.DEBUG)
|
||||
file_handler = logging.FileHandler("gui.log")
|
||||
file_handler.setFormatter(formatter)
|
||||
file_handler.addFilter(logging.Filter("lbrynet"))
|
||||
logger.addHandler(file_handler)
|
||||
|
||||
sys.stdout = open("gui.out.log", 'w')
|
||||
sys.stderr = open("gui.err.log", 'w')
|
||||
|
||||
locale.setlocale(locale.LC_ALL, '')
|
||||
|
||||
app = DownloaderApp()
|
||||
|
||||
d = task.deferLater(reactor, 0, app.start)
|
||||
|
||||
reactor.run()
|
||||
|
||||
if __name__ == "__main__":
|
||||
start_gui()
|
Before Width: | Height: | Size: 174 B |
Before Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 361 KiB |
|
@ -1,14 +0,0 @@
|
|||
#define lbry_dark_icon2_width 32
|
||||
#define lbry_dark_icon2_height 32
|
||||
static unsigned char lbry_dark_icon2_bits[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00,
|
||||
0x00, 0xc0, 0x07, 0x00, 0x00, 0x70, 0x1c, 0x00, 0x00, 0x1c, 0xf0, 0x00,
|
||||
0x00, 0x0e, 0xc0, 0x03, 0x80, 0x03, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x3c,
|
||||
0x70, 0x00, 0x00, 0x70, 0x1c, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x38,
|
||||
0x03, 0x00, 0x00, 0x0e, 0x13, 0x00, 0x00, 0x07, 0x71, 0x00, 0xc0, 0xf1,
|
||||
0xe3, 0x01, 0x60, 0x70, 0x03, 0x07, 0x38, 0x7c, 0x07, 0x1e, 0x0e, 0x0e,
|
||||
0x3c, 0x70, 0x87, 0x03, 0xf0, 0xe0, 0xc1, 0x00, 0xc0, 0x03, 0x70, 0x00,
|
||||
0x00, 0x0f, 0x1c, 0x00, 0x00, 0x38, 0x0e, 0x00, 0x00, 0xf0, 0x03, 0x00,
|
||||
0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
|
@ -1,108 +0,0 @@
|
|||
# ===== known_dht_nodes =====
|
||||
# A comma-separated list of dht nodes to use to bootstrap into the
|
||||
# DHT network. The nodes must be specified in dotted quad format
|
||||
# followed by a colon and the port number. For example:
|
||||
# 192.168.1.1:4000,10.0.0.1:4000,172.16.1.1:5000
|
||||
#
|
||||
# known_dht_nodes = 104.236.42.182:4000
|
||||
|
||||
|
||||
# ===== download_directory =====
|
||||
# On Windows, the default location for "download_directory" is the
|
||||
# directory the user has registered with the OS as the default
|
||||
# download directory, usually the 'Downloads' folder in the user's
|
||||
# home directory. On Linux, it is the current directory.
|
||||
#
|
||||
# download_directory = /path/to/example_directory
|
||||
|
||||
|
||||
# ===== data_dir =====
|
||||
# The data directory is the directory in which the application
|
||||
# stores information about the encrypted chunks stored on disk
|
||||
# and the streams they belong to, the encrypted chunks themselves,
|
||||
# and any other metadata. By default, set to '.lbrydownloader'
|
||||
# in the user's home directory.
|
||||
#
|
||||
# data_dir = /path/to/home/.lbrydownloader
|
||||
|
||||
|
||||
# ===== run_server =====
|
||||
# Turn on or off the server, which uploads encrypted chunks of data
|
||||
# to other clients on the network.
|
||||
#
|
||||
# run_server = True
|
||||
|
||||
|
||||
# ===== start_lbrycrdd =====
|
||||
# Whether to launch an lbyrcrdd server to use to send and receive
|
||||
# LBC and to look up names regisered on the LBRYcrd network.
|
||||
# Defaults to True on Windows and False on Linux.
|
||||
#
|
||||
# start_lbrycrdd = True/False
|
||||
|
||||
# ===== lbrycrdd_path =====
|
||||
# If start_lbrycrdd is set to True, the path the application will
|
||||
# use to try to run lbrycrdd. On Windows, the default path will
|
||||
# be "lbrycrdd.exe". On Linux, the default path will be "./lbrycrdd".
|
||||
#
|
||||
# lbrycrdd_path = /path/to/lbrycrdd
|
||||
|
||||
# ===== wallet_dir =====
|
||||
# The directory which the lbrycrdd instance will be given as the
|
||||
# base directory for the instance of lbrycrdd, if it is launched
|
||||
# by the application. By default, it is set to the .lbrycrd
|
||||
# directory in the user's home directory.
|
||||
#
|
||||
# wallet_dir = /path/to/home/.lbrycrd
|
||||
|
||||
|
||||
# ===== wallet_conf =====
|
||||
# The configuration file used by the lbrycrd server which will be
|
||||
# used by the application to send and receive LBC and to look up
|
||||
# registered names on the LBRYcrd network. By default, this is
|
||||
# set to the file lbrycrd.conf in the wallet_dir directory.
|
||||
#
|
||||
# wallet_conf = /path/to/home/.lbrycrd/lbrycrd.conf
|
||||
|
||||
|
||||
# ===== use_upnp =====
|
||||
# Whether to try to use UPnP to open ports in a firewall so that
|
||||
# other applications on the network can connect to the application
|
||||
#
|
||||
# use_upnp = True
|
||||
|
||||
|
||||
# ===== default_blob_data_payment_rate =====
|
||||
# The amount of LBC per megabyte to send to uploaders of data, by
|
||||
# default. Must be a positive floating point number.
|
||||
#
|
||||
# default_blob_data_payment_rate = 0.5
|
||||
|
||||
|
||||
# ===== dht_port =====
|
||||
# The UPD port which other applications will connect to in order
|
||||
# to announce their association with sha384 hashsums and to
|
||||
# find other applications which are associated with sha384
|
||||
# hashsums.
|
||||
#
|
||||
# dht_port = 4444
|
||||
|
||||
|
||||
# ===== peer_port =====
|
||||
# The TCP port which other applications will connect to in order
|
||||
# to download encrypted chunks of data from this application,
|
||||
# if this application is acting as a server.
|
||||
#
|
||||
# peer_port = 3333
|
||||
|
||||
|
||||
# ===== delete_blobs_on_stream_remove =====
|
||||
# If this is set to True, all blobs associated with the stream
|
||||
# will be deleted when the stream is removed from the GUI,
|
||||
# whether by clicking the 'x' or by closing the application.
|
||||
# If this is set to False, they will not be deleted then.
|
||||
# However, they may be deleted otherwise. For example if the
|
||||
# option to allow reuploading is set to False, they will be
|
||||
# deleted as soon as they're outputted by the application.
|
||||
#
|
||||
# delete_blobs_on_stream_remove = True
|
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 155 B |
6
setup.py
|
@ -18,7 +18,6 @@ console_scripts = ['lbrynet-console = lbrynet.lbrynet_console.LBRYConsole:launch
|
|||
'lbrynet-launch-node = lbrynet.dht.node:main',
|
||||
'lbrynet-launch-rpc-node = lbrynet.rpc_node:main',
|
||||
'lbrynet-rpc-node-cli = lbrynet.node_rpc_cli:main',
|
||||
'lbrynet-gui = lbrynet.lbrynet_gui.gui:start_gui',
|
||||
'lbrynet-lookup-hosts-for-hash = lbrynet.dht_scripts:get_hosts_for_hash_in_dht',
|
||||
'lbrynet-announce_hash_to_dht = lbrynet.dht_scripts:announce_hash_to_dht',
|
||||
'lbrynet-daemon = lbrynet.lbrynet_daemon.LBRYDaemonControl:start',
|
||||
|
@ -28,10 +27,6 @@ requires = ['pycrypto', 'twisted', 'miniupnpc', 'yapsy', 'seccure',
|
|||
'python-bitcoinrpc==0.1', 'txJSON-RPC', 'requests>=2.4.2', 'unqlite==0.2.0',
|
||||
'leveldb', 'lbryum', 'jsonrpc', 'simplejson', 'appdirs', 'six==1.9.0', 'base58']
|
||||
|
||||
gui_data_files = ['close2.gif', 'lbry-dark-242x80.gif', 'lbry-dark-icon.xbm', 'lbry-dark-icon.ico',
|
||||
'drop_down.gif', 'show_options.gif', 'hide_options.gif', 'lbry.conf', 'lbry.png']
|
||||
gui_data_paths = [os.path.join(base_dir, 'lbrynet', 'lbrynet_gui', f) for f in gui_data_files]
|
||||
|
||||
setup(name='lbrynet',
|
||||
description='A fully-decentralized content marketplace',
|
||||
version=__version__,
|
||||
|
@ -47,7 +42,6 @@ setup(name='lbrynet',
|
|||
'blindrepeater.yapsy-plugin')
|
||||
]
|
||||
),
|
||||
('lbrynet/lbrynet_gui', gui_data_paths)
|
||||
],
|
||||
dependency_links=['https://github.com/lbryio/lbryum/tarball/master/#egg=lbryum'],
|
||||
)
|
||||
|
|