publish updates

-adds a base set of metadata fields required for results to be rendered
in conf.py, including language and content-type

-dont support old style claims on the new blockchain
This commit is contained in:
Jack 2016-06-27 17:07:59 -04:00
parent f89486f5fe
commit 7cc3e9d5ef
6 changed files with 98 additions and 150 deletions

View file

@ -4,5 +4,5 @@ log = logging.getLogger(__name__)
logging.getLogger(__name__).addHandler(logging.NullHandler()) logging.getLogger(__name__).addHandler(logging.NullHandler())
log.setLevel(logging.ERROR) log.setLevel(logging.ERROR)
version = (0, 2, 5) version = (0, 2, 6)
__version__ = ".".join([str(x) for x in version]) __version__ = ".".join([str(x) for x in version])

View file

@ -17,9 +17,9 @@ MIN_VALUABLE_BLOB_HASH_PAYMENT_RATE = .05 # points/1000 infos
MAX_CONNECTIONS_PER_STREAM = 5 MAX_CONNECTIONS_PER_STREAM = 5
KNOWN_DHT_NODES = [('104.236.42.182', 4000), KNOWN_DHT_NODES = [('104.236.42.182', 4000),
('lbryum1.lbry.io', 4444), ('lbrynet1.lbry.io', 4444),
('lbryum2.lbry.io', 4444), ('lbrynet2.lbry.io', 4444),
('lbryum3.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://ec2-54-187-192-68.us-west-2.compute.amazonaws.com:2424'
#POINTTRADER_SERVER = 'http://127.0.0.1:2424' #POINTTRADER_SERVER = 'http://127.0.0.1:2424'
@ -35,7 +35,7 @@ API_PORT = 5279
ICON_PATH = "app.icns" ICON_PATH = "app.icns"
APP_NAME = "LBRY" APP_NAME = "LBRY"
API_CONNECTION_STRING = "http://%s:%i/%s" % (API_INTERFACE, API_PORT, API_ADDRESS) 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" PROTOCOL_PREFIX = "lbry"
DEFAULT_WALLET = "lbryum" DEFAULT_WALLET = "lbryum"
@ -46,3 +46,7 @@ DEFAULT_MAX_KEY_FEE = 100.0
DEFAULT_SEARCH_TIMEOUT = 3.0 DEFAULT_SEARCH_TIMEOUT = 3.0
DEFAULT_CACHE_TIME = 3600 DEFAULT_CACHE_TIME = 3600
DEFAULT_UI_BRANCH = "master" 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']

View file

@ -4,6 +4,7 @@ from lbrynet.core.client.ClientRequest import ClientRequest
from lbrynet.core.Error import UnknownNameError, InvalidStreamInfoError, RequestCanceledError from lbrynet.core.Error import UnknownNameError, InvalidStreamInfoError, RequestCanceledError
from lbrynet.core.Error import InsufficientFundsError from lbrynet.core.Error import InsufficientFundsError
from lbrynet.core.sqlite_helpers import rerun_if_locked 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 import SimpleConfig, Network
from lbryum.bitcoin import COIN, TYPE_ADDRESS from lbryum.bitcoin import COIN, TYPE_ADDRESS
@ -318,68 +319,51 @@ class LBRYWallet(object):
r_dict = {} r_dict = {}
if 'value' in result: if 'value' in result:
value = result['value'] value = result['value']
try: try:
value_dict = json.loads(value) value_dict = json.loads(value)
except (ValueError, TypeError): except (ValueError, TypeError):
return Failure(InvalidStreamInfoError(name)) return Failure(InvalidStreamInfoError(name))
known_fields = ['stream_hash', 'name', 'description', 'key_fee', 'key_fee_address', 'thumbnail', r_dict['sources'] = value_dict['sources']
'content_license', 'sources', 'fee', 'author'] for field in BASE_METADATA_FIELDS:
known_sources = ['lbry_sd_hash', 'btih', 'url'] r_dict[field] = value_dict[field]
known_fee_types = {'LBC': ['amount', 'address']} for field in value_dict:
for field in known_fields: if field in OPTIONAL_METADATA_FIELDS:
if field in value_dict: r_dict[field] = value_dict[field]
if field == 'sources':
for source in known_sources: if 'txid' in result:
if source in value_dict[field]: d = self._save_name_metadata(name, r_dict['sources']['lbry_sd_hash'], str(result['txid']))
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)
d.addCallback(lambda _: r_dict) d.addCallback(lambda _: r_dict)
return d return d
elif 'error' in result: elif 'error' in result:
log.warning("Got an error looking up a name: %s", result['error']) 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, def claim_name(self, name, bid, sources, metadata, fee=None):
key_fee_address=None, thumbnail=None, content_license=None, author=None, sources=None): value = {'sources': {}}
value = {"sources": {'lbry_sd_hash': sd_hash}} for k in SOURCE_TYPES:
if description is not None: if k in sources:
value['description'] = description value['sources'][k] = sources[k]
if key_fee is not None and key_fee_address is not None: if value['sources'] == {}:
value['fee'] = {'type': 'LBC', 'amount': key_fee, 'address': key_fee_address} return defer.fail("No source given")
if thumbnail is not None: for k in BASE_METADATA_FIELDS:
value['thumbnail'] = thumbnail if k not in metadata:
if content_license is not None: return defer.fail("Missing required field '%s'" % k)
value['content_license'] = content_license value[k] = metadata[k]
if author is not None: for k in metadata:
value['author'] = author if k not in BASE_METADATA_FIELDS:
if isinstance(sources, dict): value[k] = metadata[k]
sources['lbry_sd_hash'] = sd_hash if fee is not None:
value['sources'] = sources 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): 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) d.addCallback(lambda _: txid)
return d return d
@ -409,7 +393,7 @@ class LBRYWallet(object):
def abandon(results): def abandon(results):
if results[0][0] and results[1][0]: if results[0][0] and results[1][0]:
address = results[0][1] address = results[0][1]
amount = results[1][1] amount = float(results[1][1])
return self._send_abandon(txid, address, amount) return self._send_abandon(txid, address, amount)
elif results[0][0] is False: elif results[0][0] is False:
return defer.fail(Failure(ValueError("Couldn't get a new address"))) return defer.fail(Failure(ValueError("Couldn't get a new address")))
@ -826,7 +810,7 @@ class LBRYcrdWallet(LBRYWallet):
@_catch_connection_error @_catch_connection_error
def _send_abandon_rpc(self, txid, address, amount): def _send_abandon_rpc(self, txid, address, amount):
rpc_conn = self._get_rpc_conn() rpc_conn = self._get_rpc_conn()
return rpc_conn.abandonname(txid, address, amount) return rpc_conn.abandonclaim(txid, address, amount)
@_catch_connection_error @_catch_connection_error
def _get_blockchain_info_rpc(self): def _get_blockchain_info_rpc(self):

View file

@ -1151,12 +1151,11 @@ class LBRYDaemon(jsonrpc.JSONRPC):
def _add_key_fee(data_cost): def _add_key_fee(data_cost):
d = self._resolve_name(name) 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 return d
d = self._resolve_name(name) d = self._resolve_name(name)
d.addCallback(lambda info: info['stream_hash'] if isinstance(info['stream_hash'], str) d.addCallback(lambda info: info['sources']['lbry_sd_hash'])
else info['stream_hash']['sd_hash'])
d.addCallback(lambda sd_hash: download_sd_blob(self.session, sd_hash, d.addCallback(lambda sd_hash: download_sd_blob(self.session, sd_hash,
self.blob_request_payment_rate_manager)) self.blob_request_payment_rate_manager))
d.addCallback(self.sd_identifier.get_metadata_for_sd_blob) d.addCallback(self.sd_identifier.get_metadata_for_sd_blob)
@ -1170,10 +1169,7 @@ class LBRYDaemon(jsonrpc.JSONRPC):
def _get_lbry_file_by_uri(self, name): def _get_lbry_file_by_uri(self, name):
def _get_file(stream_info): def _get_file(stream_info):
if isinstance(stream_info['stream_hash'], str) or isinstance(stream_info['stream_hash'], unicode): sd = stream_info['sources']['lbry_sd_hash']
sd = stream_info['stream_hash']
elif isinstance(stream_info['stream_hash'], dict):
sd = stream_info['stream_hash']['sd_hash']
for l in self.lbry_file_manager.lbry_files: for l in self.lbry_file_manager.lbry_files:
if l.sd_hash == sd: if l.sd_hash == sd:
@ -1791,15 +1787,13 @@ class LBRYDaemon(jsonrpc.JSONRPC):
for r in results: for r in results:
t = {} t = {}
t.update(r[0]) t.update(r[0])
if 'name' in r[1].keys(): if not 'thumbnail' in r[1].keys():
r[1]['stream_name'] = r[1]['name'] r[1]['thumbnail'] = "img/Free-speech-flag.svg"
del r[1]['name']
t.update(r[1]) t.update(r[1])
t['cost_est'] = r[2] t['cost_est'] = r[2]
if not 'thumbnail' in t.keys():
t['thumbnail'] = "img/Free-speech-flag.svg"
consolidated_results.append(t) consolidated_results.append(t)
# log.info(str(t)) # log.info(str(t))
return consolidated_results return consolidated_results
log.info('[' + str(datetime.now()) + '] Search nametrie: ' + search) log.info('[' + str(datetime.now()) + '] Search nametrie: ' + search)
@ -1845,46 +1839,30 @@ class LBRYDaemon(jsonrpc.JSONRPC):
def jsonrpc_publish(self, p): def jsonrpc_publish(self, p):
""" """
Make a new name claim Make a new name claim and publish associated data to lbrynet
Args: Args:
'name': name to be claimed, string 'name': name to be claimed, string
'file_path': path to file to be associated with name, string 'file_path': path to file to be associated with name, string
'bid': amount of credits to commit in this claim, float 'bid': amount of credits to commit in this claim, float
optional 'author': author, string 'metadata': metadata dictionary
optional 'title': title, description optional 'fee'
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'
Returns: Returns:
Confirmation message Claim txid
""" """
# start(self, name, file_path, bid, metadata, fee=None, sources=None):
metadata_fields = ["name", "file_path", "bid", "author", "title", name = p['name']
"description", "thumbnail", "key_fee", "key_fee_address", bid = p['bid']
"content_license", "sources"] file_path = p['file_path']
metadata = p['metadata']
for k in metadata_fields: if 'fee' in p:
if k not in p.keys(): fee = p['fee']
p[k] = None else:
fee = None
pub = Publisher(self.session, self.lbry_file_manager, self.session.wallet) pub = Publisher(self.session, self.lbry_file_manager, self.session.wallet)
d = pub.start(p['name'], d = pub.start(name, file_path, bid, metadata, fee)
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.addCallbacks(lambda msg: self._render_response(msg, OK_CODE), d.addCallbacks(lambda msg: self._render_response(msg, OK_CODE),
lambda err: self._render_response(err.getTraceback(), BAD_REQUEST)) lambda err: self._render_response(err.getTraceback(), BAD_REQUEST))

View file

@ -42,15 +42,14 @@ log.addHandler(handler)
log.setLevel(logging.INFO) log.setLevel(logging.INFO)
class GetStream(object): class GetStream(object):
def __init__(self, sd_identifier, session, wallet, lbry_file_manager, max_key_fee, pay_key=True, data_rate=0.5, 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): timeout=DEFAULT_TIMEOUT, download_directory=None, file_name=None):
self.wallet = wallet self.wallet = wallet
self.resolved_name = None self.resolved_name = None
self.description = None self.description = None
self.key_fee = None self.key_fee = None
self.key_fee_address = None self.key_fee_address = None
self.data_rate = data_rate self.data_rate = data_rate
self.pay_key = pay_key
self.name = None self.name = None
self.file_name = file_name self.file_name = file_name
self.session = session self.session = session
@ -79,7 +78,7 @@ class GetStream(object):
self.finished.callback((self.stream_hash, self.download_path)) self.finished.callback((self.stream_hash, self.download_path))
elif self.timeout_counter >= self.timeout: 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.checker.stop()
self.d.cancel() self.d.cancel()
self.code = STREAM_STAGES[4] self.code = STREAM_STAGES[4]
@ -88,28 +87,24 @@ class GetStream(object):
def start(self, stream_info, name): def start(self, stream_info, name):
self.resolved_name = name self.resolved_name = name
self.stream_info = stream_info self.stream_info = stream_info
if 'stream_hash' in self.stream_info.keys(): if 'sources' in self.stream_info:
self.stream_hash = self.stream_info['stream_hash']
elif 'sources' in self.stream_info.keys():
self.stream_hash = self.stream_info['sources']['lbry_sd_hash'] self.stream_hash = self.stream_info['sources']['lbry_sd_hash']
else: else:
raise InvalidStreamInfoError(self.stream_info) raise InvalidStreamInfoError(self.stream_info)
if 'description' in self.stream_info.keys(): if 'description' in self.stream_info:
self.description = self.stream_info['description'] self.description = self.stream_info['description']
if 'key_fee' in self.stream_info.keys(): if 'fee' in self.stream_info:
self.key_fee = float(self.stream_info['key_fee']) if 'LBC' in self.stream_info['fee']:
if 'key_fee_address' in self.stream_info.keys(): self.key_fee = float(self.stream_info['fee']['LBC']['amount'])
self.key_fee_address = self.stream_info['key_fee_address'] self.key_fee_address = self.stream_info['fee']['LBC']['address']
else: else:
self.key_fee_address = None self.key_fee_address = None
else: else:
self.key_fee = None self.key_fee = None
self.key_fee_address = None self.key_fee_address = None
if self.key_fee > self.max_key_fee: if self.key_fee > self.max_key_fee:
if self.pay_key: log.info("Key fee %f above limit of %f didn't download lbry://%s" % (self.key_fee, self.max_key_fee, self.resolved_name))
log.info("Key fee (" + str(self.key_fee) + ") above limit of " + str( return defer.fail(None)
self.max_key_fee) + ", didn't download lbry://" + str(self.resolved_name))
return defer.fail(None)
else: else:
pass pass
@ -145,7 +140,7 @@ class GetStream(object):
reserved_points = self.wallet.reserve_points(self.key_fee_address, self.key_fee) reserved_points = self.wallet.reserve_points(self.key_fee_address, self.key_fee)
if reserved_points is None: if reserved_points is None:
return defer.fail(InsufficientFundsError()) 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 self.wallet.send_points_to_address(reserved_points, self.key_fee)
return defer.succeed(None) return defer.succeed(None)
@ -155,5 +150,5 @@ class GetStream(object):
d = defer.Deferred() d = defer.Deferred()
self.downloader = downloader self.downloader = downloader
self.download_path = os.path.join(downloader.download_directory, downloader.file_name) 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.file_name)))
d.addCallback(lambda _: self.downloader.start()) d.addCallback(lambda _: self.downloader.start())

View file

@ -1,4 +1,5 @@
import logging import logging
import mimetypes
import os import os
import sys import sys
@ -36,42 +37,27 @@ class Publisher(object):
self.received_file_name = False self.received_file_name = False
self.file_path = None self.file_path = None
self.file_name = None self.file_name = None
self.thumbnail = None
self.title = None
self.publish_name = None self.publish_name = None
self.bid_amount = 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.verified = False
self.lbry_file = None self.lbry_file = None
self.sd_hash = None self.txid = None
self.tx_hash = None self.sources = {}
self.content_license = None self.fee = None
self.author = None
self.sources = None
def start(self, name, file_path, bid, title=None, description=None, thumbnail=None, def start(self, name, file_path, bid, metadata, fee=None, sources={}):
key_fee=None, key_fee_address=None, content_license=None, author=None, sources=None):
def _show_result(): 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) log.info(message)
return defer.succeed(self.tx_hash) return defer.succeed(self.txid)
self.publish_name = name self.publish_name = name
self.file_path = file_path self.file_path = file_path
self.bid_amount = bid self.bid_amount = bid
self.title = title self.fee = fee
self.description = description self.metadata = metadata
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
d = self._check_file_path(self.file_path) d = self._check_file_path(self.file_path)
d.addCallback(lambda _: create_lbry_file(self.session, self.lbry_file_manager, d.addCallback(lambda _: create_lbry_file(self.session, self.lbry_file_manager,
@ -118,20 +104,21 @@ class Publisher(object):
self.lbry_file.stream_hash) self.lbry_file.stream_hash)
def set_sd_hash(sd_hash): def set_sd_hash(sd_hash):
self.sd_hash = sd_hash self.sources['lbry_sd_hash'] = sd_hash
d.addCallback(set_sd_hash) d.addCallback(set_sd_hash)
return d return d
def _claim_name(self): def _claim_name(self):
d = self.wallet.claim_name(self.publish_name, self.sd_hash, self.bid_amount, self.metadata['content-type'] = mimetypes.guess_type(os.path.join(self.lbry_file.download_directory,
description=self.description, key_fee=self.key_fee, self.lbry_file.file_name))[0]
key_fee_address=self.key_fee_address, thumbnail=self.thumbnail, d = self.wallet.claim_name(self.publish_name,
content_license=self.content_license, author=self.author, self.bid_amount,
sources=self.sources) self.sources,
self.metadata,
def set_tx_hash(tx_hash): fee=self.fee)
self.tx_hash = tx_hash def set_tx_hash(txid):
self.txid = txid
d.addCallback(set_tx_hash) d.addCallback(set_tx_hash)
return d return d