Compare commits

..

No commits in common. "master" and "imgsrc-fix" have entirely different histories.

65 changed files with 2540 additions and 4930 deletions

3
.gitignore vendored
View file

@ -1,8 +1,7 @@
/vendor/*
/config/app.php
/config/lbry.php
/tmp/*
/logs/*
lbryexplorer.zip
lbryexplorer.komodoproject
.komodotools
/.gtm/

View file

@ -5,6 +5,7 @@ dist: trusty
sudo: false
php:
- 5.6
- 7.0
- 7.1

View file

@ -1,9 +1,10 @@
The MIT License (MIT)
Copyright (c) 2017-2018 LBRY Inc.
Copyright (c) 2017-2018 LBRY Inc
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish,distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -1,95 +0,0 @@
# LBRY Block Explorer
A simple PHP block explorer for browsing transactions and claims on the [LBRY](https://lbry.com) blockchain. The explorer was developed using CakePHP which is a model-view-controller (MVC) PHP framework.
## Requirements
There are some prerequisites that need to be installed before the explorer can be accessed.
* Web server - Apache, caddy or nginx
* [lbrycrd](https://github.com/lbryio/lbrycrd) with txindex turned on
* MariaDB 10.2 or higher
* Redis Server (optional, only required for the CakePHP redis cache engine, or to run `forevermempool`)
* PHP 7.4 or higher
* php-fpm
* [igbinary extension](https://github.com/igbinary/igbinary)
* [phpredis extension](https://github.com/phpredis/phpredis)
* composer (PHP package manager)
on ubuntu you may use this to install php requirements
```bash
sudo apt install php7.4-gmp php7.4-intl php7.4-mbstring php7.4-mysql php7.4-bcmath php7.4-gd
```
### Installation steps
* Clone the Github repository. `git clone https://github.com/lbryio/block-explorer`
* Create a MariaDB database using the DDL found in `block-explorer/sql/lbryexplorer.ddl.sql`
* Change the working directory to the cloned directory and run composer.
```
cd block-explorer
composer update
```
* Create the directories, `tmp` and `logs` in the `block-explorer` folder if they have not been created yet, and make sure that they are writable by the web server.
* Copy `config/app.default.php` to `config/app.php`. Edit the database connection values to correspond to your environment.
* Copy `config/lbry.default.php` to `config/lbry.php`. Update the values for LBRY RPC URL and the Redis URL to correspond to your environment.
* Configure your web server with the host root folder set to `<path to>/block-explorer/webroot` where `<path to>` is the absolute path to the configuration. Here is a sample nginx configuration. You can make changes to this configuration to correspond to your environment.
```
server {
listen 80;
server_name my.explorer.com;
root /var/www/block-explorer/webroot;
index index.php;
location / {
try_files $uri $uri/ /index.php?$args;
}
# pass the PHP scripts to FastCGI server listening on the php-fpm socket
location ~ \.php$ {
try_files $uri =404;
include /etc/nginx/fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_ignore_client_abort on;
fastcgi_param PHP_AUTH_USER $remote_user;
fastcgi_param PHP_AUTH_PW $http_authorization;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
```
* Restart your web server.
### Cron jobs
There are a few scripts which can be set up as cron jobs or scheduled tasks.
#### blocks.sh
Detect new LBRY blocks. Can also be configured to be triggered using the lbrycrd `blocknotify` flag. This cron will create new blocks obtained from lbrycrd starting from the highest block number in the database, and then create the corresponding block transactions. If there are pending transactions created by the forevermempool script, they will be automatically associated with the respective blocks.
#### claimindex.sh
Create claims found on the LBRY blockchain in the database. This requires the Python decoder to be running in the background.
#### pricehistory.sh
Get the current LBC price in USD and store the value in the `PriceHistory` table. This also caches the most recent price in Redis.
#### forever.sh
Run the `forevermempool` script, and restart if necessary. The `forevermempool` script checks the LBRY blockchain mempool every second and creates transactions found in the database. The script makes use of Redis for caching the pending transaction IDs.
## Usage
Launch the URL for the configured web server root in a browser.
## Contributing
Contributions to this project are welcome, encouraged, and compensated. For more details, see https://lbry.tech/contribute
## License
This project is MIT licensed. For the full license, see [LICENSE](LICENSE).
## Security
We take security seriously. Please contact security@lbry.io regarding any security issues. Our PGP key is [here](https://keybase.io/lbry/key.asc) if you need it.
## Contact
The primary contact for this project is [@akinwale](https://github.com/akinwale) (akinwale@lbry.com)

View file

@ -6,15 +6,14 @@
"license": "MIT",
"require": {
"php": ">=5.6",
"cakephp/cakephp": "3.7.7",
"cakephp/cakephp": "3.4.*",
"mobiledetect/mobiledetectlib": "2.*",
"cakephp/migrations": "~1.0",
"psr/simple-cache": "^1.0.0",
"cakephp/plugin-installer": "~1.0",
"mdanter/ecc": "^0.5.0",
"mdanter/ecc": "^0.4.2",
"nesbot/carbon": "~1.18",
"predis/predis": "^1.1.1",
"endroid/qr-code": "^3.5"
"endroid/qrcode": "^2.2.2",
"predis/predis": "^1.1.1"
},
"require-dev": {
"psy/psysh": "@stable",
@ -41,6 +40,7 @@
"scripts": {
"post-install-cmd": "App\\Console\\Installer::postInstall",
"post-create-project-cmd": "App\\Console\\Installer::postInstall",
"post-autoload-dump": "Cake\\Composer\\Installer\\PluginInstaller::postAutoloadDump",
"check": [
"@test",
"@cs-check"
@ -49,11 +49,5 @@
"cs-fix": "phpcbf --colors --standard=vendor/cakephp/cakephp-codesniffer/CakePHP ./src ./tests",
"test": "phpunit --colors=always"
},
"prefer-stable": true,
"config": {
"allow-plugins": {
"cakephp/plugin-installer": true,
"kylekatarnls/update-helper": true
}
}
"prefer-stable": true
}

3287
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -218,20 +218,20 @@ return [
* See vendor\cakephp\cakephp\src\Database\Driver for complete list
*/
'Datasources' => [
'default' => [ // Chainquery database connection
'default' => [
'className' => 'Cake\Database\Connection',
'driver' => 'Cake\Database\Driver\Mysql',
'persistent' => false,
'host' => 'chainquery.lbry.com',
'host' => 'localhost',
/**
* CakePHP will use the default DB port based on the driver selected
* MySQL on MAMP uses port 8889, MAMP users will want to uncomment
* the following line and set the port accordingly
*/
//'port' => '3000',
'username' => 'username',
//'port' => 'non_standard_port_number',
'username' => 'my_app',
'password' => 'secret',
'database' => 'my_db',
'database' => 'my_app',
'encoding' => 'utf8',
'timezone' => 'UTC',
'flags' => [],
@ -257,28 +257,7 @@ return [
*/
//'init' => ['SET GLOBAL innodb_stats_on_metadata = 0'],
'url' => env('DATABASE_URL', 'chainquery.lbry.com:3600'),
],
'localdb' => [ // Local db for price history
'className' => 'Cake\Database\Connection',
'driver' => 'Cake\Database\Driver\Mysql',
'persistent' => false,
'host' => 'localhost',
/**
* CakePHP will use the default DB port based on the driver selected
* MySQL on MAMP uses port 8889, MAMP users will want to uncomment
* the following line and set the port accordingly
*/
//'port' => '3306',
'username' => 'username',
'password' => 'secret',
'database' => 'lbry',
'encoding' => 'utf8',
'timezone' => 'UTC',
'flags' => [],
'cacheMetadata' => true,
'log' => false,
'url' => env('DATABASE_URL', null),
],
/**

View file

@ -49,7 +49,6 @@ require __DIR__ . '/paths.php';
*/
require CORE_PATH . 'config' . DS . 'bootstrap.php';
use App\Application;
use Cake\Cache\Cache;
use Cake\Console\ConsoleErrorHandler;
use Cake\Core\App;
@ -61,8 +60,7 @@ use Cake\Datasource\ConnectionManager;
use Cake\Error\ErrorHandler;
use Cake\Log\Log;
use Cake\Mailer\Email;
use Cake\Mailer\TransportFactory;
use Cake\Http\ServerRequest;
use Cake\Network\Request;
use Cake\Utility\Inflector;
use Cake\Utility\Security;
@ -152,12 +150,10 @@ if (!Configure::read('App.fullBaseUrl')) {
Cache::setConfig(Configure::consume('Cache'));
ConnectionManager::setConfig(Configure::consume('Datasources'));
//Email::setConfigTransport(Configure::consume('EmailTransport'));
TransportFactory::setConfig(Configure::consume('EmailTransport'));
Email::setConfigTransport(Configure::consume('EmailTransport'));
Email::setConfig(Configure::consume('Email'));
Log::setConfig(Configure::consume('Log'));
//Security::salt(Configure::consume('Security.salt'));
Security::setSalt(Configure::consume('Security.salt'));
Security::salt(Configure::consume('Security.salt'));
/*
* The default crypto extension in 3.0 is OpenSSL.
@ -169,12 +165,12 @@ Security::setSalt(Configure::consume('Security.salt'));
/*
* Setup detectors for mobile and tablet.
*/
ServerRequest::addDetector('mobile', function ($request) {
Request::addDetector('mobile', function ($request) {
$detector = new \Detection\MobileDetect();
return $detector->isMobile();
});
ServerRequest::addDetector('tablet', function ($request) {
Request::addDetector('tablet', function ($request) {
$detector = new \Detection\MobileDetect();
return $detector->isTablet();
@ -222,8 +218,5 @@ Type::build('timestamp')
* Debug Kit should not be installed on a production system
*/
if (Configure::read('debug')) {
//Plugin::load('DebugKit', ['bootstrap' => true]);
Application::addPlugin('DebugKit', ['bootstrap' => true]);
Plugin::load('DebugKit', ['bootstrap' => true]);
}
Configure::load('lbry', 'default');

View file

@ -1,11 +0,0 @@
<?php
return [
'Lbry' => [
'RpcUrl' => 'http://user:password@127.0.0.1:9245',
],
'Redis' => [
'Url' => 'tcp://127.0.0.1:6379',
]
];

View file

@ -72,3 +72,9 @@ Router::scope('/', function (RouteBuilder $routes) {
//$routes->fallbacks(DashedRoute::class);
});
/**
* Load all plugin routes. See the Plugin documentation on
* how to customize the loading of plugin routes.
*/
Plugin::routes();

View file

@ -1,4 +1,4 @@
#!/bin/sh
cd /home/lbry/explorer.lbry.io
cd /var/www/lbry.block.ng
bin/cake block addrtxamounts

View file

@ -1,7 +1,7 @@
#!/bin/sh
cd /home/lbry/explorer.lbry.io
cd /var/www/lbry.block.ng
bin/cake block parsenewblocks
rm tmp/lock/parsenewblocks 2>/dev/null
rm tmp/lock/parsenewblocks
bin/cake block parsetxs
rm tmp/lock/parsetxs 2>/dev/null
rm tmp/lock/parsetxs

137
cron/blockstuff.php Normal file
View file

@ -0,0 +1,137 @@
<?php
define('TMP', '/tmp/');
define('DS', '/');
class BlockSyncThread extends \Thread {
private $_startHeight;
private $_endHeight;
private $_maxHeight;
public function __construct($startBlock, $endBlock, $maxHeight) {
$this->_startHeight = $startBlock;
$this->_endHeight = $endBlock;
$this->_maxHeight = $maxHeight;
}
public function run() {
$conn = new \PDO("mysql:host=localhost;dbname=lbry", 'lbry-admin', '46D861aX#!yQ');
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$data_error = false;
$conn->beginTransaction();
// TODO: Batch block synchronisation from memory to DB
for ($curr_height = $this->_startHeight; $curr_height <= $this->_endHeight; $curr_height++) {
$idx_str = str_pad($curr_height, strlen($this->_maxHeight), '0', STR_PAD_LEFT);
// get the block hash
$req = ['method' => 'getblockhash', 'params' => [$curr_height]];
$response = BlockStuff::curl_json_post(BlockStuff::rpcurl, json_encode($req));
$json = json_decode($response);
$curr_block_hash = $json->result;
$req = ['method' => 'getblock', 'params' => [$curr_block_hash]];
$response = BlockStuff::curl_json_post(BlockStuff::rpcurl, json_encode($req));
$json = json_decode($response);
$curr_block = $json->result;
$stmt = $conn->prepare('UPDATE Blocks SET Confirmations = ? WHERE Height = ?');
try {
$stmt->execute([$curr_block->confirmations, $curr_height]);
echo "[$idx_str/$this->_maxHeight] Updated block height: $curr_height with confirmations $curr_block->confirmations.\n";
} catch (Exception $e) {
$data_error = true;
}
}
if ($data_error) {
echo "Rolling back changes.\n";
$conn->rollBack();
return;
}
echo "Committing data.\n";
$conn->commit();
}
}
class BlockStuff {
const rpcurl = 'http://lrpc:lrpc@127.0.0.1:9245';
public static function blocksync() {
self::lock('blocksync');
$conn = new \PDO("mysql:host=localhost;dbname=lbry", 'lbry-admin', '46D861aX#!yQ');
$stmt = $conn->prepare('SELECT Height FROM Blocks ORDER BY Height DESC LIMIT 1');
$stmt->execute([]);
$max_block = $stmt->fetch(PDO::FETCH_OBJ);
if ($max_block) {
$chunk_limit = 2;
$curr_height = 0;
$chunks = floor($max_block->Height / $chunk_limit);
$threads = [];
for ($i = 0; $i < $chunk_limit; $i++) {
$start = $curr_height;
$end = ($i == ($chunk_limit - 1)) ? $max_block->Height : $start + $chunks;
$curr_height += $chunks + 1;
$thread = new BlockSyncThread($start, $end, $max_block->Height);
$threads[] = $thread;
$thread->start();
}
for ($i = 0; $i < count($threads); $i++) {
$threads[$i]->join();
}
}
self::unlock('blocksync');
}
public static function curl_json_post($url, $data, $headers = []) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
//Log::debug('Request execution completed.');
if ($response === false) {
$error = curl_error($ch);
$errno = curl_errno($ch);
curl_close($ch);
throw new \Exception(sprintf('The request failed: %s', $error), $errno);
} else {
curl_close($ch);
}
// Close any open file handle
return $response;
}
public static function lock($process_name) {
if (!is_dir(TMP . 'lock')) {
mkdir(TMP . 'lock');
}
$lock_file = TMP . 'lock' . DS . $process_name;
if (file_exists($lock_file)) {
echo "$process_name is already running.\n";
exit(0);
}
file_put_contents($lock_file, '1');
}
public static function unlock($process_name) {
$lock_file = TMP . 'lock' . DS . $process_name;
if (file_exists($lock_file)) {
unlink($lock_file);
}
return true;
}
}
BlockStuff::blocksync();

View file

@ -1,4 +1,4 @@
#!/bin/sh
cd /home/lbry/explorer.lbry.io
cd /var/www/lbry.block.ng
bin/cake block parsetxs

View file

@ -1,4 +1,4 @@
#!/bin/sh
cd /home/lbry/explorer.lbry.io
cd /var/www/lbry.block.ng
bin/cake block buildclaimindex

3
cron/confirmations.sh Executable file
View file

@ -0,0 +1,3 @@
#!/bin/sh
cd /var/www/lbry.block.ng/cron
php -d extension=pthreads.so blockstuff.php

View file

@ -1,4 +1,4 @@
#!/bin/sh
cd /home/lbry/explorer.lbry.io
cd /var/www/lbry.block.ng
bin/cake block fixzerooutputs

View file

@ -1,5 +0,0 @@
#!/bin/sh
pkill -f forevermempool
rm -f /home/lbry/explorer.lbry.io/tmp/lock/forevermempool 2>/dev/null
cd /home/lbry/explorer.lbry.io
bin/cake block forevermempool &

4
cron/forevermempool.sh Executable file
View file

@ -0,0 +1,4 @@
#!/bin/sh
cd /var/www/lbry.block.ng
bin/cake block forevermempool &

View file

@ -1,4 +1,4 @@
#!/bin/sh
cd /home/lbry/explorer.lbry.io
cd /var/www/lbry.block.ng
bin/cake block parsemempool

View file

@ -1,4 +1,4 @@
#!/bin/sh
cd /home/lbry/explorer.lbry.io
cd /var/www/lbry.block.ng
bin/cake aux pricehistory

View file

@ -1,4 +1,4 @@
#!/bin/sh
cd /home/lbry/explorer.lbry.io
cd /var/www/lbry.block.ng
bin/cake block updatespends

View file

@ -1,4 +1,4 @@
#!/bin/sh
cd /home/lbry/explorer.lbry.io
cd /var/www/lbry.block.ng
bin/cake aux verifytags

23
dev.sh
View file

@ -1,23 +0,0 @@
#!/bin/bash
set -e
PHPBIN=php7.4
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
if [ ! -e "config/app.php" ]; then
cp "$DIR/config/app.default.php" "$DIR/config/app.php"
fi
if ! which $PHPBIN 2>/dev/null; then
PHPBIN=php
fi
#Composer update
composer update
#$PHPBIN composer.phar install
$PHPBIN --server localhost:8000 --docroot "$DIR/webroot" "$DIR/webroot/index.php"

View file

@ -1,4 +1,4 @@
--DROP DATABASE IF EXISTS lbry;
l--DROP DATABASE IF EXISTS lbry;
CREATE DATABASE lbry DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci;
USE lbry;
@ -74,7 +74,7 @@ CREATE TABLE `Addresses`
`TotalReceived` DECIMAL(18,8) DEFAULT 0 NOT NULL,
`TotalSent` DECIMAL(18,8) DEFAULT 0 NOT NULL,
`Balance` DECIMAL(18,8) AS (`TotalReceived` - `TotalSent`) PERSISTENT,
`Tag` VARCHAR(30),
`Tag` VARCHAR(30) NOT NULL,
`TagUrl` VARCHAR(200),
`Created` DATETIME NOT NULL,
`Modified` DATETIME NOT NULL,
@ -163,11 +163,11 @@ CREATE TABLE `TransactionsAddresses`
`AddressId` BIGINT UNSIGNED NOT NULL,
`DebitAmount` DECIMAL(18,8) DEFAULT 0 NOT NULL COMMENT 'Sum of the inputs to this address for the tx',
`CreditAmount` DECIMAL(18,8) DEFAULT 0 NOT NULL COMMENT 'Sum of the outputs to this address for the tx',
`TransactionTime` DATETIME DEFAULT UTC_TIMESTAMP() NOT NULL,
`LatestTransactionTime` DATETIME DEFAULT UTC_TIMESTAMP() NOT NULL,
PRIMARY KEY `PK_TransactionAddress` (`TransactionId`, `AddressId`),
FOREIGN KEY `Idx_TransactionsAddressesTransaction` (`TransactionId`) REFERENCES `Transactions` (`Id`),
FOREIGN KEY `Idx_TransactionsAddressesAddress` (`AddressId`) REFERENCES `Addresses` (`Id`),
INDEX `Idx_TransactionsAddressesTransactionTime` (`TransactionTime`),
INDEX `Idx_TransactionsAddressesLatestTransactionTime` (`LatestTransactionTime`),
INDEX `Idx_TransactionsAddressesDebit` (`DebitAmount`),
INDEX `Idx_TransactionsAddressesCredit` (`CreditAmount`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4;

View file

@ -32,9 +32,9 @@ class ClaimsController extends AppController {
}
$conn = ConnectionManager::get('default');
// $stmt = $conn->execute('SELECT COUNT(Id) AS Total FROM Claims WHERE ThumbnailUrl IS NOT NULL AND LENGTH(TRIM(ThumbnailUrl)) > 0');
// $count = $stmt->fetch(\PDO::FETCH_OBJ);
$numClaims = 23000000;
$stmt = $conn->execute('SELECT COUNT(Id) AS Total FROM Claims WHERE ThumbnailUrl IS NOT NULL AND LENGTH(TRIM(ThumbnailUrl)) > 0');
$count = $stmt->fetch(\PDO::FETCH_OBJ);
$numClaims = $count->Total;
if ($beforeId < 0) {
$beforeId = 0;

File diff suppressed because it is too large Load diff

View file

@ -5,46 +5,7 @@ namespace App\Model\Entity;
use Cake\ORM\Entity;
class Claim extends Entity {
function getLbryLink() {
$link = $this->name;
if (isset($this->publisher)) {
$link = $this->publisher . '/' . $link;
}
$link = 'lbry://' . $link;
return $link;
}
function getExplorerLink() {
$link = '/claims/' . $this->claim_id;
return $link;
}
function getContentTag() {
$ctTag = null;
if (substr($this->content_type, 0, 5) === 'audio') {
$ctTag = 'audio';
} else if (substr($this->content_type, 0, 5) === 'video') {
$ctTag = 'video';
} else if (substr($this->content_type, 0, 5) === 'image') {
$ctTag = 'image';
}
if (!$ctTag && $this->claim_type == 2) {
$ctTag = 'identity';
}
return $ctTag;
}
function getAutoThumbText() {
$autoThumbText = '';
if ($this->claim_type == 2) {
$autoThumbText = strtoupper(substr($this->name, 1, min(strlen($this->name), 10)));
} else {
$str = (strlen(trim($this->title)) > 0) ? $this->title : $this->name;
$autoThumbText = strtoupper(substr($str, 0, min(strlen($str), 5)));
}
return $autoThumbText;
}
}
?>

View file

@ -4,7 +4,8 @@ namespace App\Model\Entity;
use Cake\ORM\Entity;
class TransactionAddress extends Entity {
class ClaimStream extends Entity {
}
?>

View file

@ -5,7 +5,7 @@ namespace App\Model\Entity;
use Cake\ORM\Entity;
class PriceHistory extends Entity {
public $useDbConfig = 'localdb';
}
?>

View file

@ -3,9 +3,9 @@
namespace App\Model\Entity;
use Cake\ORM\Entity;
use Cake\ORM\TableRegistry;
class Transaction extends Entity {
}
?>

View file

@ -8,8 +8,8 @@ class AddressesTable extends Table {
public function initialize(array $config) {
parent::initialize($config);
$this->setPrimaryKey('id');
$this->setTable('address');
$this->primaryKey('Id');
$this->table('Addresses');
$this->addBehavior('SimpleAudit');
}

View file

@ -8,8 +8,8 @@ class BlocksTable extends Table {
public function initialize(array $config) {
parent::initialize($config);
$this->setPrimaryKey('id');
$this->setTable('block');
$this->primaryKey('Id');
$this->table('Blocks');
$this->addBehavior('SimpleAudit');
}

View file

@ -0,0 +1,18 @@
<?php
namespace App\Model\Table;
use Cake\ORM\Table;
class ClaimStreamsTable extends Table {
public function initialize(array $config) {
parent::initialize($config);
$this->primaryKey('Id');
$this->table('ClaimStreams');
//$this->addBehavior('SimpleAudit');
}
}
?>

View file

@ -8,20 +8,29 @@ class ClaimsTable extends Table {
public function initialize(array $config) {
parent::initialize($config);
$this->setPrimaryKey('id');
$this->setTable('claim');
$this->primaryKey('Id');
$this->table('Claims');
//$this->addBehavior('SimpleAudit');
$this->addAssociations([
'belongsTo' => [
'publisher' => [
'Publisher' => [
'className' => 'App\Model\Table\ClaimsTable',
'foreignKey' => 'publisher_id',
'bindingKey' => 'claim_id',
'propertyName' => 'publisher'
'foreignKey' => 'PublisherId',
'bindingKey' => 'ClaimId',
'propertyName' => 'Publisher'
]
],
'hasOne' => [
'Stream' => [
'className' => 'App\Model\Table\ClaimStreamsTable',
'foreignKey' => 'Id',
'bindingKey' => 'Id',
'propertyName' => 'Stream'
]
]
]);
}
}
?>

View file

@ -8,19 +8,19 @@ class InputsTable extends Table {
public function initialize(array $config) {
parent::initialize($config);
$this->setPrimaryKey('id');
$this->setTable('input');
$this->primaryKey('Id');
$this->table('Inputs');
$this->addBehavior('SimpleAudit');
$this->addAssociations([
'belongsToMany' => [
'input_addresses' => [
'InputAddresses' => [
'className' => 'App\Model\Table\AddressesTable',
'joinTable' => 'input_addresses',
'foreignKey' => 'input_id',
'targetForeignKey' => 'address_id',
'propertyName' => 'input_addresses'
'joinTable' => 'InputsAddresses',
'foreignKey' => 'InputId',
'targetForeignKey' => 'AddressId',
'propertyName' => 'InputAddresses'
]
]
]);

View file

@ -8,26 +8,26 @@ class OutputsTable extends Table {
public function initialize(array $config) {
parent::initialize($config);
$this->setPrimaryKey('id');
$this->setTable('output');
$this->primaryKey('Id');
$this->table('Outputs');
$this->addBehavior('SimpleAudit');
$this->addAssociations([
'belongsTo' => [
'spend_input' => [
'SpendInput' => [
'className' => 'App\Model\Table\InputsTable',
'foreignKey' => 'spent_by_input_id',
'propertyName' => 'spend_input'
'foreignKey' => 'SpentByInputId',
'propertyName' => 'SpendInput'
]
],
'belongsToMany' => [
'output_addresses' => [
'OutputAddresses' => [
'className' => 'App\Model\Table\AddressesTable',
'joinTable' => 'output_addresses',
'foreignKey' => 'output_id',
'targetForeignKey' => 'address_id',
'propertyName' => 'output_addresses'
'joinTable' => 'OutputsAddresses',
'foreignKey' => 'OutputId',
'targetForeignKey' => 'AddressId',
'propertyName' => 'OutputAddresses'
]
]
]);

View file

@ -8,8 +8,8 @@ class PriceHistoryTable extends Table {
public function initialize(array $config) {
parent::initialize($config);
$this->setPrimaryKey('Id');
$this->setTable('PriceHistory');
$this->primaryKey('Id');
$this->table('PriceHistory');
}
}

View file

@ -8,8 +8,8 @@ class TagAddressRequestsTable extends Table {
public function initialize(array $config) {
parent::initialize($config);
$this->setPrimaryKey('Id');
$this->setTable('TagAddressRequests');
$this->primaryKey('Id');
$this->table('TagAddressRequests');
$this->addBehavior('SimpleAudit');
}

View file

@ -1,16 +0,0 @@
<?php
namespace App\Model\Table;
use Cake\ORM\Table;
class TransactionAddressesTable extends Table {
public function initialize(array $config) {
parent::initialize($config);
$this->setTable('transaction_address');
$this->addBehavior('SimpleAudit');
}
}
?>

View file

@ -8,8 +8,8 @@ class TransactionsTable extends Table {
public function initialize(array $config) {
parent::initialize($config);
$this->setPrimaryKey('id');
$this->setTable('transaction');
$this->primaryKey('Id');
$this->table('Transactions');
$this->addBehavior('SimpleAudit');
}

View file

@ -4,16 +4,13 @@ namespace App\Shell;
use Cake\Console\ConsoleOutput;
use Cake\Console\Shell;
use Cake\Core\Configure;
use Cake\Datasource\ConnectionManager;
use Cake\Log\Log;
use Mdanter\Ecc\EccFactory;
class AuxShell extends Shell {
public static $rpcurl;
const bittrex = 'https://api.bittrex.com/v3/markets/LBC-BTC/ticker';
const bittrex = 'https://bittrex.com/api/v1.1/public/getticker?market=BTC-LBC';
const blockchainticker = 'https://blockchain.info/ticker';
@ -23,11 +20,12 @@ class AuxShell extends Shell {
const scriptAddress = [5, 122];
const rpcurl = 'http://lrpc:lrpc@127.0.0.1:9245';
const tagrcptaddress = 'bLockNgmfvnnnZw7bM6SPz6hk5BVzhevEp';
public function initialize() {
parent::initialize();
self::$rpcurl = Configure::read('Lbry.RpcUrl');
$this->loadModel('Addresses');
$this->loadModel('Inputs');
$this->loadModel('Outputs');
@ -127,8 +125,8 @@ class AuxShell extends Shell {
public function pricehistory() {
self::lock('pricehistory');
$conn = ConnectionManager::get('localdb');
$redis = new \Predis\Client(Configure::read('Redis.Url'));
$conn = ConnectionManager::get('default');
$redis = new \Predis\Client('tcp://127.0.0.1:6379');
try {
// Only allow 5-minute update intervals
@ -150,13 +148,13 @@ class AuxShell extends Shell {
$btrxjson = json_decode(self::curl_get(self::bittrex));
$blckjson = json_decode(self::curl_get(self::blockchainticker));
if ($btrxjson) {
$btc = $btrxjson->bidRate;
if ($btrxjson->success) {
$btc = $btrxjson->result->Bid;
$usd = 0;
if (isset($blckjson->USD)) {
$usd = $btc * $blckjson->USD->buy;
$priceInfo = new \stdClass();
$priceInfo->price = number_format($usd, 3, '.', '');
$priceInfo->price = number_format($usd, 2, '.', '');
$priceInfo->time = $now->format('c');
if ($redis) {
$redis->set(self::lbcpricekey, json_encode($priceInfo));

View file

@ -4,27 +4,24 @@ namespace App\Shell;
use Cake\Console\ConsoleOutput;
use Cake\Console\Shell;
use Cake\Core\Configure;
use Cake\Datasource\ConnectionManager;
use Cake\Log\Log;
use Mdanter\Ecc\EccFactory;
class BlockShell extends Shell {
public static $rpcurl;
public static $redisurl;
const mempooltxkey = 'lbc.mempooltx';
const pubKeyAddress = [0, 85];
const scriptAddress = [5, 122];
const rpcurl = 'http://lrpc:lrpc@127.0.0.1:9245';
const redisurl = 'tcp://127.0.0.1:6379';
public function initialize() {
parent::initialize();
self::$rpcurl = Configure::read('Lbry.RpcUrl');
self::$redisurl = Configure::read('Redis.Url');
$this->loadModel('Blocks');
$this->loadModel('Addresses');
$this->loadModel('Claims');
@ -45,7 +42,7 @@ class BlockShell extends Shell {
$txid = $otx->TransactionId;
$tx = $this->Transactions->find()->select(['Hash'])->where(['Id' => $txid])->first();
$req = ['method' => 'getrawtransaction', 'params' => [$tx->Hash]];
$response = self::curl_json_post(self::$rpcurl, json_encode($req));
$response = self::curl_json_post(self::rpcurl, json_encode($req));
$json = json_decode($response);
$tx_result = $json->result;
$raw_tx = $tx_result;
@ -163,7 +160,7 @@ class BlockShell extends Shell {
$req = ['method' => 'getvalueforname', 'params' => [$claim_name]];
$json = null;
try {
$json = json_decode(self::curl_json_post(self::$rpcurl, json_encode($req)));
$json = json_decode(self::curl_json_post(self::rpcurl, json_encode($req)));
if (!$json) {
echo "[$idx_str/$count] getvalueforname failed for [$out->Hash:$vout]. Skipping.\n";
continue;
@ -274,7 +271,6 @@ class BlockShell extends Shell {
self::unlock('buildindex');
}
// TODO: Refactor for unique claim identification by claim_id instead of using the claim name.
protected function _getclaimfortxout($pubkeyasm, $tx_hash, $vout, $tx_time = null) {
$claim_data = null;
$claim_stream_data = null;
@ -296,14 +292,10 @@ class BlockShell extends Shell {
if ($json) {
$claim = json_decode($json);
if ($claim) {
if (strpos($claim_name, '#') !== false) {
$claim_name = substr($claim_name, 0, strpos($claim_name, '#'));
}
$req = ['method' => 'getvalueforname', 'params' => [$claim_name]];
$json = null;
try {
$json = json_decode(self::curl_json_post(self::$rpcurl, json_encode($req)));
$json = json_decode(self::curl_json_post(self::rpcurl, json_encode($req)));
if ($json) {
$claim_data = [];
$claim_id = $json->result->claimId;
@ -399,7 +391,7 @@ class BlockShell extends Shell {
// getraw
$req = ['method' => 'getrawtransaction', 'params' => [$tx->Hash]];
$start_ms = round(microtime(true) * 1000);
$response = self::curl_json_post(self::$rpcurl, json_encode($req));
$response = self::curl_json_post(self::rpcurl, json_encode($req));
$diff_ms = (round(microtime(true) * 1000)) - $start_ms;
$total_diff += $diff_ms;
echo "getrawtx took {$diff_ms}ms. ";
@ -681,7 +673,7 @@ class BlockShell extends Shell {
private function processtx($tx_hash, $block_ts, $block_data, &$data_error) {
// Get the raw transaction (Use getrawtx daemon instead (for speed!!!)
$req = ['method' => 'getrawtransaction', 'params' => [$tx_hash]];
$response = self::curl_json_post(self::$rpcurl, json_encode($req));
$response = self::curl_json_post(self::rpcurl, json_encode($req));
$json = json_decode($response);
$tx_result = $json->result;
$raw_tx = $tx_result;
@ -1083,13 +1075,12 @@ class BlockShell extends Shell {
try {
// Get the best block hash
$req = ['method' => 'getbestblockhash', 'params' => []];
$response = self::curl_json_post(self::$rpcurl, json_encode($req));
$response = self::curl_json_post(self::rpcurl, json_encode($req));
$json = json_decode($response);
print_r($response); print_r($json);
$best_hash = $json->result;
$req = ['method' => 'getblock', 'params' => [$best_hash]];
$response = self::curl_json_post(self::$rpcurl, json_encode($req));
$response = self::curl_json_post(self::rpcurl, json_encode($req));
$json = json_decode($response);
$best_block = $json->result;
@ -1112,20 +1103,20 @@ print_r($response); print_r($json);
for ($curr_height = $min_height; $curr_height <= $max_height; $curr_height++) {
// get the block hash
$req = ['method' => 'getblockhash', 'params' => [$curr_height]];
$response = self::curl_json_post(self::$rpcurl, json_encode($req));
$response = self::curl_json_post(self::rpcurl, json_encode($req));
$json = json_decode($response);
$curr_block_hash = $json->result;
$next_block_hash = null;
if ($curr_height < $max_height) {
$req = ['method' => 'getblockhash', 'params' => [$curr_height + 1]];
$response = self::curl_json_post(self::$rpcurl, json_encode($req));
$response = self::curl_json_post(self::rpcurl, json_encode($req));
$json = json_decode($response);
$next_block_hash = $json->result;
}
$req = ['method' => 'getblock', 'params' => [$curr_block_hash]];
$response = self::curl_json_post(self::$rpcurl, json_encode($req));
$response = self::curl_json_post(self::rpcurl, json_encode($req));
$json = json_decode($response);
$curr_block = $json->result;
@ -1136,7 +1127,7 @@ print_r($response); print_r($json);
$next_block = null;
if ($next_block_hash != null) {
$req = ['method' => 'getblock', 'params' => [$next_block_hash]];
$response = self::curl_json_post(self::$rpcurl, json_encode($req));
$response = self::curl_json_post(self::rpcurl, json_encode($req));
$json = json_decode($response);
$next_block = $json->result;
}
@ -1252,7 +1243,7 @@ print_r($response); print_r($json);
while (true) {
try {
$data = ['method' => 'getrawmempool', 'params' => []];
$res = self::curl_json_post(self::$rpcurl, json_encode($data));
$res = self::curl_json_post(self::rpcurl, json_encode($data));
$json = json_decode($res);
$txs = $json->result;
$now = new \DateTime('now', new \DateTimeZone('UTC'));
@ -1861,7 +1852,7 @@ print_r($response); print_r($json);
// Other standard: pay to pubkey hash
$define['p2pk'] = array('type' => 'pubkeyhash',
'reqSigs' => 1,
'data_index_for_hash' => 0);
'data_index_for_hash' => 1);
$rule['p2pk'] = [
'0' => '/^[0-9a-f]+$/i',
'1' => '/^OP_CHECKSIG/'
@ -2079,7 +2070,7 @@ print_r($response); print_r($json);
}
public static function _init_redis() {
$redis = new \Predis\Client(self::$redisurl);
$redis = new \Predis\Client(self::redisurl);
try {
$redis->info('mem');
} catch (\Predis\Connection\ConnectionException $e) {

View file

@ -1,85 +0,0 @@
<?php
$autoThumbText = $claim->getAutoThumbText();
$cost = '';
if (isset($claim->price) && $claim->price > 0) {
$cost = $this->Amount->formatCurrency($claim->price) . ' LBC';
} else if (isset($claim->fee) && strtolower($claim->fee_currency) === 'lbc') {
$cost = $this->Amount->formatCurrency($claim->fee) . ' LBC';
}
$a = ['purple', 'orange', 'blue', 'teal', 'green', 'yellow'];
// content type
$ctTag = $claim->getContentTag();
?>
<div data-id="<?php echo $claim->claim_id ?>" class="claim-grid-item<?php if ($idx % 3 == 0): ?> last-item<?php endif; ?><?php if ($last_row): ?> last-row<?php endif; ?>">
<?php if (strlen(trim($cost)) > 0): ?>
<div class="price-tag"><?php echo $cost ?></div>
<?php endif; ?>
<div class="tags">
<?php if ($claim->bid_state == 'Controlling'): ?>
<div class="bid-state">Controlling</div>
<?php endif; ?>
<?php if ($ctTag): ?>
<div class="content-type"><?php echo strtoupper($ctTag) ?></div>
<?php endif; ?>
<?php if ($claim->is_nsfw): ?>
<div class="nsfw">NSFW</div>
<?php endif; ?>
</div>
<div data-autothumb="<?php echo $autoThumbText ?>" class="thumbnail <?php echo $a[mt_rand(0, count($a) - 1)] ?>">
<?php if (!$claim->is_nsfw && strlen(trim($claim->thumbnail_url)) > 0): ?>
<img src="<?php echo htmlspecialchars('https://thumbnails.odycdn.com/optimize/s:1280:720/quality:85/plain/'.$claim->thumbnail_url) ?>" alt="" />
<?php else: ?>
<div class="autothumb"><?php echo $autoThumbText ?></div>
<?php endif; ?>
</div>
<?php if ($claim->isBlocked): ?>
<div class="blocked-info">
In response to a complaint we received under the US Digital Millennium Copyright Act, we have blocked access to this content from our applications. For more information, please refer to <a href="https://lbry.com/faq/dmca" target="_blank">DMCA takedown requests</a>
</div>
<?php else: ?>
<div class="metadata">
<div class="title" title="<?php echo $claim->claim_type == 1 ? $claim->name : ((strlen(trim($claim->title)) > 0) ? $claim->title : '') ?>"><?php echo $claim->claim_type == 1 ? $claim->name : ((strlen(trim($claim->title)) > 0) ? $claim->title : '<em>No Title</em>') ?></div>
<div class="link" title="<?php echo $claim->getLbryLink() ?>"><a href="<?php echo $claim->getLbryLink() ?>" rel="nofollow"><?php echo $claim->getLbryLink() ?></a></div>
<div class="desc"><?php echo strlen(trim($claim->description)) > 0 ? $claim->description : '<em>No description available</em>' ?></div>
<div class="label half-width">Transaction</div>
<div class="label half-width">Created</div>
<div class="value half-width"><a href="/tx/<?php echo $claim->transaction_hash_id ?>#output-<?php echo $claim->vout ?>" title="<?php echo $claim->transaction_hash_id ?>"><?php echo $claim->transaction_hash_id ?></a></div>
<div class="value half-width" title="<?php echo $claim->created_at->format('j M Y H:i:s') ?> UTC">
<?php echo \Carbon\Carbon::createFromTimestamp($claim->created_at->format('U'))->diffForHumans(); ?>
</div>
<div class="clear spacer"></div>
<?php if ($claim->claim_type == 1): ?>
<div class="label half-width">Content Type</div>
<div class="label half-width">Language</div>
<div class="value half-width" title="<?php echo $claim->content_type ?>"><?php echo $claim->content_type ?></div>
<div class="value half-width" title="<?php echo $claim->language == 'en' ? 'English' : $claim->language ?>"><?php echo $claim->language == 'en' ? 'English' : $claim->language ?></div>
<div class="clear spacer"></div>
<!--<div class="label half-width">Author</div>
<div class="label half-width">License</div>-->
<!--<div class="value half-width" title="<?php echo strlen(trim($claim->author)) > 0 ? $claim->author : '<em>Unspecified</em>' ?>"><?php echo strlen(trim($claim->author)) > 0 ? $claim->author : '<em>Unspecified</em>' ?></div>
<div class="value half-width" title="<?php echo strlen(trim($claim->license)) > 0 ? $claim->license : '' ?>">
<?php if (strlen(trim($claim->LicenseUrl)) > 0): ?><a href="<?php echo $claim->LicenseUrl ?>" rel="nofollow" target="_blank"><?php endif; ?>
<?php echo strlen(trim($claim->License)) > 0 ? $claim->License : '<em>Unspecified</em>' ?>
<?php if (strlen(trim($claim->LicenseUrl))): ?></a><?php endif; ?>
</div>
-->
<?php endif; ?>
</div>
<?php endif; ?>
</div>

View file

@ -17,7 +17,7 @@
<script>try{Typekit.load({ async: true });}catch(e){}</script>
<!-- Analytics -->
<?php if ($_SERVER['HTTP_HOST'] === 'explorer.lbry.com'): ?>
<?php if ($_SERVER['HTTP_HOST'] === 'explorer.lbry.io'): ?>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="//www.googletagmanager.com/gtag/js?id=UA-60403362-1"></script>
<script>
@ -57,7 +57,7 @@
<?php echo $this->fetch('content') ?>
<footer>
<div class="content">
<a href="https://lbry.com">LBRY</a>
<a href="https://lbry.io">LBRY</a>
<div class="page-time">Page took <?php echo round((microtime(true) - TIME_START) * 1000, 0) ?>ms</div>
</div>

View file

@ -1,4 +1,4 @@
<?php $this->assign('title', 'Address ' . $address->address) ?>
<?php $this->assign('title', 'Address ' . $address->Address) ?>
<?php $this->start('script') ?>
<script type="text/javascript">
@ -40,7 +40,7 @@
var btnClose = $('.btn-close');
$.ajax({
url: '/api/v1/address/<?php echo $address->address ?>/tag',
url: '/api/v1/address/<?php echo $address->Address ?>/tag',
type: 'post',
dataType: 'json',
data: req,
@ -87,15 +87,41 @@
<div class="address-head">
<h3>LBRY Address</h3>
<h4><?php echo $address->address ?></h4>
<h4><?php echo $address->Address ?></h4> <div class="tag">
<?php if (isset($address->Tag) && strlen(trim($address->Tag)) > 0): ?>
<?php if (strlen(trim($address->TagUrl)) > 0): ?><a href="<?php echo $address->TagUrl ?>" target="_blank" rel="nofollow"><?php echo $address->Tag ?></a><?php else: echo $address->Tag; endif; ?>
<?php endif; ?>
<?php else: ?><a href="#" class="tag-link">Tag this address</a><?php endif; ?></div>
<div class="tag-address-container">
<h4>Tag adddress</h4>
<?php if ($pending): ?>
<div class="desc">This address has a pending tag request. If you made this request, please send exactly <strong><?php echo $pending->VerificationAmount ?> LBC</strong> from <strong><?php echo $address->Address ?></strong> to <strong><a href="/address/bLockNgmfvnnnZw7bM6SPz6hk5BVzhevEp" target="_blank">bLockNgmfvnnnZw7bM6SPz6hk5BVzhevEp</a></strong>. Incomplete requests will be automatically deleted 7 days from the request creation date.</div>
<?php else: ?>
<div class="desc">Label your public LBRY address with a name and an optional link. In order to tag this address, please send exactly <strong><?php echo $tagRequestAmount ?> LBC</strong>
from <strong><?php echo $address->Address ?></strong> to <strong><a href="/address/bLockNgmfvnnnZw7bM6SPz6hk5BVzhevEp" target="_blank">bLockNgmfvnnnZw7bM6SPz6hk5BVzhevEp</a></strong>
and then specify the desired tag (maximum 30 characters) and link in the fields below. The transaction will be verified after at least 1 confirmation. The <strong><?php echo $tagRequestAmount ?> LBC</strong> fee is a measure to prevent spam and low-effort submissions. Verification is an automatic process, but any tags or URLs that may be considered illegal when brought to attention will be removed.</div>
<div class="form-group">
<input type="hidden" name="tag_verify_amount" value="<?php echo $tagRequestAmount ?>" />
<div class="error-message"></div>
<div class="col">
<input name="tag_value" maxlength="30" placeholder="Tag (max. 30 characters)" />
</div>
<div class="col">
<input name="tag_url" maxlength="200" placeholder="Link (max. 200 characters)" />
</div>
<div class="col buttons">
<button class="btn btn-tag">Tag address</button>
<button class="btn btn-close">Close</button>
</div>
<div class="clear"></div>
</div>
<?php endif; ?>
</div>
</div>
<div class="address-subhead">
<div class="address-qr">
<img src="/qr/lbry%3A<?php echo $address->address ?>" alt="lbry:<?php echo $address->address ?>" />
<img src="/qr/lbry%3A<?php echo $address->Address ?>" alt="lbry:<?php echo $address->Address ?>" />
</div>
<div class="address-summary">
@ -152,14 +178,19 @@
<?php foreach ($recentTxs as $tx): ?>
<tr>
<td class="w125"><?php if ($tx->height === null): ?><em>Unconfirmed</em><?php else: ?><a href="/blocks/<?php echo $tx->height ?>"><?php echo $tx->height ?></a><?php endif; ?></td>
<td class="w250"><div><a href="/tx/<?php echo $tx->hash ?>?address=<?php echo $address->address ?>#<?php echo $address->address ?>"><?php echo $tx->hash ?></a></div></td>
<td><?php echo \DateTime::createFromFormat('U', $tx->transaction_time)->format('d M Y H:i:s') . ' UTC'; ?></td>
<td class="right"><?php echo number_format($tx->confirmations, 0, '', ',') ?></td>
<td class="right"><?php echo $tx->input_count ?></td>
<td class="right"><?php echo $tx->output_count ?></td>
<td class="right<?php echo ' ' . ($tx->debit_amount > 0 && $tx->credit_amount > 0 ? 'diff' : ($tx->debit_amount > 0 ? 'debit' : 'credit')) ?>">
<?php echo number_format($tx->credit_amount - $tx->debit_amount, 8, '.', ',') ?> LBC
<td class="w125"><?php if ($tx->Height === null): ?><em>Unconfirmed</em><?php else: ?><a href="/blocks/<?php echo $tx->Height ?>"><?php echo $tx->Height ?></a><?php endif; ?></td>
<td class="w250"><div><a href="/tx/<?php echo $tx->Hash ?>?address=<?php echo $address->Address ?>#<?php echo $address->Address ?>"><?php echo $tx->Hash ?></a></div></td>
<td><?php echo \DateTime::createFromFormat('U', $tx->TxTime)->format('d M Y H:i:s') . ' UTC'; ?></td>
<td class="right"><?php echo number_format($tx->Confirmations, 0, '', ',') ?></td>
<td class="right"><?php echo $tx->InputCount ?></td>
<td class="right"><?php echo $tx->OutputCount ?></td>
<td class="right<?php echo ' ' . (($tx->DebitAmount > 0 && $tx->CreditAmount > 0) ? '' : (($tx->DebitAmount > 0) ? 'debit' : 'credit')) ?>">
<?php if ($tx->DebitAmount > 0 && $tx->CreditAmount > 0): ?>
<div class="credit">+<?php echo number_format($tx->CreditAmount, 8, '.', ',') ?> LBC</div>
<div class="debit">-<?php echo number_format($tx->DebitAmount, 8, '.', ',') ?> LBC</div>
<?php else: ?>
<?php echo (($tx->DebitAmount > 0) ? '-' : '+'); ?><?php echo number_format((($tx->DebitAmount > 0) ? $tx->DebitAmount : $tx->CreditAmount), 8, '.', ',') ?> LBC
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>

View file

@ -21,19 +21,21 @@
</script>
<?php $this->end(); ?>
<?php $this->assign('title', 'Block Height ' . $block->height) ?>
<?php $this->assign('title', 'Block Height ' . $block->Height) ?>
<div class="block-head">
<h3>LBRY Block <?php echo $block->height ?></h3>
<h4><?php echo $block->hash ?></h4>
<h3>LBRY Block <?php echo $block->Height ?></h3>
<h4><?php echo $block->Hash ?></h4>
</div>
<div class="block-nav">
<?php if ($block->height > 0): ?>
<a class="btn btn-prev" href="/blocks/<?php echo ($block->height - 1); ?>">&laquo; Previous Block</a>
<?php if (strlen(trim($block->PreviousBlockHash)) > 0): ?>
<a class="btn btn-prev" href="/blocks/<?php echo ($block->Height - 1); ?>">&laquo; Previous Block</a>
<?php endif; ?>
<a class="btn btn-next" href="/blocks/<?php echo ($block->height + 1); ?>">Next Block &raquo;</a>
<?php if (strlen(trim($block->NextBlockHash)) > 0): ?>
<a class="btn btn-next" href="/blocks/<?php echo ($block->Height + 1); ?>">Next Block &raquo;</a>
<?php endif; ?>
<div class="clear"></div>
</div>
@ -45,46 +47,44 @@
<div class="label half-width">Block Size (bytes)</div>
<div class="label half-width">Block Time</div>
<div class="value half-width"><?php echo number_format($block->block_size, 0, '', ',') ?></div>
<div class="value half-width"><?php echo \DateTime::createFromFormat('U', $block->block_time)->format('j M Y H:i:s') . ' UTC' ?></div>
<div class="value half-width"><?php echo number_format($block->BlockSize, 0, '', ',') ?></div>
<div class="value half-width"><?php echo \DateTime::createFromFormat('U', $block->BlockTime)->format('j M Y H:i:s') . ' UTC' ?></div>
<div class="clear spacer"></div>
<div class="label half-width">Bits</div>
<div class="label half-width">Confirmations</div>
<div class="value half-width"><?php echo $block->bits ?></div>
<div class="value half-width"><?php echo $confirmations ?></div>
<div class="value half-width"><?php echo $block->Bits ?></div>
<div class="value half-width"><?php echo number_format($block->Confirmations, 0, '', ',') ?></div>
<div class="clear spacer"></div>
<div class="label half-width">Difficulty</div>
<div class="label half-width">Nonce</div>
<div class="value half-width"><?php echo $this->Amount->format($block->difficulty, '') ?></div>
<div class="value half-width"><?php echo $block->nonce ?></div>
<div class="value half-width"><?php echo $this->Amount->format($block->Difficulty, '') ?></div>
<div class="value half-width"><?php echo $block->Nonce ?></div>
<div class="clear spacer"></div>
<div class="label">Chainwork</div> <div class="value"><?php echo $block->chainwork ?></div>
<div class="label">Chainwork</div> <div class="value"><?php echo $block->Chainwork ?></div>
<div class="spacer"></div>
<div class="label">MerkleRoot</div> <div class="value"><?php echo $block->merkle_root ?></div>
<div class="label">MerkleRoot</div> <div class="value"><?php echo $block->MerkleRoot ?></div>
<div class="spacer"></div>
<div class="label">NameClaimRoot</div> <div class="value"><?php echo $block->name_claim_root ?></div>
<div class="label">NameClaimRoot</div> <div class="value"><?php echo $block->NameClaimRoot ?></div>
<!--
<div class="spacer"></div>
<div class="label">Target</div> <div class="value"><?php echo $block->Target ?></div>
-->
<div class="spacer"></div>
<div class="label">Version</div> <div class="value"><?php echo $block->version ?></div>
<div class="label">Version</div> <div class="value"><?php echo $block->Version ?></div>
</div>
<div class="block-transactions">
@ -109,10 +109,10 @@
<?php foreach ($blockTxs as $tx): ?>
<tr>
<td class="w300"><div><a href="/tx/<?php echo $tx->hash ?>"><?php echo $tx->hash ?></a></div></td>
<td class="right"><?php echo $tx->input_count ?></td>
<td class="right"><?php echo $tx->output_count ?></td>
<td class="right"><div title="<?php echo $tx->value ?> LBC"><?php echo $this->Amount->formatCurrency($tx->value) ?> LBC</div></td>
<td class="w300"><div><a href="/tx/<?php echo $tx->Hash ?>"><?php echo $tx->Hash ?></a></div></td>
<td class="right"><?php echo $tx->InputCount ?></td>
<td class="right"><?php echo $tx->OutputCount ?></td>
<td class="right"><div title="<?php echo $tx->Value ?> LBC"><?php echo $this->Amount->formatCurrency($tx->Value) ?> LBC</div></td>
</tr>
<?php endforeach; ?>
</tbody>
@ -134,7 +134,236 @@
<script type="text/javascript" src="/amcharts/amcharts.js"></script>
<script type="text/javascript" src="/amcharts/serial.js"></script>
<script type="text/javascript" src="/amcharts/plugins/export/export.min.js"></script>
<script type="text/javascript" src="/js/block-size-chart.js"></script>
<script type="text/javascript">
var chart;
var chartData = [];
var chartLoadInProgress = false;
var minPeriod = 'hh';
var validPeriods = ['24h', '72h', '168h', '30d', '90d', '1y'];
var defaultPeriod = (validPeriods.indexOf(localStorage.getItem('chartPeriod')) > -1) ? localStorage.getItem('chartPeriod') : '24h';
var periodGridCounts = {'24h': 24, '72h': 24, '168h': 14, '30d': 30, '90d': 45, '1y': 12 };
AmCharts.ready(function() {
chart = AmCharts.makeChart('block-size-chart', {
type: 'serial',
theme: 'light',
mouseWheelZoomEnabled: true,
categoryField: 'date',
synchronizeGrid: true,
dataProvider: chartData,
valueAxes: [
{
id: 'v-block-size',
axisColor: '#1e88e5',
axisThickness: 2,
labelFunction: function(value) {
return (Math.round((value / 1000) * 100)/100).toFixed(2) + ' KB';
}
},
{
id: 'v-price',
axisColor: '#00e676',
offset: 75,
gridAlpha: 0,
axisThickness: 2,
labelFunction: function(value) {
return '$' + value.toFixed(2);
}
}
],
categoryAxis: {
parseDates: true,
minPeriod: minPeriod, // DD for daily
autoGridCount: false,
minorGridEnabled: true,
minorGridAlpha: 0.04,
axisColor: '#dadada',
twoLineMode: true,
dateFormats: [{
period: 'fff',
format: 'JJ:NN:SS'
}, {
period: 'ss',
format: 'JJ:NN:SS'
}, {
period: 'mm',
format: 'JJ:NN'
}, {
period: 'hh',
format: 'JJ:NN'
}, {
period: 'DD',
format: 'DD'
}, {
period: 'WW',
format: 'DD MMM'
}, {
period: 'MM',
format: 'MMM'
}, {
period: 'YYYY',
format: 'YYYY'
}]
},
graphs: [
{
id: 'g-block-size',
valueAxis: 'v-block-size', // we have to indicate which value axis should be used
title: 'Avg Block Size',
valueField: 'AvgBlockSize',
bullet: 'round',
bulletBorderThickness: 1,
bulletBorderAlpha: 1,
bulletColor: '#ffffff',
bulletSize: 5,
useLineColorForBulletBorder: true,
lineColor: '#1e88e5',
hideBulletsCount: 101,
balloonText: '[[AvgBlockSize]] KB',
switchable: false,
balloonFunction: function(item, graph) {
var result = graph.balloonText;
return result.replace('[[AvgBlockSize]]', (Math.round((item.dataContext.AvgBlockSize / 1000) * 100)/100).toFixed(2));
}
},
{
id: 'g-price',
valueAxis: 'v-price',
title: 'Average Price',
valueField: 'AvgUSD',
bullet: 'round',
bulletBorderThickness: 1,
bulletBorderAlpha: 1,
bulletColor: '#ffffff',
bulletSize: 5,
useLineColorForBulletBorder: true,
lineColor: '#00e676',
balloonText: '$[[AvgUSD]]',
balloonFunction: function(item, graph) {
var result = graph.balloonText;
if (!item.dataContext.AvgUSD) {
return '';
}
return result.replace('[[AvgUSD]]', item.dataContext.AvgUSD.toFixed(2));
},
hideBulletsCount: 101,
labelFunction: function(value) {
return '$' + value;
},
}
],
chartCursor: {
cursorAlpha: 0.1,
fullWidth: true,
valueLineBalloonEnabled: true,
categoryBalloonColor: '#333333',
cursorColor: '#1e88e5',
categoryBalloonDateFormat: minPeriod === 'hh' ? 'D MMM HH:NN ' : 'D MMM'
},
chartScrollbar: {
scrollbarHeight: 36,
color: '#888888',
gridColor: '#bbbbbb'
},
legend: {
marginLeft: 110,
useGraphSettings: true,
valueAlign: 'right',
valueWidth: 60,
spacing: 64,
valueFunction: function(item, formatted) {
if (item.dataContext) {
var g = item.graph;
if (g.id === 'g-block-size' && item.dataContext.AvgBlockSize > 0) {
return g.balloonText.replace('[[AvgBlockSize]]', (Math.round((item.dataContext.AvgBlockSize / 1000) * 100)/100).toFixed(2) );
}
if (g.id === 'g-price' && item.dataContext.AvgUSD) {
return g.balloonText.replace('[[AvgUSD]]', item.dataContext.AvgUSD.toFixed(2));
}
}
return formatted;
}
},
export: {
enabled: true,
fileName: 'lbry-block-size-chart',
position: 'bottom-right',
divId: 'chart-export'
}
});
loadChartData(defaultPeriod);
});
var loadChartData = function(dataPeriod) {
var loadProgress = $('.block-size-chart-container .load-progress');
// clear previous chart data
$.ajax({
url: '/api/v1/charts/blocksize/' + dataPeriod,
type: 'get',
dataType: 'json',
beforeSend: function() {
chartLoadInProgress = true;
loadProgress.css({ display: 'block' });
},
success: function(response) {
if (response.success) {
chartData = [];
var data = response.data;
for (var period in data) {
if (data.hasOwnProperty(period)) {
chartData.push({
date: Date.parse(period),
AvgBlockSize: data[period].AvgBlockSize,
AvgUSD: data[period].AvgUSD
});
}
}
// save selcted period to localStorage
localStorage.setItem('chartPeriod', dataPeriod);
if (chart) {
var isHourly = (dataPeriod.indexOf('h') > -1);
var gridCount = periodGridCounts[dataPeriod];
chart.categoryAxis.minPeriod = isHourly ? 'hh' : 'DD';
chart.categoryAxis.dateFormats[4].format = isHourly ? 'DD MMM' : 'DD';
chart.chartCursor.categoryBalloonDateFormat = isHourly ? 'D MMM HH:NN ' : 'D MMM YYYY';
chart.categoryAxis.gridCount = gridCount;
chart.chartScrollbar.gridCount = gridCount;
chart.dataProvider = chartData;
chart.validateNow();
chart.validateData();
}
}
},
complete: function() {
chartLoadInProgress = false;
loadProgress.css({ display: 'none' });
}
});
};
$(document).ready(function() {
$('.block-size-data-links a').on('click', function(evt) {
evt.preventDefault();
if (chartLoadInProgress) {
return;
}
var link = $(this);
if (link.hasClass('active')) {
return;
}
link.addClass('active').siblings().removeClass('active');
var period = link.attr('data-period');
loadChartData(period);
});
$('a[data-period="' + defaultPeriod + '"]').addClass('active').siblings().removeClass('active');
});
</script>
<?php $this->end(); ?>
<div class="block-head">
@ -181,13 +410,13 @@
<tbody>
<?php foreach ($blocks as $block): ?>
<tr>
<td class="right"><a href="/blocks/<?php echo $block->height ?>"><?php echo $block->height ?></a></td>
<td class="pad-left"><?php echo number_format($block->difficulty, 8, '.', '') ?></td>
<td class="right"><?php echo number_format((($currentBlock->height - $block->height) + 1), 0, '', ',') ?></td>
<td class="right"><?php echo $block->tx_count ?></td>
<td class="right"><?php echo round($block->block_size / 1024, 2) . 'KB' ?></td>
<td class="right pad-left"><?php echo $block->nonce ?></td>
<td class="pad-left"><?php echo \DateTime::createFromFormat('U', $block->block_time)->format('d M Y H:i:s') ?> UTC</td>
<td class="right"><a href="/blocks/<?php echo $block->Height ?>"><?php echo $block->Height ?></a></td>
<td class="pad-left"><?php echo number_format($block->Difficulty, 8, '.', '') ?></td>
<td class="right"><?php echo number_format($block->Confirmations, 0, '', ',') ?></td>
<td class="right"><?php echo count(json_decode($block->TransactionHashes)) ?></td>
<td class="right"><?php echo round($block->BlockSize / 1024, 2) . 'KB' ?></td>
<td class="right pad-left"><?php echo $block->Nonce ?></td>
<td class="pad-left"><?php echo \DateTime::createFromFormat('U', $block->BlockTime)->format('d M Y H:i:s') ?> UTC</td>
</tr>
<?php endforeach; ?>
</tbody>

View file

@ -39,15 +39,28 @@
<?php if (isset($claim)):
$a = ['purple', 'orange', 'blue', 'teal', 'green', 'yellow'];
$autoThumbText = $claim->getAutoThumbText();
$cost = 'Free';
if (isset($claim->price) && $claim->price > 0) {
$cost = $this->Amount->formatCurrency($claim->price) . ' LBC';
} else if (isset($claim->fee) && strtolower($claim->fee_currency) === 'lbc') {
$cost = $this->Amount->formatCurrency($claim->fee) . ' LBC';
$autoThumbText = '';
$link = $claim->Name;
$rawLink = $claim->Name;
if (isset($claim->Publisher->Name)) {
$link = urlencode($claim->Publisher->Name) . '/' . $link;
$rawLink = $claim->Publisher->Name . '/' . $rawLink;
}
$link = 'lbry://' . $link;
$rawLink = 'lbry://' . $rawLink;
if ($claim->ClaimType == 1) { $autoThumbText = strtoupper(substr($claim->Name, 1, min( strlen($claim->Name), 10 ))); } else {
$str = str_replace(' ', '', (strlen(trim($claim->Title)) > 0) ? $claim->Title : $claim->Name);
$autoThumbText = strtoupper(mb_substr($str, 0, min( strlen($str), 10 )));
}
$desc = $claim->description;
$cost = 'Free';
if (isset($claim->Price) && $claim->Price > 0) {
$cost = $this->Amount->formatCurrency($claim->Price) . ' LBC';
} else if (isset($claim->Fee) && strtolower($claim->FeeCurrency) === 'lbc') {
$cost = $this->Amount->formatCurrency($claim->Fee) . ' LBC';
}
$desc = $claim->Description;
if (strlen(trim($desc)) == 0) {
$desc = '<em>No description available.</em>';
} else {
@ -57,38 +70,29 @@ if (strlen(trim($desc)) == 0) {
?>
<?php $this->assign('title', 'Claim &bull; ' . $claim->name) ?>
<?php $this->assign('title', 'Claim &bull; ' . $claim->Name) ?>
<div class="claims-head">
<h3><a href="/claims">LBRY Claims</a> &bull; <?php echo $claim->name ?></h3>
<h4><?php echo $claim->claim_id ?></h4>
<h3><a href="/claims">LBRY Claims</a> &bull; <?php echo $claim->Name ?></h3>
<h4><?php echo $claim->ClaimId ?></h4>
</div>
<div class="claims-body">
<?php if ($claimIsBlocked): ?>
<div class="blocked-claim-info">
<div class="content">
In response to a complaint we received under the US Digital Millennium Copyright Act, we have blocked access to this content from our applications. For more information, please refer to <a href="https://lbry.com/faq/dmca" target="_blank">DMCA takedown requests</a>.
</div>
</div>
<?php else: ?>
<div class="claim-info">
<div data-autothumb="<?php echo $autoThumbText ?>" class="thumbnail <?php echo $a[mt_rand(0, count($a) - 1)] ?>">
<?php if (!$claim->is_nsfw && strlen(trim($claim->thumbnail_url)) > 0): ?>
<img src="<?php echo htmlspecialchars('https://thumbnails.odycdn.com/optimize/s:1280:720/quality:85/plain/'.$claim->thumbnail_url) ?>" alt="" />
<?php if (!$claim->IsNSFW && strlen(trim($claim->ThumbnailUrl)) > 0): ?>
<img src="<?php echo $claim->ThumbnailUrl ?>" alt="" />
<?php else: ?>
<div class="autothumb"><?php echo $autoThumbText ?></div>
<?php endif; ?>
</div>
<div class="content">
<?php if ($claim->claim_type == 1): ?>
<?php if ($claim->ClaimType == 2): ?>
<div class="label">Published By</div>
<div class="value">
<?php if (isset($claim->publisher)): ?>
<a href="lbry://<?php echo $claim->publisher ?>"><?php echo $claim->publisher ?></a>
<?php if (isset($claim->Publisher)): ?>
<a href="lbry://<?php echo $claim->Publisher->Name ?>"><?php echo $claim->Publisher->Name ?></a>
<?php else: ?>
<em>Anonymous</em>
<?php endif; ?>
@ -96,17 +100,17 @@ if (strlen(trim($desc)) == 0) {
<?php endif; ?>
<div class="label">Created On</div>
<div class="value"><?php echo \DateTime::createFromFormat('U', $claim->transaction_time > 0 ? $claim->transaction_time : $claim->created_at->format('U'))->format('j M Y H:i:s') ?> UTC</div>
<div class="value"><?php echo \DateTime::createFromFormat('U', $claim->TransactionTime > 0 ? $claim->TransactionTime : $claim->Created->format('U'))->format('j M Y H:i:s') ?> UTC</div>
<div class="label">Transaction ID</div>
<div class="value"><a href="/tx/<?php echo $claim->transaction_hash_id ?>#output-<?php echo $claim->vout ?>"><?php echo $claim->transaction_hash_id ?></a></div>
<div class="value"><a href="/tx/<?php echo $claim->TransactionHash ?>#output-<?php echo $claim->Vout ?>"><?php echo $claim->TransactionHash ?></a></div>
<?php if ($claim->claim_type == 1): ?>
<?php if ($claim->ClaimType == 2): ?>
<div class="label half-width">Cost</div>
<div class="label half-width">Safe for Work</div>
<div class="value half-width"><?php echo $cost ?></div>
<div class="value half-width"><?php echo $claim->is_nsfw ? 'No' : 'Yes' ?></div>
<div class="value half-width"><?php echo $claim->IsNSFW ? 'No' : 'Yes' ?></div>
<div class="clear"></div>
<?php endif; ?>
@ -114,11 +118,11 @@ if (strlen(trim($desc)) == 0) {
</div>
<div class="claim-metadata">
<?php if ($claim->claim_type == 2): ?>
<?php if ($claim->ClaimType == 1): ?>
<div class="title">Identity Claim</div>
<div class="desc">This is an identity claim.</div>
<?php else: ?>
<div class="title"><?php echo $claim->title ?></div>
<div class="title"><?php echo $claim->Title ?></div>
<div class="desc"><?php echo str_replace("\n", '<br />', $desc) ?></div>
<div class="details">
@ -126,33 +130,30 @@ if (strlen(trim($desc)) == 0) {
<div class="label half-width">Content Type</div>
<div class="value half-width"><?php echo strlen(trim($claim->author)) > 0 ? $claim->author : '<em>Unspecified</em>' ?></div>
<div class="value half-width"><?php echo strlen(trim($claim->content_type)) > 0 ? $claim->content_type : '<em>Unspecified</em>' ?></div>
<div class="value half-width"><?php echo strlen(trim($claim->Author)) > 0 ? $claim->Author : '<em>Unspecified</em>' ?></div>
<div class="value half-width"><?php echo strlen(trim($claim->ContentType)) > 0 ? $claim->ContentType : '<em>Unspecified</em>' ?></div>
<!--
<div class="label half-width">License</div>
-->
<div class="label">Language</div>
<div class="label half-width">Language</div>
<!--
<div class="value half-width"<?php if(strlen(trim($claim->license)) > 0): ?> title="<?php echo $claim->license ?>"<?php endif; ?>>
<div class="value half-width"<?php if(strlen(trim($claim->License)) > 0): ?> title="<?php echo $claim->License ?>"<?php endif; ?>>
<?php if (strlen(trim($claim->LicenseUrl)) > 0): ?><a href="<?php echo $claim->LicenseUrl ?>" rel="nofollow" target="_blank"><?php endif; ?>
<?php echo strlen(trim($claim->License)) > 0 ? $claim->License : '<em>Unspecified</em>' ?>
<?php if (strlen(trim($claim->LicenseUrl))): ?></a><?php endif; ?>
</div>
-->
<div class="value half-width"><?php echo strlen(trim($claim->language)) > 0 ? ($claim->language == 'en' ? 'English' : '') : '<em>Unspecified</em>' ?></div>
<div class="value half-width"><?php echo strlen(trim($claim->Language)) > 0 ? ($claim->Language == 'en' ? 'English' : '') : '<em>Unspecified</em>' ?></div>
</div>
<?php endif; ?>
<a href="<?php echo $claim->getLbryLink() ?>" class="open-lbry-link">Open in LBRY</a>
<a href="<?php echo $link ?>" class="open-lbry-link">Open in LBRY</a>
</div>
<div class="clear"></div>
<?php endif; ?>
<?php if (count($moreClaims) > 0): ?>
<div class="more-claims">
<h4><?php echo isset($claim->publisher) ? 'More from the publisher' : 'Published by this identity' ?></h4>
<h4><?php echo isset($claim->Publisher) ? 'More from the publisher' : 'Published by this identity' ?></h4>
<div class="claims-grid">
<?php $idx = 1; $row = 1; $rowCount = ceil(count($moreClaims) / 3);
@ -162,9 +163,105 @@ if (strlen(trim($desc)) == 0) {
if ($idx % 3 == 0) {
$row++;
}
echo $this->element('claimbox', array('claim' => $claim, 'idx' => $idx, 'last_row' => $last_row));
$idx++;
endforeach; ?>
$autoThumbText = '';
$link = $claim->Name;
$rawLink = $claim->Name;
if (isset($claim->Publisher->Name)) {
$link = urlencode($claim->Publisher->Name) . '/' . $link;
$rawLink = $claim->Publisher->Name . '/' . $rawLink;
}
$link = 'lbry://' . $link;
$rawLink = 'lbry://' . $rawLink;
$cost = '';
if (isset($claim->Price) && $claim->Price > 0) {
$cost = $this->Amount->formatCurrency($claim->Price) . ' LBC';
} else if (isset($claim->Fee) && strtolower($claim->FeeCurrency) === 'lbc') {
$cost = $this->Amount->formatCurrency($claim->Fee) . ' LBC';
}
// content type
$ctTag = null;
if (substr($claim->ContentType, 0, 5) === 'audio') {
$ctTag = 'audio';
} else if (substr($claim->ContentType, 0, 5) === 'video') {
$ctTag = 'video';
} else if (substr($claim->ContentType, 0, 5) === 'image') {
$ctTag = 'image';
}
if (!$ctTag && $claim->ClaimType == 1) {
$ctTag = 'identity';
}
if ($claim->ClaimType == 1) { $autoThumbText = strtoupper(substr($claim->Name, 1, min( strlen($claim->Name), 10 ))); } else {
$str = str_replace(' ', '', (strlen(trim($claim->Title)) > 0) ? $claim->Title : $claim->Name);
$autoThumbText = strtoupper(mb_substr($str, 0, min( strlen($str), 10 )));
}
?>
<div data-id="<?php echo $claim->ClaimId ?>" class="claim-grid-item<?php if ($idx % 3 == 0): ?> last-item<?php endif; ?><?php if ($last_row): ?> last-row<?php endif; ?>">
<?php if (strlen(trim($cost)) > 0): ?>
<div class="price-tag"><?php echo $cost ?></div>
<?php endif; ?>
<div class="tags">
<?php if ($ctTag): ?>
<div class="content-type"><?php echo strtoupper($ctTag) ?></div>
<?php endif; ?>
<?php if ($claim->IsNSFW): ?>
<div class="nsfw">NSFW</div>
<?php endif; ?>
</div>
<div data-autothumb="<?php echo $autoThumbText ?>" class="thumbnail <?php echo $a[mt_rand(0, count($a) - 1)] ?>">
<?php if (!$claim->IsNSFW && strlen(trim($claim->ThumbnailUrl)) > 0): ?>
<img src="<?php echo $claim->ThumbnailUrl ?>" alt="" />
<?php else: ?>
<div class="autothumb"><?php echo $autoThumbText ?></div>
<?php endif; ?>
</div>
<div class="metadata">
<div class="title" title="<?php echo $claim->ClaimType == 1 ? $claim->Name : ((strlen(trim($claim->Title)) > 0) ? $claim->Title : '') ?>"><?php echo $claim->ClaimType == 1 ? $claim->Name : ((strlen(trim($claim->Title)) > 0) ? $claim->Title : '<em>No Title</em>') ?></div>
<div class="link" title="<?php echo $rawLink ?>"><a href="<?php echo $link ?>" rel="nofollow"><?php echo $rawLink ?></a></div>
<div class="desc"><?php echo strlen(trim($claim->Description)) > 0 ? $claim->Description : '<em>No description available</em>' ?></div>
<div class="label half-width">Transaction</div>
<div class="label half-width">Created</div>
<div class="value half-width"><a href="/tx/<?php echo $claim->TransactionHash ?>#output-<?php echo $claim->Vout ?>" title="<?php echo $claim->TransactionHash ?>"><?php echo $claim->TransactionHash ?></a></div>
<div class="value half-width" title="<?php echo $claim->Created->format('j M Y H:i:s') ?> UTC">
<?php echo \Carbon\Carbon::createFromTimestamp($claim->Created->format('U'))->diffForHumans(); ?>
</div>
<div class="clear spacer"></div>
<?php if ($claim->ClaimType == 2): ?>
<div class="label half-width">Content Type</div>
<div class="label half-width">Language</div>
<div class="value half-width" title="<?php echo $claim->ContentType ?>"><?php echo $claim->ContentType ?></div>
<div class="value half-width" title="<?php echo $claim->Language == 'en' ? 'English' : $claim->Language ?>"><?php echo $claim->Language == 'en' ? 'English' : $claim->Language ?></div>
<div class="clear spacer"></div>
<div class="label half-width">Author</div>
<div class="label half-width">License</div>
<div class="value half-width" title="<?php echo strlen(trim($claim->Author)) > 0 ? $claim->Author : '<em>Unspecified</em>' ?>"><?php echo strlen(trim($claim->Author)) > 0 ? $claim->Author : '<em>Unspecified</em>' ?></div>
<div class="value half-width" title="<?php echo strlen(trim($claim->License)) > 0 ? $claim->License : '' ?>">
<?php if (strlen(trim($claim->LicenseUrl)) > 0): ?><a href="<?php echo $claim->LicenseUrl ?>" rel="nofollow" target="_blank"><?php endif; ?>
<?php echo strlen(trim($claim->License)) > 0 ? $claim->License : '<em>Unspecified</em>' ?>
<?php if (strlen(trim($claim->LicenseUrl))): ?></a><?php endif; ?>
</div>
<?php endif; ?>
</div>
</div>
<?php $idx++; endforeach; ?>
<div class="clear"></div>
</div>
</div>
@ -193,9 +290,103 @@ if (strlen(trim($desc)) == 0) {
if ($idx % 3 == 0) {
$row++;
}
echo $this->element('claimbox', array('claim' => $claim, 'idx' => $idx, 'last_row' => $last_row));
$idx++;
endforeach; ?>
$autoThumbText = '';
$link = $claim->Name;
$rawLink = $claim->Name;
if (isset($claim->Publisher->Name)) {
$link = urlencode($claim->Publisher->Name) . '/' . $link;
$rawLink = $claim->Publisher->Name . '/' . $rawLink;
}
$link = 'lbry://' . $link;
$rawLink = 'lbry://' . $rawLink;
$cost = '';
if (isset($claim->Price) && $claim->Price > 0) {
$cost = $this->Amount->formatCurrency($claim->Price) . ' LBC';
} else if (isset($claim->Fee) && strtolower($claim->FeeCurrency) === 'lbc') {
$cost = $this->Amount->formatCurrency($claim->Fee) . ' LBC';
}
// content type
$ctTag = null;
if (substr($claim->ContentType, 0, 5) === 'audio') {
$ctTag = 'audio';
} else if (substr($claim->ContentType, 0, 5) === 'video') {
$ctTag = 'video';
} else if (substr($claim->ContentType, 0, 5) === 'image') {
$ctTag = 'image';
}
if (!$ctTag && $claim->ClaimType == 1) {
$ctTag = 'identity';
}
if ($claim->ClaimType == 1) { $autoThumbText = strtoupper(substr($claim->Name, 1, min( strlen($claim->Name), 10 ))); } else {
$str = str_replace(' ', '', (strlen(trim($claim->Title)) > 0) ? $claim->Title : $claim->Name);
$autoThumbText = strtoupper(mb_substr($str, 0, min( strlen($str), 10 )));
}
?>
<div data-id="<?php echo $claim->ClaimId ?>" class="claim-grid-item<?php if ($idx % 3 == 0): ?> last-item<?php endif; ?><?php if ($last_row): ?> last-row<?php endif; ?>">
<?php if (strlen(trim($cost)) > 0): ?>
<div class="price-tag"><?php echo $cost ?></div>
<?php endif; ?>
<div class="tags">
<?php if ($ctTag): ?>
<div class="content-type"><?php echo strtoupper($ctTag) ?></div>
<?php endif; ?>
<?php if ($claim->IsNSFW): ?>
<div class="nsfw">NSFW</div>
<?php endif; ?>
</div>
<div data-autothumb="<?php echo $autoThumbText ?>" class="thumbnail <?php echo $a[mt_rand(0, count($a) - 1)] ?>">
<?php if (!$claim->IsNSFW && strlen(trim($claim->ThumbnailUrl)) > 0): ?>
<img src="<?php echo $claim->ThumbnailUrl ?>" alt="" />
<?php else: ?>
<div class="autothumb"><?php echo $autoThumbText ?></div>
<?php endif; ?>
</div>
<div class="metadata">
<div class="title" title="<?php echo $claim->ClaimType == 1 ? $claim->Name : ((strlen(trim($claim->Title)) > 0) ? $claim->Title : '') ?>"><?php echo $claim->ClaimType == 1 ? $claim->Name : ((strlen(trim($claim->Title)) > 0) ? $claim->Title : '<em>No Title</em>') ?></div>
<div class="link" title="<?php echo $rawLink ?>"><a href="<?php echo $link ?>" rel="nofollow"><?php echo $rawLink ?></a></div>
<div class="desc"><?php echo strlen(trim($claim->Description)) > 0 ? $claim->Description : '<em>No description available</em>' ?></div>
<div class="label half-width">Transaction</div>
<div class="label half-width">Created</div>
<div class="value half-width"><a href="/tx/<?php echo $claim->TransactionHash ?>#output-<?php echo $claim->Vout ?>" title="<?php echo $claim->TransactionHash ?>"><?php echo $claim->TransactionHash ?></a></div>
<div class="value half-width" title="<?php echo $claim->Created->format('j M Y H:i:s') ?> UTC">
<?php echo \Carbon\Carbon::createFromTimestamp($claim->TransactionTime > 0 ? $claim->TransactionTime : $claim->Created->format('U'))->diffForHumans(); ?>
</div>
<div class="clear spacer"></div>
<?php if ($claim->ClaimType == 2): ?>
<div class="label half-width">Content Type</div>
<div class="label half-width">Language</div>
<div class="value half-width" title="<?php echo $claim->ContentType ?>"><?php echo $claim->ContentType ?></div>
<div class="value half-width" title="<?php echo $claim->Language == 'en' ? 'English' : $claim->Language ?>"><?php echo $claim->Language == 'en' ? 'English' : $claim->Language ?></div>
<div class="clear spacer"></div>
<div class="label half-width">Author</div>
<div class="label half-width">License</div>
<div class="value half-width" title="<?php echo strlen(trim($claim->Author)) > 0 ? $claim->Author : '<em>Unspecified</em>' ?>"><?php echo strlen(trim($claim->Author)) > 0 ? $claim->Author : '<em>Unspecified</em>' ?></div>
<div class="value half-width" title="<?php echo strlen(trim($claim->License)) > 0 ? $claim->License : '' ?>">
<?php if (strlen(trim($claim->LicenseUrl)) > 0): ?><a href="<?php echo $claim->LicenseUrl ?>" rel="nofollow" target="_blank"><?php endif; ?>
<?php echo strlen(trim($claim->License)) > 0 ? $claim->License : '<em>Unspecified</em>' ?>
<?php if (strlen(trim($claim->LicenseUrl))): ?></a><?php endif; ?>
</div>
<?php endif; ?>
</div>
</div>
<?php $idx++; endforeach; ?>
<div class="clear"></div>
</div>

View file

@ -1,66 +0,0 @@
<?php $this->start('script'); ?>
<script type="text/javascript">
var resizeCards = function() {
var claimInfo = $('.claim-info');
var claimMtdt = $('.claim-metadata');
if (claimMtdt.outerHeight() < claimInfo.outerHeight()) {
claimMtdt.outerHeight(claimInfo.outerHeight());
} else if (claimInfo.outerHeight() < claimMtdt.outerHeight()) {
claimInfo.outerHeight(claimMtdt.outerHeight());
}
};
window.onload = function() {
resizeCards();
};
$(document).ready(function() {
resizeCards();
$('.claim-grid-item img,.claim-info img').on('error', function() {
var img = $(this);
var parent = img.parent();
var text = parent.attr('data-autothumb');
img.remove();
parent.append(
$('<div></div>').attr({'class': 'autothumb' }).text(text)
);
});
$(document).on('click', '.claim-grid-item', function() {
var id = $(this).attr('data-id');
location.href = '/claims/' + id;
});
});
</script>
<?php $this->end(); ?>
<?php echo $this->element('header') ?>
<?php $this->assign('title', 'Search Results') ?>
<div class="claims-head">
<h3>Search results</h3>
</div>
<div class="claims-grid">
<?php if (isset($claims) && count($claims) > 0): ?>
<?php
$idx = 1;
$row = 1;
$rowCount = ceil(count($claims) / 3);
$a = ['purple', 'orange', 'blue', 'teal', 'green', 'yellow'];
foreach ($claims as $claim):
$last_row = ($row == $rowCount);
if ($idx % 3 == 0) {
$row++;
}
echo $this->element('claimbox', array('claim' => $claim, 'idx' => $idx, 'last_row' => $last_row));
$idx++;
endforeach; ?>
<?php else: ?>
<div class="no-results">No results were found.</div>
<?php endif; ?>
<div class="clear"></div>
</div>
<?php echo $this->element('pagination') ?>

View file

@ -127,22 +127,22 @@
</div>
<div class="stats">
<div class="box box-20">
<div class="box">
<div class="title">Block Height</div>
<div class="value"><?php echo $recentBlocks[0]->height ?></div>
<div class="value"><?php echo $recentBlocks[0]->Height ?></div>
</div>
<div class="box box-30">
<div class="box">
<div class="title">Difficulty</div>
<div class="value" title="<?php echo $recentBlocks[0]->difficulty ?>"><?php echo number_format($recentBlocks[0]->difficulty, 2, '.', '') ?></div>
<div class="value" title="<?php echo $recentBlocks[0]->Difficulty ?>"><?php echo number_format($recentBlocks[0]->Difficulty, 2, '.', '') ?></div>
</div>
<div class="box box-30">
<div class="box">
<div class="title">Network</div>
<div class="value"><?php echo $hashRate ?></div>
</div>
<div class="box box-20 last">
<div class="box last">
<div class="title">Price</div>
<div class="value"><?php echo $lbcUsdPrice ?></div>
</div>
@ -167,13 +167,13 @@
<tbody>
<?php foreach ($recentBlocks as $block): ?>
<tr data-height="<?php echo $block->height ?>" data-time="<?php echo $block->block_time ?>">
<td><a href="/blocks/<?php echo $block->height ?>"><?php echo $block->height ?></a></td>
<td><?php echo \Carbon\Carbon::createFromTimestamp($block->block_time)->diffForHumans(); ?></td>
<td class="right"><?php echo round($block->block_size / 1024, 2) . 'KB' ?></td>
<td class="right"><?php echo $block->tx_count ?></td>
<td class="right"><?php echo number_format($block->difficulty, 2, '.', '') ?></td>
<td class="last-cell"><?php echo DateTime::createFromFormat('U', $block->block_time)->format('d M Y H:i:s') . ' UTC' ?></td>
<tr data-height="<?php echo $block->Height ?>" data-time="<?php echo $block->BlockTime ?>">
<td><a href="/blocks/<?php echo $block->Height ?>"><?php echo $block->Height ?></a></td>
<td><?php echo \Carbon\Carbon::createFromTimestamp($block->BlockTime)->diffForHumans(); ?></td>
<td class="right"><?php echo round($block->BlockSize / 1024, 2) . 'KB' ?></td>
<td class="right"><?php echo $block->TransactionCount ?></td>
<td class="right"><?php echo number_format($block->Difficulty, 2, '.', '') ?></td>
<td class="last-cell"><?php echo DateTime::createFromFormat('U', $block->BlockTime)->format('d M Y H:i:s') . ' UTC' ?></td>
</tr>
<?php endforeach; ?>
</tbody>
@ -183,43 +183,66 @@
<div class="recent-claims">
<h3>Recent Claims</h3>
<a class="claim-explorer-link" href="/claims">Claims Explorer</a>
<?php $idx = 0; $a = ['purple', 'orange', 'blue', 'teal', 'green', 'yellow'];
foreach ($recentClaims as $claim):
<?php $idx = 0; $a = ['purple', 'orange', 'blue', 'teal', 'green', 'yellow']; foreach ($recentClaims as $claim):
$idx++;
$autoThumbText = $claim->getAutoThumbText();
$autoThumbText = '';
$link = $claim->Name;
$rawLink = $claim->Name;
if (isset($claim->Publisher->Name)) {
$link = urlencode($claim->Publisher->Name) . '/' . $link;
$rawLink = $claim->Publisher->Name . '/' . $link;
}
$link = 'lbry://' . $link;
$rawLink = 'lbry://' . $rawLink;
// content type
$ctTag = $claim->getContentTag();
$ctTag = null;
if (substr($claim->ContentType, 0, 5) === 'audio') {
$ctTag = 'audio';
} else if (substr($claim->ContentType, 0, 5) === 'video') {
$ctTag = 'video';
} else if (substr($claim->ContentType, 0, 5) === 'image') {
$ctTag = 'image';
}
if (!$ctTag && $claim->ClaimType == 1) {
$ctTag = 'identity';
}
if ($claim->ClaimType == 1) { $autoThumbText = strtoupper(substr($claim->Name, 1, min( strlen($claim->Name), 3 ))); } else {
$str = (strlen(trim($claim->Title)) > 0) ? $claim->Title : $claim->Name;
$autoThumbText = strtoupper(substr($str, 0, min (strlen($str), 2 )));
}
?>
<div data-id="<?php echo $claim->claim_id ?>" class="claim-box<?php if ($idx == 5): ?> last<?php endif; ?>">
<div data-id="<?php echo $claim->ClaimId ?>" class="claim-box<?php if ($idx == 5): ?> last<?php endif; ?>">
<div class="tags">
<?php if ($ctTag): ?>
<div class="content-type"><?php echo strtoupper($ctTag) ?></div>
<?php endif; ?>
<?php if ($claim->is_nsfw): ?>
<?php if ($claim->IsNSFW): ?>
<div class="nsfw">NSFW</div>
<?php endif; ?>
</div>
<div data-autothumb="<?php echo $autoThumbText ?>" class="thumbnail <?php echo $a[mt_rand(0, count($a) - 1)] ?>">
<?php if (!$claim->is_nsfw && strlen(trim($claim->thumbnail_url)) > 0): ?>
<img src="<?php echo strip_tags('https://thumbnails.odycdn.com/optimize/s:1280:720/quality:85/plain/'.$claim->thumbnail_url) ?>" alt="" />
<?php if (!$claim->IsNSFW && strlen(trim($claim->ThumbnailUrl)) > 0): ?>
<img src="<?php echo strip_tags($claim->ThumbnailUrl) ?>" alt="" />
<?php else: ?>
<div class="autothumb"><?php echo $autoThumbText ?></div>
<?php endif; ?>
</div>
<div class="metadata">
<div class="title" title="<?php echo $claim->claim_type == 1 ? $claim->name : ((strlen(trim($claim->title)) > 0) ? $claim->title : ''); ?>"><?php echo $claim->claim_type == 1 ? $claim->name : ((strlen(trim($claim->title)) > 0) ? $claim->title : '<em>No Title</em>') ?></div>
<div class="link" title="<?php echo $claim->getLbryLink() ?>"><a href="<?php echo $claim->getLbryLink() ?>"><?php echo $claim->getLbryLink() ?></a></div>
<div class="title" title="<?php echo $claim->ClaimType == 1 ? $claim->Name : ((strlen(trim($claim->Title)) > 0) ? $claim->Title : ''); ?>"><?php echo $claim->ClaimType == 1 ? $claim->Name : ((strlen(trim($claim->Title)) > 0) ? $claim->Title : '<em>No Title</em>') ?></div>
<div class="link" title="<?php echo $rawLink ?>"><a href="<?php echo $link ?>"><?php echo $rawLink ?></a></div>
<div class="clear"></div>
<?php if ($claim->claim_type == 2 && strlen(trim($claim->description)) > 0): ?>
<div class="desc"><?php echo $claim->description ?></div>
<?php if ($claim->ClaimType == 2 && strlen(trim($claim->Description)) > 0): ?>
<div class="desc"><?php echo $claim->Description ?></div>
<?php endif; ?>
</div>
<a class="tx-link" href="/tx/<?php echo $claim->transaction_hash_id ?>#output-<?php echo $claim->vout ?>" target="_blank">Transaction</a>
<a class="tx-link" href="/tx/<?php echo $claim->TransactionHash ?>#output-<?php echo $claim->Vout ?>" target="_blank">Transaction</a>
</div>
<?php endforeach; ?>

View file

@ -128,10 +128,10 @@
<tbody>
<?php foreach ($blocks as $block): ?>
<tr data-height="<?php echo $block->height ?>" data-time="<?php echo $block->block_time ?>">
<td><a href="/blocks/<?php echo $block->height ?>" target="_blank"><?php echo $block->height ?></a></td>
<td><?php echo \Carbon\Carbon::createFromTimestamp($block->block_time)->diffForHumans(); ?></td>
<td class="right"><?php echo $block->tx_count ?></td>
<tr data-height="<?php echo $block->Height ?>" data-time="<?php echo $block->BlockTime ?>">
<td><a href="/blocks/<?php echo $block->Height ?>" target="_blank"><?php echo $block->Height ?></a></td>
<td><?php echo \Carbon\Carbon::createFromTimestamp($block->BlockTime)->diffForHumans(); ?></td>
<td class="right"><?php echo $block->TransactionCount ?></td>
</tr>
<?php endforeach; ?>
</tbody>
@ -153,12 +153,12 @@
<tbody>
<?php foreach ($txs as $tx): ?>
<tr data-hash="<?php echo $tx->hash ?>" data-time="<?php echo $tx->transaction_time ?>">
<td class="w200"><div><a href="/tx/<?php echo $tx->hash ?>" target="_blank"><?php echo $tx->hash ?></a></div></td>
<td><?php echo $tx->created_at->diffForHumans(); ?></td>
<td class="right"><?php echo $tx->input_count ?></td>
<td class="right"><?php echo $tx->output_count ?></td>
<td class="right"><?php echo number_format($tx->value, 8, '.', '') ?> LBC</td>
<tr data-hash="<?php echo $tx->Hash ?>" data-time="<?php echo $tx->TxTime ?>">
<td class="w200"><div><a href="/tx/<?php echo $tx->Hash ?>" target="_blank"><?php echo $tx->Hash ?></a></div></td>
<td><?php echo \Carbon\Carbon::createFromTimestamp($tx->TxTime)->diffForHumans(); ?></td>
<td class="right"><?php echo $tx->InputCount ?></td>
<td class="right"><?php echo $tx->OutputCount ?></td>
<td class="right"><?php echo number_format($tx->Value, 8, '.', '') ?> LBC</td>
</tr>
<?php endforeach; ?>
</tbody>

View file

@ -1,34 +1,19 @@
<?php $this->assign('title', 'Stats &amp; Rich List') ?>
<?php $this->start('script'); ?>
<script type="text/javascript">
</script>
<?php $this->end(); ?>
<?php echo $this->element('header') ?>
<?php $this->start('script'); ?>
<script src="https://www.amcharts.com/lib/3/amcharts.js"></script>
<script src="https://www.amcharts.com/lib/3/serial.js"></script>
<script src="https://www.amcharts.com/lib/3/plugins/export/export.min.js"></script>
<script src="https://www.amcharts.com/lib/3/plugins/responsive/responsive.min.js" type="text/javascript"></script>
<script type="text/javascript" src="/js/mining-inflation-chart.js"></script>
<?php $this->end(); ?>
<?php
$this->start('css');
echo $this->Html->css('/css/mining-inflation-chart.css');
echo $this->Html->css('https://www.amcharts.com/lib/3/plugins/export/export.css');
$this->end();
?>
<div class="stats-head">
<h3>LBRY Stats</h3>
</div>
<div class="stats-main">
<div class="mining-inflation-chart-container">
<div class="load-progress inc"></div>
<h3>Mining Inflation Chart</h3>
<div id="mining-inflation-chart" class="chart"></div>
<div id="chart-export" class="btn-chart-export"></div>
</div>
<div class="richlist">
<h3>LBRY Rich List (Top 500)</h3>
<table class="table">
@ -47,25 +32,22 @@
<?php $rank = 0; foreach ($richList as $item): $rank++; ?>
<tr>
<td class="right topvalign"><?php echo $rank ?></td>
<td class="topvalign"><a href="/address/<?php echo $item->address ?>" target="_blank"><?php echo $item->address ?></a>
<?php if(in_array($item->address, $lbryAddresses)): ?>
<span class="lbry-address">
<img src="/img/lbry.png" height="18px" width="18px" title="Address owned by LBRY Inc."/>
</span>
<?php endif; ?>
<td class="topvalign"><a href="/address/<?php echo $item->Address ?>" target="_blank"><?php echo $item->Address ?></a>
<?php if (isset($item->Tag) && strlen(trim($item->Tag)) > 0): ?>
<div class="tag">
<?php if (strlen(trim($item->TagUrl)) > 0): ?><a href="<?php echo $item->TagUrl ?>" target="_blank" rel="nofollow"><?php echo $tiem->Tag ?></a><?php else: echo $item->Tag; endif; ?>
</div>
<?php endif; ?></td>
<td class="right topvalign"><?php echo number_format($item->balance, 8, '.', ',') ?></td>
<td class="right topvalign">$<?php echo number_format(bcmul($item->balance, $rate, 8), 2, '.', ',') ?></td>
<td class="med-pad-left topvalign"><?php echo $item->first_seen->format('d M Y H:i:s') . ' UTC'; ?></td>
<td class="right topvalign"><?php echo number_format($item->Balance, 8, '.', ',') ?></td>
<td class="right topvalign">$<?php echo number_format(bcmul($item->Balance, $rate, 8), 2, '.', ',') ?></td>
<td class="med-pad-left topvalign"><?php echo $item->FirstSeen->format('d M Y H:i:s') . ' UTC'; ?></td>
<td class="w150 center top500-percent-cell"><div class="top500-percent" style="width: <?php echo $item->MinMaxPercent ?>%"></div><div class="text"><?php echo number_format($item->Top500Percent, 5, '.', '') ?>%</div></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<div class="clear"></div>
</div>

View file

@ -14,22 +14,22 @@
<div class="tx-head">
<h3>LBRY Transaction</h3>
<h4><?php echo $tx->hash ?></h4>
<h4><?php echo $tx->Hash ?></h4>
</div>
<div class="tx-time">
<div class="created-time">
<h3 title="Represents the time this transaction was created on the explorer">Time Created</h3>
<div><?php echo $tx->created_at->format('j M Y H:i:s') . ' UTC '; ?></div>
<div><?php echo $tx->Created->format('j M Y H:i:s') . ' UTC '; ?></div>
</div>
<div class="conf-time">
<h3 title="The time the first confirmation of this transaction happened on the blockchain">Block Time</h3>
<div><?php echo ($tx->transaction_time == null || strlen(trim($tx->transaction_time)) == 0) ? '<em>Not yet confirmed</em>' :
\DateTime::createFromFormat('U', $tx->transaction_time)->format('j M Y H:i:s') . ' UTC' ?>
<div><?php echo ($tx->TransactionTime == null || strlen(trim($tx->TransactionTime)) == 0) ? '<em>Not yet confirmed</em>' :
\DateTime::createFromFormat('U', $tx->TransactionTime)->format('j M Y H:i:s') . ' UTC' ?>
<?php if ($tx->transaction_time > $tx->created_at->getTimestamp()):
$diffSeconds = $tx->transaction_time - $tx->created_at->getTimestamp();
<?php if ($tx->TransactionTime > $tx->Created->getTimestamp()):
$diffSeconds = $tx->TransactionTime - $tx->Created->getTimestamp();
if ($diffSeconds <= 60) {
echo sprintf(' (+%s second%s)', $diffSeconds, $diffSeconds == 1 ? '' : 's');
} else {
@ -47,15 +47,15 @@
<div class="tx-summary">
<div class="box p25">
<div class="title">Amount (LBC)</div>
<div class="value"><?php echo $this->Amount->format($tx->value) ?></div>
<div class="value"><?php echo $this->Amount->format($tx->Value) ?></div>
</div>
<div class="box p15">
<div class="title">Block Height</div>
<?php if (!isset($tx->block_hash_id) || strlen(trim($tx->block_hash_id)) === 0): ?>
<?php if (!isset($tx->BlockHash) || strlen(trim($tx->BlockHash)) === 0): ?>
<div class="value" title="Unconfirmed">Unconf.</div>
<?php else: ?>
<div class="value" title="<?php echo $tx->block_hash_id ?>"><a href="/blocks/<?php echo $block->height ?>"><?php echo $block->height ?></a></div>
<div class="value" title="<?php echo $tx->BlockHash ?>"><a href="/blocks/<?php echo $block->Height ?>"><?php echo $block->Height ?></a></div>
<?php endif; ?>
</div>
@ -66,17 +66,17 @@
<div class="box p15">
<div class="title">Size (bytes)</div>
<div class="value"><?php echo number_format($tx->transaction_size, 0, '', ',') ?></div>
<div class="value"><?php echo number_format($tx->TransactionSize, 0, '', ',') ?></div>
</div>
<div class="box p15">
<div class="title">Inputs</div>
<div class="value"><?php echo $tx->input_count ?></div>
<div class="value"><?php echo $tx->InputCount ?></div>
</div>
<div class="box p15 last">
<div class="title">Outputs</div>
<div class="value"><?php echo $tx->output_count ?></div>
<div class="value"><?php echo $tx->OutputCount ?></div>
</div>
<div class="clear"></div>
@ -86,29 +86,28 @@
<h3>Details</h3>
<div class="tx-details-layout">
<div class="inputs">
<div class="subtitle"><?php echo $tx->input_count ?> input<?php echo $tx->input_count === 1 ? '' : 's'; ?></div>
<div class="subtitle"><?php echo $tx->InputCount ?> input<?php echo $tx->InputCount === 1 ? '' : 's'; ?></div>
<?php
$setAddressIds = [];
foreach ($inputs as $in):
?>
<div id="input-<?php echo $in->id ?>" class="input <?php if (isset($in->input_addresses) && count($in->input_addresses) > 0 && $in->input_addresses[0]->address == $sourceAddress): ?>is-source<?php endif; ?>">
<?php if ($in->is_coinbase): ?>
<div id="input-<?php echo $in->Id ?>" class="input <?php if (isset($in['InputAddresses']) && count($in['InputAddresses']) > 0 && $in['InputAddresses'][0]->Address == $sourceAddress): ?>is-source<?php endif; ?>">
<?php if ($in['IsCoinbase']): ?>
<div>Block Reward (New Coins)</div>
<?php else: ?>
<?php if (strlen(trim($in->value)) == 0): ?>
<?php if (strlen(trim($in->Value)) == 0): ?>
<div>Incomplete data</div>
<?php else:
$addr = $in->input_addresses[0];
$addr = $in['InputAddresses'][0];
if (!isset($setAddressIds[$addr->address])):
$setAddressIds[$addr->address] = 1; ?>
<a id="<?php echo $addr->address ?>"></a>
if (!isset($setAddressIds[$addr->Address])):
$setAddressIds[$addr->Address] = 1; ?>
<a id="<?php echo $addr->Address ?>"></a>
<?php endif; ?>
<div><span class="value"><?php echo $this->Amount->format($in->value) ?> LBC</span> from</div>
<div class="address"><a href="/address/<?php echo $addr->address ?>"><?php echo $addr->address ?></a>
(<a class="output-link" href="/tx/<?php echo $in->prevout_hash ?>#output-<?php echo $in->prevout_n ?>">output</a>)
<div><span class="value"><?php echo $this->Amount->format($in['Value']) ?> LBC</span> from</div>
<div class="address"><a href="/address/<?php echo $addr->Address ?>"><?php echo $addr->Address ?></a>
(<a class="output-link" href="/tx/<?php echo $in->PrevoutHash ?>#output-<?php echo $in->PrevoutN ?>">output</a>)
<?php if (isset($addr->Tag) && strlen(trim($addr->Tag)) > 0): ?>
<div class="tag">
<?php if (strlen(trim($addr->TagUrl)) > 0): ?><a href="<?php echo $addr->TagUrl ?>" target="_blank" rel="nofollow"><?php echo $addr->Tag ?></a><?php else: echo $addr->Tag; endif; ?>
@ -126,7 +125,7 @@
</div>
<div class="outputs">
<div class="subtitle"><?php echo $tx->output_count ?> output<?php echo $tx->output_count === 1 ? '' : 's'; ?>
<div class="subtitle"><?php echo $tx->OutputCount ?> output<?php echo $tx->OutputCount === 1 ? '' : 's'; ?>
<?php if ($fee > 0): ?>
<span class="fee"><span class="label">Fee</span> <span class="value"><?php echo $this->Amount->format($fee) ?> LBC</span></span>
@ -135,27 +134,26 @@
<?php
foreach ($outputs as $out): ?>
<div id="output-<?php echo $out->vout ?>" class="output <?php if (isset($out->output_addresses) && count($out->output_addresses) > 0 && $out->output_addresses[0]->address == $sourceAddress): ?>is-source<?php endif; ?>">
<div id="output-<?php echo $out->Vout ?>" class="output <?php if (isset($out['OutputAddresses']) && count($out['OutputAddresses']) > 0 && $out['OutputAddresses'][0]->Address == $sourceAddress): ?>is-source<?php endif; ?>">
<div class="labels">
<?php if($out->Claim && ($out->IsClaim or $out->IsSupportClaim or $out->IsUpdateClaim)): ?><a class="view-claim" href="<?php echo $out->Claim->getExplorerLink() ?>">View</a><?php endif; ?>
<?php if($out->IsSupportClaim): ?><div class="support">SUPPORT</div><?php endif; ?>
<?php if($out->IsUpdateClaim): ?><div class="update">UPDATE</div><?php endif; ?>
<?php if($out->IsClaim): ?><div class="claim">CLAIM</div><?php endif; ?>
</div>
<?php if (strlen(trim($out->value)) == 0): ?>
<?php if (strlen(trim($out['Value'])) == 0): ?>
<div>Incomplete data</div>
<?php else:
$addr = $out->output_addresses[0];
$addr = $out['OutputAddresses'][0];
if (!isset($setAddressIds[$addr->address])):
$setAddressIds[$addr->address] = 1; ?>
<a id="<?php echo $addr->address ?>"></a>
if (!isset($setAddressIds[$addr->Address])):
$setAddressIds[$addr->Address] = 1; ?>
<a id="<?php echo $addr->Address ?>"></a>
<?php endif; ?>
<div><span class="value"><?php echo $this->Amount->format($out->value) ?> LBC</span> to</div>
<div class="address"><a href="/address/<?php echo $addr->address ?>"><?php echo $addr->address ?></a>
<div><span class="value"><?php echo $this->Amount->format($out['Value']) ?> LBC</span> to</div>
<div class="address"><a href="/address/<?php echo $addr->Address ?>"><?php echo $addr->Address ?></a>
<?php if ($out->is_spent): ?>(<a href="/tx/<?php if(isset($out->spend_input_id)) { echo $out->spend_input_hash; } ?>#input-<?php if(isset($out->spend_input_id)) {echo $out->spend_input_id; } ?>">spent</a>)<?php else: ?>(unspent)<?php endif; ?>
<?php if ($out->IsSpent): ?>(<a href="/tx/<?php echo $out->SpendInput->TransactionHash ?>#input-<?php echo $out->SpendInput->Id ?>">spent</a>)<?php else: ?>(unspent)<?php endif; ?>
<?php if (isset($addr->Tag) && strlen(trim($addr->Tag)) > 0): ?>
<div class="tag">

View file

@ -15,7 +15,7 @@
namespace App\View;
use Cake\Event\EventManager;
use Cake\Http\ServerRequest;
use Cake\Network\Request;
use Cake\Network\Response;
/**

4
tmp/.gitignore vendored
View file

@ -1,4 +0,0 @@
*
!*/
!.git*

View file

@ -5,7 +5,7 @@ Version: 1.1.2
## Description
Smoothly animates the `dataProvider`.
Smoothly animates the `dataProvider`
It works with serial, pie, XY, funnel, and radar.
@ -96,13 +96,13 @@ http://www.apache.org/licenses/LICENSE-2.0
## Changelog
### 1.1.2
* Fixing a bug with the minimum/maximum.
* Fixing a bug with the minimum/maximum
### 1.1.1
* It now automatically sets the minimum/maximum on the value axes while animating.
* It now automatically sets the minimum/maximum on the value axes while animating
### 1.1.0
* Adding in support for XY charts.
* Adding in support for XY charts
### 1.0.0
* Initial release.
* Initial release

View file

@ -5,13 +5,13 @@ Version: 1.0.16
## Description
By default, all amCharts libraries accept data in JSON format. It needs to be
By default all amCharts libraries accept data in JSON format. It needs to be
there when the web page loads, defined in-line or loaded via custom code.
This plugin introduces our native wrapper that enables automatic loading of data
from external data sources in CSV and JSON formats.
This plugin introduces are native wrapper that enables automatic loading of data
from external data data sources in CSV and JSON formats.
Most of the time, you will just need to provide a URL of the external data
Most of the times you will just need to provide a URL of the external data
source - static file or dynamically generated - and it will do the rest.
@ -25,7 +25,7 @@ So, any of the examples loaded locally (file:///) will not work.
The page needs to be loaded via web server (http://) in order to work properly.
Loading data from another domain than the web page is loaded is possible, but is
Loading data from another domain than the web page is loaded is possible but is
a subject for `Access-Control-Allow-Origin` policies defined by the web server
you are loading data from.
@ -78,7 +78,7 @@ AmCharts.makeChart( "chartdiv", {
That's it. The plugin will make sure the files are loaded and dataProvider is
populated with their content *before* the chart is built.
Some formats like CSV, will require additional parameters needed to parse the
Some formats, like CSV, will require additional parameters needed to parse the
data, such as "separator".
If the "format" is omitted, the plugin will assume JSON.
@ -104,32 +104,32 @@ chart["dataLoader"] = {
Property | Default | Description
-------- | ------- | -----------
async | true | If set to false (not recommended), everything will wait until data is fully loaded.
complete | | Callback function to execute when loader is done.
delimiter | , | [CSV only] a delimiter for columns (use \t for tab delimiters).
emptyAs | undefined | [CSV only] replace empty columns with whatever is set here.
error | | Callback function to execute if file load fails.
init | | Callback function to execute when Data Loader is initialized, before any loading starts.
format | json | Type of data: json, csv.
headers | | An array of objects with two properties (key and value) to attach to HTTP request.
load | | Callback function to execute when file is successfully loaded (might be invoked multiple times).
noStyles | false | If set to true, no styles will be applied to "Data loading" curtain.
numberFields | | [CSV only] An array of fields in data to treat as numbers.
postProcess | | If set to function reference, that function will be called to "post-process" loaded data before passing it on to chart. The handler function will receive two parameters: loaded data, Data Loader options.
async | true | If set to false (not recommended) everything will wait until data is fully loaded
complete | | Callback function to execute when loader is done
delimiter | , | [CSV only] a delimiter for columns (use \t for tab delimiters)
emptyAs | undefined | [CSV only] replace empty columns with whatever is set here
error | | Callback function to execute if file load fails
init | | Callback function to execute when Data Loader is initialized, before any loading starts
format | json | Type of data: json, csv
headers | | An array of objects with two properties (key and value) to attach to HTTP request
load | | Callback function to execute when file is successfully loaded (might be invoked multiple times)
noStyles | false | If set to true no styles will be applied to "Data loading" curtain
numberFields | | [CSV only] An array of fields in data to treat as numbers
postProcess | | If set to function reference, that function will be called to "post-process" loaded data before passing it on to chart. The handler function will receive two parameters: loaded data, Data Loader options
progress | | Set this to function reference to track progress of the load. The function will be passed in three parameters: global progress, individual file progress, file URL.
showErrors | true | Show loading errors in a chart curtain.
showCurtain | true| Show curtain over the chart area when loading data.
reload | 0 | Reload data every X seconds.
reverse | false | [CSV only] add data points in revers order.
skip | 0 | [CSV only] skip X first rows in data (includes first row if useColumnNames is used).
skipEmpty | true | [CSV only] Ignore empty lines in data.
timestamp | false | Add current timestamp to data URLs (to avoid caching).
useColumnNames | false | [CSV only] Use first row in data as column names when parsing.
showErrors | true | Show loading errors in a chart curtain
showCurtain | true| Show curtain over the chart area when loading data
reload | 0 | Reload data every X seconds
reverse | false | [CSV only] add data points in revers order
skip | 0 | [CSV only] skip X first rows in data (includes first row if useColumnNames is used)
skipEmpty | true | [CSV only] Ignore empty lines in data
timestamp | false | Add current timestamp to data URLs (to avoid caching)
useColumnNames | false | [CSV only] Use first row in data as column names when parsing
## Using in JavaScript Stock Chart
In JavaScript Stock Chart, it works exactly the same as in other chart types,
In JavaScript Stock Chart it works exactly the same as in other chart types,
with the exception that `dataLoader` is set as a property to the data set
definition. I.e.:
@ -251,9 +251,9 @@ The three available functions are as follows:
Function | Parameters | Description
-------- | ---------- | -----------
AmCharts.loadFile() | url, options, callback | Loads the file and passes it into callback function (unparsed).
AmCharts.parseCSV() | data, options | Parses data in string CSV format and returns JavaScript Array.
AmCharts.parseJSON() | data | Parses data in string JSON format and returns JavaScript Array.
AmCharts.loadFile() | url, options, callback | Loads the file and passes it into callback function (unparsed)
AmCharts.parseCSV() | data, options | Parses data in string CSV format and returns JavaScript Array
AmCharts.parseJSON() | data | Parses data in string JSON format and returns JavaScript Array
The options passed into standalone functions are the same as discussed in [Complete list of available dataLoader settings](#complete-list-of-available-dataloader-settings) chapter.
@ -280,7 +280,7 @@ AmCharts.loadFile(dataset_url, {}, function(data) {
## Translating into other languages
Depending on configuration options, the plugin will display a small number of
Depending on configuration options the plugin will display a small number of
text prompts, like 'Data loading...'.
Plugin will try matching chart's `language` property and display text prompts in
@ -354,72 +354,72 @@ http://www.apache.org/licenses/LICENSE-2.0
## Changelog
### 1.0.16
* Added "numberFields" config array.
* Added "numberFields" config array
### 1.0.15
* Added "emptyAs" config property. Empty CSV values will be set to this (default `undefined`).
* Added "emptyAs" config property. Empty CSV values will be set to this (default `undefined`)
### 1.0.14
* Added "init" event handler, which is called **before** loading starts.
* Added "init" event handler, which is called **before** loading starts
### 1.0.13
* Added "progress" handler, which can be used to monitor data load progress.
* Added "progress" handler, which can be used to monitor data load progress
### 1.0.12
* Better default options handling in external calls to AmCharts.loadFile.
* Fixed the latest version of Stock Chart not resetting to default pre-defined period.
* New example: Using Data Loader functions externally (map_json_external_function.html).
* Better default options handling in external calls to AmCharts.loadFile
* Fixed the latest version of Stock Chart not resetting to default pre-defined period
* New example: Using Data Loader functions externally (map_json_external_function.html)
### 1.0.11
* New translation: Added French translation. Thanks Remy!
* Tweaks to allow better animation after data load on Pie chart.
* Tweaks to allow better animation after data load on Pie chart
### 1.0.10
* Fixed error related to headers not being set when using standalone data load functions.
* Fixed error related to headers not being set when using standalone data load functions
### 1.0.9
* Plugin will now ignore empty CSV lines by default (configurable with `skipEmpty` property).
* Plugin will now ignore empty CSV lines by default (configurable with `skipEmpty` property)
### 1.0.8
* Added `headers` config variable which allows adding custom headers to HTTP requests.
* Added `headers` config variable which allows adding custom headers to HTTP requests
### 1.0.7
* Fixed an issue with the Pie chart when it is being loaded in inactive tab.
* Fixed an issue with the Pie chart when it is being loaded in inactive tab
### 1.0.6
* Added support for Gauge chart (loads `arrows` array).
* Added support for Gauge chart (loads `arrows` array)
### 1.0.5
* Fixed JS error if periodSelector was not defined in chart config.
* Now all callback functions (complete, error, load) receive additional parameter: chart.
* postProcess function will now have "this" context set to Data Loader object as well as receive chart reference as third parameter.
* Fixed JS error if periodSelector was not defined in chart config
* Now all callback functions (complete, error, load) receive additional parameter: chart
* postProcess function will now have "this" context set to Data Loader object as well as receive chart reference as third paramater
### 1.0.4
* Added `chart.dataLoader.loadData()` function which can be used to manually trigger all data reload.
* Added `chart.dataLoader.loadData()` function which can be used to manually trigger all data reload
### 1.0.3
* Fixed the bug where defaults were not being applied properly.
* Fixed the bug with translations not being applied properly.
* Cleaned up the code (to pass JSHint validation).
* Fixed the bug where defaults were not being applied properly
* Fixed the bug with translations not being applied properly
* Cleaned up the code (to pass JSHint validation)
### 1.0.2
* Fixed the issue with modified Array prototypes.
* Fixed the issue with modified Array prototypes
### 1.0.1
* Added `complete`, `load` and `error` properties that can be set with function handlers to be invoked on load completion, successful file load or failed load respectively.
* Fixed language container initialization bug.
* Fixed bug that was causing parse errors not be displayed.
* Added `complete`, `load` and `error` properties that can be set with function handlers to be invoked on load completion, successful file load or failed load respectively
* Fixed language container initialization bug
* Fixed bug that was causing parse errors not be displayed
### 1.0
* Added GANTT chart support.
* Added GANTT chart support
### 0.9.2
* Added global data load methods that can be used to load and parse data by code outside plugin.
* Trim CSV column names.
* Translation added: Lithuanian.
* Added global data load methods that can be used to load and parse data by code outside plugin
* Trim CSV column names
* Translation added: Lithuanian
### 0.9.1
* Fix chart animations not playing after asynchronous load.
* Fix chart animations not playing after asynchronous load
### 0.9
* Initial release.
* Initial release

File diff suppressed because it is too large Load diff

View file

@ -1,8 +0,0 @@
.bids-chart-container { width: 1200px; margin: 0 auto 48px auto; box-shadow: 0 2px 6px rgba(0,0,0,.175); border: 1px solid rgba(0,0,0,.15); padding: 24px 36px; position: relative; overflow: hidden }
.bids-chart-container .load-progress { position: absolute; top: 0; left: 0; width: 100%; height: 3px; background: #1e88e5; animation: indeterminate 4s linear infinite; }
.bids-chart-container .chart { height: 414px }
.bids-chart-container .btn-chart-export { position: absolute; right: 40px; bottom: 36px }
@keyframes indeterminate {
from { left: -70%; }
to { left: 100% }
}

View file

@ -81,23 +81,18 @@ border-radius: 0 8px 8px 0 }
.claims-grid .claim-grid-item .thumbnail .autothumb { display: block; margin: 73px auto 0 auto; text-align: center; font-size: 240%; color: #fff; line-height: 54px }
.claims-grid .claim-grid-item .tags > div { display: inline-block; padding: 4px 12px; margin-left: 2px }
.claims-grid .claim-grid-item .tags .nsfw { background: #e53935; text-align: center; color: #fff; position: relative; left: 1px }
.claims-grid .claim-grid-item .tags .bid-state { background: #551CA1; text-align: center; color: #fff; }
.claims-grid .claim-grid-item .tags .content-type { background: #880e4f; text-align: center; color: #fff; }
.claims-grid .claim-grid-item .blocked-info { padding: 24px; font-size: 90%; }
.claims-grid .claim-grid-item .metadata { padding: 24px; font-size: 90% }
.claims-grid .claim-grid-item .title { font-size: 120%; height: 25px; line-height: 25px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap }
.claims-grid .claim-grid-item .desc { font-size: 90%; font-weight: 300; height: 72px; overflow: hidden; text-overflow: ellipsis; margin: 8px 0 20px 0; line-height: 24px }
.claims-grid .claim-grid-item .link { font-size: 95%; font-weight: 300; margin-top: 3px; overflow: hidden; text-overflow: ellipsis; line-height: 20px; height: 20px; margin-top: 6px }
.claims-grid .claim-grid-item .label { font-size: 80%; color: #1e88e5 }
.claims-grid .no-results {font-style: italic; width: 100%; height: 300px; text-align: center; font-size: 90%; color: grey; }
.claims-grid .claim-grid-item .value { font-weight: 300; word-break: break-word; word-wrap: break-word; font-size: 95%; line-height: 24px; height: 24px }
.claims-grid .claim-grid-item .half-width { width: 155px; float: left; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding-right: 12px }
.claims-grid .claim-grid-item .spacer { height: 16px }
.claims-body { width: 1200px; margin: 0 auto 0 auto; cursor: default }
.claims-body .blocked-claim-info { border: 1px solid rgba(0,0,0,.15); cursor: default }
.claims-body .blocked-claim-info .content { padding: 48px }
.claims-body .claim-info { width: 400px; float: left; /*box-shadow: 0 2px 4px rgba(0,0,0,.175);*/ border: 1px solid rgba(0,0,0,.15); cursor: default }
.claims-body .claim-info .thumbnail { width: 100%; height: 220px; background: #f0f0f0; display: block; position: relative; overflow: hidden }
.claims-body .claim-info .thumbnail img { width: 100% }
@ -224,9 +219,7 @@ footer .content .page-time { position: absolute; right: 12px; bottom: 0px; paddi
.stats-main h3 { font-weight: 300; margin: 0 0 12px 0 }
.stats { width: 1000px; margin: 0 auto 48px auto; box-shadow: 0 2px 6px rgba(0,0,0,.175); border: 1px solid rgba(0,0,0,.15); padding: 24px; cursor: default }
.stats .box { padding: 24px 0; border-right: 1px solid #ccc; float: left; text-align: center }
.stats .box-20 { width: 20% }
.stats .box-30 { width: 30% }
.stats .box { padding: 24px 0; border-right: 1px solid #ccc; float: left; text-align: center; width: 25% }
.stats .box .title { color: #1e88e5; font-size: 90% }
.stats .box .value { font-size: 180%; font-weight: 300; margin-top: 8px }
.stats .box.last { border-color: transparent }
@ -259,7 +252,6 @@ footer .content .page-time { position: absolute; right: 12px; bottom: 0px; paddi
.tx-details-layout .outputs .output .labels .support { background: #ffeb3b }
.tx-details-layout .outputs .output .labels .update { background: #ea80fc }
.tx-details-layout .outputs .output .labels .claim { background: #76ff03 }
.tx-details-layout .outputs .output .view-claim { font-size: 80%; }
.tx-details-layout .inputs .input .value, .tx-details-layout .outputs .output .value { font-weight: normal }
.tx-details-layout .inputs .input.is-source, .tx-details-layout .outputs .output.is-source { border-right-width: 18px; border-right-color: #1e88e5; background: #e3f2fd }
.tx-details-layout .inputs .input.highlighted, .tx-details-layout .outputs .output.highlighted { background: #f1f8e9 }
@ -303,7 +295,6 @@ footer .content .page-time { position: absolute; right: 12px; bottom: 0px; paddi
.tx-table td { vertical-align: top; line-height: 24px }
.tx-table td.credit, .tx-table td div.credit { color: #00e676 }
.tx-table td.debit, .tx-table td div.debit { color: #ff0000 }
.tx-table td.diff, .tx-table td div.diff{ color: #337ab7 }
.tx-table td div.debit { padding-top: 8px }
.pagination { width: 1200px; margin: 36px auto 0 auto; cursor: default }

View file

@ -1,8 +0,0 @@
.mining-inflation-chart-container { width: 1200px; margin: 0 auto 48px auto; box-shadow: 0 2px 6px rgba(0,0,0,.175); border: 1px solid rgba(0,0,0,.15); padding: 24px 36px; position: relative; overflow: hidden }
.mining-inflation-chart-container .load-progress { position: absolute; top: 0; left: 0; width: 100%; height: 3px; background: #1e88e5; animation: indeterminate 4s linear infinite; }
.mining-inflation-chart-container .chart { height: 414px }
.mining-inflation-chart-container .btn-chart-export { position: absolute; right: 40px; bottom: 36px }
@keyframes indeterminate {
from { left: -70%; }
to { left: 100% }
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

View file

@ -1,170 +0,0 @@
function buildChartData(claimsData) {
var chartData = [];
var lastDate = 0;
var nbClaimsDay = 0;
var nbClaimsTotal = 0;
var bidClaimsDay = 0;
var bidClaimsTotal = 0;
var nbChannelsDay = 0;
var nbChannelsTotal = 0;
for(var i = 0; i < claimsData.length; i++) {
if(claimsData[i].transaction_time == 0) {
continue;
}
var transactionDate = new Date(claimsData[i].transaction_time * 1000);
transactionDate.setHours(0,0,0,0)
if(lastDate == 0) {
lastDate = transactionDate;
}
if(transactionDate.toString() != lastDate.toString()) {
nbClaimsTotal += nbClaimsDay;
bidClaimsTotal += bidClaimsDay;
var dateData = {
date: lastDate,
NumberClaims: nbClaimsTotal,
BidsClaims: bidClaimsTotal,
};
chartData.push(dateData);
nbClaimsDay = 0;
bidClaimsDay = 0;
lastDate = transactionDate;
}
if(claimsData[i].claim_type == 1) {
nbClaimsDay += 1;
bidClaimsDay += claimsData[i].effective_amount/100000000;
}
}
return chartData;
}
function loadChartData() {
var api_url = "https://chainquery.odysee.tv/api/sql?query=";
var query = "SELECT c1.claim_type, c1.bid_state, c1.effective_amount, c1.transaction_time, o.transaction_time AS 'spent_time' FROM claim c1 LEFT JOIN (SELECT output.claim_id, tx.transaction_time FROM output INNER JOIN input ON input.prevout_hash = output.transaction_hash AND input.prevout_n = output.vout INNER JOIN transaction tx ON tx.id = input.transaction_id) o ON o.claim_id=c1.claim_id AND c1.bid_state='Spent' ORDER BY c1.transaction_time ASC";
var url = api_url + query;
var loadProgress = $('.bids-chart-container .load-progress');
$.ajax({
url: url,
type: 'get',
dataType: 'json',
beforeSend: function() {
chartLoadInProgress = true;
loadProgress.css({ display: 'block' });
},
success: function(response) {
if(response.success) {
chartData = buildChartData(response.data);
if(chart) {
chart.dataProvider = chartData;
chart.validateNow();
chart.validateData();
}
}
else {
console.log("Could not fetch block data.");
}
},
complete: function() {
chartLoadInProgress = false;
loadProgress.css({ display: 'none' });
}
});
}
var chart;
var chartData = [];
var chartLoadInProgress = false;
AmCharts.ready(function() {
chart = AmCharts.makeChart('bids-chart', {
type: 'serial',
theme: 'light',
mouseWheelZoomEnabled: true,
height: '100%',
categoryField: 'date',
synchronizeGrid: true,
dataProvider: chartData,
responsive: {
enabled: true,
},
valueAxes: [
{
id: 'v-number-claims',
axisColor: '#1e88e5',
axisThickness: 2,
position: 'left',
},
{
id: 'v-bids-claims',
axisColor: '#0b7a06',
axisThickness: 2,
position: 'left',
offset: 75,
},
],
categoryAxis: {
parseDates: true,
autoGridCount: false,
minorGridEnabled: true,
minorGridAlpha: 0.04,
axisColor: '#dadada',
twoLineMode: true
},
graphs: [
{
id: 'g-number-claims',
valueAxis: 'v-number-claims',
title: 'Number of claims',
valueField: 'NumberClaims',
bullet: 'round',
bulletBorderThickness: 1,
bulletBorderAlpha: 1,
bulletColor: '#ffffff',
bulletSize: 5,
useLineColorForBulletBorder: true,
lineColor: '#1e88e5',
hideBulletsCount: 101,
balloonText: '[[NumberClaims]]',
},
{
id: 'g-bids-claims',
valueAxis: 'v-bids-claims',
title: 'Bids for claims (LBC)',
valueField: 'BidsClaims',
bullet: 'round',
bulletBorderThickness: 1,
bulletBorderAlpha: 1,
bulletColor: '#ffffff',
bulletSize: 5,
useLineColorForBulletBorder: true,
lineColor: '#0b7a06',
balloonText: '[[BidsClaims]] LBC',
hideBulletsCount: 101
},
],
chartCursor: {
cursorAlpha: 0.1,
fullWidth: true,
valueLineBalloonEnabled: true,
categoryBalloonColor: '#333333',
cursorColor: '#1e88e5'
},
chartScrollbar: {
scrollbarHeight: 36,
color: '#888888',
gridColor: '#bbbbbb'
},
legend: {
marginLeft: 110,
useGraphSettings: true,
valueText: "",
spacing: 64,
},
export: {
enabled: true,
fileName: 'lbry-bids-chart',
position: 'bottom-right',
divId: 'chart-export'
}
});
loadChartData();
});

View file

@ -1,228 +0,0 @@
var chart;
var chartData = [];
var chartLoadInProgress = false;
var minPeriod = 'hh';
var validPeriods = ['24h', '72h', '168h', '30d', '90d', '1y'];
var defaultPeriod = (validPeriods.indexOf(localStorage.getItem('chartPeriod')) > -1) ? localStorage.getItem('chartPeriod') : '24h';
var periodGridCounts = {'24h': 24, '72h': 24, '168h': 14, '30d': 30, '90d': 45, '1y': 12 };
AmCharts.ready(function() {
chart = AmCharts.makeChart('block-size-chart', {
type: 'serial',
theme: 'light',
mouseWheelZoomEnabled: true,
categoryField: 'date',
synchronizeGrid: true,
dataProvider: chartData,
valueAxes: [
{
id: 'v-block-size',
axisColor: '#1e88e5',
axisThickness: 2,
labelFunction: function(value) {
return (Math.round((value / 1000) * 100)/100).toFixed(2) + ' KB';
}
},
{
id: 'v-price',
axisColor: '#00e676',
offset: 75,
gridAlpha: 0,
axisThickness: 2,
labelFunction: function(value) {
return '$' + value.toFixed(2);
}
}
],
categoryAxis: {
parseDates: true,
minPeriod: minPeriod, // DD for daily
autoGridCount: false,
minorGridEnabled: true,
minorGridAlpha: 0.04,
axisColor: '#dadada',
twoLineMode: true,
dateFormats: [{
period: 'fff',
format: 'JJ:NN:SS'
}, {
period: 'ss',
format: 'JJ:NN:SS'
}, {
period: 'mm',
format: 'JJ:NN'
}, {
period: 'hh',
format: 'JJ:NN'
}, {
period: 'DD',
format: 'DD'
}, {
period: 'WW',
format: 'DD MMM'
}, {
period: 'MM',
format: 'MMM'
}, {
period: 'YYYY',
format: 'YYYY'
}]
},
graphs: [
{
id: 'g-block-size',
valueAxis: 'v-block-size', // we have to indicate which value axis should be used
title: 'Avg Block Size',
valueField: 'AvgBlockSize',
bullet: 'round',
bulletBorderThickness: 1,
bulletBorderAlpha: 1,
bulletColor: '#ffffff',
bulletSize: 5,
useLineColorForBulletBorder: true,
lineColor: '#1e88e5',
hideBulletsCount: 101,
balloonText: '[[AvgBlockSize]] KB',
switchable: false,
balloonFunction: function(item, graph) {
var result = graph.balloonText;
return result.replace('[[AvgBlockSize]]', (Math.round((item.dataContext.AvgBlockSize / 1000) * 100)/100).toFixed(2));
}
},
{
id: 'g-price',
valueAxis: 'v-price',
title: 'Average Price',
valueField: 'AvgUSD',
bullet: 'round',
bulletBorderThickness: 1,
bulletBorderAlpha: 1,
bulletColor: '#ffffff',
bulletSize: 5,
useLineColorForBulletBorder: true,
lineColor: '#00e676',
balloonText: '$[[AvgUSD]]',
balloonFunction: function(item, graph) {
var result = graph.balloonText;
if (!item.dataContext.AvgUSD) {
return '';
}
return result.replace('[[AvgUSD]]', item.dataContext.AvgUSD.toFixed(2));
},
hideBulletsCount: 101,
labelFunction: function(value) {
return '$' + value;
},
}
],
chartCursor: {
cursorAlpha: 0.1,
fullWidth: true,
valueLineBalloonEnabled: true,
categoryBalloonColor: '#333333',
cursorColor: '#1e88e5',
categoryBalloonDateFormat: minPeriod === 'hh' ? 'D MMM HH:NN ' : 'D MMM'
},
chartScrollbar: {
scrollbarHeight: 36,
color: '#888888',
gridColor: '#bbbbbb'
},
legend: {
marginLeft: 110,
useGraphSettings: true,
valueAlign: 'right',
valueWidth: 60,
spacing: 64,
valueFunction: function(item, formatted) {
if (item.dataContext) {
var g = item.graph;
if (g.id === 'g-block-size' && item.dataContext.AvgBlockSize > 0) {
return g.balloonText.replace('[[AvgBlockSize]]', (Math.round((item.dataContext.AvgBlockSize / 1000) * 100)/100).toFixed(2) );
}
if (g.id === 'g-price' && item.dataContext.AvgUSD) {
return g.balloonText.replace('[[AvgUSD]]', item.dataContext.AvgUSD.toFixed(2));
}
}
return formatted;
}
},
export: {
enabled: true,
fileName: 'lbry-block-size-chart',
position: 'bottom-right',
divId: 'chart-export'
}
});
loadChartData(defaultPeriod);
});
var loadChartData = function(dataPeriod) {
var loadProgress = $('.block-size-chart-container .load-progress');
// clear previous chart data
$.ajax({
url: '/api/v1/charts/blocksize/' + dataPeriod,
type: 'get',
dataType: 'json',
beforeSend: function() {
chartLoadInProgress = true;
loadProgress.css({ display: 'block' });
},
success: function(response) {
if (response.success) {
chartData = [];
var data = response.data;
for (var period in data) {
if (data.hasOwnProperty(period)) {
chartData.push({
date: Date.parse(period),
AvgBlockSize: data[period].AvgBlockSize,
AvgUSD: data[period].AvgUSD
});
}
}
// save selcted period to localStorage
localStorage.setItem('chartPeriod', dataPeriod);
if (chart) {
var isHourly = (dataPeriod.indexOf('h') > -1);
var gridCount = periodGridCounts[dataPeriod];
chart.categoryAxis.minPeriod = isHourly ? 'hh' : 'DD';
chart.categoryAxis.dateFormats[4].format = isHourly ? 'DD MMM' : 'DD';
chart.chartCursor.categoryBalloonDateFormat = isHourly ? 'D MMM HH:NN ' : 'D MMM YYYY';
chart.categoryAxis.gridCount = gridCount;
chart.chartScrollbar.gridCount = gridCount;
chart.dataProvider = chartData;
chart.validateNow();
chart.validateData();
}
}
},
complete: function() {
chartLoadInProgress = false;
loadProgress.css({ display: 'none' });
}
});
};
$(document).ready(function() {
$('.block-size-data-links a').on('click', function(evt) {
evt.preventDefault();
if (chartLoadInProgress) {
return;
}
var link = $(this);
if (link.hasClass('active')) {
return;
}
link.addClass('active').siblings().removeClass('active');
var period = link.attr('data-period');
loadChartData(period);
});
$('a[data-period="' + defaultPeriod + '"]').addClass('active').siblings().removeClass('active');
});

View file

@ -1,264 +0,0 @@
function getReward(blockHeight) {
if (blockHeight == 0) {
return 400000000;
}
else if (blockHeight <= 5100) {
return 1;
}
else if (blockHeight <= 55000) {
return 1 + Math.floor((blockHeight - 5001) / 100);
}
else {
var level = Math.floor((blockHeight - 55001) / 32);
var reduction = Math.floor((Math.floor(Math.sqrt((8 * level) + 1)) - 1) / 2);
while(!(withinLevelBounds(reduction, level))) {
if(Math.floor((reduction * reduction + reduction) / 2) > level) {
reduction--;
}
else {
reduction++;
}
}
return Math.max(0, 500 - reduction);
}
}
function withinLevelBounds(reduction, level) {
if(Math.floor((reduction * reduction + reduction) / 2) > level) {
return false;
}
reduction += 1;
if(Math.floor((reduction * reduction + reduction) / 2) <= level) {
return false;
}
return true;
}
function getAverageBlockTime(blocks) {
var numBlocks = blocks.length;
var windowSize = 100;
var sum = 0;
for(i = numBlocks - windowSize; i < numBlocks; i++) {
sum += blocks[i].block_time - blocks[i-1].block_time;
}
return sum / windowSize;
}
function buildChartData(blockData) {
var chartData = [];
var supply = 0;
var reward = 0;
var averageBlockTime = getAverageBlockTime(blockData);
var blockTime = 0;
var lastBlock = 4071017; // Last block with reward
var skip = 100;
var blocksPerYear = Math.floor((3600*24*365) / averageBlockTime);
var historicalSupply = {};
var lastYearSupply = 0;
var lastYearBlock = 0;
var inflationRate = 0;
for(var i = 0; i < lastBlock; i++) {
reward = getReward(i);
supply += reward;
historicalSupply[i + 1] = supply;
if(i == 0) { // Reward for 1st block set to 0 for scale
reward = 0;
}
if(i < blockData.length) {
// Historical Data
var b = blockData[i];
blockTime = b.block_time;
}
else {
// Future blocks
skip = 1000;
blockTime += averageBlockTime;
}
// Inflation Rate
if(i + 1 - blocksPerYear <= 0) {
lastYearBlock = 1;
}
else {
lastYearBlock = i + 1 - blocksPerYear;
}
lastYearSupply = historicalSupply[lastYearBlock];
inflationRate = ((supply - lastYearSupply) / lastYearSupply) * 100;
if(i % skip == 0) { // Only push 1/<skip> of all blocks to optimize data loading
chartData.push({
date: new Date(blockTime * 1000),
AvailableSupply: supply,
RewardLBC: reward,
InflationRate: inflationRate,
BlockId: i + 1
});
}
}
return chartData;
}
function loadChartData() {
var api_url = "https://chainquery.odysee.tv/api/sql?query=";
var query = "SELECT height, block_time FROM block WHERE confirmations > 0 ORDER BY height";
var url = api_url + query;
var loadProgress = $('.mining-inflation-chart-container .load-progress');
$.ajax({
url: url,
type: 'get',
dataType: 'json',
beforeSend: function() {
chartLoadInProgress = true;
loadProgress.css({ display: 'block' });
},
success: function(response) {
if(response.success) {
chartData = buildChartData(response.data);
if(chart) {
chart.dataProvider = chartData;
chart.validateNow();
chart.validateData();
}
}
else {
console.log("Could not fetch block data.");
}
},
complete: function() {
chartLoadInProgress = false;
loadProgress.css({ display: 'none' });
}
});
}
var chart;
var chartData = [];
var chartLoadInProgress = false;
AmCharts.ready(function() {
chart = AmCharts.makeChart('mining-inflation-chart', {
type: 'serial',
theme: 'light',
mouseWheelZoomEnabled: true,
height: '100%',
categoryField: 'date',
synchronizeGrid: true,
dataProvider: chartData,
responsive: {
enabled: true,
},
valueAxes: [
{
id: 'v-supply',
axisColor: '#1e88e5',
axisThickness: 2,
position: 'left',
labelFunction: function(value) {
return (Math.round((value / 1000000) * 1000000)/1000000).toFixed(2);
}
},
{
id: 'v-reward',
axisColor: '#0b7a06',
axisThickness: 2,
position: 'left',
offset: 75,
},
{
id: 'v-inflation-rate',
axisColor: '#ff9900',
axisThickness: 2,
position: 'right',
labelFunction: function(value) {
return value.toFixed(2);
}
},
],
categoryAxis: {
parseDates: true,
autoGridCount: false,
minorGridEnabled: true,
minorGridAlpha: 0.04,
axisColor: '#dadada',
twoLineMode: true
},
graphs: [
{
id: 'g-supply',
valueAxis: 'v-supply', // we have to indicate which value axis should be used
title: 'Available supply (millions LBC)',
valueField: 'AvailableSupply',
bullet: 'round',
bulletBorderThickness: 1,
bulletBorderAlpha: 1,
bulletColor: '#ffffff',
bulletSize: 5,
useLineColorForBulletBorder: true,
lineColor: '#1e88e5',
hideBulletsCount: 101,
balloonText: '[[AvailableSupply]]',
balloonFunction: function(item, graph) {
var result = graph.balloonText;
return result.replace('[[AvailableSupply]]', (Math.round((item.dataContext.AvailableSupply / 1000000) * 1000000)/1000000).toFixed(2));
}
},
{
id: 'g-reward',
valueAxis: 'v-reward',
title: 'Block Reward (LBC)',
valueField: 'RewardLBC',
bullet: 'round',
bulletBorderThickness: 1,
bulletBorderAlpha: 1,
bulletColor: '#ffffff',
bulletSize: 5,
useLineColorForBulletBorder: true,
lineColor: '#0b7a06',
balloonText: '[[RewardLBC]] LBC<br>Block [[BlockId]]',
hideBulletsCount: 101
},
{
id: 'g-inflation-rate',
valueAxis: 'v-inflation-rate',
title: 'Annualized Inflation Rate',
valueField: 'InflationRate',
bullet: 'round',
bulletBorderThickness: 1,
bulletBorderAlpha: 1,
bulletColor: '#ffffff',
bulletSize: 5,
useLineColorForBulletBorder: true,
lineColor: '#ff9900',
balloonText: '[[InflationRate]]%',
hideBulletsCount: 101,
balloonFunction: function(item, graph) {
var result = graph.balloonText;
return result.replace('[[InflationRate]]', item.dataContext.InflationRate.toFixed(2));
}
}
],
chartCursor: {
cursorAlpha: 0.1,
fullWidth: true,
valueLineBalloonEnabled: true,
categoryBalloonColor: '#333333',
cursorColor: '#1e88e5'
},
chartScrollbar: {
scrollbarHeight: 36,
color: '#888888',
gridColor: '#bbbbbb'
},
legend: {
marginLeft: 110,
useGraphSettings: true,
valueText: "",
spacing: 64,
},
export: {
enabled: true,
fileName: 'lbry-supply-chart',
position: 'bottom-right',
divId: 'chart-export'
}
});
loadChartData();
});