Compare commits

..

122 commits

Author SHA1 Message Date
Niko Storni
4065389798 retain the same resolution as the frontend 2022-06-21 18:21:12 +02:00
Niko Storni
a252dc05e6 fix typo 2022-06-17 20:00:48 +02:00
Niko Storni
e8c58e8c15 try 3 2022-06-17 18:59:32 +02:00
Niko Storni
e8e9346a70 tmp fix for stupid queries 2022-06-17 18:58:10 +02:00
Niko Storni
fdecf39f93 don't run stupid queries 2022-06-17 18:54:42 +02:00
Niko Storni
d3cd0e13f6 remove missing field 2022-06-17 18:32:31 +02:00
Niko Storni
f769cac5da fix thumbnails 2022-06-17 17:53:50 +02:00
Niko Storni
9b554eec1b fix issues with new chainquery schema
fix bittrex API
2022-06-17 17:15:19 +02:00
Niko Storni
07d9521cfe Merge remote-tracking branch 'origin/dependabot/composer/composer/composer-1.10.26' 2022-06-17 15:39:07 +02:00
dependabot[bot]
820f20a479
Bump composer/composer from 1.10.19 to 1.10.26
Bumps [composer/composer](https://github.com/composer/composer) from 1.10.19 to 1.10.26.
- [Release notes](https://github.com/composer/composer/releases)
- [Changelog](https://github.com/composer/composer/blob/1.10.26/CHANGELOG.md)
- [Commits](https://github.com/composer/composer/compare/1.10.19...1.10.26)

---
updated-dependencies:
- dependency-name: composer/composer
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-22 20:45:40 +00:00
Thomas Zarebczan
0c84ba3fae
Add new hot wallet 2021-02-03 11:20:40 -05:00
Niko Storni
e74d5b7b2d fix dependencies 2021-01-12 23:03:22 +01:00
Akinwale Ariwodola
fc0abe8d33
More claims fix (#91) 2020-10-28 15:57:26 +01:00
Jeremy Kauffman
7e9851ccfc
Merge pull request #80 from lbryio/dependabot/composer/cakephp/cakephp-3.7.7
Bump cakephp/cakephp from 3.7.1 to 3.7.7
2020-03-16 14:04:26 -04:00
Jeremy Kauffman
d7fb718dd0
Merge pull request #86 from kcseb/master
Change footer to .com
2020-03-16 14:03:03 -04:00
Kenneth C
6f4fa32078
Updated a missed .io 2020-03-09 20:33:19 -04:00
Kenneth C
8873373465
Update URL to .com 2020-03-09 20:32:16 -04:00
Akinwale Ariwodola
a73d65b1c2
Merge pull request #85 from lbryio/fix-utxosupply
fix custom configuration loading and gettxoutsetinfo request
2020-03-04 16:04:37 +01:00
Thomas Zarebczan
bb595d0027
update LBRY addresses 2020-02-27 18:22:34 -05:00
Akinwale Ariwodola
52d13987e5 fix custom configuration loading and gettxoutsetinfo request 2020-01-08 22:02:03 +01:00
Niko
57219734c3
Merge pull request #82 from lbryio/fix-utxosupply
Fix utxosupply
2020-01-08 14:06:36 +01:00
Akinwale Ariwodola
a7c1b9b346 update community, operational and institutional addresses 2020-01-08 08:04:00 +01:00
Akinwale Ariwodola
77ca91757b fix _gettxoutsetinfo return type 2020-01-07 23:37:50 +01:00
Akinwale Ariwodola
a147665e96 fix utxo supply 2020-01-07 23:34:50 +01:00
dependabot[bot]
0f197fc571
Bump cakephp/cakephp from 3.7.1 to 3.7.7
Bumps [cakephp/cakephp](https://github.com/cakephp/cakephp) from 3.7.1 to 3.7.7.
- [Release notes](https://github.com/cakephp/cakephp/releases)
- [Commits](https://github.com/cakephp/cakephp/compare/3.7.1...3.7.7)

Signed-off-by: dependabot[bot] <support@github.com>
2020-01-07 22:14:57 +00:00
Akinwale Ariwodola
31d515e992
Blocked claims (#81)
* handle blocked claims
* fix chainquery endpoint
* channel-level blocking
* don't show blocked claims in the result grid
* optimisation: break out of foreach loop if match found
* add caching for api request
* rename cache key
2020-01-07 23:13:38 +01:00
Niko
02551e98d7
Merge pull request #70 from lbryio/crash-fix
Crash fix
2019-10-21 11:41:58 -04:00
Akinwale Ariwodola
007cf0d34c add missing operator 2019-10-15 22:39:27 +01:00
Akinwale Ariwodola
c18431394c fix crash on large page numbers? 2019-10-15 22:28:45 +01:00
Niko
04cbdbcaee
Merge pull request #65 from lbryio/fix-dupes
fix dupes
2019-08-02 21:40:44 +02:00
Thomas Zarebczan
9b3a1f4097
remove decoder 2019-07-30 12:11:49 -04:00
Thomas Zarebczan
9582342a3a
fix dupes
fixed dupes on bMvUBo1h5WS46ThHtmfmXftz3z33VHL7wc
2019-07-17 09:41:25 -04:00
Thomas Zarebczan
bbc07e8238
Merge pull request #61 from ykris45/patch-1
Update README.md
2019-04-01 13:19:12 -04:00
YULIUS KURNIAWAN KRISTIANTO
4a7be9d61d
Update README.md 2019-04-02 00:16:30 +07:00
Thomas Zarebczan
6054ddc6c0
Merge pull request #59 from marcdeb1/confirmations_fix
Confirmations fix
2019-03-26 17:32:10 -04:00
marcdeb1
a0dac9c35b Mempool transactions confirmation 2019-03-26 11:04:22 +01:00
marcdeb1
5c5c7924af Confirmations number fix 2019-03-25 23:23:08 +01:00
marcdeb1
b8a685a8dc Home page lbry link fix 2019-03-25 23:03:03 +01:00
marcdeb1
9f98c64d18 Merging 2019-03-23 15:25:37 +01:00
Niko
1b13f2711b
Merge pull request #49 from marcdeb1/chainquery
Chainquery integration
2019-02-13 13:01:12 -05:00
marcdeb1
55a3736233 Deprecation warnings 2019-01-26 22:57:30 +01:00
marcdeb1
fd8a6953f3 Deprecation warnings 2019-01-26 22:21:50 +01:00
marcdeb1
70069a29ec Test Travis 2019-01-26 21:56:01 +01:00
marcdeb1
b96d40241d Name Transaction Address table file 2019-01-26 21:04:46 +01:00
marcdeb1
f3564d7809 TransactionAddress loading fix 2019-01-26 20:54:30 +01:00
marcdeb1
2941698c2b Updated CakePHP 2019-01-26 20:37:30 +01:00
Akinwale Ariwodola
0ca160336f
Merge pull request #51 from lbryio/claim-id-null-fix
fix issue with claim names being returned with a hash
2019-01-26 13:43:51 +01:00
Akinwale Ariwodola
e8eaf19490 fix issue with claim names being returned with a hash 2019-01-26 13:41:10 +01:00
marcdeb1
9e984c94c1
Merge branch 'master' into chainquery 2019-01-05 22:51:30 +01:00
marcdeb1
19b35b0685 Controlling tag and sorting by bid state in claim search 2019-01-05 22:34:08 +01:00
marcdeb1
1ba751acb3 Thumbnail text and content tag fix 2019-01-05 21:44:37 +01:00
Niko
fae8b3e98a
Merge pull request #47 from lbryio/cache2
Adds caching to vulnerable API call
2019-01-04 13:57:14 +01:00
Niko
07d937d0ef
Merge pull request #48 from marcdeb1/fix_mining_chart
Fix mining chart
2019-01-03 00:37:29 +01:00
marcdeb1
a428ebdd73 Chainquery update, transaction value and address balance 2019-01-01 15:40:45 +01:00
Mark Beamer Jr
262e90a2e1
Fixed some deprecation warnings.
Fixed a few claim queries that were using a distinct causing a group by to be performed with full table scan.
Added `dev.sh` file to quickly startup the explorer.
2018-12-21 23:41:30 -05:00
marcdeb1
17b0ef58a9 Find page bug 2018-12-21 17:19:55 +01:00
marcdeb1
5064b86fc6 Transaction address table 2018-12-21 17:15:36 +01:00
marcdeb1
b99285cfa5 Minor bugs 2018-12-21 17:15:02 +01:00
marcdeb1
d61d9ff015 DB comments 2018-12-21 17:12:00 +01:00
marcdeb1
0d49e4d0c8 Claim address in tx page 2018-12-21 16:53:55 +01:00
marcdeb1
80e55f53e2 Circulating supply API 2018-12-21 16:21:28 +01:00
marcdeb1
1edc128b61 Address balance API 2018-12-21 15:51:36 +01:00
marcdeb1
8bef4e5cec Address page 2018-12-21 15:48:33 +01:00
marcdeb1
9d88e2eaec Queries and bugs 2018-12-21 14:18:39 +01:00
marcdeb1
3569fdb4ff Improved index query 2018-12-21 13:55:59 +01:00
marcdeb1
4e0eeab3d1 Improved queries 2018-12-21 13:50:17 +01:00
marcdeb1
f7318d64fc Improved block page queries 2018-12-21 13:42:57 +01:00
marcdeb1
90eee866fc Block list page 2018-12-19 00:57:43 +01:00
marcdeb1
dfd7af81f9 Realtme action improvements 2018-12-19 00:53:39 +01:00
marcdeb1
cbee21c07c Other claim page bugs 2018-12-19 00:37:01 +01:00
marcdeb1
a09a0148c2 Fix claim page bugs 2018-12-19 00:12:14 +01:00
marcdeb1
6c45f432de Clam and publisher in one query 2018-12-18 23:02:09 +01:00
marcdeb1
830df53d74 Address balance API 2018-12-18 22:11:00 +01:00
marcdeb1
af39804ce7 Address action 2018-12-18 21:56:41 +01:00
marcdeb1
fbfd5b8f39 Price history db name 2018-12-18 20:17:34 +01:00
marcdeb1
edbc11db7f API tests 2018-12-18 19:21:12 +01:00
marcdeb1
0bd3836b31 Claim box 2018-12-18 18:14:42 +01:00
marcdeb1
e5d16d0100 Find action 2018-12-18 17:58:49 +01:00
marcdeb1
3cddd6ece1 Tx spend input 2018-12-18 17:47:49 +01:00
marcdeb1
e7a030ddf9 Rename API fields 2018-12-18 16:20:19 +01:00
marcdeb1
9a32c9a930 Transaction page improvement 2018-12-18 16:09:37 +01:00
marcdeb1
695f85262b DB in app.default 2018-12-18 13:53:03 +01:00
marcdeb1
5c681657cb Added old database for PriceHistory 2018-12-18 13:51:19 +01:00
marcdeb1
25a50ca2aa API realtime actions 2018-12-18 13:42:45 +01:00
marcdeb1
b61a1545a7 Realtime action 2018-12-18 01:20:54 +01:00
marcdeb1
86a1631144 Fix index transaction hash bug 2018-12-17 22:36:13 +01:00
marcdeb1
94682cc4d4 Fixed transaction value issue 2018-12-17 12:35:54 +01:00
marcdeb1
6e8a651980 Tx and index page 2018-12-17 00:49:26 +01:00
marcdeb1
0df9658b87 composer 2018-12-12 00:40:49 +01:00
marcdeb1
5b7c9f7e72 Fixing mining inflation chart bug 2018-12-12 00:22:39 +01:00
Niko Storni
aeceeec732 fix QR code
fix table declaration
2018-12-04 20:55:41 -05:00
Niko Storni
3884c74e7d add cache only 2018-12-03 20:17:19 -05:00
Akinwale Ariwodola
3eab838967 composer package updates 2018-12-03 17:26:01 +00:00
Akinwale Ariwodola
e8d3ead2c7 update home page style to accommodate new difficulty values 2018-12-03 18:23:59 +01:00
Akinwale Ariwodola
5983c61820
Merge pull request #46 from lbryio/hot-wallet
add additional hot wallet
2018-11-28 16:04:09 +01:00
marcdeb1
d98e9a3fb2 Improve search (#40)
* Added search page results
* Added getContentTag and getAutoThumbText to Claims model
* Order in search results
2018-11-28 16:03:41 +01:00
Thomas Zarebczan
c7c1e7299f
add additional hot wallet 2018-11-26 17:27:36 -05:00
Thomas Zarebczan
9246952c08
Merge pull request #38 from preserveddarnell/newcopyedits
Update various typos, punctuations & errors.
2018-11-12 11:42:46 -05:00
Thomas Zarebczan
59d23dc2a7
Update LICENSE 2018-11-12 11:42:30 -05:00
Akinwale Ariwodola
c58676cd69 only get the claim link if the claim object is not null 2018-11-01 07:08:27 +01:00
preserveddarnell
b9917c89da Update various typos, punctuations & errors. 2018-10-22 17:49:46 -04:00
marcdeb1
26a79d8340 Lbry addresses (#35)
* Added logo to indicate addresses owned by LBRY
2018-10-19 16:00:50 +01:00
marcdeb1
f903235c24 Added mining inflation chart to stats page (#34) 2018-10-19 13:22:50 +01:00
Akinwale Ariwodola
d8734c1b8e
Merge fix for PR 33 (#37)
* Added claim link to transaction
* Added 'View' link next to Claim label
2018-10-19 12:54:54 +01:00
marcdeb1
c13c06f74f Claim LBRY link and Thumbnail (#32)
* Claim LBRY link and Thumbnail
* Added getLink function to Model
* Changed getLink function name
2018-10-19 12:49:22 +01:00
Akinwale Ariwodola
ad82fc3975
Merge pull request #36 from marcdeb1/db_column_name
Changed LatestTransactionTime column name
2018-10-18 12:20:46 +01:00
marcdeb1
4d0efbaff8 Changed LatestTransactionTime column name 2018-10-11 07:42:46 +02:00
Akinwale Ariwodola
c8462afdee
Update README.md with installation instructions (#30) 2018-08-09 21:30:21 +01:00
Akinwale Ariwodola
a8a956f2bc update confirmations calculation on block list page 2018-07-26 12:22:51 +01:00
Akinwale Ariwodola
b91b3681d3 tweak confirmation calculation 2018-07-26 12:14:48 +01:00
Akinwale Ariwodola
190d998e4c Merge branch 'master' of https://github.com/lbryio/block-explorer 2018-07-26 12:08:56 +01:00
Akinwale Ariwodola
667097f35d better confirmations calculation 2018-07-26 12:08:15 +01:00
Akinwale Ariwodola
8d552afe8f removed unused cron file 2018-07-26 10:30:13 +00:00
Akinwale Ariwodola
ad4615cc5a forevermempool reset cron 2018-07-26 07:59:20 +01:00
Akinwale Ariwodola
3ad5db032b fix p2pk hash index 2018-07-26 07:27:12 +01:00
Akinwale Ariwodola
e25cd7807e
Merge pull request #26 from lbryio/diff
show diff on address page when tx spends back into the same wallet
2018-07-21 01:26:13 +01:00
Akinwale Ariwodola
71c7834521 move RPC URL value to configuration file 2018-07-21 00:18:24 +00:00
Akinwale Ariwodola
27ff22ff5a Updated mdanter/ecc version. Some cron file updates based on new environment. 2018-07-19 19:19:59 +00:00
Alex Grintsvayg
70032020f5 show diff on address page when tx spends back into the same wallet 2018-06-08 13:44:40 -04:00
Akinwale Ariwodola
c8ca48220f display verified tags 2018-05-28 21:09:16 +01:00
Akinwale Ariwodola
c2a19d91c1 remove address tagging 2018-05-23 00:46:55 +01:00
akinwale
d3e542dd91
Merge pull request #22 from lbryio/imgsrc-fix
strip tags from claim thumbnail url
2018-04-09 16:49:50 +01:00
65 changed files with 4934 additions and 2544 deletions

3
.gitignore vendored
View file

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

View file

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

View file

@ -1,10 +1,9 @@
The MIT License (MIT) 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 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. 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

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

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

View file

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

11
config/lbry.default.php Normal file
View file

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

View file

@ -72,9 +72,3 @@ Router::scope('/', function (RouteBuilder $routes) {
//$routes->fallbacks(DashedRoute::class); //$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 #!/bin/sh
cd /var/www/lbry.block.ng cd /home/lbry/explorer.lbry.io
bin/cake block addrtxamounts bin/cake block addrtxamounts

View file

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

View file

@ -1,137 +0,0 @@
<?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 #!/bin/sh
cd /var/www/lbry.block.ng cd /home/lbry/explorer.lbry.io
bin/cake block parsetxs bin/cake block parsetxs

View file

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

View file

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

View file

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

5
cron/forever.sh Executable file
View file

@ -0,0 +1,5 @@
#!/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 &

View file

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

View file

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

View file

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

View file

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

View file

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

23
dev.sh Executable file
View file

@ -0,0 +1,23 @@
#!/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 @@
l--DROP DATABASE IF EXISTS lbry; --DROP DATABASE IF EXISTS lbry;
CREATE DATABASE lbry DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE DATABASE lbry DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci;
USE lbry; USE lbry;
@ -74,7 +74,7 @@ CREATE TABLE `Addresses`
`TotalReceived` DECIMAL(18,8) DEFAULT 0 NOT NULL, `TotalReceived` DECIMAL(18,8) DEFAULT 0 NOT NULL,
`TotalSent` DECIMAL(18,8) DEFAULT 0 NOT NULL, `TotalSent` DECIMAL(18,8) DEFAULT 0 NOT NULL,
`Balance` DECIMAL(18,8) AS (`TotalReceived` - `TotalSent`) PERSISTENT, `Balance` DECIMAL(18,8) AS (`TotalReceived` - `TotalSent`) PERSISTENT,
`Tag` VARCHAR(30) NOT NULL, `Tag` VARCHAR(30),
`TagUrl` VARCHAR(200), `TagUrl` VARCHAR(200),
`Created` DATETIME NOT NULL, `Created` DATETIME NOT NULL,
`Modified` DATETIME NOT NULL, `Modified` DATETIME NOT NULL,
@ -163,11 +163,11 @@ CREATE TABLE `TransactionsAddresses`
`AddressId` BIGINT UNSIGNED NOT NULL, `AddressId` BIGINT UNSIGNED NOT NULL,
`DebitAmount` DECIMAL(18,8) DEFAULT 0 NOT NULL COMMENT 'Sum of the inputs to this address for the tx', `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', `CreditAmount` DECIMAL(18,8) DEFAULT 0 NOT NULL COMMENT 'Sum of the outputs to this address for the tx',
`LatestTransactionTime` DATETIME DEFAULT UTC_TIMESTAMP() NOT NULL, `TransactionTime` DATETIME DEFAULT UTC_TIMESTAMP() NOT NULL,
PRIMARY KEY `PK_TransactionAddress` (`TransactionId`, `AddressId`), PRIMARY KEY `PK_TransactionAddress` (`TransactionId`, `AddressId`),
FOREIGN KEY `Idx_TransactionsAddressesTransaction` (`TransactionId`) REFERENCES `Transactions` (`Id`), FOREIGN KEY `Idx_TransactionsAddressesTransaction` (`TransactionId`) REFERENCES `Transactions` (`Id`),
FOREIGN KEY `Idx_TransactionsAddressesAddress` (`AddressId`) REFERENCES `Addresses` (`Id`), FOREIGN KEY `Idx_TransactionsAddressesAddress` (`AddressId`) REFERENCES `Addresses` (`Id`),
INDEX `Idx_TransactionsAddressesLatestTransactionTime` (`LatestTransactionTime`), INDEX `Idx_TransactionsAddressesTransactionTime` (`TransactionTime`),
INDEX `Idx_TransactionsAddressesDebit` (`DebitAmount`), INDEX `Idx_TransactionsAddressesDebit` (`DebitAmount`),
INDEX `Idx_TransactionsAddressesCredit` (`CreditAmount`) INDEX `Idx_TransactionsAddressesCredit` (`CreditAmount`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4; ) 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'); $conn = ConnectionManager::get('default');
$stmt = $conn->execute('SELECT COUNT(Id) AS Total FROM Claims WHERE ThumbnailUrl IS NOT NULL AND LENGTH(TRIM(ThumbnailUrl)) > 0'); // $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); // $count = $stmt->fetch(\PDO::FETCH_OBJ);
$numClaims = $count->Total; $numClaims = 23000000;
if ($beforeId < 0) { if ($beforeId < 0) {
$beforeId = 0; $beforeId = 0;

File diff suppressed because it is too large Load diff

View file

@ -5,7 +5,46 @@ namespace App\Model\Entity;
use Cake\ORM\Entity; use Cake\ORM\Entity;
class Claim extends 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

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,18 +0,0 @@
<?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,29 +8,20 @@ class ClaimsTable extends Table {
public function initialize(array $config) { public function initialize(array $config) {
parent::initialize($config); parent::initialize($config);
$this->primaryKey('Id'); $this->setPrimaryKey('id');
$this->table('Claims'); $this->setTable('claim');
//$this->addBehavior('SimpleAudit'); //$this->addBehavior('SimpleAudit');
$this->addAssociations([ $this->addAssociations([
'belongsTo' => [ 'belongsTo' => [
'Publisher' => [ 'publisher' => [
'className' => 'App\Model\Table\ClaimsTable', 'className' => 'App\Model\Table\ClaimsTable',
'foreignKey' => 'PublisherId', 'foreignKey' => 'publisher_id',
'bindingKey' => 'ClaimId', 'bindingKey' => 'claim_id',
'propertyName' => 'Publisher' '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) { public function initialize(array $config) {
parent::initialize($config); parent::initialize($config);
$this->primaryKey('Id'); $this->setPrimaryKey('id');
$this->table('Inputs'); $this->setTable('input');
$this->addBehavior('SimpleAudit'); $this->addBehavior('SimpleAudit');
$this->addAssociations([ $this->addAssociations([
'belongsToMany' => [ 'belongsToMany' => [
'InputAddresses' => [ 'input_addresses' => [
'className' => 'App\Model\Table\AddressesTable', 'className' => 'App\Model\Table\AddressesTable',
'joinTable' => 'InputsAddresses', 'joinTable' => 'input_addresses',
'foreignKey' => 'InputId', 'foreignKey' => 'input_id',
'targetForeignKey' => 'AddressId', 'targetForeignKey' => 'address_id',
'propertyName' => 'InputAddresses' 'propertyName' => 'input_addresses'
] ]
] ]
]); ]);

View file

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

View file

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

View file

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

View file

@ -0,0 +1,16 @@
<?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) { public function initialize(array $config) {
parent::initialize($config); parent::initialize($config);
$this->primaryKey('Id'); $this->setPrimaryKey('id');
$this->table('Transactions'); $this->setTable('transaction');
$this->addBehavior('SimpleAudit'); $this->addBehavior('SimpleAudit');
} }

View file

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

View file

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

View file

@ -0,0 +1,85 @@
<?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> <script>try{Typekit.load({ async: true });}catch(e){}</script>
<!-- Analytics --> <!-- Analytics -->
<?php if ($_SERVER['HTTP_HOST'] === 'explorer.lbry.io'): ?> <?php if ($_SERVER['HTTP_HOST'] === 'explorer.lbry.com'): ?>
<!-- Global site tag (gtag.js) - Google Analytics --> <!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="//www.googletagmanager.com/gtag/js?id=UA-60403362-1"></script> <script async src="//www.googletagmanager.com/gtag/js?id=UA-60403362-1"></script>
<script> <script>
@ -57,7 +57,7 @@
<?php echo $this->fetch('content') ?> <?php echo $this->fetch('content') ?>
<footer> <footer>
<div class="content"> <div class="content">
<a href="https://lbry.io">LBRY</a> <a href="https://lbry.com">LBRY</a>
<div class="page-time">Page took <?php echo round((microtime(true) - TIME_START) * 1000, 0) ?>ms</div> <div class="page-time">Page took <?php echo round((microtime(true) - TIME_START) * 1000, 0) ?>ms</div>
</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') ?> <?php $this->start('script') ?>
<script type="text/javascript"> <script type="text/javascript">
@ -40,7 +40,7 @@
var btnClose = $('.btn-close'); var btnClose = $('.btn-close');
$.ajax({ $.ajax({
url: '/api/v1/address/<?php echo $address->Address ?>/tag', url: '/api/v1/address/<?php echo $address->address ?>/tag',
type: 'post', type: 'post',
dataType: 'json', dataType: 'json',
data: req, data: req,
@ -87,41 +87,15 @@
<div class="address-head"> <div class="address-head">
<h3>LBRY Address</h3> <h3>LBRY Address</h3>
<h4><?php echo $address->Address ?></h4> <div class="tag"> <h4><?php echo $address->address ?></h4>
<?php if (isset($address->Tag) && strlen(trim($address->Tag)) > 0): ?> <?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 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 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; ?> <?php endif; ?>
</div>
</div> </div>
<div class="address-subhead"> <div class="address-subhead">
<div class="address-qr"> <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>
<div class="address-summary"> <div class="address-summary">
@ -178,19 +152,14 @@
<?php foreach ($recentTxs as $tx): ?> <?php foreach ($recentTxs as $tx): ?>
<tr> <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="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 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><?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 number_format($tx->confirmations, 0, '', ',') ?></td>
<td class="right"><?php echo $tx->InputCount ?></td> <td class="right"><?php echo $tx->input_count ?></td>
<td class="right"><?php echo $tx->OutputCount ?></td> <td class="right"><?php echo $tx->output_count ?></td>
<td class="right<?php echo ' ' . (($tx->DebitAmount > 0 && $tx->CreditAmount > 0) ? '' : (($tx->DebitAmount > 0) ? 'debit' : 'credit')) ?>"> <td class="right<?php echo ' ' . ($tx->debit_amount > 0 && $tx->credit_amount > 0 ? 'diff' : ($tx->debit_amount > 0 ? 'debit' : 'credit')) ?>">
<?php if ($tx->DebitAmount > 0 && $tx->CreditAmount > 0): ?> <?php echo number_format($tx->credit_amount - $tx->debit_amount, 8, '.', ',') ?> LBC
<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> </td>
</tr> </tr>
<?php endforeach; ?> <?php endforeach; ?>

View file

@ -21,21 +21,19 @@
</script> </script>
<?php $this->end(); ?> <?php $this->end(); ?>
<?php $this->assign('title', 'Block Height ' . $block->Height) ?> <?php $this->assign('title', 'Block Height ' . $block->height) ?>
<div class="block-head"> <div class="block-head">
<h3>LBRY Block <?php echo $block->Height ?></h3> <h3>LBRY Block <?php echo $block->height ?></h3>
<h4><?php echo $block->Hash ?></h4> <h4><?php echo $block->hash ?></h4>
</div> </div>
<div class="block-nav"> <div class="block-nav">
<?php if (strlen(trim($block->PreviousBlockHash)) > 0): ?> <?php if ($block->height > 0): ?>
<a class="btn btn-prev" href="/blocks/<?php echo ($block->Height - 1); ?>">&laquo; Previous Block</a> <a class="btn btn-prev" href="/blocks/<?php echo ($block->height - 1); ?>">&laquo; Previous Block</a>
<?php endif; ?> <?php endif; ?>
<?php if (strlen(trim($block->NextBlockHash)) > 0): ?> <a class="btn btn-next" href="/blocks/<?php echo ($block->height + 1); ?>">Next Block &raquo;</a>
<a class="btn btn-next" href="/blocks/<?php echo ($block->Height + 1); ?>">Next Block &raquo;</a>
<?php endif; ?>
<div class="clear"></div> <div class="clear"></div>
</div> </div>
@ -47,44 +45,46 @@
<div class="label half-width">Block Size (bytes)</div> <div class="label half-width">Block Size (bytes)</div>
<div class="label half-width">Block Time</div> <div class="label half-width">Block Time</div>
<div class="value half-width"><?php echo number_format($block->BlockSize, 0, '', ',') ?></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->BlockTime)->format('j M Y H:i:s') . ' UTC' ?></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="clear spacer"></div> <div class="clear spacer"></div>
<div class="label half-width">Bits</div> <div class="label half-width">Bits</div>
<div class="label half-width">Confirmations</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 $block->bits ?></div>
<div class="value half-width"><?php echo number_format($block->Confirmations, 0, '', ',') ?></div> <div class="value half-width"><?php echo $confirmations ?></div>
<div class="clear spacer"></div> <div class="clear spacer"></div>
<div class="label half-width">Difficulty</div> <div class="label half-width">Difficulty</div>
<div class="label half-width">Nonce</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 $this->Amount->format($block->difficulty, '') ?></div>
<div class="value half-width"><?php echo $block->Nonce ?></div> <div class="value half-width"><?php echo $block->nonce ?></div>
<div class="clear spacer"></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="spacer"></div>
<div class="label">MerkleRoot</div> <div class="value"><?php echo $block->MerkleRoot ?></div> <div class="label">MerkleRoot</div> <div class="value"><?php echo $block->merkle_root ?></div>
<div class="spacer"></div> <div class="spacer"></div>
<div class="label">NameClaimRoot</div> <div class="value"><?php echo $block->NameClaimRoot ?></div> <div class="label">NameClaimRoot</div> <div class="value"><?php echo $block->name_claim_root ?></div>
<!--
<div class="spacer"></div> <div class="spacer"></div>
<div class="label">Target</div> <div class="value"><?php echo $block->Target ?></div> <div class="label">Target</div> <div class="value"><?php echo $block->Target ?></div>
-->
<div class="spacer"></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>
<div class="block-transactions"> <div class="block-transactions">
@ -109,10 +109,10 @@
<?php foreach ($blockTxs as $tx): ?> <?php foreach ($blockTxs as $tx): ?>
<tr> <tr>
<td class="w300"><div><a href="/tx/<?php echo $tx->Hash ?>"><?php echo $tx->Hash ?></a></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->input_count ?></td>
<td class="right"><?php echo $tx->OutputCount ?></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="right"><div title="<?php echo $tx->value ?> LBC"><?php echo $this->Amount->formatCurrency($tx->value) ?> LBC</div></td>
</tr> </tr>
<?php endforeach; ?> <?php endforeach; ?>
</tbody> </tbody>
@ -134,236 +134,7 @@
<script type="text/javascript" src="/amcharts/amcharts.js"></script> <script type="text/javascript" src="/amcharts/amcharts.js"></script>
<script type="text/javascript" src="/amcharts/serial.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="/amcharts/plugins/export/export.min.js"></script>
<script type="text/javascript"> <script type="text/javascript" src="/js/block-size-chart.js"></script>
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(); ?> <?php $this->end(); ?>
<div class="block-head"> <div class="block-head">
@ -410,13 +181,13 @@
<tbody> <tbody>
<?php foreach ($blocks as $block): ?> <?php foreach ($blocks as $block): ?>
<tr> <tr>
<td class="right"><a href="/blocks/<?php echo $block->Height ?>"><?php echo $block->Height ?></a></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="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 number_format((($currentBlock->height - $block->height) + 1), 0, '', ',') ?></td>
<td class="right"><?php echo count(json_decode($block->TransactionHashes)) ?></td> <td class="right"><?php echo $block->tx_count ?></td>
<td class="right"><?php echo round($block->BlockSize / 1024, 2) . 'KB' ?></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="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> <td class="pad-left"><?php echo \DateTime::createFromFormat('U', $block->block_time)->format('d M Y H:i:s') ?> UTC</td>
</tr> </tr>
<?php endforeach; ?> <?php endforeach; ?>
</tbody> </tbody>

View file

@ -39,28 +39,15 @@
<?php if (isset($claim)): <?php if (isset($claim)):
$a = ['purple', 'orange', 'blue', 'teal', 'green', 'yellow']; $a = ['purple', 'orange', 'blue', 'teal', 'green', 'yellow'];
$autoThumbText = ''; $autoThumbText = $claim->getAutoThumbText();
$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 )));
}
$cost = 'Free'; $cost = 'Free';
if (isset($claim->Price) && $claim->Price > 0) { if (isset($claim->price) && $claim->price > 0) {
$cost = $this->Amount->formatCurrency($claim->Price) . ' LBC'; $cost = $this->Amount->formatCurrency($claim->price) . ' LBC';
} else if (isset($claim->Fee) && strtolower($claim->FeeCurrency) === 'lbc') { } else if (isset($claim->fee) && strtolower($claim->fee_currency) === 'lbc') {
$cost = $this->Amount->formatCurrency($claim->Fee) . ' LBC'; $cost = $this->Amount->formatCurrency($claim->fee) . ' LBC';
} }
$desc = $claim->Description; $desc = $claim->description;
if (strlen(trim($desc)) == 0) { if (strlen(trim($desc)) == 0) {
$desc = '<em>No description available.</em>'; $desc = '<em>No description available.</em>';
} else { } else {
@ -70,29 +57,38 @@ 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"> <div class="claims-head">
<h3><a href="/claims">LBRY Claims</a> &bull; <?php echo $claim->Name ?></h3> <h3><a href="/claims">LBRY Claims</a> &bull; <?php echo $claim->name ?></h3>
<h4><?php echo $claim->ClaimId ?></h4> <h4><?php echo $claim->claim_id ?></h4>
</div> </div>
<div class="claims-body"> <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 class="claim-info">
<div data-autothumb="<?php echo $autoThumbText ?>" class="thumbnail <?php echo $a[mt_rand(0, count($a) - 1)] ?>"> <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): ?> <?php if (!$claim->is_nsfw && strlen(trim($claim->thumbnail_url)) > 0): ?>
<img src="<?php echo $claim->ThumbnailUrl ?>" alt="" /> <img src="<?php echo htmlspecialchars('https://thumbnails.odycdn.com/optimize/s:1280:720/quality:85/plain/'.$claim->thumbnail_url) ?>" alt="" />
<?php else: ?> <?php else: ?>
<div class="autothumb"><?php echo $autoThumbText ?></div> <div class="autothumb"><?php echo $autoThumbText ?></div>
<?php endif; ?> <?php endif; ?>
</div> </div>
<div class="content"> <div class="content">
<?php if ($claim->ClaimType == 2): ?> <?php if ($claim->claim_type == 1): ?>
<div class="label">Published By</div> <div class="label">Published By</div>
<div class="value"> <div class="value">
<?php if (isset($claim->Publisher)): ?> <?php if (isset($claim->publisher)): ?>
<a href="lbry://<?php echo $claim->Publisher->Name ?>"><?php echo $claim->Publisher->Name ?></a> <a href="lbry://<?php echo $claim->publisher ?>"><?php echo $claim->publisher ?></a>
<?php else: ?> <?php else: ?>
<em>Anonymous</em> <em>Anonymous</em>
<?php endif; ?> <?php endif; ?>
@ -100,17 +96,17 @@ if (strlen(trim($desc)) == 0) {
<?php endif; ?> <?php endif; ?>
<div class="label">Created On</div> <div class="label">Created On</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="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="label">Transaction ID</div> <div class="label">Transaction ID</div>
<div class="value"><a href="/tx/<?php echo $claim->TransactionHash ?>#output-<?php echo $claim->Vout ?>"><?php echo $claim->TransactionHash ?></a></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>
<?php if ($claim->ClaimType == 2): ?> <?php if ($claim->claim_type == 1): ?>
<div class="label half-width">Cost</div> <div class="label half-width">Cost</div>
<div class="label half-width">Safe for Work</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 $cost ?></div>
<div class="value half-width"><?php echo $claim->IsNSFW ? 'No' : 'Yes' ?></div> <div class="value half-width"><?php echo $claim->is_nsfw ? 'No' : 'Yes' ?></div>
<div class="clear"></div> <div class="clear"></div>
<?php endif; ?> <?php endif; ?>
@ -118,11 +114,11 @@ if (strlen(trim($desc)) == 0) {
</div> </div>
<div class="claim-metadata"> <div class="claim-metadata">
<?php if ($claim->ClaimType == 1): ?> <?php if ($claim->claim_type == 2): ?>
<div class="title">Identity Claim</div> <div class="title">Identity Claim</div>
<div class="desc">This is an identity claim.</div> <div class="desc">This is an identity claim.</div>
<?php else: ?> <?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="desc"><?php echo str_replace("\n", '<br />', $desc) ?></div>
<div class="details"> <div class="details">
@ -130,30 +126,33 @@ if (strlen(trim($desc)) == 0) {
<div class="label half-width">Content Type</div> <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->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="value half-width"><?php echo strlen(trim($claim->content_type)) > 0 ? $claim->content_type : '<em>Unspecified</em>' ?></div>
<!--
<div class="label half-width">License</div> <div class="label half-width">License</div>
<div class="label half-width">Language</div> -->
<div class="label">Language</div>
<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; ?> <div class="value half-width"<?php if(strlen(trim($claim->license)) > 0): ?> title="<?php echo $claim->license ?>"<?php endif; ?>>
<?php echo strlen(trim($claim->License)) > 0 ? $claim->License : '<em>Unspecified</em>' ?> <?php echo strlen(trim($claim->License)) > 0 ? $claim->License : '<em>Unspecified</em>' ?>
<?php if (strlen(trim($claim->LicenseUrl))): ?></a><?php endif; ?>
</div> </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> </div>
<?php endif; ?> <?php endif; ?>
<a href="<?php echo $link ?>" class="open-lbry-link">Open in LBRY</a> <a href="<?php echo $claim->getLbryLink() ?>" class="open-lbry-link">Open in LBRY</a>
</div> </div>
<div class="clear"></div> <div class="clear"></div>
<?php endif; ?>
<?php if (count($moreClaims) > 0): ?> <?php if (count($moreClaims) > 0): ?>
<div class="more-claims"> <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"> <div class="claims-grid">
<?php $idx = 1; $row = 1; $rowCount = ceil(count($moreClaims) / 3); <?php $idx = 1; $row = 1; $rowCount = ceil(count($moreClaims) / 3);
@ -163,105 +162,9 @@ if (strlen(trim($desc)) == 0) {
if ($idx % 3 == 0) { if ($idx % 3 == 0) {
$row++; $row++;
} }
echo $this->element('claimbox', array('claim' => $claim, 'idx' => $idx, 'last_row' => $last_row));
$autoThumbText = ''; $idx++;
$link = $claim->Name; endforeach; ?>
$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 class="clear"></div>
</div> </div>
</div> </div>
@ -290,103 +193,9 @@ if (strlen(trim($desc)) == 0) {
if ($idx % 3 == 0) { if ($idx % 3 == 0) {
$row++; $row++;
} }
$autoThumbText = ''; echo $this->element('claimbox', array('claim' => $claim, 'idx' => $idx, 'last_row' => $last_row));
$link = $claim->Name; $idx++;
$rawLink = $claim->Name; endforeach; ?>
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 class="clear"></div>
</div> </div>

View file

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

View file

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

View file

@ -1,19 +1,34 @@
<?php $this->assign('title', 'Stats &amp; Rich List') ?> <?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 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"> <div class="stats-head">
<h3>LBRY Stats</h3> <h3>LBRY Stats</h3>
</div> </div>
<div class="stats-main"> <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"> <div class="richlist">
<h3>LBRY Rich List (Top 500)</h3> <h3>LBRY Rich List (Top 500)</h3>
<table class="table"> <table class="table">
@ -32,22 +47,25 @@
<?php $rank = 0; foreach ($richList as $item): $rank++; ?> <?php $rank = 0; foreach ($richList as $item): $rank++; ?>
<tr> <tr>
<td class="right topvalign"><?php echo $rank ?></td> <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> <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; ?>
<?php if (isset($item->Tag) && strlen(trim($item->Tag)) > 0): ?> <?php if (isset($item->Tag) && strlen(trim($item->Tag)) > 0): ?>
<div class="tag"> <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; ?> <?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> </div>
<?php endif; ?></td> <?php endif; ?></td>
<td class="right topvalign"><?php echo number_format($item->Balance, 8, '.', ',') ?></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="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="med-pad-left topvalign"><?php echo $item->first_seen->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> <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> </tr>
<?php endforeach; ?> <?php endforeach; ?>
</tbody> </tbody>
</table> </table>
</div> </div>
<div class="clear"></div> <div class="clear"></div>
</div> </div>

View file

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

View file

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

4
tmp/.gitignore vendored Normal file
View file

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

View file

@ -5,7 +5,7 @@ Version: 1.1.2
## Description ## Description
Smoothly animates the `dataProvider` Smoothly animates the `dataProvider`.
It works with serial, pie, XY, funnel, and radar. It works with serial, pie, XY, funnel, and radar.
@ -96,13 +96,13 @@ http://www.apache.org/licenses/LICENSE-2.0
## Changelog ## Changelog
### 1.1.2 ### 1.1.2
* Fixing a bug with the minimum/maximum * Fixing a bug with the minimum/maximum.
### 1.1.1 ### 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 ### 1.1.0
* Adding in support for XY charts * Adding in support for XY charts.
### 1.0.0 ### 1.0.0
* Initial release * Initial release.

View file

@ -5,13 +5,13 @@ Version: 1.0.16
## Description ## 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. there when the web page loads, defined in-line or loaded via custom code.
This plugin introduces are native wrapper that enables automatic loading of data This plugin introduces our native wrapper that enables automatic loading of data
from external data data sources in CSV and JSON formats. from external data sources in CSV and JSON formats.
Most of the times you will just need to provide a URL of the external data Most of the time, you will just need to provide a URL of the external data
source - static file or dynamically generated - and it will do the rest. 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. 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 a subject for `Access-Control-Allow-Origin` policies defined by the web server
you are loading data from. 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 That's it. The plugin will make sure the files are loaded and dataProvider is
populated with their content *before* the chart is built. 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". data, such as "separator".
If the "format" is omitted, the plugin will assume JSON. If the "format" is omitted, the plugin will assume JSON.
@ -104,32 +104,32 @@ chart["dataLoader"] = {
Property | Default | Description Property | Default | Description
-------- | ------- | ----------- -------- | ------- | -----------
async | true | If set to false (not recommended) everything will wait until data is fully loaded 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 complete | | Callback function to execute when loader is done.
delimiter | , | [CSV only] a delimiter for columns (use \t for tab delimiters) delimiter | , | [CSV only] a delimiter for columns (use \t for tab delimiters).
emptyAs | undefined | [CSV only] replace empty columns with whatever is set here emptyAs | undefined | [CSV only] replace empty columns with whatever is set here.
error | | Callback function to execute if file load fails error | | Callback function to execute if file load fails.
init | | Callback function to execute when Data Loader is initialized, before any loading starts init | | Callback function to execute when Data Loader is initialized, before any loading starts.
format | json | Type of data: json, csv format | json | Type of data: json, csv.
headers | | An array of objects with two properties (key and value) to attach to HTTP request 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) 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 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 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 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. 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 showErrors | true | Show loading errors in a chart curtain.
showCurtain | true| Show curtain over the chart area when loading data showCurtain | true| Show curtain over the chart area when loading data.
reload | 0 | Reload data every X seconds reload | 0 | Reload data every X seconds.
reverse | false | [CSV only] add data points in revers order 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) 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 skipEmpty | true | [CSV only] Ignore empty lines in data.
timestamp | false | Add current timestamp to data URLs (to avoid caching) 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 useColumnNames | false | [CSV only] Use first row in data as column names when parsing.
## Using in JavaScript Stock Chart ## 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 with the exception that `dataLoader` is set as a property to the data set
definition. I.e.: definition. I.e.:
@ -251,9 +251,9 @@ The three available functions are as follows:
Function | Parameters | Description Function | Parameters | Description
-------- | ---------- | ----------- -------- | ---------- | -----------
AmCharts.loadFile() | url, options, callback | Loads the file and passes it into callback function (unparsed) 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.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.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. 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 ## 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...'. text prompts, like 'Data loading...'.
Plugin will try matching chart's `language` property and display text prompts in 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 ## Changelog
### 1.0.16 ### 1.0.16
* Added "numberFields" config array * Added "numberFields" config array.
### 1.0.15 ### 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 ### 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 ### 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 ### 1.0.12
* Better default options handling in external calls to AmCharts.loadFile * Better default options handling in external calls to AmCharts.loadFile.
* Fixed the latest version of Stock Chart not resetting to default pre-defined period * 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) * New example: Using Data Loader functions externally (map_json_external_function.html).
### 1.0.11 ### 1.0.11
* New translation: Added French translation. Thanks Remy! * 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 ### 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 ### 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 ### 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 ### 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 ### 1.0.6
* Added support for Gauge chart (loads `arrows` array) * Added support for Gauge chart (loads `arrows` array).
### 1.0.5 ### 1.0.5
* Fixed JS error if periodSelector was not defined in chart config * Fixed JS error if periodSelector was not defined in chart config.
* Now all callback functions (complete, error, load) receive additional parameter: chart * 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 * postProcess function will now have "this" context set to Data Loader object as well as receive chart reference as third parameter.
### 1.0.4 ### 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 ### 1.0.3
* Fixed the bug where defaults were not being applied properly * Fixed the bug where defaults were not being applied properly.
* Fixed the bug with translations not being applied properly * Fixed the bug with translations not being applied properly.
* Cleaned up the code (to pass JSHint validation) * Cleaned up the code (to pass JSHint validation).
### 1.0.2 ### 1.0.2
* Fixed the issue with modified Array prototypes * Fixed the issue with modified Array prototypes.
### 1.0.1 ### 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 * 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 language container initialization bug.
* Fixed bug that was causing parse errors not be displayed * Fixed bug that was causing parse errors not be displayed.
### 1.0 ### 1.0
* Added GANTT chart support * Added GANTT chart support.
### 0.9.2 ### 0.9.2
* Added global data load methods that can be used to load and parse data by code outside plugin * Added global data load methods that can be used to load and parse data by code outside plugin.
* Trim CSV column names * Trim CSV column names.
* Translation added: Lithuanian * Translation added: Lithuanian.
### 0.9.1 ### 0.9.1
* Fix chart animations not playing after asynchronous load * Fix chart animations not playing after asynchronous load.
### 0.9 ### 0.9
* Initial release * Initial release.

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,8 @@
.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,18 +81,23 @@ 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 .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 > 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 .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 .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 .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 .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 .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 .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 .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 .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 .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-grid .claim-grid-item .spacer { height: 16px }
.claims-body { width: 1200px; margin: 0 auto 0 auto; cursor: default } .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 { 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 { width: 100%; height: 220px; background: #f0f0f0; display: block; position: relative; overflow: hidden }
.claims-body .claim-info .thumbnail img { width: 100% } .claims-body .claim-info .thumbnail img { width: 100% }
@ -219,7 +224,9 @@ footer .content .page-time { position: absolute; right: 12px; bottom: 0px; paddi
.stats-main h3 { font-weight: 300; margin: 0 0 12px 0 } .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 { 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; width: 25% } .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 .title { color: #1e88e5; font-size: 90% } .stats .box .title { color: #1e88e5; font-size: 90% }
.stats .box .value { font-size: 180%; font-weight: 300; margin-top: 8px } .stats .box .value { font-size: 180%; font-weight: 300; margin-top: 8px }
.stats .box.last { border-color: transparent } .stats .box.last { border-color: transparent }
@ -252,6 +259,7 @@ 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 .support { background: #ffeb3b }
.tx-details-layout .outputs .output .labels .update { background: #ea80fc } .tx-details-layout .outputs .output .labels .update { background: #ea80fc }
.tx-details-layout .outputs .output .labels .claim { background: #76ff03 } .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 .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.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 } .tx-details-layout .inputs .input.highlighted, .tx-details-layout .outputs .output.highlighted { background: #f1f8e9 }
@ -295,6 +303,7 @@ footer .content .page-time { position: absolute; right: 12px; bottom: 0px; paddi
.tx-table td { vertical-align: top; line-height: 24px } .tx-table td { vertical-align: top; line-height: 24px }
.tx-table td.credit, .tx-table td div.credit { color: #00e676 } .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.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 } .tx-table td div.debit { padding-top: 8px }
.pagination { width: 1200px; margin: 36px auto 0 auto; cursor: default } .pagination { width: 1200px; margin: 36px auto 0 auto; cursor: default }

View file

@ -0,0 +1,8 @@
.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% }
}

BIN
webroot/img/lbry.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

170
webroot/js/bids-chart.js Normal file
View file

@ -0,0 +1,170 @@
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

@ -0,0 +1,228 @@
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

@ -0,0 +1,264 @@
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();
});