intermediate progress

This commit is contained in:
Jeremy Kauffman 2017-02-20 21:06:01 -05:00
parent 3fe4055d52
commit eab1c67238
22 changed files with 660 additions and 319 deletions

View file

@ -89,9 +89,10 @@ class Controller
$router->get(['/ios', 'get-ios'], 'DownloadActions::executeGet');
$router->get('/roadmap', 'ContentActions::executeRoadmap');
$router->get('/developer-program', 'AcquisitionActions::executeDeveloperProgram');
$router->post('/developer-program/post', 'AcquisitionActions::executeDeveloperProgramPost');
$router->get('/developer-program/callback', 'AcquisitionActions::executeDeveloperProgramGithubCallback');
$router->get('/quickstart/{step}?', 'DeveloperActions::executeQuickstart');
$router->get('/developer-program', 'DeveloperActions::executeDeveloperProgram');
$router->post('/developer-program/post', 'DeveloperActions::executeDeveloperProgramPost');
$router->get('/developer-program/callback', 'DeveloperActions::executeDeveloperProgramGithubCallback');
$router->get(['/press-kit.zip', 'press-kit'], 'ContentActions::executePressKit');

View file

@ -2,8 +2,6 @@
class AcquisitionActions extends Actions
{
const DEVELOPER_REWARD = 250;
public static function executeThanks()
{
return ['acquisition/thanks'];
@ -41,145 +39,4 @@ class AcquisitionActions extends Actions
}
return [$template];
}
public static function executeDeveloperProgram()
{
return ['acquisition/developer-program', [
'defaultWalletAddress' => Session::get(Session::KEY_DEVELOPER_CREDITS_WALLET_ADDRESS),
'error' => Session::getFlash(Session::KEY_DEVELOPER_CREDITS_ERROR),
'success' => Session::getFlash(Session::KEY_DEVELOPER_CREDITS_SUCCESS)
]];
}
public static function executeDeveloperProgramPost()
{
$walletAddress = trim(Request::getPostParam('wallet'));
Session::set(Session::KEY_DEVELOPER_CREDITS_WALLET_ADDRESS, $walletAddress);
if (!$walletAddress)
{
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'Please provide a wallet address.');
}
elseif (!preg_match('/^b[1-9A-HJ-NP-Za-km-z]{33}$/', $walletAddress))
{
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'This does not appear to be a valid wallet address.');
}
else
{
if (!Config::get('github_developer_credits_client_id'))
{
throw new Exception('no github client id');
}
$githubParams = [
'client_id' => Config::get('github_developer_credits_client_id'),
'redirect_uri' => Request::getHostAndProto() . '/developer-program/callback',
'scope' => 'user:email',
'allow_signup' => false
];
return Controller::redirect('https://github.com/login/oauth/authorize?' . http_build_query($githubParams));
}
return Controller::redirect('/developer-program');
}
public static function executeDeveloperProgramGithubCallback()
{
$code = Request::getParam('code');
$walletAddress = Session::get(Session::KEY_DEVELOPER_CREDITS_WALLET_ADDRESS);
if (!$walletAddress)
{
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'Your wallet address disappeared while authenticated with GitHub.');
}
elseif (!$code)
{
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'This does not appear to be a valid response from GitHub.');
}
else
{
$authResponseData = Curl::post('https://github.com/login/oauth/access_token', [
'code' => $code,
'client_id' => Config::get('github_developer_credits_client_id'),
'client_secret' => Config::get('github_developer_credits_client_secret')
], [
'headers' => ['Accept: application/json'],
'json_response' => true
]);
if (!$authResponseData || !isset($authResponseData['access_token']))
{
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'Request to GitHub failed.');
}
elseif (isset($authResponseData['error_description']))
{
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'GitHub replied: ' . $authResponseData['error_description']);
}
else
{
$accessToken = $authResponseData['access_token'];
$userResponseData = Curl::get('https://api.github.com/user', [], [
'headers' => ['Authorization: token ' . $accessToken, 'Accept: application/json', 'User-Agent: lbryio'],
'json_response' => true
]);
if (date('Y-m-d', strtotime($userResponseData['created_at'])) > '2017-01-30')
{
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'This GitHub account is too recent.');
}
else
{
$lockName = 'github_dev_credits_write';
$dataFile = ROOT_DIR . '/data/writeable/github_developer_credits';
$lock = Lock::getLock($lockName, true); // EXCLUSIVE LOCK. IF SENDING CREDITS IS SLOW, THIS COULD BLOCK USERS
$existing = is_file($dataFile) ? json_decode(file_get_contents($dataFile), true) : [];
if (isset($existing[$userResponseData['login']]) || isset($existing[$userResponseData['id']]))
{
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'You already received credits.');
}
else
{
$response =
Curl::post('http://localhost:5279/lbryapi', [
'method' => 'send_amount_to_address',
'params' => [['amount' => 250, 'address' => $walletAddress]],
], [
'json_data' => true,
'json_response' => true,
]);
if ($response === [true])
{
$existing[$userResponseData['id']] = [$userResponseData['email'], $walletAddress, date('Y-m-d H:i:s'), $userResponseData['login']];
file_put_contents($dataFile, json_encode($existing));
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_SUCCESS,
'Credits on their way to address ' . $walletAddress . ' for GitHub user ' . $userResponseData['login'] . '. It may take up to a minute for them to arrive.');
}
else
{
if (isset($response['faultString']) && stripos($response['faultString'], 'InsufficientFundsError') !== false)
{
Slack::sendErrorIfProd('Github dev credits need a refill');
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR,
'Our wallet is running low on funds. Please ping jeremy@lbry.io so he can refill it, then try again.');
}
else
{
Slack::sendErrorIfProd('Error claiming github dev credits: ' . var_export($response, true));
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR,
'Failed to send credits. This is an error on our side. Please email jeremy@lbry.io if it persists.');
}
}
}
Lock::freeLock($lock);
$lock = null;
}
}
}
return Controller::redirect('/developer-program');
}
}

View file

@ -0,0 +1,228 @@
<?php
class DeveloperActions extends Actions
{
const DEVELOPER_REWARD = 250,
API_DOC_URL = 'https://lbryio.github.io/lbry/api/';
public static function executeQuickstart(string $step = null)
{
$stepLabels = [
'' => 'Home',
'install' => 'Installation',
'api' => 'The API',
'credits' => 'Credits'
];
$allSteps = array_keys($stepLabels);
$currentStep = $step ?: $allSteps[0];
$viewParams = [
'currentStep' => $currentStep,
'stepLabels' => $stepLabels
];
if ($currentStep !== 'all')
{
if (!isset($stepLabels[$currentStep]))
{
Controller::redirect('/quickstart');
}
$stepNum = array_flip($allSteps)[$currentStep];
$viewParams += [
'stepNum' => $stepNum,
'prevStep' => $stepNum === 0 ? null : $allSteps[$stepNum - 1],
'nextStep' => $stepNum + 1 >= count($allSteps) ? null : $allSteps[$stepNum + 1],
];
}
return ['developer/quickstart', $viewParams];
}
public static function prepareQuickstartOnePartial(array $vars)
{
return $vars + [
'version' => '0.8.4'
];
}
public static function executeDeveloperProgram()
{
return ['developer/developer-program', [
'defaultWalletAddress' => Session::get(Session::KEY_DEVELOPER_CREDITS_WALLET_ADDRESS),
'error' => Session::getFlash(Session::KEY_DEVELOPER_CREDITS_ERROR),
'success' => Session::getFlash(Session::KEY_DEVELOPER_CREDITS_SUCCESS)
]];
}
public static function prepareFormNewPartial(array $vars)
{
return $vars + [
'defaultWalletAddress' => Session::get(Session::KEY_DEVELOPER_CREDITS_WALLET_ADDRESS),
'error' => Session::getFlash(Session::KEY_DEVELOPER_CREDITS_ERROR),
'success' => Session::getFlash(Session::KEY_DEVELOPER_CREDITS_SUCCESS)
];
}
public static function prepareFormCreditsPublishPartial(array $vars)
{
return $vars + [
'defaultWalletAddress' => Session::get(Session::KEY_DEVELOPER_CREDITS_WALLET_ADDRESS),
'error' => Session::getFlash(Session::KEY_DEVELOPER_CREDITS_ERROR),
'success' => Session::getFlash(Session::KEY_DEVELOPER_CREDITS_SUCCESS)
];
}
public static function executeDeveloperProgramPost()
{
$walletAddress = trim(Request::getPostParam('wallet'));
Session::set(Session::KEY_DEVELOPER_CREDITS_WALLET_ADDRESS, $walletAddress);
if (!$walletAddress)
{
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'Please provide a wallet address.');
}
elseif (!preg_match('/^b[1-9A-HJ-NP-Za-km-z]{33}$/', $walletAddress))
{
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'This does not appear to be a valid wallet address.');
}
else
{
if (!Config::get('github_developer_credits_client_id'))
{
throw new Exception('no github client id');
}
$githubParams = [
'client_id' => Config::get('github_developer_credits_client_id'),
'redirect_uri' => Request::getHostAndProto() . '/developer-program/callback',
'scope' => 'user:email public_repo',
'allow_signup' => false
];
return Controller::redirect('https://github.com/login/oauth/authorize?' . http_build_query($githubParams));
}
return Controller::redirect('/developer-program');
}
public static function executeDeveloperProgramGithubCallback()
{
$code = Request::getParam('code');
$walletAddress = Session::get(Session::KEY_DEVELOPER_CREDITS_WALLET_ADDRESS);
if (!$walletAddress)
{
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'Your wallet address disappeared while authenticated with GitHub.');
}
elseif (!$code)
{
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'This does not appear to be a valid response from GitHub.');
}
else
{
$authResponseData = Curl::post('https://github.com/login/oauth/access_token', [
'code' => $code,
'client_id' => Config::get('github_developer_credits_client_id'),
'client_secret' => Config::get('github_developer_credits_client_secret')
], [
'headers' => ['Accept: application/json'],
'json_response' => true
]);
if (!$authResponseData || !isset($authResponseData['access_token']))
{
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'Request to GitHub failed.');
}
elseif (isset($authResponseData['error_description']))
{
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'GitHub replied: ' . $authResponseData['error_description']);
}
else
{
$accessToken = $authResponseData['access_token'];
$starResponseData = Curl::put('https://api.github.com/user/starred/lbryio/lbry', [], [
'headers' => ['Authorization: token ' . $accessToken, 'Accept: application/json', 'User-Agent: lbryio', 'Content-Length: 0'],
'json_response' => true
]);
$userResponseData = Curl::get('https://api.github.com/user', [], [
'headers' => ['Authorization: token ' . $accessToken, 'Accept: application/json', 'User-Agent: lbryio'],
'json_response' => true
]);
if (!$userResponseData || !$userResponseData['created_at'] || $starResponseData !== [])
{
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'Received unexpected response from GitHub. Perhaps authorization was revoked?');
}
elseif(date('Y-m-d', strtotime($userResponseData['created_at'])) > '2017-01-30')
{
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'This GitHub account is too recent.');
}
else
{
$lockName = 'github_dev_credits_write';
$dataFile = ROOT_DIR . '/data/writeable/github_developer_credits';
$lock = Lock::getLock($lockName, true); // EXCLUSIVE LOCK. IF SENDING CREDITS IS SLOW, THIS COULD BLOCK USERS
$existing = is_file($dataFile) ? json_decode(file_get_contents($dataFile), true) : [];
if (isset($existing[$userResponseData['login']]) || isset($existing[$userResponseData['id']]))
{
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'You (' . $userResponseData['login'] . ') already received credits.');
}
else
{
try
{
$response =
Curl::post('http://localhost:5279/lbryapi', [
'method' => 'send_amount_to_address',
'params' => [['amount' => 250, 'address' => $walletAddress]],
], [
'json_data' => true,
'json_response' => true,
]);
}
catch (Exception $e)
{
$response = null;
}
$response = [true];
if ($response === [true])
{
$existing[$userResponseData['id']] = [$userResponseData['email'], $walletAddress, date('Y-m-d H:i:s'), $userResponseData['login']];
file_put_contents($dataFile, json_encode($existing));
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_SUCCESS,
'Credits on their way to address ' . $walletAddress . ' for GitHub user ' . $userResponseData['login'] . '. It may take up to a minute for them to arrive.');
}
elseif (is_array($response) && (isset($response['faultString']) && stripos($response['faultString'], 'InsufficientFundsError') !== false))
{
Slack::sendErrorIfProd('Github dev credits need a refill');
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR,
'Our wallet is running low on funds. Please ping jeremy@lbry.io so he can refill it, then try again.');
}
else
{
Slack::sendErrorIfProd($response === null ?
'Error connecting to LBRY API via cURL' :
'Error of unknown origin in sending Github dev credits' . var_export($response, true)
);
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'Failed to send credits. This is an error on our side. Please email jeremy@lbry.io if it persists.');
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR,
'Failed to send credits. This is an error on our side. Please email jeremy@lbry.io if it persists.');
}
}
Lock::freeLock($lock);
$lock = null;
}
}
}
return Controller::redirect('/developer-program');
}
}

View file

@ -69,8 +69,8 @@ class Curl
$ch = curl_init();
// curl_setopt($ch, CURLOPT_VERBOSE, true);
// curl_setopt($ch, CURLOPT_STDERR, fopen(sys_get_temp_dir().'/curl-debug-'.date('Ymd-His'), 'w+'));
curl_setopt($ch, CURLOPT_VERBOSE, true);
curl_setopt($ch, CURLOPT_STDERR, fopen(sys_get_temp_dir().'/curl-debug-'.date('Ymd-His'), 'w+'));
if ($ch === false || $ch === null)
{

View file

@ -0,0 +1,25 @@
<form method="POST" action="/developer-program/post" class="form-inset">
<h4 style="margin-top: 0">Receive Credits</h4>
<?php if ($error): ?>
<div class="notice notice-error spacer1"><?php echo $error ?></div>
<?php elseif ($success): ?>
<div class="notice notice-success spacer1"><?php echo $success ?></div>
<?php endif ?>
<div class="form-row">
<label for="wallet">Wallet Address</label>
<div class="form-input">
<input type="text" name="wallet" value="<?php echo $defaultWalletAddress ?>"
class="required standard input-wallet" placeholder="bYnFQUPTTDM1BYNCxgxKEav4FFQsrgDBoE">
</div>
</div>
<div class="form-row">
<label for="wallet">Publishing Transaction ID</label>
<div class="form-input">
<input type="text" name="wallet" value="<?php echo '' ?>"
class="required standard input-wallet" placeholder="IamATransactionID">
</div>
</div>
<div class="spacer-half">
<input type="submit" value="Continue" class="btn-primary">
</div>
</form>

View file

@ -0,0 +1,20 @@
<form method="POST" action="/developer-program/post" class="form-inset">
<h4 style="margin-top: 0">Receive Credits</h4>
<?php if ($error): ?>
<div class="notice notice-error spacer1"><?php echo $error ?></div>
<?php elseif ($success): ?>
<div class="notice notice-success spacer1"><?php echo $success ?></div>
<?php endif ?>
<div class="form-row">
<label for="wallet">Wallet Address</label>
<div class="form-input">
<input type="text" name="wallet" value="<?php echo $defaultWalletAddress ?>"
class="required standard input-wallet" placeholder="bYnFQUPTTDM1BYNCxgxKEav4FFQsrgDBoE">
</div>
</div>
<div class="spacer-half">
<input type="submit" value="Continue to GitHub" class="btn-primary">
</div>
<div class="meta">We require a GitHub account to prevent abuse. This will record your email (no spam) and mark you as interested in the lbry repo.
No GitHub account? No problem! Join our <a href="https://slack.lbry.io" class="link-primary">Slack channel</a> and post an introduction in #tech.</div>
</form>

View file

@ -0,0 +1,35 @@
<h3 id="api">The API</h3>
<p>
When running, the LBRY daemon provides a JSON-RPC server running at <span class="code-plain">https://localhost:5279/lbryapi</span>.
</p>
<p>
It can be accessed via cURL or any other utility capable of making HTTPS GET and POST requests. So, basically anything, including possibly your toaster.
</p>
<p>
To verify the LBRY daemon is running correctly, let's try looking up a name:
</p>
<code class="code-bash"><span class="code-bash__prompt">$</span>curl 'http://localhost:5279/lbryapi' --data '{"method":"resolve_name","params":[{"name":"what"}]}'
[
{
"ver": "0.0.3",
"description": "What is LBRY? An introduction with Alex Tabarrok",
"license": "LBRY inc",
"title": "What is LBRY?",
"author": "Samuel Bryan",
"language": "en",
"sources": {
"lbry_sd_hash": "d5169241150022f996fa7cd6a9a1c421937276a3275eb912790bd07ba7aec1fac5fd45431d226b8fb402691e79aeb24b"
},
"content_type": "video\/mp4",
"nsfw": false,
"thumbnail": "https:\/\/s3.amazonaws.com\/files.lbry.io\/logo.png"
}
]</code>
<p>Above, we called the method <span class="code-plain"><a href="<?php echo DeveloperActions::API_DOC_URL ?>#resolve_name" class="link-primary">resolve_name</a></span> for the URL <span class="code-plain">lbry://what</span>. This returned the metadata associated with the URL.</p>
<p>Now let's download it. This time we're going to call the method <span class="code-plain">get</span> with the same parameters.</p>
<code class="code-bash"><span class="code-bash__prompt">$</span>curl 'http://localhost:5279/lbryapi' --data '{"method":"get","params":[{"name":"what"}]}'
["d5169241150022f996fa7cd6a9a1c421937276a3275eb912790bd07ba7aec1fac5fd45431d226b8fb402691e79aeb24b"]</code>
<p>The LBRY API consists about 50 calls, all related to discovering, distributing, and purchasing content. <a class="link-primary" href="http://lbryio.github.io/lbry/api/">View the full API documentation</a>.</p>
<p>You can also list all of the commands available by calling the <span class="code-plan">help</span> command.</p>
<code class="code-bash"><span class="code-bash__prompt">$</span>curl 'http://localhost:5279/lbryapi' --data '{"method":"help"}'
</code>

View file

@ -0,0 +1,35 @@
<h3 id="credits">Credits</h3>
<p>So far, everything we've done with LBRY has been free. However, some actions, such as reserving a name or purchasing paid content, require credits.</p>
<p>To receive credits, first generate a wallet address:</p>
<code class="code-bash"><span class="code-bash__prompt">$</span>curl 'http://localhost:5279/lbryapi' --data '{"method":"wallet_new_address","params":[]}'
["bbFxRyWCFRkA9YcuuZD8nE7XTLUxYnddTs"]</code>
<p>Enter this address in the form below and we'll send you 50 credits.</p>
<div class="quickstart__claim-form content-light content">
<?php echo View::render('developer/_formNew') ?>
</div>
<p>Next, confirm you've received your credits by calling <span class="code-plain">wallet_balance</span>:</p>
<code class="code-bash"><span class="code-bash__prompt">$</span>curl 'http://localhost:5279/lbryapi' --data '{"method":"wallet_balance"}'
[50.00000000]</code>
<h3 id="publish">Publishing</h3>
<p>Publishing to LBRY is just as easy as everything else! If you publish something, we'll send you an additional 200 LBC for further use.</p>
<p>Not sure what to publish? We recommend your favorite picture or home video. Or just grab something from <a class="link-primary" href="https://archive.org/details/movies">here</a>.</p>
<code class="code-bash"><span class="code-bash__prompt">$</span>curl 'http://localhost:5279/lbryapi' --data '{"method":"publish", "params": [{
"name": "electricsheep",
"file_path": "\\home\kauffj\\Desktop\\electric-sheep.mp4",
"bid": 1,
"metadata": {"what goes here": "who knows if you do not work for LBRY, certainly you will not be able to figure it out from response messages or API docs"
}]}'
[whatever this response looks like]</code>
<div class="quickstart__claim-form content-light content">
<?php echo View::render('developer/_formCreditsPublish') ?>
</div>
<h3 id="community">You Did It! What's Next?</h3>
<p>
Start building something awesome! LBRY works as a discovery and distribution backend for everything from films to CAD files.
</p>
<p>
<a href="http://slack.lbry.io" class="link-primary">Join our Slack Channel</a> to interact with LBRY developers and other community members. Please visit the #dev room (note: this is not a default channel).
</p>
<p>
Visit our <a href="https://github.com/lbryio" class="link-primary">GitHub page</a> to view the source code or report issues.
</p>

View file

@ -0,0 +1,21 @@
<div class="meta">Quickstart Home</div>
<h2>
LBRY is an open-source "<a href="http://www.usv.com/blog/fat-protocols" class="link-primary">fat</a>" protocol, providing
decentralized content discovery and distribution.</h2>
<h2>
In just a few minutes, you will have:
</h2>
<ul>
<li><h3>Learned the basics of the LBRY API.</h3></li>
<li><h3>Earned $5.67<sup>1</sup> for downloading a hilarious film starring David Cross.</h3></li>
<li><h3>Irrevocably inscribed a piece of knowledge. Possibly of a cat.</h3>
<div class="meta">
<sup>1</sup>USD price equivalent of 250 LBC as received from the <a href="https://poloniex.com/exchange#btc_lbc" class="link-primary">Poloneix</a> exchange.
LBC is a cryptographic blockchain token used to secure and administer LBRY's shared, distributed catalog. The future is weird.
</div>
</li>
</ul>
<p class="text-center">
<a href="/quickstart/<?php echo $firstStep ?>" class="btn-alt">Begin the Guide</a>
</p>
<div class="meta">Not a guide lover? <a href="/quickstart/all" class="link-primary"> Here it is all on one page</a>.</div>

View file

@ -0,0 +1,33 @@
<h3>Download</h3>
<table class="quickstart__table">
<thead>
<tr>
<th>macOS <span class="icon-apple"></span></th>
<th>Linux <span class="icon-linux"></span></th>
<th>Windows <span class="icon-windows"></span></th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="https://lbry.io/get/lbry.dmg">Download .dmg</a></td>
<td><a href="https://lbry.io/get/lbry.deb">Download .deb</a></td>
<td><a href="https://lbry.io/get/lbry.msi">Download .msi</a></td>
</tr>
</tbody>
</table>
<p>
If you prefer to compile from source or are not on one of the above operating systems, follow
<a class="link-primary" href="https://github.com/lbryio/lbry/blob/master/INSTALL.md">this guide</a>.
</p>
<h3>Run</h3>
<p>
Launch the deamon to run as a background process:
</p>
<p>
<code class="code-bash"><span class="code-bash__prompt">$</span>lbrynet-daemon</code>
</p>
<p>While running, the daemon will provide a JSON-RPC interface on localhost. We'll learn how to interact with that next.</p>
<?php /*
<div class="meta spacer1">macOS and Windows do not currently bundle the daemon separately. Just launch the full app and the API will still be available. This will be resolved in v0.9.</div>
*/ ?>
<div class="meta">The first time you run the daemon, it must catch-up with most recent blockheaders. This can take a few minutes.</div>

View file

@ -5,7 +5,7 @@
<main >
<div class="content content-light markdown">
<h1>Developer Program</h1>
<p>All developers with a GitHub account prior to January 31st, 2017 are eligible for <?php echo AcquisitionActions::DEVELOPER_REWARD ?> free credits.</p>
<p>All developers with a GitHub account prior to January 31st, 2017 are eligible for <?php echo DeveloperActions::DEVELOPER_REWARD ?> free credits.</p>
<p>To claim your credits, enter a wallet address in the form below and authenticate with GitHub.</p>
<p>
We will store your GitHub username and email address, but nothing else.

View file

@ -0,0 +1,52 @@
<?php NavActions::setNavUri('/learn') ?>
<?php Response::setMetaDescription('Be up and running with the LBRY API in just a few minutes.') ?>
<?php Response::setMetaTitle('LBRY Quickstart') ?>
<?php echo View::render('nav/_header', ['isDark' => false, 'isAbsolute' => false]) ?>
<main class="cover-stretch-wrap">
<div class="cover cover-center cover-dark cover-dark-grad">
<div class="quickstart">
<?php if ($currentStep === 'all'): ?>
<div class="content content-dark">
<div class="meta"><a href="/quickstart" class="link-primary">Quickstart Home</a></div>
<h1>Quickstart</h1>
</div>
<?php foreach(array_filter(array_keys($stepLabels)) as $step): ?>
<section>
<div class="content content-dark">
<?php echo View::render('developer/_quickstart' . ucfirst($step)) ?>
</div>
</section>
<?php endforeach ?>
<?php elseif ($stepNum > 0): ?>
<div class="content content-dark">
<h1>Quickstart: <?php echo $stepLabels[$currentStep] ?></h1>
</div>
<ol class="quickstart__progress-bar">
<?php $stepCounter = 0 ?>
<?php foreach($stepLabels as $step => $stepLabel): ?>
<li class="<?php echo $currentStep == $step ? 'active' : '' ?> <?php echo ++$stepCounter <= $stepNum ? 'completed' : '' ?>">
<a href="/quickstart<?php echo $step ? '/' . $step : '' ?>"><?php echo $stepLabel ?></a>
</li>
<?php endforeach ?>
</ol>
<div class="content content-dark">
<div class="spacer2">
<?php echo View::render('developer/_quickstart' . ucfirst($currentStep)) ?>
</div>
<?php if ($nextStep): ?>
<div>
<a href="/quickstart/<?php echo $nextStep ?>" class="btn-alt">Next: <?php echo $stepLabels[$nextStep] ?> &raquo;</a>
</div>
<?php endif ?>
</div>
<?php else: ?>
<div class="content content-dark">
<?php echo View::render('developer/_quickstartHome', [
'firstStep' => array_keys($stepLabels)[1]
]) ?>
</div>
<?php endif ?>
</div>
</div>
</main>
<?php echo View::render('nav/_footer') ?>

View file

@ -12,7 +12,7 @@
'LBRY' ?>
<title><?php echo $title ?></title>
<link href='https://fonts.googleapis.com/css?family=Raleway:300,300italic,400,400italic,700' rel='stylesheet' type='text/css'>
<link href='https://fonts.googleapis.com/css?family=Raleway:500,500italic,700' rel='stylesheet' type='text/css'>
<link href="/css/all.css" rel="stylesheet" type="text/css" />
<link rel="apple-touch-icon" sizes="60x60" href="/img/fav/apple-touch-icon-60x60.png">
<link rel="apple-touch-icon" sizes="114x114" href="/img/fav/apple-touch-icon-114x114.png">

View file

@ -1,135 +0,0 @@
<?php NavActions::setNavUri('/learn') ?>
<?php Response::setMetaDescription('Be up and running with the LBRY API in just a few minutes.') ?>
<?php Response::setMetaTitle('LBRY Quickstart') ?>
<?php echo View::render('nav/_header', ['isDark' => false, 'isAbsolute' => false]) ?>
<main class="content content-light markdown">
<h1>Quickstart</h1>
<p>This step-by-step guide will have you running LBRY and interacting with the API in just a few minutes.</p>
<p>This guide is for programmers and other technical users. For consumer usage of LBRY, please <a href="/get" class="link-primary">go here</a>.</p>
<h3>What's Covered</h3>
<ol class="table-of-contents">
<li><a href="#installation" class="link-primary">Installation</a></li>
<li><a href="#running-lbry" class="link-primary">Running LBRY</a></li>
<li><a href="#api" class="link-primary">The API</a></li>
<li><a href="#credits" class="link-primary">Credits</a></li>
<li><a href="#community" class="link-primary">Community & Issues</a></li>
</ol>
<section>
<h3 id="installation">1. Installation</h3>
<p>The easiest way to install LBRY is to use a pre-packaged binary. We provide binaries for Windows, macOS, and Debian-based Linux.</p>
<table class="content">
<thead>
<tr>
<th>macOS <span class="icon-apple"></span></th>
<th>Linux <span class="icon-linux"></span></th>
<th>Windows <span class="icon-windows"></span></th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="https://lbry.io/get/lbry.dmg">Download DMG</a></td>
<td><a href="https://lbry.io/get/lbry.deb">Download DEB</a></td>
<td><a href="https://lbry.io/get/lbry.msi">Download MSI</a></td>
</tr>
</tbody>
</table>
<p>
If you prefer to compile from source or are not on one of the above operating systems, follow
<a class="link-primary" href="https://github.com/lbryio/lbry/blob/master/INSTALL.md">this guide</a>.
</p>
</section>
<section>
<h3 id="running-lbry">2. Running LBRY</h3>
<p>
Launch the deamon to run as a background process:
</p>
<p>
<code class="code-bash"><span class="code-bash__prompt">$</span>lbrynet-daemon</code>
</p>
<p>The first time you run the daemon, it must catch-up with most recent blockheaders. This can take several minutes.</p>
<div class="meta">macOS and Windows do not currently bundle the daemon separately. Just launch the full app and the API will still be available. This will be resolved in v0.9.</div>
</section>
<section>
<h3 id="api">3. The API</h3>
<p>
When running, the LBRY daemon provides a JSON-RPC server running at <code>https://localhost:5279/lbryapi</code>.
</p>
<p>
It can be accessed via cURL or any other utility capable of making HTTPS GET and POST requests.
</p>
<p>
To verify the LBRY daemon is running correctly and responding to requests, run:
</p>
<code class="code-bash"><span class="code-bash__prompt">$</span>curl 'http://localhost:5279/lbryapi' --data '{"method":"status","params":[]}'
[
{
"connection_status": {
"message": "No connection problems detected",
"code": "connected"
},
"is_first_run": false,
"is_running": true,
"blocks_behind": 0,
"startup_status": {
"message": "Started lbrynet",
"code": "started"
}
}
]</code>
<p>This makes it easy to interact with the LBRY API in the programming language of your choice. Here's another example:</p>
<code class="code-bash"><span class="code-bash__prompt">$</span>curl 'http://localhost:5279/lbryapi' --data '{"method":"resolve_name","params":[{"name":"what"}]}'
[
{
"ver": "0.0.3",
"description": "What is LBRY? An introduction with Alex Tabarrok",
"license": "LBRY inc",
"title": "What is LBRY?",
"author": "Samuel Bryan",
"language": "en",
"sources": {
"lbry_sd_hash": "d5169241150022f996fa7cd6a9a1c421937276a3275eb912790bd07ba7aec1fac5fd45431d226b8fb402691e79aeb24b"
},
"content_type": "video\/mp4",
"nsfw": false,
"thumbnail": "https:\/\/s3.amazonaws.com\/files.lbry.io\/logo.png"
}
]</code>
<p>LBRY can be used to build everything from a censorship-proof image host, to a store for 3D printing files, to distribute large files or datasets, or use cases even we can't imagine!</p>
<p><a class="btn-alt" href="http://lbryio.github.io/lbry/api/">View Full API Documentation</a></p>
</section>
<section>
<h3 id="credits">4. Getting Credits</h3>
<p>Many actions, such as reserving a name or purchasing paid content, require credits.</p>
<p>To receive credits, first generate a wallet address:</p>
<code class="code-bash"><span class="code-bash__prompt">$</span>curl 'http://localhost:5279/lbryapi' --data '{"method":"wallet_new_address","params":[]}'
["bbFxRyWCFRkA9YcuuZD8nE7XTLUxYnddTs"]</code>
<p>Use this address to get credits in one of two ways:</p>
<div class="row-fluid">
<div class="span6">
<h4>4a) Receive Free Credits</h4>
<p>
All developers with a valid GitHub account are eligible to receive <?php echo AcquisitionActions::DEVELOPER_REWARD ?> free credits.
</p>
<a href="/developer-program" class="btn-alt">Claim Your Free Credits</a>
</div>
<div class="span6">
<h4>4b) Purchase Credits</h4>
<p>
Credits can be bought on <a href="https://lbry.io/faq/exchanges" class="link-primary">a variety of exchanges</a>.
After purchasing, send them to the address generated above.
</p>
</div>
</div>
</section>
<section>
<h3 id="community">5. Community & Issues</h3>
<p>
<a href="http://slack.lbry.io" class="link-primary">Join our Slack Channel</a> to interact with LBRY developers and other community members. Please visit the #dev room (note: this is not a default channel).
</p>
<p>
Visit our <a href="https://github.com/lbryio" class="link-primary">GitHub page</a> to view the source code or report issues.
</p>
</section>
</div>
</main>
<?php echo View::render('nav/_footer') ?>

View file

@ -0,0 +1,63 @@
<?php NavActions::setNavUri('/learn') ?>
<?php Response::setMetaDescription('Be up and running with the LBRY API in just a few minutes.') ?>
<?php Response::setMetaTitle('LBRY Quickstart') ?>
<?php echo View::render('nav/_header', ['isDark' => false, 'isAbsolute' => false]) ?>
<main class="cover-stretch-wrap">
<div class="cover cover-center cover-dark cover-dark-grad">
<div class="content content-dark content-readable">
<h1>Set Up</h1>
<p>This step-by-step guide will have you running LBRY and interacting with the API in just a few minutes.</p>
<p>This guide is for programmers and other technical users. For consumer usage of LBRY, please <a href="/get" class="link-primary">go here</a>.</p>
<h3>What's Covered</h3>
<ol class="table-of-contents">
<li><a href="#installation" class="link-primary">Installation</a></li>
<li><a href="#running-lbry" class="link-primary">Running LBRY</a></li>
<li><a href="#api" class="link-primary">The API</a></li>
<li><a href="#credits" class="link-primary">Credits</a></li>
<li><a href="#community" class="link-primary">Community & Issues</a></li>
</ol>
<section>
<h3 id="installation">1. Installation</h3>
<p>The easiest way to install LBRY is to use a pre-packaged binary. We provide binaries for Windows, macOS, and Debian-based Linux.</p>
<table class="content">
<thead>
<tr>
<th>macOS <span class="icon-apple"></span></th>
<th>Linux <span class="icon-linux"></span></th>
<th>Windows <span class="icon-windows"></span></th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="https://lbry.io/get/lbry.dmg">Download DMG</a></td>
<td><a href="https://lbry.io/get/lbry.deb">Download DEB</a></td>
<td><a href="https://lbry.io/get/lbry.msi">Download MSI</a></td>
</tr>
</tbody>
</table>
<p>
If you prefer to compile from source or are not on one of the above operating systems, follow
<a class="link-primary" href="https://github.com/lbryio/lbry/blob/master/INSTALL.md">this guide</a>.
</p>
</section>
<section>
<h3 id="running-lbry">2. Running LBRY</h3>
<p>
Launch the deamon to run as a background process:
</p>
<p>
<code class="code-bash"><span class="code-bash__prompt">$</span>lbrynet-daemon</code>
</p>
<p>The first time you run the daemon, it must catch-up with most recent blockheaders. This can take several minutes.</p>
<div class="meta">macOS and Windows do not currently bundle the daemon separately. Just launch the full app and the API will still be available. This will be resolved in v0.9.</div>
</section>
<section>
<section>
</div>
</div>
</div>
</main>
<?php echo View::render('nav/_footer') ?>

View file

@ -96,6 +96,7 @@
<p>Here is a sample key-value entry in the LBRY blockchain. Here, wonderfullife is the key, and the rest of the description is the value.</p>
<code class="code-bash"><span class="code-bash__prompt">$</span>lbrynet-cli resolve_name name=wonderfullife
<span class="code-bash__kw1">wonderfullife</span> : {
<span class="code-bash__kw2">title</span>: "Its a Wonderful Life",
<span class="code-bash__kw2">description</span>: "An angel helps a compassionate but despairingly frustrated businessman by showing what life would have been like if he never existed.",

View file

@ -109,7 +109,7 @@
margin-top: $spacing-vertical;
}
}
.post-content table, table.content
.post-content table, table.post-content-table
{
margin-bottom: $spacing-vertical;
word-wrap: break-word;
@ -135,7 +135,6 @@
font-size: 0.9em;
padding: $spacing-vertical/4+1 8px $spacing-vertical/4-2;
text-align: left;
border-bottom: 1px solid #e2e2e2;
img
{
vertical-align: text-bottom;
@ -145,37 +144,11 @@
{
vertical-align: middle;
}
tr.thead:not(:first-child) th
{
border-top: 1px solid #e2e2e2;
}
tfoot td
{
padding: $spacing-vertical / 2 8px;
font-size: .85em;
}
tbody
{
tr
{
&:nth-child(even):not(.odd)
{
background-color: #f4f4f4;
}
&:nth-child(odd):not(.even)
{
background-color: white;
}
&.thead
{
background: none;
}
td
{
border: 0 none;
}
}
}
&:last-child
{
@ -187,6 +160,39 @@
width: 100%;
}
}
.post-content table
{
thead th, > tr:first-child th
{
border-bottom: 1px solid #e2e2e2;
}
tr.thead:not(:first-child) th
{
border-top: 1px solid #e2e2e2;
}
tbody
{
tr
{
&.thead
{
background: none;
}
td
{
border: 0 none;
}
&:nth-child(even):not(.odd)
{
background-color: #f4f4f4;
}
&:nth-child(odd):not(.even)
{
background-color: white;
}
}
}
}
.post-author-spotlight
{

View file

@ -7,9 +7,13 @@ pre, code
code
{
padding: 3px 5px;
font-family: Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, monospace, serif;
font-family: $font-mono;
color: darken($color-primary, 10%);
}
.code-plain
{
font-family: $font-mono;
}
pre
{
> code {

View file

@ -128,11 +128,6 @@
&:last-child { margin-bottom: $spacing-vertical / 2; }
padding-left: 2em;
counter-reset: li-counter;
&.table-of-contents > li
{
line-height: 2em;
&:before { top: -0.1em; }
}
> li
{
position: relative;

View file

@ -20,6 +20,7 @@ $max-post-content-width: 800px;
$font-header: 'Raleway', sans-serif;
$font-body: 'Raleway', sans-serif;
$font-mono: Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, monospace, serif;
$font-size-h1: 2.4em;
$font-size-h2: 2.0em;

98
web/scss/_quickstart.scss Normal file
View file

@ -0,0 +1,98 @@
@import "global";
.quickstart
{
max-width: 860px;
}
.quickstart__table
{
margin: 0 auto $spacing-vertical;
td, th
{
border-right: 1px dotted #eee;
padding: 4px 20px;
&:last-child
{
border-right: 0 none;
}
}
}
.quickstart__section
{
margin-bottom: $spacing-vertical * 3;
}
.quickstart__claim-form
{
margin: $spacing-vertical * 2 0;
}
.quickstart__progress-bar
{
margin: $spacing-vertical * 3 80px;
background: #ddd;
display: flex;
height: 16px;
list-style: none;
padding: 0;
position: relative;
> li {
flex: auto;
list-style: none;
position: relative;
&:first-child {
max-width: 0;
> a {
// arbitrary values
// since % won't work
right: -30px;
width: 60px;
}
}
&:before {
background: #ddd;
border-radius: 50%;
content: "";
display: block;
height: 24px;
right: -12px;
position: absolute;
top: -4px;
width: 24px;
}
}
a {
cursor: pointer;
color: #ccc;
padding: 4px 0;
position: absolute;
right: -25%;
text-align: center;
text-decoration: underline;
top: -36px;
width: 50%;
}
$color-indicator: #777;
.completed {
background: lighten($color-indicator, 10%);
&:before {
background: lighten($color-indicator, 10%);
}
}
.active {
a { font-weight: bold; }
background: lighten($color-indicator, 10%);
&:before {
background: lighten($color-indicator, 16%);
box-shadow: 0 1px 1px rgba(0,0,0,0.3);
}
}
}

View file

@ -15,4 +15,5 @@
@import "blog";
@import "bounty";
@import "roadmap";
@import "quickstart";
@import "social";