Initial commit
This commit is contained in:
commit
cf9b0cfdaf
18 changed files with 2291 additions and 0 deletions
30
.gitignore
vendored
Normal file
30
.gitignore
vendored
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
/node_modules
|
||||||
|
/LBRY-darwin-x64
|
||||||
|
/dist
|
||||||
|
|
||||||
|
/src/main/dist
|
||||||
|
/src/main/locales
|
||||||
|
/src/main/node_modules
|
||||||
|
/src/renderer/dist
|
||||||
|
/build/venv
|
||||||
|
/build/daemon.ver
|
||||||
|
/lbry-app-venv
|
||||||
|
/lbry-app
|
||||||
|
/lbry-venv
|
||||||
|
/static/daemon/lbrynet*
|
||||||
|
/static/locales
|
||||||
|
/daemon/build
|
||||||
|
/daemon/venv
|
||||||
|
/daemon/requirements.txt
|
||||||
|
/.idea
|
||||||
|
|
||||||
|
*.pyc
|
||||||
|
*.iml
|
||||||
|
.#*
|
||||||
|
|
||||||
|
build/daemon.zip
|
||||||
|
.vimrc
|
||||||
|
|
||||||
|
package-lock.json
|
||||||
|
|
||||||
|
.DS_Store
|
1085
build/index.js
Normal file
1085
build/index.js
Normal file
File diff suppressed because it is too large
Load diff
111
package.json
Normal file
111
package.json
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
{
|
||||||
|
"name": "lbry-redux",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "Common shared components for desktop and mobile.",
|
||||||
|
"homepage": "https://lbry.io/",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/lbryio/lbry-redux/issues"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/lbryio/lbry-redux"
|
||||||
|
},
|
||||||
|
"author": {
|
||||||
|
"name": "LBRY Inc.",
|
||||||
|
"email": "hello@lbry.io"
|
||||||
|
},
|
||||||
|
"main": "build/index.js",
|
||||||
|
"scripts": {
|
||||||
|
"build": "webpack",
|
||||||
|
"lint": "eslint 'src/**/*.{js,jsx}' --fix",
|
||||||
|
"format": "prettier 'src/**/*.{js,jsx,scss,json}' --write"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"lbry"
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"amplitude-js": "^4.0.0",
|
||||||
|
"bluebird": "^3.5.1",
|
||||||
|
"classnames": "^2.2.5",
|
||||||
|
"electron-dl": "^1.6.0",
|
||||||
|
"formik": "^0.10.4",
|
||||||
|
"from2": "^2.3.0",
|
||||||
|
"install": "^0.10.2",
|
||||||
|
"jayson": "^2.0.2",
|
||||||
|
"jshashes": "^1.0.7",
|
||||||
|
"keytar": "^4.0.3",
|
||||||
|
"localforage": "^1.5.0",
|
||||||
|
"npm": "^5.5.1",
|
||||||
|
"qrcode.react": "^0.7.2",
|
||||||
|
"rc-progress": "^2.0.6",
|
||||||
|
"react": "^16.2.0",
|
||||||
|
"react-dom": "^16.2.0",
|
||||||
|
"react-markdown": "^2.5.0",
|
||||||
|
"react-modal": "^3.1.7",
|
||||||
|
"react-paginate": "^5.0.0",
|
||||||
|
"react-redux": "^5.0.3",
|
||||||
|
"react-simplemde-editor": "^3.6.11",
|
||||||
|
"redux": "^3.6.0",
|
||||||
|
"redux-action-buffer": "^1.1.0",
|
||||||
|
"redux-logger": "^3.0.1",
|
||||||
|
"redux-persist": "^4.8.0",
|
||||||
|
"redux-persist-transform-compress": "^4.2.0",
|
||||||
|
"redux-persist-transform-filter": "0.0.10",
|
||||||
|
"redux-thunk": "^2.2.0",
|
||||||
|
"render-media": "^2.10.0",
|
||||||
|
"reselect": "^3.0.0",
|
||||||
|
"semver": "^5.3.0",
|
||||||
|
"shapeshift.io": "^1.3.1",
|
||||||
|
"source-map-support": "^0.5.0",
|
||||||
|
"tree-kill": "^1.1.0",
|
||||||
|
"y18n": "^4.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"babel-eslint": "^8.0.3",
|
||||||
|
"babel-plugin-module-resolver": "^3.0.0",
|
||||||
|
"babel-plugin-react-require": "^3.0.0",
|
||||||
|
"babel-polyfill": "^6.20.0",
|
||||||
|
"babel-preset-env": "^1.6.1",
|
||||||
|
"babel-preset-react": "^6.24.1",
|
||||||
|
"babel-preset-stage-2": "^6.18.0",
|
||||||
|
"devtron": "^1.4.0",
|
||||||
|
"electron": "^1.7.9",
|
||||||
|
"electron-builder": "^19.49.0",
|
||||||
|
"electron-devtools-installer": "^2.2.1",
|
||||||
|
"electron-webpack": "^1.11.0",
|
||||||
|
"eslint": "^4.13.1",
|
||||||
|
"eslint-config-airbnb": "^16.1.0",
|
||||||
|
"eslint-config-prettier": "^2.9.0",
|
||||||
|
"eslint-import-resolver-webpack": "^0.8.3",
|
||||||
|
"eslint-plugin-flowtype": "^2.40.1",
|
||||||
|
"eslint-plugin-import": "^2.8.0",
|
||||||
|
"eslint-plugin-jsx-a11y": "^6.0.3",
|
||||||
|
"eslint-plugin-prettier": "^2.4.0",
|
||||||
|
"eslint-plugin-react": "^7.5.1",
|
||||||
|
"flow-babel-webpack-plugin": "^1.1.0",
|
||||||
|
"flow-bin": "^0.61.0",
|
||||||
|
"flow-typed": "^2.2.3",
|
||||||
|
"husky": "^0.14.3",
|
||||||
|
"i18n-extract": "^0.5.1",
|
||||||
|
"json-loader": "^0.5.4",
|
||||||
|
"lint-staged": "^6.0.0",
|
||||||
|
"node-loader": "^0.6.0",
|
||||||
|
"node-sass": "^4.7.2",
|
||||||
|
"prettier": "^1.4.2",
|
||||||
|
"sass-loader": "^6.0.6",
|
||||||
|
"webpack": "^3.10.0",
|
||||||
|
"webpack-build-notifier": "^0.1.18"
|
||||||
|
},
|
||||||
|
"resolutions": {
|
||||||
|
"webpack/webpack-sources": "1.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6",
|
||||||
|
"yarn": "^1.3"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"lbrySettings": {
|
||||||
|
"lbrynetDaemonVersion": "0.18.0",
|
||||||
|
"lbrynetDaemonUrlTemplate": "https://github.com/lbryio/lbry/releases/download/vDAEMONVER/lbrynet-daemon-vDAEMONVER-OSNAME.zip"
|
||||||
|
}
|
||||||
|
}
|
164
src/constants/action_types.js
Normal file
164
src/constants/action_types.js
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
export const OPEN_MODAL = 'OPEN_MODAL';
|
||||||
|
export const CLOSE_MODAL = 'CLOSE_MODAL';
|
||||||
|
export const SHOW_SNACKBAR = 'SHOW_SNACKBAR';
|
||||||
|
export const REMOVE_SNACKBAR_SNACK = 'REMOVE_SNACKBAR_SNACK';
|
||||||
|
export const WINDOW_FOCUSED = 'WINDOW_FOCUSED';
|
||||||
|
export const DAEMON_READY = 'DAEMON_READY';
|
||||||
|
export const DAEMON_VERSION_MATCH = 'DAEMON_VERSION_MATCH';
|
||||||
|
export const DAEMON_VERSION_MISMATCH = 'DAEMON_VERSION_MISMATCH';
|
||||||
|
export const VOLUME_CHANGED = 'VOLUME_CHANGED';
|
||||||
|
|
||||||
|
// Navigation
|
||||||
|
export const CHANGE_AFTER_AUTH_PATH = 'CHANGE_AFTER_AUTH_PATH';
|
||||||
|
export const WINDOW_SCROLLED = 'WINDOW_SCROLLED';
|
||||||
|
export const HISTORY_NAVIGATE = 'HISTORY_NAVIGATE';
|
||||||
|
|
||||||
|
// Upgrades
|
||||||
|
export const UPGRADE_CANCELLED = 'UPGRADE_CANCELLED';
|
||||||
|
export const DOWNLOAD_UPGRADE = 'DOWNLOAD_UPGRADE';
|
||||||
|
export const UPGRADE_DOWNLOAD_STARTED = 'UPGRADE_DOWNLOAD_STARTED';
|
||||||
|
export const UPGRADE_DOWNLOAD_COMPLETED = 'UPGRADE_DOWNLOAD_COMPLETED';
|
||||||
|
export const UPGRADE_DOWNLOAD_PROGRESSED = 'UPGRADE_DOWNLOAD_PROGRESSED';
|
||||||
|
export const CHECK_UPGRADE_AVAILABLE = 'CHECK_UPGRADE_AVAILABLE';
|
||||||
|
export const CHECK_UPGRADE_START = 'CHECK_UPGRADE_START';
|
||||||
|
export const CHECK_UPGRADE_SUCCESS = 'CHECK_UPGRADE_SUCCESS';
|
||||||
|
export const CHECK_UPGRADE_FAIL = 'CHECK_UPGRADE_FAIL';
|
||||||
|
export const CHECK_UPGRADE_SUBSCRIBE = 'CHECK_UPGRADE_SUBSCRIBE';
|
||||||
|
export const UPDATE_VERSION = 'UPDATE_VERSION';
|
||||||
|
export const UPDATE_REMOTE_VERSION = 'UPDATE_REMOTE_VERSION';
|
||||||
|
export const SKIP_UPGRADE = 'SKIP_UPGRADE';
|
||||||
|
export const START_UPGRADE = 'START_UPGRADE';
|
||||||
|
|
||||||
|
// Wallet
|
||||||
|
export const GET_NEW_ADDRESS_STARTED = 'GET_NEW_ADDRESS_STARTED';
|
||||||
|
export const GET_NEW_ADDRESS_COMPLETED = 'GET_NEW_ADDRESS_COMPLETED';
|
||||||
|
export const FETCH_TRANSACTIONS_STARTED = 'FETCH_TRANSACTIONS_STARTED';
|
||||||
|
export const FETCH_TRANSACTIONS_COMPLETED = 'FETCH_TRANSACTIONS_COMPLETED';
|
||||||
|
export const UPDATE_BALANCE = 'UPDATE_BALANCE';
|
||||||
|
export const CHECK_ADDRESS_IS_MINE_STARTED = 'CHECK_ADDRESS_IS_MINE_STARTED';
|
||||||
|
export const CHECK_ADDRESS_IS_MINE_COMPLETED = 'CHECK_ADDRESS_IS_MINE_COMPLETED';
|
||||||
|
export const SET_DRAFT_TRANSACTION_AMOUNT = 'SET_DRAFT_TRANSACTION_AMOUNT';
|
||||||
|
export const SET_DRAFT_TRANSACTION_ADDRESS = 'SET_DRAFT_TRANSACTION_ADDRESS';
|
||||||
|
export const SEND_TRANSACTION_STARTED = 'SEND_TRANSACTION_STARTED';
|
||||||
|
export const SEND_TRANSACTION_COMPLETED = 'SEND_TRANSACTION_COMPLETED';
|
||||||
|
export const SEND_TRANSACTION_FAILED = 'SEND_TRANSACTION_FAILED';
|
||||||
|
export const FETCH_BLOCK_SUCCESS = 'FETCH_BLOCK_SUCCESS';
|
||||||
|
export const SUPPORT_TRANSACTION_STARTED = 'SUPPORT_TRANSACTION_STARTED';
|
||||||
|
export const SUPPORT_TRANSACTION_COMPLETED = 'SUPPORT_TRANSACTION_COMPLETED';
|
||||||
|
export const SUPPORT_TRANSACTION_FAILED = 'SUPPORT_TRANSACTION_FAILED';
|
||||||
|
|
||||||
|
// Claims
|
||||||
|
export const FETCH_FEATURED_CONTENT_STARTED = 'FETCH_FEATURED_CONTENT_STARTED';
|
||||||
|
export const FETCH_FEATURED_CONTENT_COMPLETED = 'FETCH_FEATURED_CONTENT_COMPLETED';
|
||||||
|
export const RESOLVE_URIS_STARTED = 'RESOLVE_URIS_STARTED';
|
||||||
|
export const RESOLVE_URIS_COMPLETED = 'RESOLVE_URIS_COMPLETED';
|
||||||
|
export const FETCH_CHANNEL_CLAIMS_STARTED = 'FETCH_CHANNEL_CLAIMS_STARTED';
|
||||||
|
export const FETCH_CHANNEL_CLAIMS_COMPLETED = 'FETCH_CHANNEL_CLAIMS_COMPLETED';
|
||||||
|
export const FETCH_CHANNEL_CLAIM_COUNT_STARTED = 'FETCH_CHANNEL_CLAIM_COUNT_STARTED';
|
||||||
|
export const FETCH_CHANNEL_CLAIM_COUNT_COMPLETED = 'FETCH_CHANNEL_CLAIM_COUNT_COMPLETED';
|
||||||
|
export const FETCH_CLAIM_LIST_MINE_STARTED = 'FETCH_CLAIM_LIST_MINE_STARTED';
|
||||||
|
export const FETCH_CLAIM_LIST_MINE_COMPLETED = 'FETCH_CLAIM_LIST_MINE_COMPLETED';
|
||||||
|
export const ABANDON_CLAIM_STARTED = 'ABANDON_CLAIM_STARTED';
|
||||||
|
export const ABANDON_CLAIM_SUCCEEDED = 'ABANDON_CLAIM_SUCCEEDED';
|
||||||
|
export const FETCH_CHANNEL_LIST_MINE_STARTED = 'FETCH_CHANNEL_LIST_MINE_STARTED';
|
||||||
|
export const FETCH_CHANNEL_LIST_MINE_COMPLETED = 'FETCH_CHANNEL_LIST_MINE_COMPLETED';
|
||||||
|
export const CREATE_CHANNEL_STARTED = 'CREATE_CHANNEL_STARTED';
|
||||||
|
export const CREATE_CHANNEL_COMPLETED = 'CREATE_CHANNEL_COMPLETED';
|
||||||
|
export const PUBLISH_STARTED = 'PUBLISH_STARTED';
|
||||||
|
export const PUBLISH_COMPLETED = 'PUBLISH_COMPLETED';
|
||||||
|
export const PUBLISH_FAILED = 'PUBLISH_FAILED';
|
||||||
|
export const SET_PLAYING_URI = 'PLAY_URI';
|
||||||
|
|
||||||
|
// Files
|
||||||
|
export const FILE_LIST_STARTED = 'FILE_LIST_STARTED';
|
||||||
|
export const FILE_LIST_SUCCEEDED = 'FILE_LIST_SUCCEEDED';
|
||||||
|
export const FETCH_FILE_INFO_STARTED = 'FETCH_FILE_INFO_STARTED';
|
||||||
|
export const FETCH_FILE_INFO_COMPLETED = 'FETCH_FILE_INFO_COMPLETED';
|
||||||
|
export const FETCH_COST_INFO_STARTED = 'FETCH_COST_INFO_STARTED';
|
||||||
|
export const FETCH_COST_INFO_COMPLETED = 'FETCH_COST_INFO_COMPLETED';
|
||||||
|
export const LOADING_VIDEO_STARTED = 'LOADING_VIDEO_STARTED';
|
||||||
|
export const LOADING_VIDEO_COMPLETED = 'LOADING_VIDEO_COMPLETED';
|
||||||
|
export const LOADING_VIDEO_FAILED = 'LOADING_VIDEO_FAILED';
|
||||||
|
export const DOWNLOADING_STARTED = 'DOWNLOADING_STARTED';
|
||||||
|
export const DOWNLOADING_PROGRESSED = 'DOWNLOADING_PROGRESSED';
|
||||||
|
export const DOWNLOADING_COMPLETED = 'DOWNLOADING_COMPLETED';
|
||||||
|
export const PLAY_VIDEO_STARTED = 'PLAY_VIDEO_STARTED';
|
||||||
|
export const FETCH_AVAILABILITY_STARTED = 'FETCH_AVAILABILITY_STARTED';
|
||||||
|
export const FETCH_AVAILABILITY_COMPLETED = 'FETCH_AVAILABILITY_COMPLETED';
|
||||||
|
export const FILE_DELETE = 'FILE_DELETE';
|
||||||
|
|
||||||
|
// Search
|
||||||
|
export const SEARCH_STARTED = 'SEARCH_STARTED';
|
||||||
|
export const SEARCH_COMPLETED = 'SEARCH_COMPLETED';
|
||||||
|
export const SEARCH_CANCELLED = 'SEARCH_CANCELLED';
|
||||||
|
|
||||||
|
// Settings
|
||||||
|
export const DAEMON_SETTINGS_RECEIVED = 'DAEMON_SETTINGS_RECEIVED';
|
||||||
|
export const CLIENT_SETTING_CHANGED = 'CLIENT_SETTING_CHANGED';
|
||||||
|
|
||||||
|
// User
|
||||||
|
export const AUTHENTICATION_STARTED = 'AUTHENTICATION_STARTED';
|
||||||
|
export const AUTHENTICATION_SUCCESS = 'AUTHENTICATION_SUCCESS';
|
||||||
|
export const AUTHENTICATION_FAILURE = 'AUTHENTICATION_FAILURE';
|
||||||
|
export const USER_EMAIL_DECLINE = 'USER_EMAIL_DECLINE';
|
||||||
|
export const USER_EMAIL_NEW_STARTED = 'USER_EMAIL_NEW_STARTED';
|
||||||
|
export const USER_EMAIL_NEW_SUCCESS = 'USER_EMAIL_NEW_SUCCESS';
|
||||||
|
export const USER_EMAIL_NEW_EXISTS = 'USER_EMAIL_NEW_EXISTS';
|
||||||
|
export const USER_EMAIL_NEW_FAILURE = 'USER_EMAIL_NEW_FAILURE';
|
||||||
|
export const USER_EMAIL_VERIFY_STARTED = 'USER_EMAIL_VERIFY_STARTED';
|
||||||
|
export const USER_EMAIL_VERIFY_SUCCESS = 'USER_EMAIL_VERIFY_SUCCESS';
|
||||||
|
export const USER_EMAIL_VERIFY_FAILURE = 'USER_EMAIL_VERIFY_FAILURE';
|
||||||
|
export const USER_IDENTITY_VERIFY_STARTED = 'USER_IDENTITY_VERIFY_STARTED';
|
||||||
|
export const USER_IDENTITY_VERIFY_SUCCESS = 'USER_IDENTITY_VERIFY_SUCCESS';
|
||||||
|
export const USER_IDENTITY_VERIFY_FAILURE = 'USER_IDENTITY_VERIFY_FAILURE';
|
||||||
|
export const USER_FETCH_STARTED = 'USER_FETCH_STARTED';
|
||||||
|
export const USER_FETCH_SUCCESS = 'USER_FETCH_SUCCESS';
|
||||||
|
export const USER_FETCH_FAILURE = 'USER_FETCH_FAILURE';
|
||||||
|
export const USER_INVITE_STATUS_FETCH_STARTED = 'USER_INVITE_STATUS_FETCH_STARTED';
|
||||||
|
export const USER_INVITE_STATUS_FETCH_SUCCESS = 'USER_INVITE_STATUS_FETCH_SUCCESS';
|
||||||
|
export const USER_INVITE_STATUS_FETCH_FAILURE = 'USER_INVITE_STATUS_FETCH_FAILURE';
|
||||||
|
export const USER_INVITE_NEW_STARTED = 'USER_INVITE_NEW_STARTED';
|
||||||
|
export const USER_INVITE_NEW_SUCCESS = 'USER_INVITE_NEW_SUCCESS';
|
||||||
|
export const USER_INVITE_NEW_FAILURE = 'USER_INVITE_NEW_FAILURE';
|
||||||
|
export const FETCH_ACCESS_TOKEN_SUCCESS = 'FETCH_ACCESS_TOKEN_SUCCESS';
|
||||||
|
|
||||||
|
// Rewards
|
||||||
|
export const FETCH_REWARDS_STARTED = 'FETCH_REWARDS_STARTED';
|
||||||
|
export const FETCH_REWARDS_COMPLETED = 'FETCH_REWARDS_COMPLETED';
|
||||||
|
export const CLAIM_REWARD_STARTED = 'CLAIM_REWARD_STARTED';
|
||||||
|
export const CLAIM_REWARD_SUCCESS = 'CLAIM_REWARD_SUCCESS';
|
||||||
|
export const CLAIM_REWARD_FAILURE = 'CLAIM_REWARD_FAILURE';
|
||||||
|
export const CLAIM_REWARD_CLEAR_ERROR = 'CLAIM_REWARD_CLEAR_ERROR';
|
||||||
|
export const FETCH_REWARD_CONTENT_COMPLETED = 'FETCH_REWARD_CONTENT_COMPLETED';
|
||||||
|
|
||||||
|
// Language
|
||||||
|
export const DOWNLOAD_LANGUAGE_SUCCEEDED = 'DOWNLOAD_LANGUAGE_SUCCEEDED';
|
||||||
|
export const DOWNLOAD_LANGUAGE_FAILED = 'DOWNLOAD_LANGUAGE_FAILED';
|
||||||
|
|
||||||
|
// ShapeShift
|
||||||
|
export const GET_SUPPORTED_COINS_START = 'GET_SUPPORTED_COINS_START';
|
||||||
|
export const GET_SUPPORTED_COINS_SUCCESS = 'GET_SUPPORTED_COINS_SUCCESS';
|
||||||
|
export const GET_SUPPORTED_COINS_FAIL = 'GET_SUPPORTED_COINS_FAIL';
|
||||||
|
export const GET_COIN_STATS_START = 'GET_COIN_STATS_START';
|
||||||
|
export const GET_COIN_STATS_SUCCESS = 'GET_COIN_STATS_SUCCESS';
|
||||||
|
export const GET_COIN_STATS_FAIL = 'GET_COIN_STATS_FAIL';
|
||||||
|
export const PREPARE_SHAPE_SHIFT_START = 'PREPARE_SHAPE_SHIFT_START';
|
||||||
|
export const PREPARE_SHAPE_SHIFT_SUCCESS = 'PREPARE_SHAPE_SHIFT_SUCCESS';
|
||||||
|
export const PREPARE_SHAPE_SHIFT_FAIL = 'PREPARE_SHAPE_SHIFT_FAIL';
|
||||||
|
export const GET_ACTIVE_SHIFT_START = 'GET_ACTIVE_SHIFT_START';
|
||||||
|
export const GET_ACTIVE_SHIFT_SUCCESS = 'GET_ACTIVE_SHIFT_SUCCESS';
|
||||||
|
export const GET_ACTIVE_SHIFT_FAIL = 'GET_ACTIVE_SHIFT_FAIL';
|
||||||
|
export const CLEAR_SHAPE_SHIFT = 'CLEAR_SHAPE_SHIFT';
|
||||||
|
|
||||||
|
// Subscriptions
|
||||||
|
export const CHANNEL_SUBSCRIBE = 'CHANNEL_SUBSCRIBE';
|
||||||
|
export const CHANNEL_UNSUBSCRIBE = 'CHANNEL_UNSUBSCRIBE';
|
||||||
|
export const HAS_FETCHED_SUBSCRIPTIONS = 'HAS_FETCHED_SUBSCRIPTIONS';
|
||||||
|
|
||||||
|
// Video controls
|
||||||
|
export const SET_VIDEO_PAUSE = 'SET_VIDEO_PAUSE';
|
||||||
|
|
||||||
|
// Media controls
|
||||||
|
export const MEDIA_PLAY = 'MEDIA_PLAY';
|
||||||
|
export const MEDIA_PAUSE = 'MEDIA_PAUSE';
|
||||||
|
export const MEDIA_POSITION = 'MEDIA_POSITION';
|
5
src/constants/icons.js
Normal file
5
src/constants/icons.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
export const FEATURED = 'rocket';
|
||||||
|
export const LOCAL = 'folder';
|
||||||
|
export const FILE = 'file';
|
||||||
|
export const HISTORY = 'history';
|
||||||
|
export const HELP_CIRCLE = 'question-circle';
|
187
src/constants/languages.js
Normal file
187
src/constants/languages.js
Normal file
|
@ -0,0 +1,187 @@
|
||||||
|
const LANGUAGES = {
|
||||||
|
aa: ['Afar', 'Afar'],
|
||||||
|
ab: ['Abkhazian', 'Аҧсуа'],
|
||||||
|
af: ['Afrikaans', 'Afrikaans'],
|
||||||
|
ak: ['Akan', 'Akana'],
|
||||||
|
am: ['Amharic', 'አማርኛ'],
|
||||||
|
an: ['Aragonese', 'Aragonés'],
|
||||||
|
ar: ['Arabic', 'العربية'],
|
||||||
|
as: ['Assamese', 'অসমীয়া'],
|
||||||
|
av: ['Avar', 'Авар'],
|
||||||
|
ay: ['Aymara', 'Aymar'],
|
||||||
|
az: ['Azerbaijani', 'Azərbaycanca / آذربايجان'],
|
||||||
|
ba: ['Bashkir', 'Башҡорт'],
|
||||||
|
be: ['Belarusian', 'Беларуская'],
|
||||||
|
bg: ['Bulgarian', 'Български'],
|
||||||
|
bh: ['Bihari', 'भोजपुरी'],
|
||||||
|
bi: ['Bislama', 'Bislama'],
|
||||||
|
bm: ['Bambara', 'Bamanankan'],
|
||||||
|
bn: ['Bengali', 'বাংলা'],
|
||||||
|
bo: ['Tibetan', 'བོད་ཡིག / Bod skad'],
|
||||||
|
br: ['Breton', 'Brezhoneg'],
|
||||||
|
bs: ['Bosnian', 'Bosanski'],
|
||||||
|
ca: ['Catalan', 'Català'],
|
||||||
|
ce: ['Chechen', 'Нохчийн'],
|
||||||
|
ch: ['Chamorro', 'Chamoru'],
|
||||||
|
co: ['Corsican', 'Corsu'],
|
||||||
|
cr: ['Cree', 'Nehiyaw'],
|
||||||
|
cs: ['Czech', 'Česky'],
|
||||||
|
cu: ['Old Church Slavonic / Old Bulgarian', 'словѣньскъ / slověnĭskŭ'],
|
||||||
|
cv: ['Chuvash', 'Чăваш'],
|
||||||
|
cy: ['Welsh', 'Cymraeg'],
|
||||||
|
da: ['Danish', 'Dansk'],
|
||||||
|
de: ['German', 'Deutsch'],
|
||||||
|
dv: ['Divehi', 'ދިވެހިބަސް'],
|
||||||
|
dz: ['Dzongkha', 'ཇོང་ཁ'],
|
||||||
|
ee: ['Ewe', 'Ɛʋɛ'],
|
||||||
|
el: ['Greek', 'Ελληνικά'],
|
||||||
|
en: ['English', 'English'],
|
||||||
|
eo: ['Esperanto', 'Esperanto'],
|
||||||
|
es: ['Spanish', 'Español'],
|
||||||
|
et: ['Estonian', 'Eesti'],
|
||||||
|
eu: ['Basque', 'Euskara'],
|
||||||
|
fa: ['Persian', 'فارسی'],
|
||||||
|
ff: ['Peul', 'Fulfulde'],
|
||||||
|
fi: ['Finnish', 'Suomi'],
|
||||||
|
fj: ['Fijian', 'Na Vosa Vakaviti'],
|
||||||
|
fo: ['Faroese', 'Føroyskt'],
|
||||||
|
fr: ['French', 'Français'],
|
||||||
|
fy: ['West Frisian', 'Frysk'],
|
||||||
|
ga: ['Irish', 'Gaeilge'],
|
||||||
|
gd: ['Scottish Gaelic', 'Gàidhlig'],
|
||||||
|
gl: ['Galician', 'Galego'],
|
||||||
|
gn: ['Guarani', "Avañe'ẽ"],
|
||||||
|
gu: ['Gujarati', 'ગુજરાતી'],
|
||||||
|
gv: ['Manx', 'Gaelg'],
|
||||||
|
ha: ['Hausa', 'هَوُسَ'],
|
||||||
|
he: ['Hebrew', 'עברית'],
|
||||||
|
hi: ['Hindi', 'हिन्दी'],
|
||||||
|
ho: ['Hiri Motu', 'Hiri Motu'],
|
||||||
|
hr: ['Croatian', 'Hrvatski'],
|
||||||
|
ht: ['Haitian', 'Krèyol ayisyen'],
|
||||||
|
hu: ['Hungarian', 'Magyar'],
|
||||||
|
hy: ['Armenian', 'Հայերեն'],
|
||||||
|
hz: ['Herero', 'Otsiherero'],
|
||||||
|
ia: ['Interlingua', 'Interlingua'],
|
||||||
|
id: ['Indonesian', 'Bahasa Indonesia'],
|
||||||
|
ie: ['Interlingue', 'Interlingue'],
|
||||||
|
ig: ['Igbo', 'Igbo'],
|
||||||
|
ii: ['Sichuan Yi', 'ꆇꉙ / 四川彝语'],
|
||||||
|
ik: ['Inupiak', 'Iñupiak'],
|
||||||
|
io: ['Ido', 'Ido'],
|
||||||
|
is: ['Icelandic', 'Íslenska'],
|
||||||
|
it: ['Italian', 'Italiano'],
|
||||||
|
iu: ['Inuktitut', 'ᐃᓄᒃᑎᑐᑦ'],
|
||||||
|
ja: ['Japanese', '日本語'],
|
||||||
|
jv: ['Javanese', 'Basa Jawa'],
|
||||||
|
ka: ['Georgian', 'ქართული'],
|
||||||
|
kg: ['Kongo', 'KiKongo'],
|
||||||
|
ki: ['Kikuyu', 'Gĩkũyũ'],
|
||||||
|
kj: ['Kuanyama', 'Kuanyama'],
|
||||||
|
kk: ['Kazakh', 'Қазақша'],
|
||||||
|
kl: ['Greenlandic', 'Kalaallisut'],
|
||||||
|
km: ['Cambodian', 'ភាសាខ្មែរ'],
|
||||||
|
kn: ['Kannada', 'ಕನ್ನಡ'],
|
||||||
|
ko: ['Korean', '한국어'],
|
||||||
|
kr: ['Kanuri', 'Kanuri'],
|
||||||
|
ks: ['Kashmiri', 'कश्मीरी / كشميري'],
|
||||||
|
ku: ['Kurdish', 'Kurdî / كوردی'],
|
||||||
|
kv: ['Komi', 'Коми'],
|
||||||
|
kw: ['Cornish', 'Kernewek'],
|
||||||
|
ky: ['Kirghiz', 'Kırgızca / Кыргызча'],
|
||||||
|
la: ['Latin', 'Latina'],
|
||||||
|
lb: ['Luxembourgish', 'Lëtzebuergesch'],
|
||||||
|
lg: ['Ganda', 'Luganda'],
|
||||||
|
li: ['Limburgian', 'Limburgs'],
|
||||||
|
ln: ['Lingala', 'Lingála'],
|
||||||
|
lo: ['Laotian', 'ລາວ / Pha xa lao'],
|
||||||
|
lt: ['Lithuanian', 'Lietuvių'],
|
||||||
|
lv: ['Latvian', 'Latviešu'],
|
||||||
|
mg: ['Malagasy', 'Malagasy'],
|
||||||
|
mh: ['Marshallese', 'Kajin Majel / Ebon'],
|
||||||
|
mi: ['Maori', 'Māori'],
|
||||||
|
mk: ['Macedonian', 'Македонски'],
|
||||||
|
ml: ['Malayalam', 'മലയാളം'],
|
||||||
|
mn: ['Mongolian', 'Монгол'],
|
||||||
|
mo: ['Moldovan', 'Moldovenească'],
|
||||||
|
mr: ['Marathi', 'मराठी'],
|
||||||
|
ms: ['Malay', 'Bahasa Melayu'],
|
||||||
|
mt: ['Maltese', 'bil-Malti'],
|
||||||
|
my: ['Burmese', 'Myanmasa'],
|
||||||
|
na: ['Nauruan', 'Dorerin Naoero'],
|
||||||
|
nd: ['North Ndebele', 'Sindebele'],
|
||||||
|
ne: ['Nepali', 'नेपाली'],
|
||||||
|
ng: ['Ndonga', 'Oshiwambo'],
|
||||||
|
nl: ['Dutch', 'Nederlands'],
|
||||||
|
nn: ['Norwegian Nynorsk', 'Norsk (nynorsk)'],
|
||||||
|
no: ['Norwegian', 'Norsk (bokmål / riksmål)'],
|
||||||
|
nr: ['South Ndebele', 'isiNdebele'],
|
||||||
|
nv: ['Navajo', 'Diné bizaad'],
|
||||||
|
ny: ['Chichewa', 'Chi-Chewa'],
|
||||||
|
oc: ['Occitan', 'Occitan'],
|
||||||
|
oj: ['Ojibwa', 'ᐊᓂᔑᓈᐯᒧᐎᓐ / Anishinaabemowin'],
|
||||||
|
om: ['Oromo', 'Oromoo'],
|
||||||
|
or: ['Oriya', 'ଓଡ଼ିଆ'],
|
||||||
|
os: ['Ossetian / Ossetic', 'Иронау'],
|
||||||
|
pa: ['Panjabi / Punjabi', 'ਪੰਜਾਬੀ / पंजाबी / پنجابي'],
|
||||||
|
pi: ['Pali', 'Pāli / पाऴि'],
|
||||||
|
pl: ['Polish', 'Polski'],
|
||||||
|
ps: ['Pashto', 'پښتو'],
|
||||||
|
pt: ['Portuguese', 'Português'],
|
||||||
|
qu: ['Quechua', 'Runa Simi'],
|
||||||
|
rm: ['Raeto Romance', 'Rumantsch'],
|
||||||
|
rn: ['Kirundi', 'Kirundi'],
|
||||||
|
ro: ['Romanian', 'Română'],
|
||||||
|
ru: ['Russian', 'Русский'],
|
||||||
|
rw: ['Rwandi', 'Kinyarwandi'],
|
||||||
|
sa: ['Sanskrit', 'संस्कृतम्'],
|
||||||
|
sc: ['Sardinian', 'Sardu'],
|
||||||
|
sd: ['Sindhi', 'सिनधि'],
|
||||||
|
se: ['Northern Sami', 'Sámegiella'],
|
||||||
|
sg: ['Sango', 'Sängö'],
|
||||||
|
sh: ['Serbo-Croatian', 'Srpskohrvatski / Српскохрватски'],
|
||||||
|
si: ['Sinhalese', 'සිංහල'],
|
||||||
|
sk: ['Slovak', 'Slovenčina'],
|
||||||
|
sl: ['Slovenian', 'Slovenščina'],
|
||||||
|
sm: ['Samoan', 'Gagana Samoa'],
|
||||||
|
sn: ['Shona', 'chiShona'],
|
||||||
|
so: ['Somalia', 'Soomaaliga'],
|
||||||
|
sq: ['Albanian', 'Shqip'],
|
||||||
|
sr: ['Serbian', 'Српски'],
|
||||||
|
ss: ['Swati', 'SiSwati'],
|
||||||
|
st: ['Southern Sotho', 'Sesotho'],
|
||||||
|
su: ['Sundanese', 'Basa Sunda'],
|
||||||
|
sv: ['Swedish', 'Svenska'],
|
||||||
|
sw: ['Swahili', 'Kiswahili'],
|
||||||
|
ta: ['Tamil', 'தமிழ்'],
|
||||||
|
te: ['Telugu', 'తెలుగు'],
|
||||||
|
tg: ['Tajik', 'Тоҷикӣ'],
|
||||||
|
th: ['Thai', 'ไทย / Phasa Thai'],
|
||||||
|
ti: ['Tigrinya', 'ትግርኛ'],
|
||||||
|
tk: ['Turkmen', 'Туркмен / تركمن'],
|
||||||
|
tl: ['Tagalog / Filipino', 'Tagalog'],
|
||||||
|
tn: ['Tswana', 'Setswana'],
|
||||||
|
to: ['Tonga', 'Lea Faka-Tonga'],
|
||||||
|
tr: ['Turkish', 'Türkçe'],
|
||||||
|
ts: ['Tsonga', 'Xitsonga'],
|
||||||
|
tt: ['Tatar', 'Tatarça'],
|
||||||
|
tw: ['Twi', 'Twi'],
|
||||||
|
ty: ['Tahitian', 'Reo Mā`ohi'],
|
||||||
|
ug: ['Uyghur', 'Uyƣurqə / ئۇيغۇرچە'],
|
||||||
|
uk: ['Ukrainian', 'Українська'],
|
||||||
|
ur: ['Urdu', 'اردو'],
|
||||||
|
uz: ['Uzbek', 'Ўзбек'],
|
||||||
|
ve: ['Venda', 'Tshivenḓa'],
|
||||||
|
vi: ['Vietnamese', 'Tiếng Việt'],
|
||||||
|
vo: ['Volapük', 'Volapük'],
|
||||||
|
wa: ['Walloon', 'Walon'],
|
||||||
|
wo: ['Wolof', 'Wollof'],
|
||||||
|
xh: ['Xhosa', 'isiXhosa'],
|
||||||
|
yi: ['Yiddish', 'ייִדיש'],
|
||||||
|
yo: ['Yoruba', 'Yorùbá'],
|
||||||
|
za: ['Zhuang', 'Cuengh / Tôô / 壮语'],
|
||||||
|
zh: ['Chinese', '中文'],
|
||||||
|
zu: ['Zulu', 'isiZulu'],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LANGUAGES;
|
15
src/constants/modal_types.js
Normal file
15
src/constants/modal_types.js
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
export const CONFIRM_FILE_REMOVE = 'confirmFileRemove';
|
||||||
|
export const INCOMPATIBLE_DAEMON = 'incompatibleDaemon';
|
||||||
|
export const FILE_TIMEOUT = 'file_timeout';
|
||||||
|
export const DOWNLOADING = 'downloading';
|
||||||
|
export const ERROR = 'error';
|
||||||
|
export const INSUFFICIENT_CREDITS = 'insufficient_credits';
|
||||||
|
export const UPGRADE = 'upgrade';
|
||||||
|
export const WELCOME = 'welcome';
|
||||||
|
export const EMAIL_COLLECTION = 'email_collection';
|
||||||
|
export const FIRST_REWARD = 'first_reward';
|
||||||
|
export const AUTHENTICATION_FAILURE = 'auth_failure';
|
||||||
|
export const TRANSACTION_FAILED = 'transaction_failed';
|
||||||
|
export const REWARD_APPROVAL_REQUIRED = 'reward_approval_required';
|
||||||
|
export const AFFIRM_PURCHASE = 'affirm_purchase';
|
||||||
|
export const CONFIRM_CLAIM_REVOKE = 'confirmClaimRevoke';
|
13
src/constants/settings.js
Normal file
13
src/constants/settings.js
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
/* hardcoded names still exist for these in reducers/settings.js - only discovered when debugging */
|
||||||
|
/* Many SETTINGS are stored in the localStorage by their name -
|
||||||
|
be careful about changing the value of a SETTINGS constant, as doing so can invalidate existing SETTINGS */
|
||||||
|
export const CREDIT_REQUIRED_ACKNOWLEDGED = 'credit_required_acknowledged';
|
||||||
|
export const NEW_USER_ACKNOWLEDGED = 'welcome_acknowledged';
|
||||||
|
export const EMAIL_COLLECTION_ACKNOWLEDGED = 'email_collection_acknowledged';
|
||||||
|
export const LANGUAGE = 'language';
|
||||||
|
export const SHOW_NSFW = 'showNsfw';
|
||||||
|
export const SHOW_UNAVAILABLE = 'showUnavailable';
|
||||||
|
export const INSTANT_PURCHASE_ENABLED = 'instantPurchaseEnabled';
|
||||||
|
export const INSTANT_PURCHASE_MAX = 'instantPurchaseMax';
|
||||||
|
export const THEME = 'theme';
|
||||||
|
export const THEMES = 'themes';
|
3
src/constants/shape_shift.js
Normal file
3
src/constants/shape_shift.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
export const NO_DEPOSITS = 'no_deposits';
|
||||||
|
export const RECEIVED = 'received';
|
||||||
|
export const COMPLETE = 'complete';
|
2
src/constants/transaction_types.js
Normal file
2
src/constants/transaction_types.js
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
// eslint-disable-next-line import/prefer-default-export
|
||||||
|
export const TIP = 'tip';
|
2
src/index.js
Normal file
2
src/index.js
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export { lbry } from './lbry';
|
||||||
|
export { lbryio } from './lbryio';
|
86
src/jsonrpc.js
Normal file
86
src/jsonrpc.js
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
const jsonrpc = {};
|
||||||
|
|
||||||
|
jsonrpc.call = (
|
||||||
|
connectionString,
|
||||||
|
method,
|
||||||
|
params,
|
||||||
|
callback,
|
||||||
|
errorCallback,
|
||||||
|
connectFailedCallback
|
||||||
|
) => {
|
||||||
|
function checkAndParse(response) {
|
||||||
|
if (response.status >= 200 && response.status < 300) {
|
||||||
|
return response.json();
|
||||||
|
}
|
||||||
|
return response.json().then(json => {
|
||||||
|
let error;
|
||||||
|
if (json.error) {
|
||||||
|
error = new Error(json.error);
|
||||||
|
} else {
|
||||||
|
error = new Error('Protocol error with unknown response signature');
|
||||||
|
}
|
||||||
|
return Promise.reject(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const counter = parseInt(sessionStorage.getItem('JSONRPCCounter') || 0, 10);
|
||||||
|
const url = connectionString;
|
||||||
|
const options = {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
method,
|
||||||
|
params,
|
||||||
|
id: counter,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
sessionStorage.setItem('JSONRPCCounter', counter + 1);
|
||||||
|
|
||||||
|
return fetch(url, options)
|
||||||
|
.then(checkAndParse)
|
||||||
|
.then(response => {
|
||||||
|
const error = response.error || (response.result && response.result.error);
|
||||||
|
|
||||||
|
if (!error && typeof callback === 'function') {
|
||||||
|
return callback(response.result);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error && typeof errorCallback === 'function') {
|
||||||
|
return errorCallback(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const errorEvent = new CustomEvent('unhandledError', {
|
||||||
|
detail: {
|
||||||
|
connectionString,
|
||||||
|
method,
|
||||||
|
params,
|
||||||
|
code: error.code,
|
||||||
|
message: error.message || error,
|
||||||
|
data: error.data,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
document.dispatchEvent(errorEvent);
|
||||||
|
|
||||||
|
return Promise.resolve();
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (connectFailedCallback) {
|
||||||
|
return connectFailedCallback(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const errorEvent = new CustomEvent('unhandledError', {
|
||||||
|
detail: {
|
||||||
|
connectionString,
|
||||||
|
method,
|
||||||
|
params,
|
||||||
|
code: error.response && error.response.status,
|
||||||
|
message: __('Connection to API server failed'),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
document.dispatchEvent(errorEvent);
|
||||||
|
return Promise.resolve();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default jsonrpc;
|
289
src/lbry.js
Normal file
289
src/lbry.js
Normal file
|
@ -0,0 +1,289 @@
|
||||||
|
import jsonrpc from 'jsonrpc';
|
||||||
|
|
||||||
|
const CHECK_DAEMON_STARTED_TRY_NUMBER = 200;
|
||||||
|
|
||||||
|
const Lbry = {
|
||||||
|
isConnected: false,
|
||||||
|
daemonConnectionString: 'http://localhost:5279',
|
||||||
|
pendingPublishTimeout: 20 * 60 * 1000,
|
||||||
|
};
|
||||||
|
|
||||||
|
function apiCall(method, params, resolve, reject) {
|
||||||
|
return jsonrpc.call(Lbry.daemonConnectionString, method, params, resolve, reject, reject);
|
||||||
|
}
|
||||||
|
|
||||||
|
const lbryProxy = new Proxy(Lbry, {
|
||||||
|
get(target, name) {
|
||||||
|
if (name in target) {
|
||||||
|
return target[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
return (params = {}) =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
apiCall(name, params, resolve, reject);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
function getLocal(key, fallback = undefined) {
|
||||||
|
const itemRaw = localStorage.getItem(key);
|
||||||
|
return itemRaw === null ? fallback : JSON.parse(itemRaw);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setLocal(key, value) {
|
||||||
|
localStorage.setItem(key, JSON.stringify(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Records a publish attempt in local storage. Returns a dictionary with all the data needed to
|
||||||
|
* needed to make a dummy claim or file info object.
|
||||||
|
*/
|
||||||
|
let pendingId = 0;
|
||||||
|
function savePendingPublish({ name, channelName }) {
|
||||||
|
pendingId += 1;
|
||||||
|
const pendingPublishes = getLocal('pendingPublishes') || [];
|
||||||
|
const newPendingPublish = {
|
||||||
|
name,
|
||||||
|
channelName,
|
||||||
|
claim_id: `pending-${pendingId}`,
|
||||||
|
txid: `pending-${pendingId}`,
|
||||||
|
nout: 0,
|
||||||
|
outpoint: `pending-${pendingId}:0`,
|
||||||
|
time: Date.now(),
|
||||||
|
};
|
||||||
|
setLocal('pendingPublishes', [...pendingPublishes, newPendingPublish]);
|
||||||
|
return newPendingPublish;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If there is a pending publish with the given name or outpoint, remove it.
|
||||||
|
* A channel name may also be provided along with name.
|
||||||
|
*/
|
||||||
|
function removePendingPublishIfNeeded({ name, channelName, outpoint }) {
|
||||||
|
function pubMatches(pub) {
|
||||||
|
return (
|
||||||
|
pub.outpoint === outpoint ||
|
||||||
|
(pub.name === name && (!channelName || pub.channel_name === channelName))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
setLocal('pendingPublishes', Lbry.getPendingPublishes().filter(pub => !pubMatches(pub)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current list of pending publish attempts. Filters out any that have timed out and
|
||||||
|
* removes them from the list.
|
||||||
|
*/
|
||||||
|
Lbry.getPendingPublishes = () => {
|
||||||
|
const pendingPublishes = getLocal('pendingPublishes') || [];
|
||||||
|
const newPendingPublishes = pendingPublishes.filter(
|
||||||
|
pub => Date.now() - pub.time <= Lbry.pendingPublishTimeout
|
||||||
|
);
|
||||||
|
setLocal('pendingPublishes', newPendingPublishes);
|
||||||
|
return newPendingPublishes;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a pending publish attempt by its name or (fake) outpoint. A channel name can also be
|
||||||
|
* provided along withe the name. If no pending publish is found, returns null.
|
||||||
|
*/
|
||||||
|
function getPendingPublish({ name, channelName, outpoint }) {
|
||||||
|
const pendingPublishes = Lbry.getPendingPublishes();
|
||||||
|
return (
|
||||||
|
pendingPublishes.find(
|
||||||
|
pub =>
|
||||||
|
pub.outpoint === outpoint ||
|
||||||
|
(pub.name === name && (!channelName || pub.channel_name === channelName))
|
||||||
|
) || null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function pendingPublishToDummyClaim({ channelName, name, outpoint, claimId, txid, nout }) {
|
||||||
|
return { name, outpoint, claimId, txid, nout, channelName };
|
||||||
|
}
|
||||||
|
|
||||||
|
function pendingPublishToDummyFileInfo({ name, outpoint, claimId }) {
|
||||||
|
return { name, outpoint, claimId, metadata: null };
|
||||||
|
}
|
||||||
|
|
||||||
|
// core
|
||||||
|
Lbry.connectPromise = null;
|
||||||
|
Lbry.connect = () => {
|
||||||
|
if (Lbry.connectPromise === null) {
|
||||||
|
Lbry.connectPromise = new Promise((resolve, reject) => {
|
||||||
|
let tryNum = 0;
|
||||||
|
|
||||||
|
// Check every half second to see if the daemon is accepting connections
|
||||||
|
function checkDaemonStarted() {
|
||||||
|
tryNum += 1;
|
||||||
|
lbryProxy
|
||||||
|
.status()
|
||||||
|
.then(resolve)
|
||||||
|
.catch(() => {
|
||||||
|
if (tryNum <= CHECK_DAEMON_STARTED_TRY_NUMBER) {
|
||||||
|
setTimeout(checkDaemonStarted, tryNum < 50 ? 400 : 1000);
|
||||||
|
} else {
|
||||||
|
reject(new Error('Unable to connect to LBRY'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
checkDaemonStarted();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return Lbry.connectPromise;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Publishes a file. The optional fileListedCallback is called when the file becomes available in
|
||||||
|
* lbry.file_list() during the publish process.
|
||||||
|
*
|
||||||
|
* This currently includes a work-around to cache the file in local storage so that the pending
|
||||||
|
* publish can appear in the UI immediately.
|
||||||
|
*/
|
||||||
|
Lbry.publishDeprecated = (params, fileListedCallback, publishedCallback, errorCallback) => {
|
||||||
|
// Give a short grace period in case publish() returns right away or (more likely) gives an error
|
||||||
|
const returnPendingTimeout = setTimeout(
|
||||||
|
() => {
|
||||||
|
const { name, channel_name: channelName } = params;
|
||||||
|
if (publishedCallback || fileListedCallback) {
|
||||||
|
savePendingPublish({
|
||||||
|
name,
|
||||||
|
channelName,
|
||||||
|
});
|
||||||
|
publishedCallback(true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
2000,
|
||||||
|
{ once: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
lbryProxy.publish(params).then(
|
||||||
|
result => {
|
||||||
|
if (returnPendingTimeout) clearTimeout(returnPendingTimeout);
|
||||||
|
publishedCallback(result);
|
||||||
|
},
|
||||||
|
err => {
|
||||||
|
if (returnPendingTimeout) clearTimeout(returnPendingTimeout);
|
||||||
|
errorCallback(err);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
Lbry.imagePath = file => `${staticResourcesPath}/img/${file}`;
|
||||||
|
|
||||||
|
Lbry.getMediaType = (contentType, fileName) => {
|
||||||
|
if (contentType) {
|
||||||
|
return /^[^/]+/.exec(contentType)[0];
|
||||||
|
} else if (fileName) {
|
||||||
|
const dotIndex = fileName.lastIndexOf('.');
|
||||||
|
if (dotIndex === -1) {
|
||||||
|
return 'unknown';
|
||||||
|
}
|
||||||
|
|
||||||
|
const ext = fileName.substr(dotIndex + 1);
|
||||||
|
if (/^mp4|m4v|webm|flv|f4v|ogv$/i.test(ext)) {
|
||||||
|
return 'video';
|
||||||
|
} else if (/^mp3|m4a|aac|wav|flac|ogg|opus$/i.test(ext)) {
|
||||||
|
return 'audio';
|
||||||
|
} else if (/^html|htm|xml|pdf|odf|doc|docx|md|markdown|txt|epub|org$/i.test(ext)) {
|
||||||
|
return 'document';
|
||||||
|
}
|
||||||
|
return 'unknown';
|
||||||
|
}
|
||||||
|
return 'unknown';
|
||||||
|
};
|
||||||
|
|
||||||
|
Lbry.getAppVersionInfo = () =>
|
||||||
|
new Promise(resolve => {
|
||||||
|
/*ipcRenderer.once('version-info-received', (event, versionInfo) => {
|
||||||
|
resolve(versionInfo);
|
||||||
|
});
|
||||||
|
ipcRenderer.send('version-info-requested');*/
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrappers for API methods to simulate missing or future behavior. Unlike the old-style stubs,
|
||||||
|
* these are designed to be transparent wrappers around the corresponding API methods.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns results from the file_list API method, plus dummy entries for pending publishes.
|
||||||
|
* (If a real publish with the same name is found, the pending publish will be ignored and removed.)
|
||||||
|
*/
|
||||||
|
Lbry.file_list = (params = {}) =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
const { name, channel_name: channelName, outpoint } = params;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If we're searching by outpoint, check first to see if there's a matching pending publish.
|
||||||
|
* Pending publishes use their own faux outpoints that are always unique, so we don't need
|
||||||
|
* to check if there's a real file.
|
||||||
|
*/
|
||||||
|
if (outpoint) {
|
||||||
|
const pendingPublish = getPendingPublish({ outpoint });
|
||||||
|
if (pendingPublish) {
|
||||||
|
resolve([pendingPublishToDummyFileInfo(pendingPublish)]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apiCall(
|
||||||
|
'file_list',
|
||||||
|
params,
|
||||||
|
fileInfos => {
|
||||||
|
removePendingPublishIfNeeded({ name, channelName, outpoint });
|
||||||
|
|
||||||
|
// if a naked file_list call, append the pending file infos
|
||||||
|
if (!name && !channelName && !outpoint) {
|
||||||
|
const dummyFileInfos = Lbry.getPendingPublishes().map(pendingPublishToDummyFileInfo);
|
||||||
|
|
||||||
|
resolve([...fileInfos, ...dummyFileInfos]);
|
||||||
|
} else {
|
||||||
|
resolve(fileInfos);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
reject
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Lbry.claim_list_mine = (params = {}) =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
apiCall(
|
||||||
|
'claim_list_mine',
|
||||||
|
params,
|
||||||
|
claims => {
|
||||||
|
claims.forEach(({ name, channel_name: channelName, txid, nout }) => {
|
||||||
|
removePendingPublishIfNeeded({
|
||||||
|
name,
|
||||||
|
channelName,
|
||||||
|
outpoint: `${txid}:${nout}`,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const dummyClaims = Lbry.getPendingPublishes().map(pendingPublishToDummyClaim);
|
||||||
|
resolve([...claims, ...dummyClaims]);
|
||||||
|
},
|
||||||
|
reject
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Lbry.resolve = (params = {}) =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
apiCall(
|
||||||
|
'resolve',
|
||||||
|
params,
|
||||||
|
data => {
|
||||||
|
if ('uri' in params) {
|
||||||
|
// If only a single URI was requested, don't nest the results in an object
|
||||||
|
resolve(data && data[params.uri] ? data[params.uri] : {});
|
||||||
|
} else {
|
||||||
|
resolve(data || {});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
reject
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default lbryProxy;
|
176
src/lbryio.js
Normal file
176
src/lbryio.js
Normal file
|
@ -0,0 +1,176 @@
|
||||||
|
import Lbry from 'lbry';
|
||||||
|
import querystring from 'querystring';
|
||||||
|
|
||||||
|
const Lbryio = {
|
||||||
|
enabled: true,
|
||||||
|
authenticationPromise: null,
|
||||||
|
exchangePromise: null,
|
||||||
|
exchangeLastFetched: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
const CONNECTION_STRING = process.env.LBRY_APP_API_URL
|
||||||
|
? process.env.LBRY_APP_API_URL.replace(/\/*$/, '/') // exactly one slash at the end
|
||||||
|
: 'https://api.lbry.io/';
|
||||||
|
|
||||||
|
const EXCHANGE_RATE_TIMEOUT = 20 * 60 * 1000;
|
||||||
|
|
||||||
|
Lbryio.getExchangeRates = () => {
|
||||||
|
if (
|
||||||
|
!Lbryio.exchangeLastFetched ||
|
||||||
|
Date.now() - Lbryio.exchangeLastFetched > EXCHANGE_RATE_TIMEOUT
|
||||||
|
) {
|
||||||
|
Lbryio.exchangePromise = new Promise((resolve, reject) => {
|
||||||
|
Lbryio.call('lbc', 'exchange_rate', {}, 'get', true)
|
||||||
|
.then(({ lbc_usd: LBC_USD, lbc_btc: LBC_BTC, btc_usd: BTC_USD }) => {
|
||||||
|
const rates = { LBC_USD, LBC_BTC, BTC_USD };
|
||||||
|
resolve(rates);
|
||||||
|
})
|
||||||
|
.catch(reject);
|
||||||
|
});
|
||||||
|
Lbryio.exchangeLastFetched = Date.now();
|
||||||
|
}
|
||||||
|
return Lbryio.exchangePromise;
|
||||||
|
};
|
||||||
|
|
||||||
|
Lbryio.call = (resource, action, params = {}, method = 'get') => {
|
||||||
|
if (!Lbryio.enabled) {
|
||||||
|
console.log(__('Internal API disabled'));
|
||||||
|
return Promise.reject(new Error(__('LBRY internal API is disabled')));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(method === 'get' || method === 'post')) {
|
||||||
|
return Promise.reject(new Error(__('Invalid method')));
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkAndParse(response) {
|
||||||
|
if (response.status >= 200 && response.status < 300) {
|
||||||
|
return response.json();
|
||||||
|
}
|
||||||
|
return response.json().then(json => {
|
||||||
|
let error;
|
||||||
|
if (json.error) {
|
||||||
|
error = new Error(json.error);
|
||||||
|
} else {
|
||||||
|
error = new Error('Unknown API error signature');
|
||||||
|
}
|
||||||
|
error.response = response; // This is primarily a hack used in actions/user.js
|
||||||
|
return Promise.reject(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeRequest(url, options) {
|
||||||
|
return fetch(url, options).then(checkAndParse);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Lbryio.getAuthToken().then(token => {
|
||||||
|
const fullParams = { auth_token: token, ...params };
|
||||||
|
const qs = querystring.stringify(fullParams);
|
||||||
|
let url = `${CONNECTION_STRING}${resource}/${action}?${qs}`;
|
||||||
|
|
||||||
|
let options = {
|
||||||
|
method: 'GET',
|
||||||
|
};
|
||||||
|
|
||||||
|
if (method === 'post') {
|
||||||
|
options = {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
|
},
|
||||||
|
body: qs,
|
||||||
|
};
|
||||||
|
url = `${CONNECTION_STRING}${resource}/${action}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return makeRequest(url, options).then(response => response.data);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Lbryio.authToken = null;
|
||||||
|
|
||||||
|
Lbryio.getAuthToken = () =>
|
||||||
|
new Promise(resolve => {
|
||||||
|
if (Lbryio.authToken) {
|
||||||
|
resolve(Lbryio.authToken);
|
||||||
|
} else {
|
||||||
|
/*ipcRenderer.once('auth-token-response', (event, token) => {
|
||||||
|
Lbryio.authToken = token;
|
||||||
|
return resolve(token);
|
||||||
|
});
|
||||||
|
ipcRenderer.send('get-auth-token');*/
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Lbryio.setAuthToken = token => {
|
||||||
|
Lbryio.authToken = token ? token.toString().trim() : null;
|
||||||
|
//ipcRenderer.send('set-auth-token', token);
|
||||||
|
};
|
||||||
|
|
||||||
|
Lbryio.getCurrentUser = () => Lbryio.call('user', 'me');
|
||||||
|
|
||||||
|
Lbryio.authenticate = () => {
|
||||||
|
if (!Lbryio.enabled) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
resolve({
|
||||||
|
id: 1,
|
||||||
|
language: 'en',
|
||||||
|
primary_email: 'disabled@lbry.io',
|
||||||
|
has_verified_email: true,
|
||||||
|
is_identity_verified: true,
|
||||||
|
is_reward_approved: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Lbryio.authenticationPromise === null) {
|
||||||
|
Lbryio.authenticationPromise = new Promise((resolve, reject) => {
|
||||||
|
Lbryio.getAuthToken()
|
||||||
|
.then(token => {
|
||||||
|
if (!token || token.length > 60) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check that token works
|
||||||
|
return Lbryio.getCurrentUser()
|
||||||
|
.then(() => true)
|
||||||
|
.catch(() => false);
|
||||||
|
})
|
||||||
|
.then(isTokenValid => {
|
||||||
|
if (isTokenValid) {
|
||||||
|
return reject;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Lbry.status()
|
||||||
|
.then(status =>
|
||||||
|
Lbryio.call(
|
||||||
|
'user',
|
||||||
|
'new',
|
||||||
|
{
|
||||||
|
auth_token: '',
|
||||||
|
language: 'en',
|
||||||
|
app_id: status.installation_id,
|
||||||
|
},
|
||||||
|
'post'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.then(response => {
|
||||||
|
if (!response.auth_token) {
|
||||||
|
throw new Error(__('auth_token is missing from response'));
|
||||||
|
}
|
||||||
|
return Lbryio.setAuthToken(response.auth_token);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.then(Lbryio.getCurrentUser)
|
||||||
|
.then(resolve, reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return Lbryio.authenticationPromise;
|
||||||
|
};
|
||||||
|
|
||||||
|
Lbryio.getStripeToken = () =>
|
||||||
|
CONNECTION_STRING.startsWith('http://localhost:')
|
||||||
|
? 'pk_test_NoL1JWL7i1ipfhVId5KfDZgo'
|
||||||
|
: 'pk_live_e8M4dRNnCCbmpZzduEUZBgJO';
|
||||||
|
|
||||||
|
export default Lbryio;
|
38
src/redux/actions/cost_info.js
Normal file
38
src/redux/actions/cost_info.js
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
import * as ACTIONS from 'constants/action_types';
|
||||||
|
import Lbryio from 'lbryio';
|
||||||
|
import { selectClaimsByUri } from 'redux/selectors/claims';
|
||||||
|
|
||||||
|
// eslint-disable-next-line import/prefer-default-export
|
||||||
|
export function doFetchCostInfoForUri(uri) {
|
||||||
|
return (dispatch, getState) => {
|
||||||
|
const state = getState();
|
||||||
|
const claim = null; //selectClaimsByUri(state)[uri];
|
||||||
|
|
||||||
|
if (!claim) return;
|
||||||
|
|
||||||
|
function resolve(costInfo) {
|
||||||
|
dispatch({
|
||||||
|
type: ACTIONS.FETCH_COST_INFO_COMPLETED,
|
||||||
|
data: {
|
||||||
|
uri,
|
||||||
|
costInfo,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const fee =
|
||||||
|
claim.value && claim.value.stream && claim.value.stream.metadata
|
||||||
|
? claim.value.stream.metadata.fee
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
if (fee === undefined) {
|
||||||
|
resolve({ cost: 0, includesData: true });
|
||||||
|
} else if (fee.currency === 'LBC') {
|
||||||
|
resolve({ cost: fee.amount, includesData: true });
|
||||||
|
} else {
|
||||||
|
Lbryio.getExchangeRates().then(({ LBC_USD }) => {
|
||||||
|
resolve({ cost: fee.amount / LBC_USD, includesData: true });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
34
src/redux/reducers/cost_info.js
Normal file
34
src/redux/reducers/cost_info.js
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
import * as ACTIONS from 'constants/action_types';
|
||||||
|
|
||||||
|
const reducers = {};
|
||||||
|
const defaultState = {};
|
||||||
|
|
||||||
|
reducers[ACTIONS.FETCH_COST_INFO_STARTED] = (state, action) => {
|
||||||
|
const { uri } = action.data;
|
||||||
|
const newFetching = Object.assign({}, state.fetching);
|
||||||
|
newFetching[uri] = true;
|
||||||
|
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
fetching: newFetching,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
reducers[ACTIONS.FETCH_COST_INFO_COMPLETED] = (state, action) => {
|
||||||
|
const { uri, costInfo } = action.data;
|
||||||
|
const newByUri = Object.assign({}, state.byUri);
|
||||||
|
const newFetching = Object.assign({}, state.fetching);
|
||||||
|
|
||||||
|
newByUri[uri] = costInfo;
|
||||||
|
delete newFetching[uri];
|
||||||
|
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
byUri: newByUri,
|
||||||
|
fetching: newFetching,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function reducer(state = defaultState, action) {
|
||||||
|
const handler = reducers[action.type];
|
||||||
|
if (handler) return handler(state, action);
|
||||||
|
return state;
|
||||||
|
}
|
20
src/redux/selectors/cost_info.js
Normal file
20
src/redux/selectors/cost_info.js
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import { createSelector } from 'reselect';
|
||||||
|
import { selectCurrentParams } from 'redux/selectors/navigation';
|
||||||
|
|
||||||
|
export const selectState = state => state.costInfo || {};
|
||||||
|
|
||||||
|
export const selectAllCostInfoByUri = createSelector(selectState, state => state.byUri || {});
|
||||||
|
|
||||||
|
export const makeSelectCostInfoForUri = uri =>
|
||||||
|
createSelector(selectAllCostInfoByUri, costInfos => costInfos && costInfos[uri]);
|
||||||
|
|
||||||
|
export const selectCostForCurrentPageUri = createSelector(
|
||||||
|
selectAllCostInfoByUri,
|
||||||
|
selectCurrentParams,
|
||||||
|
(costInfo, params) => (params.uri && costInfo[params.uri] ? costInfo[params.uri].cost : undefined)
|
||||||
|
);
|
||||||
|
|
||||||
|
export const selectFetchingCostInfo = createSelector(selectState, state => state.fetching || {});
|
||||||
|
|
||||||
|
export const makeSelectFetchingCostInfoForUri = uri =>
|
||||||
|
createSelector(selectFetchingCostInfo, fetchingByUri => fetchingByUri && fetchingByUri[uri]);
|
31
webpack.config.js
Normal file
31
webpack.config.js
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
const path = require('path');
|
||||||
|
module.exports = {
|
||||||
|
entry: './src/index.js',
|
||||||
|
output: {
|
||||||
|
path: path.resolve(__dirname, 'build'),
|
||||||
|
filename: 'index.js',
|
||||||
|
libraryTarget: 'commonjs2'
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.js$/,
|
||||||
|
include: path.resolve(__dirname, 'src'),
|
||||||
|
exclude: /(node_modules|bower_components|build)/,
|
||||||
|
use: {
|
||||||
|
loader: 'babel-loader',
|
||||||
|
options: {
|
||||||
|
presets: ['env', 'react', 'stage-2']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
modules: [path.resolve(__dirname, 'src/'), 'node_modules', __dirname],
|
||||||
|
extensions: ['.js', '.jsx', '.scss'],
|
||||||
|
},
|
||||||
|
externals: {
|
||||||
|
'react': 'commonjs react'
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in a new issue