--languages, --locations fully support all attributes, add BTC

This commit is contained in:
Lex Berezhny 2019-03-29 20:26:10 -04:00
parent 4e6bca1389
commit a3bd335f7f
8 changed files with 644 additions and 111 deletions

View file

@ -1757,8 +1757,9 @@ class Daemon(metaclass=JSONRPCServerType):
Usage:
channel_create (<name> | --name=<name>) (<bid> | --bid=<bid>)
[--tags=<tags>...] [--allow_duplicate_name=<allow_duplicate_name>]
[--title=<title>] [--description=<description>] [--language=<language>]
[--allow_duplicate_name=<allow_duplicate_name>]
[--title=<title>] [--description=<description>]
[--tags=<tags>...] [--languages=<languages>...] [--locations=<locations>...]
[--contact_email=<contact_email>]
[--homepage_url=<homepage_url>] [--thumbnail_url=<thumbnail_url>] [--cover_url=<cover_url>]
[--account_id=<account_id>] [--claim_address=<claim_address>] [--preview]
@ -1768,10 +1769,47 @@ class Daemon(metaclass=JSONRPCServerType):
--allow_duplicate_name=<allow_duplicate_name> : (bool) create new channel even if one already exists with
given name. default: false.
--bid=<bid> : (decimal) amount to back the claim
--tags=<tags> : (list) content tags
--title=<title> : (str) title of the publication
--description=<description> : (str) description of the publication
--language=<language> : (str) primary language of the channel
--tags=<tags> : (list) content tags
--languages=<languages> : (list) languages used by the channel,
using RFC 5646 format, eg:
for English `--languages=en`
for Spanish (Spain) `--languages=es-ES`
for Spanish (Mexican) `--languages=es-MX`
for Chinese (Simplified) `--languages=zh-Hans`
for Chinese (Traditional) `--languages=zh-Hant`
--locations=<locations> : (list) locations of the channel, consisting of 2 letter
`country` code and a `state`, `city` and a postal
`code` along with a `latitude` and `longitude`.
for JSON RPC: pass a dictionary with aforementioned
attributes as keys, eg:
...
"locations": [{'country': 'US', 'state': 'NH'}]
...
for command line: pass a colon delimited list
with values in the following order:
"COUNTRY:STATE:CITY:CODE:LATITUDE:LONGITUDE"
making sure to include colon for blank values, for
example to provide only the city:
--locations"::Manchester"
with all values set:
--locations="US:NH:Manchester:03101:42.990605:-71.460989"
optionally, you can just pass the "LATITUDE:LONGITUDE":
--locations="42.990605:-71.460989"
finally, you can also pass JSON string of dictionary
on the command line as you would via JSON RPC
--locations="{'country': 'US', 'state': 'NH'}"
--contact_email=<contact_email>: (str) email of channel owner
--homepage_url=<homepage_url> : (str) homepage url
--thumbnail_url=<thumbnail_url>: (str) thumbnail url
@ -1825,19 +1863,61 @@ class Daemon(metaclass=JSONRPCServerType):
Usage:
channel_update (<claim_id> | --claim_id=<claim_id>) [<bid> | --bid=<bid>]
[--tags=<tags>...] [--clear_tags] [--title=<title>] [--description=<description>]
[--language=<language>] [--contact_email=<contact_email>]
[--title=<title>] [--description=<description>]
[--tags=<tags>...] [--clear_tags]
[--languages=<languages>...] [--clear_languages]
[--locations=<locations>...] [--clear_locations]
[--contact_email=<contact_email>]
[--homepage_url=<homepage_url>] [--thumbnail_url=<thumbnail_url>] [--cover_url=<cover_url>]
[--account_id=<account_id>] [--claim_address=<claim_address>] [--new_signing_key] [--preview]
Options:
--claim_id=<claim_id> : (str) claim_id of the channel to update
--bid=<bid> : (decimal) amount to back the claim
--tags=<tags> : (list) add content tags
--clear_tags : (bool) clear existing tags (prior to adding new ones)
--title=<title> : (str) title of the publication
--description=<description> : (str) description of the publication
--language=<language> : (str) primary language of the channel
--clear_tags : (bool) clear existing tags (prior to adding new ones)
--tags=<tags> : (list) add content tags
--clear_languages : (bool) clear existing languages (prior to adding new ones)
--languages=<languages> : (list) languages used by the channel,
using RFC 5646 format, eg:
for English `--languages=en`
for Spanish (Spain) `--languages=es-ES`
for Spanish (Mexican) `--languages=es-MX`
for Chinese (Simplified) `--languages=zh-Hans`
for Chinese (Traditional) `--languages=zh-Hant`
--clear_locations : (bool) clear existing locations (prior to adding new ones)
--locations=<locations> : (list) locations of the channel, consisting of 2 letter
`country` code and a `state`, `city` and a postal
`code` along with a `latitude` and `longitude`.
for JSON RPC: pass a dictionary with aforementioned
attributes as keys, eg:
...
"locations": [{'country': 'US', 'state': 'NH'}]
...
for command line: pass a colon delimited list
with values in the following order:
"COUNTRY:STATE:CITY:CODE:LATITUDE:LONGITUDE"
making sure to include colon for blank values, for
example to provide only the city:
--locations"::Manchester"
with all values set:
--locations="US:NH:Manchester:03101:42.990605:-71.460989"
optionally, you can just pass the "LATITUDE:LONGITUDE":
--locations="42.990605:-71.460989"
finally, you can also pass JSON string of dictionary
on the command line as you would via JSON RPC
--locations="{'country': 'US', 'state': 'NH'}"
--contact_email=<contact_email>: (str) email of channel owner
--homepage_url=<homepage_url> : (str) homepage url
--thumbnail_url=<thumbnail_url>: (str) thumbnail url
@ -1968,7 +2048,10 @@ class Daemon(metaclass=JSONRPCServerType):
Usage:
publish (<name> | --name=<name>) [--bid=<bid>] [--file_path=<file_path>]
[<stream_type> | --stream_type=<stream_type>] [--tags=<tags>...]
[<stream_type> | --stream_type=<stream_type>]
[--tags=<tags>...] [--clear_tags]
[--languages=<languages>...] [--clear_languages]
[--locations=<locations>...] [--clear_locations]
[--fee_currency=<fee_currency>] [--fee_amount=<fee_amount>] [--fee_address=<fee_address>]
[--title=<title>] [--description=<description>] [--author=<author>] [--language=<language>]
[--license=<license>] [--license_url=<license_url>] [--thumbnail_url=<thumbnail_url>]
@ -1984,7 +2067,6 @@ class Daemon(metaclass=JSONRPCServerType):
--bid=<bid> : (decimal) amount to back the claim
--file_path=<file_path> : (str) path to file to be associated with name.
--stream_type=<stream_type> : (str) type of stream
--tags=<tags> : (list) content tags
--fee_currency=<fee_currency> : (string) specify fee currency
--fee_amount=<fee_amount> : (decimal) content download fee
--fee_address=<fee_address> : (str) address where to send fee payments, will use
@ -1996,7 +2078,48 @@ class Daemon(metaclass=JSONRPCServerType):
who is not the publisher and is not represented by the channel. For
example, a pdf file of 'The Odyssey' has an author of 'Homer' but may
by published to a channel such as '@classics', or to no channel at all
--language=<language> : (str) language of the publication
--clear_tags : (bool) clear existing tags (prior to adding new ones)
--tags=<tags> : (list) add content tags
--clear_languages : (bool) clear existing languages (prior to adding new ones)
--languages=<languages> : (list) languages used by the channel,
using RFC 5646 format, eg:
for English `--languages=en`
for Spanish (Spain) `--languages=es-ES`
for Spanish (Mexican) `--languages=es-MX`
for Chinese (Simplified) `--languages=zh-Hans`
for Chinese (Traditional) `--languages=zh-Hant`
--clear_locations : (bool) clear existing locations (prior to adding new ones)
--locations=<locations> : (list) locations of the channel, consisting of 2 letter
`country` code and a `state`, `city` and a postal
`code` along with a `latitude` and `longitude`.
for JSON RPC: pass a dictionary with aforementioned
attributes as keys, eg:
...
"locations": [{'country': 'US', 'state': 'NH'}]
...
for command line: pass a colon delimited list
with values in the following order:
"COUNTRY:STATE:CITY:CODE:LATITUDE:LONGITUDE"
making sure to include colon for blank values, for
example to provide only the city:
--locations"::Manchester"
with all values set:
--locations="US:NH:Manchester:03101:42.990605:-71.460989"
optionally, you can just pass the "LATITUDE:LONGITUDE":
--locations="42.990605:-71.460989"
finally, you can also pass JSON string of dictionary
on the command line as you would via JSON RPC
--locations="{'country': 'US', 'state': 'NH'}"
--license=<license> : (str) publication license
--license_url=<license_url> : (str) publication license url
--thumbnail_url=<thumbnail_url>: (str) thumbnail url
@ -2049,9 +2172,10 @@ class Daemon(metaclass=JSONRPCServerType):
Usage:
stream_create (<name> | --name=<name>) (<bid> | --bid=<bid>)
(<file_path> | --file_path=<file_path>) [<stream_type> | --stream_type=<stream_type>]
[--tags=<tags>...] [--allow_duplicate_name=<allow_duplicate_name>]
[--allow_duplicate_name=<allow_duplicate_name>]
[--tags=<tags>...] [--languages=<languages>...] [--locations=<locations>...]
[--fee_currency=<fee_currency>] [--fee_amount=<fee_amount>] [--fee_address=<fee_address>]
[--title=<title>] [--description=<description>] [--author=<author>] [--language=<language>]
[--title=<title>] [--description=<description>] [--author=<author>]
[--license=<license>] [--license_url=<license_url>] [--thumbnail_url=<thumbnail_url>]
[--release_time=<release_time>]
[--video_width=<video_width>] [--video_height=<video_height>] [--video_duration=<video_duration>]
@ -2067,7 +2191,6 @@ class Daemon(metaclass=JSONRPCServerType):
--bid=<bid> : (decimal) amount to back the claim
--file_path=<file_path> : (str) path to file to be associated with name.
--stream_type=<stream_type> : (str) type of stream
--tags=<tags> : (list) content tags
--fee_currency=<fee_currency> : (string) specify fee currency
--fee_amount=<fee_amount> : (decimal) content download fee
--fee_address=<fee_address> : (str) address where to send fee payments, will use
@ -2079,7 +2202,45 @@ class Daemon(metaclass=JSONRPCServerType):
who is not the publisher and is not represented by the channel. For
example, a pdf file of 'The Odyssey' has an author of 'Homer' but may
by published to a channel such as '@classics', or to no channel at all
--language=<language> : (str) language of the publication
--tags=<tags> : (list) add content tags
--languages=<languages> : (list) languages used by the channel,
using RFC 5646 format, eg:
for English `--languages=en`
for Spanish (Spain) `--languages=es-ES`
for Spanish (Mexican) `--languages=es-MX`
for Chinese (Simplified) `--languages=zh-Hans`
for Chinese (Traditional) `--languages=zh-Hant`
--locations=<locations> : (list) locations of the channel, consisting of 2 letter
`country` code and a `state`, `city` and a postal
`code` along with a `latitude` and `longitude`.
for JSON RPC: pass a dictionary with aforementioned
attributes as keys, eg:
...
"locations": [{'country': 'US', 'state': 'NH'}]
...
for command line: pass a colon delimited list
with values in the following order:
"COUNTRY:STATE:CITY:CODE:LATITUDE:LONGITUDE"
making sure to include colon for blank values, for
example to provide only the city:
--locations"::Manchester"
with all values set:
--locations="US:NH:Manchester:03101:42.990605:-71.460989"
optionally, you can just pass the "LATITUDE:LONGITUDE":
--locations="42.990605:-71.460989"
finally, you can also pass JSON string of dictionary
on the command line as you would via JSON RPC
--locations="{'country': 'US', 'state': 'NH'}"
--license=<license> : (str) publication license
--license_url=<license_url> : (str) publication license url
--thumbnail_url=<thumbnail_url>: (str) thumbnail url
@ -2155,8 +2316,10 @@ class Daemon(metaclass=JSONRPCServerType):
Update an existing stream claim and if a new file is provided announce it to lbrynet.
Usage:
stream_update (<claim_id> | --claim_id=<claim_id>)
[--bid=<bid>] [--file_path=<file_path>] [--tags=<tags>...] [--clear_tags]
stream_update (<claim_id> | --claim_id=<claim_id>) [--bid=<bid>] [--file_path=<file_path>]
[--tags=<tags>...] [--clear_tags]
[--languages=<languages>...] [--clear_languages]
[--locations=<locations>...] [--clear_locations]
[--fee_currency=<fee_currency>] [--fee_amount=<fee_amount>] [--fee_address=<fee_address>]
[--title=<title>] [--description=<description>] [--author=<author>] [--language=<language>]
[--license=<license>] [--license_url=<license_url>] [--thumbnail_url=<thumbnail_url>]
@ -2171,8 +2334,6 @@ class Daemon(metaclass=JSONRPCServerType):
--claim_id=<claim_id> : (str) id of the stream claim to update
--bid=<bid> : (decimal) amount to back the claim
--file_path=<file_path> : (str) path to file to be associated with name.
--tags=<tags> : (list) content tags
--clear_tags : (bool) clear existing tags (prior to adding new ones)
--fee_currency=<fee_currency> : (string) specify fee currency
--fee_amount=<fee_amount> : (decimal) content download fee
--fee_address=<fee_address> : (str) address where to send fee payments, will use
@ -2184,7 +2345,48 @@ class Daemon(metaclass=JSONRPCServerType):
who is not the publisher and is not represented by the channel. For
example, a pdf file of 'The Odyssey' has an author of 'Homer' but may
by published to a channel such as '@classics', or to no channel at all
--language=<language> : (str) language of the publication
--clear_tags : (bool) clear existing tags (prior to adding new ones)
--tags=<tags> : (list) add content tags
--clear_languages : (bool) clear existing languages (prior to adding new ones)
--languages=<languages> : (list) languages used by the channel,
using RFC 5646 format, eg:
for English `--languages=en`
for Spanish (Spain) `--languages=es-ES`
for Spanish (Mexican) `--languages=es-MX`
for Chinese (Simplified) `--languages=zh-Hans`
for Chinese (Traditional) `--languages=zh-Hant`
--clear_locations : (bool) clear existing locations (prior to adding new ones)
--locations=<locations> : (list) locations of the channel, consisting of 2 letter
`country` code and a `state`, `city` and a postal
`code` along with a `latitude` and `longitude`.
for JSON RPC: pass a dictionary with aforementioned
attributes as keys, eg:
...
"locations": [{'country': 'US', 'state': 'NH'}]
...
for command line: pass a colon delimited list
with values in the following order:
"COUNTRY:STATE:CITY:CODE:LATITUDE:LONGITUDE"
making sure to include colon for blank values, for
example to provide only the city:
--locations"::Manchester"
with all values set:
--locations="US:NH:Manchester:03101:42.990605:-71.460989"
optionally, you can just pass the "LATITUDE:LONGITUDE":
--locations="42.990605:-71.460989"
finally, you can also pass JSON string of dictionary
on the command line as you would via JSON RPC
--locations="{'country': 'US', 'state': 'NH'}"
--license=<license> : (str) publication license
--license_url=<license_url> : (str) publication license url
--thumbnail_url=<thumbnail_url>: (str) thumbnail url

View file

@ -28,10 +28,17 @@ class JSONResponseEncoder(JSONEncoder):
claim_dict = obj.to_dict()
if obj.is_stream:
claim_dict['stream']['sd_hash'] = obj.stream.sd_hash
if 'fee' in claim_dict['stream'] and 'address' in claim_dict['stream']['fee']:
claim_dict['stream']['fee']['address'] = obj.stream.fee.address
fee = claim_dict['stream'].get('fee', {})
if 'address' in fee:
fee['address'] = obj.stream.fee.address
if 'amount' in fee:
fee['amount'] = obj.stream.fee.amount
if 'languages' in claim_dict['stream']:
claim_dict['stream']['languages'] = obj.stream.langtags
elif obj.is_channel:
claim_dict['channel']['public_key'] = obj.channel.public_key
if 'languages' in claim_dict['channel']:
claim_dict['channel']['languages'] = obj.channel.langtags
return claim_dict
if isinstance(obj, datetime):
return obj.strftime("%Y%m%dT%H:%M:%S")

View file

@ -1,5 +1,7 @@
import os.path
from typing import List, Tuple
import json
from string import ascii_letters
from typing import List, Tuple, Iterator, TypeVar, Generic
from decimal import Decimal
from binascii import hexlify, unhexlify
@ -87,6 +89,39 @@ class Claim(Signable):
return claim
I = TypeVar('I')
class BaseMessageList(Generic[I]):
__slots__ = 'message',
item_class = None
def __init__(self, message):
self.message = message
def add(self) -> I:
return self.item_class(self.message.add())
def extend(self, values: List[str]):
for value in values:
self.append(value)
def append(self, value: str):
raise NotImplemented
def __len__(self):
return len(self.message)
def __iter__(self) -> Iterator[I]:
for lang in self.message:
yield self.item_class(lang)
def __getitem__(self, item) -> I:
return self.item_class(self.message[item])
class Dimmensional:
__slots__ = ()
@ -215,6 +250,8 @@ class Fee:
def amount(self) -> Decimal:
if self.currency == 'LBC':
return self.lbc
if self.currency == 'BTC':
return self.btc
if self.currency == 'USD':
return self.usd
@ -241,6 +278,29 @@ class Fee:
self._fee.amount = amount
self._fee.currency = FeeMessage.LBC
SATOSHIES = Decimal(COIN)
@property
def btc(self) -> Decimal:
if self._fee.currency != FeeMessage.BTC:
raise ValueError('BTC can only be returned for BTC fees.')
return Decimal(self._fee.amount / self.SATOSHIES)
@btc.setter
def btc(self, amount: Decimal):
self.satoshis = int(amount * self.SATOSHIES)
@property
def satoshis(self) -> int:
if self._fee.currency != FeeMessage.BTC:
raise ValueError('Satoshies can only be returned for BTC fees.')
return self._fee.amount
@satoshis.setter
def satoshis(self, amount: int):
self._fee.amount = amount
self._fee.currency = FeeMessage.BTC
PENNIES = Decimal(100.0)
@property
@ -265,6 +325,176 @@ class Fee:
self._fee.currency = FeeMessage.USD
class Language:
__slots__ = 'message',
def __init__(self, message):
self.message = message
@property
def langtag(self) -> str:
langtag = []
if self.language:
langtag.append(self.language)
if self.script:
langtag.append(self.script)
if self.region:
langtag.append(self.region)
return '-'.join(langtag)
@langtag.setter
def langtag(self, langtag: str):
parts = langtag.split('-')
self.language = parts.pop(0)
if parts and len(parts[0]) == 4:
self.script = parts.pop(0)
if parts and len(parts[0]) == 2:
self.region = parts.pop(0)
assert not parts, f"Failed to parse language tag: {langtag}"
@property
def language(self) -> str:
if self.message.language:
return LanguageMessage.Language.Name(self.message.language)
@language.setter
def language(self, language: str):
self.message.language = LanguageMessage.Language.Value(language)
@property
def script(self) -> str:
if self.message.script:
return LanguageMessage.Script.Name(self.message.script)
@script.setter
def script(self, script: str):
self.message.script = LanguageMessage.Script.Value(script)
@property
def region(self) -> str:
if self.message.region:
return LocationMessage.Country.Name(self.message.region)
@region.setter
def region(self, region: str):
self.message.region = LocationMessage.Country.Value(region)
class LanguageList(BaseMessageList[Language]):
__slots__ = ()
item_class = Language
def append(self, value: str):
self.add().langtag = value
class Location:
__slots__ = 'message',
def __init__(self, message):
self.message = message
def from_value(self, value):
if isinstance(value, str) and value.startswith('{'):
value = json.loads(value)
if isinstance(value, dict):
for key, val in value.items():
setattr(self, key, val)
elif isinstance(value, str):
parts = value.split(':')
if len(parts) > 2 or (parts[0] and parts[0][0] in ascii_letters):
country = parts and parts.pop(0)
if country:
self.country = country
state = parts and parts.pop(0)
if state:
self.state = state
city = parts and parts.pop(0)
if city:
self.city = city
code = parts and parts.pop(0)
if code:
self.code = code
latitude = parts and parts.pop(0)
if latitude:
self.latitude = latitude
longitude = parts and parts.pop(0)
if longitude:
self.longitude = longitude
else:
raise ValueError(f'Could not parse country value: {value}')
@property
def country(self) -> str:
if self.message.country:
return LocationMessage.Country.Name(self.message.country)
@country.setter
def country(self, country: str):
self.message.country = LocationMessage.Country.Value(country)
@property
def state(self) -> str:
return self.message.state
@state.setter
def state(self, state: str):
self.message.state = state
@property
def city(self) -> str:
return self.message.city
@city.setter
def city(self, city: str):
self.message.city = city
@property
def code(self) -> str:
return self.message.code
@code.setter
def code(self, code: str):
self.message.code = code
GPS_PRECISION = Decimal('10000000')
@property
def latitude(self) -> str:
if self.message.latitude:
return str(Decimal(self.message.latitude) / self.GPS_PRECISION)
@latitude.setter
def latitude(self, latitude: str):
latitude = Decimal(latitude)
assert -90 <= latitude <= 90, "Latitude must be between -90 and 90 degrees."
self.message.latitude = int(latitude * self.GPS_PRECISION)
@property
def longitude(self) -> str:
if self.message.longitude:
return str(Decimal(self.message.longitude) / self.GPS_PRECISION)
@longitude.setter
def longitude(self, longitude: str):
longitude = Decimal(longitude)
assert -180 <= longitude <= 180, "Longitude must be between -180 and 180 degrees."
self.message.longitude = int(longitude * self.GPS_PRECISION)
class LocationList(BaseMessageList[Location]):
__slots__ = ()
item_class = Location
def append(self, value):
self.add().from_value(value)
class BaseClaimSubType:
__slots__ = 'claim', 'message'
@ -272,10 +502,6 @@ class BaseClaimSubType:
def __init__(self, claim: Claim):
self.claim = claim or Claim()
@property
def tags(self) -> List:
return self.message.tags
@property
def title(self) -> str:
return self.message.title
@ -301,54 +527,36 @@ class BaseClaimSubType:
self.message.thumbnail_url = thumbnail_url
@property
def language(self) -> str:
if len(self.languages) > 0:
return LanguageMessage.Language.Name(self.languages[0].language)
@language.setter
def language(self, language: str):
value = LanguageMessage.Language.Value(language)
if len(self.languages) > 0:
self.languages[0].language = value
else:
self.languages.add().language = value
def tags(self) -> List:
return self.message.tags
@property
def languages(self):
return self.message.languages
def languages(self) -> LanguageList:
return LanguageList(self.message.languages)
@property
def location_country(self) -> str:
if len(self.locations) > 0:
return LocationMessage.Country.Name(self.locations[0].country)
@location_country.setter
def location_country(self, country: str):
value = LocationMessage.Country.Value(country)
if len(self.locations) > 0:
self.locations[0].location = value
else:
self.locations.add().location = value
def langtags(self) -> List[str]:
return [l.langtag for l in self.languages]
@property
def locations(self):
return self.message.locations
def locations(self) -> LocationList:
return LocationList(self.message.locations)
def to_dict(self):
return MessageToDict(self.message, preserving_proto_field_name=True)
def update(self, tags=None, clear_tags=False, **kwargs):
if clear_tags:
self.message.ClearField('tags')
if tags is not None:
if isinstance(tags, str):
self.tags.append(tags)
elif isinstance(tags, list):
self.tags.extend(tags)
else:
raise ValueError(f"Unknown tag type: {tags}")
def update(self, **kwargs):
for l in ('tags', 'languages', 'locations'):
if kwargs.pop(f'clear_{l}', False):
self.message.ClearField('tags')
items = kwargs.pop(l, None)
if items is not None:
if isinstance(items, str):
getattr(self, l).append(items)
elif isinstance(items, list):
getattr(self, l).extend(items)
else:
raise ValueError(f"Unknown {l} value: {items}")
for key, value in kwargs.items():
setattr(self, key, value)
@ -454,6 +662,8 @@ class Stream(BaseClaimSubType):
self.fee.address = fee_address
if fee_currency.lower() == 'lbc':
self.fee.lbc = Decimal(fee_amount)
elif fee_currency.lower() == 'btc':
self.fee.btc = Decimal(fee_amount)
elif fee_currency.lower() == 'usd':
self.fee.usd = Decimal(fee_amount)
else:

View file

@ -2,7 +2,6 @@ import json
from decimal import Decimal
from lbrynet.schema.types.v1.legacy_claim_pb2 import Claim as OldClaimMessage
from lbrynet.schema.types.v1.metadata_pb2 import Metadata as MetadataMessage
from lbrynet.schema.types.v1.certificate_pb2 import KeyType
from lbrynet.schema.types.v1.fee_pb2 import Fee as FeeMessage
@ -22,7 +21,7 @@ def from_old_json_schema(claim, payload: bytes):
if language.lower() == 'english':
language = 'en'
try:
stream.language = language
stream.languages.append(language)
except:
pass
stream.sd_hash = value['sources']['lbry_sd_hash']
@ -35,6 +34,8 @@ def from_old_json_schema(claim, payload: bytes):
stream.fee.lbc = Decimal(fee[currency]['amount'])
elif currency == 'USD':
stream.fee.usd = Decimal(fee[currency]['amount'])
elif currency == 'BTC':
stream.fee.btc = Decimal(fee[currency]['amount'])
else:
raise ValueError(f'Unknown currency: {currency}')
stream.fee.address = fee[currency]['address']
@ -53,7 +54,7 @@ def from_types_v1(claim, payload: bytes):
stream.license_url = old.stream.metadata.licenseUrl
stream.thumbnail_url = old.stream.metadata.thumbnail
if old.stream.metadata.HasField('language'):
stream.languages.add().language = old.stream.metadata.language
stream.languages.add().message.language = old.stream.metadata.language
stream.media_type = old.stream.source.contentType
stream.sd_hash_bytes = old.stream.source.source
if old.stream.metadata.nsfw:
@ -66,6 +67,8 @@ def from_types_v1(claim, payload: bytes):
stream.fee.lbc = Decimal(fee.amount)
elif currency == 'USD':
stream.fee.usd = Decimal(fee.amount)
elif currency == 'BTC':
stream.fee.btc = Decimal(fee.amount)
else:
raise ValueError(f'Unsupported currency: {currency}')
if old.HasField('publisherSignature'):

File diff suppressed because one or more lines are too long

View file

@ -1,6 +1,7 @@
import hashlib
import tempfile
from binascii import unhexlify
from decimal import Decimal
import ecdsa
@ -73,14 +74,15 @@ class ChannelCommands(CommandTestCase):
'title': "Cool Channel",
'description': "Best channel on LBRY.",
'thumbnail_url': "https://co.ol/thumbnail.png",
'language': "en",
'languages': ["en-US"],
'locations': ['US::Manchester'],
'contact_email': "human@email.com",
'homepage_url': "https://co.ol",
'cover_url': "https://co.ol/cover.png",
}
fixed_values = values.copy()
del fixed_values['language']
fixed_values['languages'] = [{'language': 'en'}]
fixed_values['languages'] = ['en-US']
fixed_values['locations'] = [{'country': 'US', 'city': 'Manchester'}]
# create new channel with all fields set
tx = await self.out(self.channel_create('@bigchannel', **values))
@ -259,13 +261,14 @@ class StreamCommands(CommandTestCase):
'hovercraft3', channel_id=baz_id, channel_account_id=[account1_id]
)
async def test_setting_claim_fields(self):
async def test_setting_stream_fields(self):
values = {
'tags': ["cool", "awesome"],
'title': "Cool Content",
'description': "Best content on LBRY.",
'thumbnail_url': "https://co.ol/thumbnail.png",
'language': "en",
'languages': ["en"],
'locations': ['{"country": "UA"}'],
'author': "Jules Verne",
'license': 'Public Domain',
@ -280,8 +283,8 @@ class StreamCommands(CommandTestCase):
'video_height': 600
}
fixed_values = values.copy()
del fixed_values['language']
fixed_values['languages'] = [{'language': 'en'}]
fixed_values['languages'] = ['en']
fixed_values['locations'] = [{'country': 'UA'}]
# create new channel with all fields set
tx = await self.out(self.stream_create('big', **values))
@ -293,7 +296,7 @@ class StreamCommands(CommandTestCase):
fixed_values['release_time'] = str(values['release_time'])
fixed_values['fee'] = {
'address': fixed_values.pop('fee_address'),
'amount': fixed_values.pop('fee_amount').replace('.', ''),
'amount': float(fixed_values.pop('fee_amount')),
'currency': fixed_values.pop('fee_currency').upper()
}
fixed_values['video'] = {

View file

@ -20,7 +20,7 @@ class TestOldJSONSchemaCompatibility(TestCase):
self.assertEqual(stream.description, '10MB test file to measure download speed on Lbry p2p-network.')
self.assertEqual(stream.license, 'None')
self.assertEqual(stream.author, 'root')
self.assertEqual(stream.language, 'en')
self.assertEqual(stream.langtags, ['en'])
self.assertEqual(stream.media_type, 'application/octet-stream')
self.assertEqual(stream.thumbnail_url, '/home/robert/lbry/speed.jpg')
self.assertEqual(
@ -51,7 +51,7 @@ class TestOldJSONSchemaCompatibility(TestCase):
self.assertEqual(stream.license, 'Creative Commons Attribution 3.0 United States')
self.assertEqual(stream.license_url, 'https://creativecommons.org/licenses/by/3.0/us/legalcode')
self.assertEqual(stream.author, 'Mii')
self.assertEqual(stream.language, 'en')
self.assertEqual(stream.langtags, ['en'])
self.assertEqual(stream.media_type, 'application/x-msdownload')
self.assertEqual(
stream.sd_hash,
@ -77,7 +77,7 @@ class TestOldJSONSchemaCompatibility(TestCase):
self.assertEqual(stream.description, 'asd')
self.assertEqual(stream.license, 'Creative Commons Attribution 4.0 International')
self.assertEqual(stream.author, 'sgb')
self.assertEqual(stream.language, 'en')
self.assertEqual(stream.langtags, ['en'])
self.assertEqual(stream.media_type, 'video/mp4')
self.assertEqual(
stream.sd_hash,
@ -120,7 +120,7 @@ class TestTypesV1Compatibility(TestCase):
)
self.assertEqual(stream.license, 'Copyrighted (contact author)')
self.assertEqual(stream.author, 'The Linux Gamer')
self.assertEqual(stream.language, 'en')
self.assertEqual(stream.langtags, ['en'])
self.assertEqual(stream.media_type, 'video/mp4')
self.assertEqual(stream.thumbnail_url, 'https://berk.ninja/thumbnails/FrTdBCOS_fc')
self.assertEqual(
@ -157,7 +157,7 @@ class TestTypesV1Compatibility(TestCase):
self.assertEqual(stream.description, 'midi')
self.assertEqual(stream.license, 'Creative Commons Attribution 4.0 International')
self.assertEqual(stream.author, 'rpg midi')
self.assertEqual(stream.language, 'en')
self.assertEqual(stream.langtags, ['en'])
self.assertEqual(stream.media_type, 'application/x-zip-compressed')
self.assertEqual(
stream.sd_hash,

View file

@ -61,3 +61,103 @@ class TestFee(TestCase):
print(stream.fee.lbc)
with self.assertRaisesRegex(ValueError, 'Dewies can only be returned for LBC fees.'):
print(stream.fee.dewies)
class TestLanguages(TestCase):
def test_language_successful_parsing(self):
stream = Stream()
stream.languages.append('en')
self.assertEqual(stream.languages[0].langtag, 'en')
self.assertEqual(stream.languages[0].language, 'en')
self.assertEqual(stream.langtags, ['en'])
stream.languages.append('en-US')
self.assertEqual(stream.languages[1].langtag, 'en-US')
self.assertEqual(stream.languages[1].language, 'en')
self.assertEqual(stream.languages[1].region, 'US')
self.assertEqual(stream.langtags, ['en', 'en-US'])
stream.languages.append('en-Latn-US')
self.assertEqual(stream.languages[2].langtag, 'en-Latn-US')
self.assertEqual(stream.languages[2].language, 'en')
self.assertEqual(stream.languages[2].script, 'Latn')
self.assertEqual(stream.languages[2].region, 'US')
self.assertEqual(stream.langtags, ['en', 'en-US', 'en-Latn-US'])
stream = Stream()
stream.languages.extend(['en-Latn-US', 'es-ES', 'de-DE'])
self.assertEqual(stream.languages[0].language, 'en')
self.assertEqual(stream.languages[1].language, 'es')
self.assertEqual(stream.languages[2].language, 'de')
def test_language_error_parsing(self):
stream = Stream()
with self.assertRaisesRegex(ValueError, 'Language has no value defined for name zz'):
stream.languages.append('zz')
with self.assertRaisesRegex(ValueError, 'Script has no value defined for name Zabc'):
stream.languages.append('en-Zabc')
with self.assertRaisesRegex(ValueError, 'Country has no value defined for name ZZ'):
stream.languages.append('en-Zzzz-ZZ')
with self.assertRaisesRegex(AssertionError, 'Failed to parse language tag: en-Zzz-US'):
stream.languages.append('en-Zzz-US')
class TestLocations(TestCase):
def test_location_successful_parsing(self):
# from simple string
stream = Stream()
stream.locations.append('US')
self.assertEqual(stream.locations[0].country, 'US')
# from full string
stream = Stream()
stream.locations.append('US:NH:Manchester:03101:42.990605:-71.460989')
self.assertEqual(stream.locations[0].country, 'US')
self.assertEqual(stream.locations[0].state, 'NH')
self.assertEqual(stream.locations[0].city, 'Manchester')
self.assertEqual(stream.locations[0].code, '03101')
self.assertEqual(stream.locations[0].latitude, '42.990605')
self.assertEqual(stream.locations[0].longitude, '-71.460989')
# from partial string
stream = Stream()
stream.locations.append('::Manchester:03101:')
self.assertEqual(stream.locations[0].country, None)
self.assertEqual(stream.locations[0].state, '')
self.assertEqual(stream.locations[0].city, 'Manchester')
self.assertEqual(stream.locations[0].code, '03101')
self.assertEqual(stream.locations[0].latitude, None)
self.assertEqual(stream.locations[0].longitude, None)
# from partial string lat/long
stream = Stream()
stream.locations.append('::::42.990605:-71.460989')
self.assertEqual(stream.locations[0].country, None)
self.assertEqual(stream.locations[0].state, '')
self.assertEqual(stream.locations[0].city, '')
self.assertEqual(stream.locations[0].code, '')
self.assertEqual(stream.locations[0].latitude, '42.990605')
self.assertEqual(stream.locations[0].longitude, '-71.460989')
# from short circuit lat/long
stream = Stream()
stream.locations.append('42.990605:-71.460989')
self.assertEqual(stream.locations[0].country, None)
self.assertEqual(stream.locations[0].state, '')
self.assertEqual(stream.locations[0].city, '')
self.assertEqual(stream.locations[0].code, '')
self.assertEqual(stream.locations[0].latitude, '42.990605')
self.assertEqual(stream.locations[0].longitude, '-71.460989')
# from json string
stream = Stream()
stream.locations.append('{"country": "ES"}')
self.assertEqual(stream.locations[0].country, 'ES')
# from dict
stream = Stream()
stream.locations.append({"country": "UA"})
self.assertEqual(stream.locations[0].country, 'UA')