forked from LBRYCommunity/lbry-sdk
added --replace option to stream_update and channel_update, publish defaults to --replace
This commit is contained in:
parent
3618de1227
commit
da637b9c0e
3 changed files with 89 additions and 20 deletions
|
@ -1852,7 +1852,7 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
@requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED])
|
@requires(WALLET_COMPONENT, conditions=[WALLET_IS_UNLOCKED])
|
||||||
async def jsonrpc_channel_update(
|
async def jsonrpc_channel_update(
|
||||||
self, claim_id, bid=None, account_id=None, claim_address=None,
|
self, claim_id, bid=None, account_id=None, claim_address=None,
|
||||||
new_signing_key=False, preview=False, **kwargs):
|
new_signing_key=False, preview=False, replace=False, **kwargs):
|
||||||
"""
|
"""
|
||||||
Update an existing channel claim.
|
Update an existing channel claim.
|
||||||
|
|
||||||
|
@ -1865,7 +1865,8 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
[--locations=<locations>...] [--clear_locations]
|
[--locations=<locations>...] [--clear_locations]
|
||||||
[--email=<email>]
|
[--email=<email>]
|
||||||
[--website_url=<website_url>] [--thumbnail_url=<thumbnail_url>] [--cover_url=<cover_url>]
|
[--website_url=<website_url>] [--thumbnail_url=<thumbnail_url>] [--cover_url=<cover_url>]
|
||||||
[--account_id=<account_id>] [--claim_address=<claim_address>] [--new_signing_key] [--preview]
|
[--account_id=<account_id>] [--claim_address=<claim_address>] [--new_signing_key]
|
||||||
|
[--preview] [--replace]
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
--claim_id=<claim_id> : (str) claim_id of the channel to update
|
--claim_id=<claim_id> : (str) claim_id of the channel to update
|
||||||
|
@ -1923,6 +1924,10 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
--account_id=<account_id> : (str) id of the account to store channel
|
--account_id=<account_id> : (str) id of the account to store channel
|
||||||
--claim_address=<claim_address>: (str) address where the channel is sent
|
--claim_address=<claim_address>: (str) address where the channel is sent
|
||||||
--new_signing_key : (bool) generate a new signing key, will invalidate all previous publishes
|
--new_signing_key : (bool) generate a new signing key, will invalidate all previous publishes
|
||||||
|
--replace : (bool) instead of modifying specific values on
|
||||||
|
the channel, this will clear all existing values
|
||||||
|
and only save passed in values, useful for form
|
||||||
|
submissions where all values are always set
|
||||||
--preview : (bool) do not broadcast the transaction
|
--preview : (bool) do not broadcast the transaction
|
||||||
|
|
||||||
Returns: {Transaction}
|
Returns: {Transaction}
|
||||||
|
@ -1950,7 +1955,11 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
else:
|
else:
|
||||||
claim_address = old_txo.get_address(account.ledger)
|
claim_address = old_txo.get_address(account.ledger)
|
||||||
|
|
||||||
claim = Claim.from_bytes(old_txo.claim.to_bytes())
|
if replace:
|
||||||
|
claim = Claim()
|
||||||
|
claim.channel.public_key_bytes = old_txo.claim.channel.public_key_bytes
|
||||||
|
else:
|
||||||
|
claim = Claim.from_bytes(old_txo.claim.to_bytes())
|
||||||
claim.channel.update(**kwargs)
|
claim.channel.update(**kwargs)
|
||||||
tx = await Transaction.claim_update(
|
tx = await Transaction.claim_update(
|
||||||
old_txo, claim, amount, claim_address, [account], account
|
old_txo, claim, amount, claim_address, [account], account
|
||||||
|
@ -2092,13 +2101,11 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
conditions=[WALLET_IS_UNLOCKED])
|
conditions=[WALLET_IS_UNLOCKED])
|
||||||
async def jsonrpc_publish(self, name, **kwargs):
|
async def jsonrpc_publish(self, name, **kwargs):
|
||||||
"""
|
"""
|
||||||
Create or update a stream claim at a given name (use 'stream create/update' for more control).
|
Create or replace a stream claim at a given name (use 'stream create/update' for more control).
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
publish (<name> | --name=<name>) [--bid=<bid>] [--file_path=<file_path>]
|
publish (<name> | --name=<name>) [--bid=<bid>] [--file_path=<file_path>]
|
||||||
[--tags=<tags>...] [--clear_tags]
|
[--tags=<tags>...] [--languages=<languages>...] [--locations=<locations>...]
|
||||||
[--languages=<languages>...] [--clear_languages]
|
|
||||||
[--locations=<locations>...] [--clear_locations]
|
|
||||||
[--fee_currency=<fee_currency>] [--fee_amount=<fee_amount>] [--fee_address=<fee_address>]
|
[--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>] [--language=<language>]
|
||||||
[--license=<license>] [--license_url=<license_url>] [--thumbnail_url=<thumbnail_url>]
|
[--license=<license>] [--license_url=<license_url>] [--thumbnail_url=<thumbnail_url>]
|
||||||
|
@ -2122,9 +2129,7 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
who is not the publisher and is not represented by the channel. For
|
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
|
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
|
by published to a channel such as '@classics', or to no channel at all
|
||||||
--clear_tags : (bool) clear existing tags (prior to adding new ones)
|
|
||||||
--tags=<tags> : (list) add content tags
|
--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,
|
--languages=<languages> : (list) languages used by the channel,
|
||||||
using RFC 5646 format, eg:
|
using RFC 5646 format, eg:
|
||||||
for English `--languages=en`
|
for English `--languages=en`
|
||||||
|
@ -2132,7 +2137,6 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
for Spanish (Mexican) `--languages=es-MX`
|
for Spanish (Mexican) `--languages=es-MX`
|
||||||
for Chinese (Simplified) `--languages=zh-Hans`
|
for Chinese (Simplified) `--languages=zh-Hans`
|
||||||
for Chinese (Traditional) `--languages=zh-Hant`
|
for Chinese (Traditional) `--languages=zh-Hant`
|
||||||
--clear_locations : (bool) clear existing locations (prior to adding new ones)
|
|
||||||
--locations=<locations> : (list) locations relevant to the stream, consisting of 2 letter
|
--locations=<locations> : (list) locations relevant to the stream, consisting of 2 letter
|
||||||
`country` code and a `state`, `city` and a postal
|
`country` code and a `state`, `city` and a postal
|
||||||
`code` along with a `latitude` and `longitude`.
|
`code` along with a `latitude` and `longitude`.
|
||||||
|
@ -2193,7 +2197,7 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
return await self.jsonrpc_stream_create(name, **kwargs)
|
return await self.jsonrpc_stream_create(name, **kwargs)
|
||||||
elif len(claims) == 1:
|
elif len(claims) == 1:
|
||||||
assert claims[0].claim.is_stream, f"Claim at name '{name}' is not a stream claim."
|
assert claims[0].claim.is_stream, f"Claim at name '{name}' is not a stream claim."
|
||||||
return await self.jsonrpc_stream_update(claims[0].claim_id, **kwargs)
|
return await self.jsonrpc_stream_update(claims[0].claim_id, replace=True, **kwargs)
|
||||||
raise Exception(
|
raise Exception(
|
||||||
f"There are {len(claims)} claims for '{name}', please use 'stream update' command "
|
f"There are {len(claims)} claims for '{name}', please use 'stream update' command "
|
||||||
f"to update a specific stream claim."
|
f"to update a specific stream claim."
|
||||||
|
@ -2339,7 +2343,7 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
self, claim_id, bid=None, file_path=None,
|
self, claim_id, bid=None, file_path=None,
|
||||||
channel_id=None, channel_name=None, channel_account_id=None, clear_channel=False,
|
channel_id=None, channel_name=None, channel_account_id=None, clear_channel=False,
|
||||||
account_id=None, claim_address=None,
|
account_id=None, claim_address=None,
|
||||||
preview=False, **kwargs):
|
preview=False, replace=False, **kwargs):
|
||||||
"""
|
"""
|
||||||
Update an existing stream claim and if a new file is provided announce it to lbrynet.
|
Update an existing stream claim and if a new file is provided announce it to lbrynet.
|
||||||
|
|
||||||
|
@ -2356,7 +2360,8 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
[--release_time=<release_time>] [--width=<width>] [--height=<height>] [--duration=<duration>]
|
[--release_time=<release_time>] [--width=<width>] [--height=<height>] [--duration=<duration>]
|
||||||
[--channel_id=<channel_id>] [--channel_name=<channel_name>] [--clear_channel]
|
[--channel_id=<channel_id>] [--channel_name=<channel_name>] [--clear_channel]
|
||||||
[--channel_account_id=<channel_account_id>...]
|
[--channel_account_id=<channel_account_id>...]
|
||||||
[--account_id=<account_id>] [--claim_address=<claim_address>] [--preview]
|
[--account_id=<account_id>] [--claim_address=<claim_address>]
|
||||||
|
[--preview] [--replace]
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
--claim_id=<claim_id> : (str) id of the stream claim to update
|
--claim_id=<claim_id> : (str) id of the stream claim to update
|
||||||
|
@ -2433,6 +2438,10 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
--account_id=<account_id> : (str) account to use for funding the transaction
|
--account_id=<account_id> : (str) account to use for funding the transaction
|
||||||
--claim_address=<claim_address>: (str) address where the claim is sent to, if not specified
|
--claim_address=<claim_address>: (str) address where the claim is sent to, if not specified
|
||||||
it will be determined automatically from the account
|
it will be determined automatically from the account
|
||||||
|
--replace : (bool) instead of modifying specific values on
|
||||||
|
the stream, this will clear all existing values
|
||||||
|
and only save passed in values, useful for form
|
||||||
|
submissions where all values are always set
|
||||||
--preview : (bool) do not broadcast the transaction
|
--preview : (bool) do not broadcast the transaction
|
||||||
|
|
||||||
Returns: {Transaction}
|
Returns: {Transaction}
|
||||||
|
@ -2442,7 +2451,7 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
existing_claims = await account.get_claims(claim_id=claim_id)
|
existing_claims = await account.get_claims(claim_id=claim_id)
|
||||||
if len(existing_claims) != 1:
|
if len(existing_claims) != 1:
|
||||||
raise Exception(
|
raise Exception(
|
||||||
f"Can't find the claim '{claim_id}' in account '{account_id}'."
|
f"Can't find the claim '{claim_id}' in account '{account.id}'."
|
||||||
)
|
)
|
||||||
old_txo = existing_claims[0]
|
old_txo = existing_claims[0]
|
||||||
if not old_txo.claim.is_stream:
|
if not old_txo.claim.is_stream:
|
||||||
|
@ -2469,8 +2478,20 @@ class Daemon(metaclass=JSONRPCServerType):
|
||||||
if 'fee_address' in kwargs:
|
if 'fee_address' in kwargs:
|
||||||
self.valid_address_or_error(kwargs['fee_address'])
|
self.valid_address_or_error(kwargs['fee_address'])
|
||||||
|
|
||||||
claim = Claim.from_bytes(old_txo.claim.to_bytes())
|
if replace:
|
||||||
claim.stream.update(file_path=file_path, **kwargs)
|
claim = Claim()
|
||||||
|
claim.stream.message.source.CopyFrom(
|
||||||
|
old_txo.claim.stream.message.source
|
||||||
|
)
|
||||||
|
stream_type = old_txo.claim.stream.stream_type
|
||||||
|
if stream_type:
|
||||||
|
old_stream_type = getattr(old_txo.claim.stream.message, stream_type)
|
||||||
|
new_stream_type = getattr(claim.stream.message, stream_type)
|
||||||
|
new_stream_type.CopyFrom(old_stream_type)
|
||||||
|
claim.stream.update(file_path=file_path, **kwargs)
|
||||||
|
else:
|
||||||
|
claim = Claim.from_bytes(old_txo.claim.to_bytes())
|
||||||
|
claim.stream.update(file_path=file_path, **kwargs)
|
||||||
tx = await Transaction.claim_update(
|
tx = await Transaction.claim_update(
|
||||||
old_txo, claim, amount, claim_address, [account], account, channel
|
old_txo, claim, amount, claim_address, [account], account, channel
|
||||||
)
|
)
|
||||||
|
|
|
@ -233,10 +233,11 @@ class Stream(BaseClaim):
|
||||||
if stream_type in ('image', 'video', 'audio'):
|
if stream_type in ('image', 'video', 'audio'):
|
||||||
media = getattr(self, stream_type)
|
media = getattr(self, stream_type)
|
||||||
media_args = {'file_metadata': None}
|
media_args = {'file_metadata': None}
|
||||||
try:
|
if file_path is not None:
|
||||||
media_args['file_metadata'] = binary_file_metadata(binary_file_parser(file_path))
|
try:
|
||||||
except:
|
media_args['file_metadata'] = binary_file_metadata(binary_file_parser(file_path))
|
||||||
log.exception('Could not read file metadata.')
|
except:
|
||||||
|
log.exception('Could not read file metadata.')
|
||||||
if isinstance(media, Playable):
|
if isinstance(media, Playable):
|
||||||
media_args['duration'] = duration
|
media_args['duration'] = duration
|
||||||
if isinstance(media, Dimmensional):
|
if isinstance(media, Dimmensional):
|
||||||
|
@ -290,6 +291,10 @@ class Stream(BaseClaim):
|
||||||
def source(self) -> Source:
|
def source(self) -> Source:
|
||||||
return Source(self.message.source)
|
return Source(self.message.source)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def stream_type(self) -> str:
|
||||||
|
return self.message.WhichOneof('type')
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def image(self) -> Image:
|
def image(self) -> Image:
|
||||||
return Image(self.message.image)
|
return Image(self.message.image)
|
||||||
|
|
|
@ -125,6 +125,13 @@ class ChannelCommands(CommandTestCase):
|
||||||
channel = tx['outputs'][0]['value']
|
channel = tx['outputs'][0]['value']
|
||||||
self.assertNotEqual(channel['public_key'], fixed_values['public_key'])
|
self.assertNotEqual(channel['public_key'], fixed_values['public_key'])
|
||||||
|
|
||||||
|
# replace mode (clears everything except public_key)
|
||||||
|
tx = await self.out(self.channel_update(claim_id, replace=True, title='foo', email='new@email.com'))
|
||||||
|
self.assertEqual(
|
||||||
|
tx['outputs'][0]['value'],
|
||||||
|
{'public_key': channel['public_key'], 'title': 'foo', 'email': 'new@email.com'}
|
||||||
|
)
|
||||||
|
|
||||||
# send channel to someone else
|
# send channel to someone else
|
||||||
new_account = await self.out(self.daemon.jsonrpc_account_create('second account'))
|
new_account = await self.out(self.daemon.jsonrpc_account_create('second account'))
|
||||||
account2_id, account2 = new_account['id'], self.daemon.get_account_or_error(new_account['id'])
|
account2_id, account2 = new_account['id'], self.daemon.get_account_or_error(new_account['id'])
|
||||||
|
@ -470,6 +477,42 @@ class StreamCommands(CommandTestCase):
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def test_replace_mode_preserves_source_and_type(self):
|
||||||
|
expected = {
|
||||||
|
'tags': ['blah'],
|
||||||
|
'languages': ['uk'],
|
||||||
|
'locations': [{'country': 'UA', 'city': 'Kyiv'}],
|
||||||
|
'source': {
|
||||||
|
'size': '2299653',
|
||||||
|
'name': 'ForBiggerEscapes.mp4',
|
||||||
|
'media_type': 'video/mp4',
|
||||||
|
'hash': 'f846d9c7f5ed28f0ed47e9d9b4198a03075e6df967ac54078af85ea1bf0ddd87',
|
||||||
|
},
|
||||||
|
'stream_type': 'video',
|
||||||
|
'video': {
|
||||||
|
'width': 1280,
|
||||||
|
'height': 720,
|
||||||
|
'duration': 15
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tx = await self.out(self.daemon.jsonrpc_stream_create(
|
||||||
|
'chrome', '1.0', file_path=self.video_file_name,
|
||||||
|
tags='blah', languages='uk', locations='UA::Kyiv'
|
||||||
|
))
|
||||||
|
await self.on_transaction_dict(tx)
|
||||||
|
txo = tx['outputs'][0]
|
||||||
|
expected['source']['sd_hash'] = txo['value']['source']['sd_hash']
|
||||||
|
self.assertEqual(txo['value'], expected)
|
||||||
|
tx = await self.out(self.daemon.jsonrpc_stream_update(
|
||||||
|
txo['claim_id'], title='new title', replace=True
|
||||||
|
))
|
||||||
|
txo = tx['outputs'][0]
|
||||||
|
expected['title'] = 'new title'
|
||||||
|
del expected['tags']
|
||||||
|
del expected['languages']
|
||||||
|
del expected['locations']
|
||||||
|
self.assertEqual(txo['value'], expected)
|
||||||
|
|
||||||
async def test_create_update_and_abandon_stream(self):
|
async def test_create_update_and_abandon_stream(self):
|
||||||
await self.assertBalance(self.account, '10.0')
|
await self.assertBalance(self.account, '10.0')
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue