diff --git a/.eslintrc.json b/.eslintrc.json index 1860ea4..9ac4855 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -10,7 +10,6 @@ "__": true }, "rules": { - "camelcase": 0, "no-multi-spaces": 0, "new-cap": 0, "prefer-promise-reject-errors": 0, diff --git a/.flowconfig b/.flowconfig index bcc0450..aca52ab 100644 --- a/.flowconfig +++ b/.flowconfig @@ -6,11 +6,9 @@ ./flow-typed [options] -suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe module.system.node.resolve_dirname=./src module.name_mapper='^redux\(.*\)$' -> '/src/redux\1' module.name_mapper='^util\(.*\)$' -> '/src/util\1' module.name_mapper='^constants\(.*\)$' -> '/src/constants\1' module.name_mapper='^lbry\(.*\)$' -> '/src/lbry\1' -module.name_mapper='^lbry-first\(.*\)$' -> '/src/lbry-first\1' module.name_mapper='^lbryURI\(.*\)$' -> '/src/lbryURI\1' diff --git a/.gitignore b/.gitignore index cb86625..f495bd8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,3 @@ /node_modules yarn-error.log -package-lock.json - -# Jetbrains -.idea/ - +package-lock.json \ No newline at end of file diff --git a/.lintstagedrc.json b/.lintstagedrc.json index caae289..6abc007 100644 --- a/.lintstagedrc.json +++ b/.lintstagedrc.json @@ -1,6 +1,12 @@ { "linters": { - "src/**/*.{js,json}": ["prettier --write", "git add"], - "src/**/*.js": ["eslint --fix", "git add"] + "src/**/*.{js,json}": [ + "prettier --write", + "git add" + ], + "src/**/*.js": [ + "eslint --fix", + "git add" + ] } -} +} \ No newline at end of file diff --git a/LICENSE b/LICENSE index e8be4ab..1973ea2 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2017-2020 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, diff --git a/README.md b/README.md index 5486461..cf44e21 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,22 @@ Add `lbry-redux` as a dependency to your `package.json` file. If you intend to make changes to the module and test immediately, you can use `npm link` to add the package to your `node_modules` folder. This will create a symlink to the folder where `lbry-redux` was cloned to. ``` cd lbry-redux -yarn link -cd /// (ex: cd ~/lbry-desktop) -yarn link lbry-redux +sudo npm link +cd ////node_modules +npm link lbry-redux ```` ### Build -Run `$ yarn build`. If the symlink does not work, just build the file and move the `bundle.js` file into the `node_modules/` folder. +Run `$ yarn build`. If the symlink does not work, just build the file and move the `bundle.js` file in to the `node_modules/` folder. + +#### Local Development with `lbry-desktop` +If you're working with the desktop app and you've followed the steps above, then you'll want to +run `$ yarn dev` (or equivalently `$ webpack --watch`). This will allow any changes made to the code +to be automatically reflected in `dist/bundle.js`. + +Once you've made your changes, running `(lbry-desktop)$ yarn dev` should have it automatically +reloading changes. If this doesn't happen, just rebuild `lbry-redux` and +[relink it to `lbry-desktop`](.README.md:11) ## Contributing We :heart: contributions from everyone! We welcome [bug reports](https://github.com/lbryio/lbry-redux/issues/), [bug fixes](https://github.com/lbryio/lbry-redux/pulls) and feedback on the module is always appreciated. @@ -27,4 +36,4 @@ We :heart: contributions from everyone! We welcome [bug reports](https://github. ## License -This module is released under the [MIT License](LICENSE) +This module is released under the [MIT License](license) diff --git a/dist/bundle.es.js b/dist/bundle.es.js index 17e89d9..07340a5 100644 --- a/dist/bundle.es.js +++ b/dist/bundle.es.js @@ -8,26 +8,11 @@ require('proxy-polyfill'); var reselect = require('reselect'); var uuid = _interopDefault(require('uuid/v4')); -const MINIMUM_PUBLISH_BID = 0.00000001; - -const CHANNEL_ANONYMOUS = 'anonymous'; -const CHANNEL_NEW = 'new'; -const PAGE_SIZE = 20; - -var claim = /*#__PURE__*/Object.freeze({ - MINIMUM_PUBLISH_BID: MINIMUM_PUBLISH_BID, - CHANNEL_ANONYMOUS: CHANNEL_ANONYMOUS, - CHANNEL_NEW: CHANNEL_NEW, - PAGE_SIZE: PAGE_SIZE -}); - const WINDOW_FOCUSED = 'WINDOW_FOCUSED'; const DAEMON_READY = 'DAEMON_READY'; const DAEMON_VERSION_MATCH = 'DAEMON_VERSION_MATCH'; const DAEMON_VERSION_MISMATCH = 'DAEMON_VERSION_MISMATCH'; const VOLUME_CHANGED = 'VOLUME_CHANGED'; -const SET_WELCOME_VERSION = 'SET_WELCOME_VERSION'; -const SET_ALLOW_ANALYTICS = 'SET_ALLOW_ANALYTICS'; // Navigation const CHANGE_AFTER_AUTH_PATH = 'CHANGE_AFTER_AUTH_PATH'; @@ -58,19 +43,6 @@ const GET_NEW_ADDRESS_STARTED = 'GET_NEW_ADDRESS_STARTED'; const GET_NEW_ADDRESS_COMPLETED = 'GET_NEW_ADDRESS_COMPLETED'; const FETCH_TRANSACTIONS_STARTED = 'FETCH_TRANSACTIONS_STARTED'; const FETCH_TRANSACTIONS_COMPLETED = 'FETCH_TRANSACTIONS_COMPLETED'; -const FETCH_TXO_PAGE_STARTED = 'FETCH_TXO_PAGE_STARTED'; -const FETCH_TXO_PAGE_COMPLETED = 'FETCH_TXO_PAGE_COMPLETED'; -const FETCH_TXO_PAGE_FAILED = 'FETCH_TXO_PAGE_FAILED'; -const UPDATE_TXO_FETCH_PARAMS = 'UPDATE_TXO_FETCH_PARAMS'; -const FETCH_SUPPORTS_STARTED = 'FETCH_SUPPORTS_STARTED'; -const FETCH_SUPPORTS_COMPLETED = 'FETCH_SUPPORTS_COMPLETED'; -const ABANDON_SUPPORT_STARTED = 'ABANDON_SUPPORT_STARTED'; -const ABANDON_SUPPORT_COMPLETED = 'ABANDON_SUPPORT_COMPLETED'; -const ABANDON_CLAIM_SUPPORT_STARTED = 'ABANDON_CLAIM_SUPPORT_STARTED'; -const ABANDON_CLAIM_SUPPORT_COMPLETED = 'ABANDON_CLAIM_SUPPORT_COMPLETED'; -const ABANDON_CLAIM_SUPPORT_FAILED = 'ABANDON_CLAIM_SUPPORT_FAILED'; -const ABANDON_CLAIM_SUPPORT_PREVIEW = 'ABANDON_CLAIM_SUPPORT_PREVIEW'; -const PENDING_SUPPORTS_UPDATED = 'PENDING_SUPPORTS_UPDATED'; const UPDATE_BALANCE = 'UPDATE_BALANCE'; const UPDATE_TOTAL_BALANCE = 'UPDATE_TOTAL_BALANCE'; const CHECK_ADDRESS_IS_MINE_STARTED = 'CHECK_ADDRESS_IS_MINE_STARTED'; @@ -78,10 +50,10 @@ const CHECK_ADDRESS_IS_MINE_COMPLETED = 'CHECK_ADDRESS_IS_MINE_COMPLETED'; const SEND_TRANSACTION_STARTED = 'SEND_TRANSACTION_STARTED'; const SEND_TRANSACTION_COMPLETED = 'SEND_TRANSACTION_COMPLETED'; const SEND_TRANSACTION_FAILED = 'SEND_TRANSACTION_FAILED'; +const FETCH_BLOCK_SUCCESS = 'FETCH_BLOCK_SUCCESS'; const SUPPORT_TRANSACTION_STARTED = 'SUPPORT_TRANSACTION_STARTED'; const SUPPORT_TRANSACTION_COMPLETED = 'SUPPORT_TRANSACTION_COMPLETED'; const SUPPORT_TRANSACTION_FAILED = 'SUPPORT_TRANSACTION_FAILED'; -const CLEAR_SUPPORT_TRANSACTION = 'CLEAR_SUPPORT_TRANSACTION'; const WALLET_ENCRYPT_START = 'WALLET_ENCRYPT_START'; const WALLET_ENCRYPT_COMPLETED = 'WALLET_ENCRYPT_COMPLETED'; const WALLET_ENCRYPT_FAILED = 'WALLET_ENCRYPT_FAILED'; @@ -96,8 +68,6 @@ const WALLET_LOCK_COMPLETED = 'WALLET_LOCK_COMPLETED'; const WALLET_LOCK_FAILED = 'WALLET_LOCK_FAILED'; const WALLET_STATUS_START = 'WALLET_STATUS_START'; const WALLET_STATUS_COMPLETED = 'WALLET_STATUS_COMPLETED'; -const WALLET_RESTART = 'WALLET_RESTART'; -const WALLET_RESTART_COMPLETED = 'WALLET_RESTART_COMPLETED'; const SET_TRANSACTION_LIST_FILTER = 'SET_TRANSACTION_LIST_FILTER'; const UPDATE_CURRENT_HEIGHT = 'UPDATE_CURRENT_HEIGHT'; const SET_DRAFT_TRANSACTION_AMOUNT = 'SET_DRAFT_TRANSACTION_AMOUNT'; @@ -114,16 +84,9 @@ const ABANDON_CLAIM_STARTED = 'ABANDON_CLAIM_STARTED'; const ABANDON_CLAIM_SUCCEEDED = 'ABANDON_CLAIM_SUCCEEDED'; const FETCH_CHANNEL_LIST_STARTED = 'FETCH_CHANNEL_LIST_STARTED'; const FETCH_CHANNEL_LIST_COMPLETED = 'FETCH_CHANNEL_LIST_COMPLETED'; -const FETCH_CHANNEL_LIST_FAILED = 'FETCH_CHANNEL_LIST_FAILED'; const CREATE_CHANNEL_STARTED = 'CREATE_CHANNEL_STARTED'; const CREATE_CHANNEL_COMPLETED = 'CREATE_CHANNEL_COMPLETED'; const CREATE_CHANNEL_FAILED = 'CREATE_CHANNEL_FAILED'; -const UPDATE_CHANNEL_STARTED = 'UPDATE_CHANNEL_STARTED'; -const UPDATE_CHANNEL_COMPLETED = 'UPDATE_CHANNEL_COMPLETED'; -const UPDATE_CHANNEL_FAILED = 'UPDATE_CHANNEL_FAILED'; -const IMPORT_CHANNEL_STARTED = 'IMPORT_CHANNEL_STARTED'; -const IMPORT_CHANNEL_COMPLETED = 'IMPORT_CHANNEL_COMPLETED'; -const IMPORT_CHANNEL_FAILED = 'IMPORT_CHANNEL_FAILED'; const PUBLISH_STARTED = 'PUBLISH_STARTED'; const PUBLISH_COMPLETED = 'PUBLISH_COMPLETED'; const PUBLISH_FAILED = 'PUBLISH_FAILED'; @@ -132,52 +95,12 @@ const SET_CONTENT_POSITION = 'SET_CONTENT_POSITION'; const SET_CONTENT_LAST_VIEWED = 'SET_CONTENT_LAST_VIEWED'; const CLEAR_CONTENT_HISTORY_URI = 'CLEAR_CONTENT_HISTORY_URI'; const CLEAR_CONTENT_HISTORY_ALL = 'CLEAR_CONTENT_HISTORY_ALL'; -const CLAIM_SEARCH_STARTED = 'CLAIM_SEARCH_STARTED'; -const CLAIM_SEARCH_COMPLETED = 'CLAIM_SEARCH_COMPLETED'; -const CLAIM_SEARCH_FAILED = 'CLAIM_SEARCH_FAILED'; -const CLAIM_SEARCH_BY_TAGS_STARTED = 'CLAIM_SEARCH_BY_TAGS_STARTED'; -const CLAIM_SEARCH_BY_TAGS_COMPLETED = 'CLAIM_SEARCH_BY_TAGS_COMPLETED'; -const CLAIM_SEARCH_BY_TAGS_FAILED = 'CLAIM_SEARCH_BY_TAGS_FAILED'; -const CLAIM_REPOST_STARTED = 'CLAIM_REPOST_STARTED'; -const CLAIM_REPOST_COMPLETED = 'CLAIM_REPOST_COMPLETED'; -const CLAIM_REPOST_FAILED = 'CLAIM_REPOST_FAILED'; -const CLEAR_REPOST_ERROR = 'CLEAR_REPOST_ERROR'; -const CLEAR_CHANNEL_ERRORS = 'CLEAR_CHANNEL_ERRORS'; -const CHECK_PUBLISH_NAME_STARTED = 'CHECK_PUBLISH_NAME_STARTED'; -const CHECK_PUBLISH_NAME_COMPLETED = 'CHECK_PUBLISH_NAME_COMPLETED'; -const UPDATE_PENDING_CLAIMS = 'UPDATE_PENDING_CLAIMS'; -const UPDATE_CONFIRMED_CLAIMS = 'UPDATE_CONFIRMED_CLAIMS'; -const ADD_FILES_REFLECTING = 'ADD_FILES_REFLECTING'; -const UPDATE_FILES_REFLECTING = 'UPDATE_FILES_REFLECTING'; -const TOGGLE_CHECKING_REFLECTING = 'TOGGLE_CHECKING_REFLECTING'; -const TOGGLE_CHECKING_PENDING = 'TOGGLE_CHECKING_PENDING'; -const PURCHASE_LIST_STARTED = 'PURCHASE_LIST_STARTED'; -const PURCHASE_LIST_COMPLETED = 'PURCHASE_LIST_COMPLETED'; -const PURCHASE_LIST_FAILED = 'PURCHASE_LIST_FAILED'; - -// Comments -const COMMENT_LIST_STARTED = 'COMMENT_LIST_STARTED'; -const COMMENT_LIST_COMPLETED = 'COMMENT_LIST_COMPLETED'; -const COMMENT_LIST_FAILED = 'COMMENT_LIST_FAILED'; -const COMMENT_CREATE_STARTED = 'COMMENT_CREATE_STARTED'; -const COMMENT_CREATE_COMPLETED = 'COMMENT_CREATE_COMPLETED'; -const COMMENT_CREATE_FAILED = 'COMMENT_CREATE_FAILED'; -const COMMENT_ABANDON_STARTED = 'COMMENT_ABANDON_STARTED'; -const COMMENT_ABANDON_COMPLETED = 'COMMENT_ABANDON_COMPLETED'; -const COMMENT_ABANDON_FAILED = 'COMMENT_ABANDON_FAILED'; -const COMMENT_UPDATE_STARTED = 'COMMENT_UPDATE_STARTED'; -const COMMENT_UPDATE_COMPLETED = 'COMMENT_UPDATE_COMPLETED'; -const COMMENT_UPDATE_FAILED = 'COMMENT_UPDATE_FAILED'; -const COMMENT_HIDE_STARTED = 'COMMENT_HIDE_STARTED'; -const COMMENT_HIDE_COMPLETED = 'COMMENT_HIDE_COMPLETED'; -const COMMENT_HIDE_FAILED = 'COMMENT_HIDE_FAILED'; // Files const FILE_LIST_STARTED = 'FILE_LIST_STARTED'; const FILE_LIST_SUCCEEDED = 'FILE_LIST_SUCCEEDED'; const FETCH_FILE_INFO_STARTED = 'FETCH_FILE_INFO_STARTED'; const FETCH_FILE_INFO_COMPLETED = 'FETCH_FILE_INFO_COMPLETED'; -const FETCH_FILE_INFO_FAILED = 'FETCH_FILE_INFO_FAILED'; const LOADING_VIDEO_STARTED = 'LOADING_VIDEO_STARTED'; const LOADING_VIDEO_COMPLETED = 'LOADING_VIDEO_COMPLETED'; const LOADING_VIDEO_FAILED = 'LOADING_VIDEO_FAILED'; @@ -190,18 +113,11 @@ const FETCH_AVAILABILITY_STARTED = 'FETCH_AVAILABILITY_STARTED'; const FETCH_AVAILABILITY_COMPLETED = 'FETCH_AVAILABILITY_COMPLETED'; const FILE_DELETE = 'FILE_DELETE'; const SET_FILE_LIST_SORT = 'SET_FILE_LIST_SORT'; -const PURCHASE_URI_STARTED = 'PURCHASE_URI_STARTED'; -const PURCHASE_URI_COMPLETED = 'PURCHASE_URI_COMPLETED'; -const PURCHASE_URI_FAILED = 'PURCHASE_URI_FAILED'; -const CLEAR_PURCHASED_URI_SUCCESS = 'CLEAR_PURCHASED_URI_SUCCESS'; // Search const SEARCH_START = 'SEARCH_START'; const SEARCH_SUCCESS = 'SEARCH_SUCCESS'; const SEARCH_FAIL = 'SEARCH_FAIL'; -const RESOLVED_SEARCH_START = 'RESOLVED_SEARCH_START'; -const RESOLVED_SEARCH_SUCCESS = 'RESOLVED_SEARCH_SUCCESS'; -const RESOLVED_SEARCH_FAIL = 'RESOLVED_SEARCH_FAIL'; const UPDATE_SEARCH_QUERY = 'UPDATE_SEARCH_QUERY'; const UPDATE_SEARCH_OPTIONS = 'UPDATE_SEARCH_OPTIONS'; const UPDATE_SEARCH_SUGGESTIONS = 'UPDATE_SEARCH_SUGGESTIONS'; @@ -210,9 +126,6 @@ const SEARCH_BLUR = 'SEARCH_BLUR'; // Settings const DAEMON_SETTINGS_RECEIVED = 'DAEMON_SETTINGS_RECEIVED'; -const DAEMON_STATUS_RECEIVED = 'DAEMON_STATUS_RECEIVED'; -const SHARED_PREFERENCE_SET = 'SHARED_PREFERENCE_SET'; -const SAVE_CUSTOM_WALLET_SERVERS = 'SAVE_CUSTOM_WALLET_SERVERS'; const CLIENT_SETTING_CHANGED = 'CLIENT_SETTING_CHANGED'; const UPDATE_IS_NIGHT = 'UPDATE_IS_NIGHT'; @@ -264,6 +177,21 @@ const FETCH_REWARD_CONTENT_COMPLETED = 'FETCH_REWARD_CONTENT_COMPLETED'; const DOWNLOAD_LANGUAGE_SUCCEEDED = 'DOWNLOAD_LANGUAGE_SUCCEEDED'; const DOWNLOAD_LANGUAGE_FAILED = 'DOWNLOAD_LANGUAGE_FAILED'; +// ShapeShift +const GET_SUPPORTED_COINS_START = 'GET_SUPPORTED_COINS_START'; +const GET_SUPPORTED_COINS_SUCCESS = 'GET_SUPPORTED_COINS_SUCCESS'; +const GET_SUPPORTED_COINS_FAIL = 'GET_SUPPORTED_COINS_FAIL'; +const GET_COIN_STATS_START = 'GET_COIN_STATS_START'; +const GET_COIN_STATS_SUCCESS = 'GET_COIN_STATS_SUCCESS'; +const GET_COIN_STATS_FAIL = 'GET_COIN_STATS_FAIL'; +const PREPARE_SHAPE_SHIFT_START = 'PREPARE_SHAPE_SHIFT_START'; +const PREPARE_SHAPE_SHIFT_SUCCESS = 'PREPARE_SHAPE_SHIFT_SUCCESS'; +const PREPARE_SHAPE_SHIFT_FAIL = 'PREPARE_SHAPE_SHIFT_FAIL'; +const GET_ACTIVE_SHIFT_START = 'GET_ACTIVE_SHIFT_START'; +const GET_ACTIVE_SHIFT_SUCCESS = 'GET_ACTIVE_SHIFT_SUCCESS'; +const GET_ACTIVE_SHIFT_FAIL = 'GET_ACTIVE_SHIFT_FAIL'; +const CLEAR_SHAPE_SHIFT = 'CLEAR_SHAPE_SHIFT'; + // Subscriptions const CHANNEL_SUBSCRIBE = 'CHANNEL_SUBSCRIBE'; const CHANNEL_UNSUBSCRIBE = 'CHANNEL_UNSUBSCRIBE'; @@ -297,315 +225,285 @@ const DISMISS_ERROR = 'DISMISS_ERROR'; const FETCH_DATE = 'FETCH_DATE'; -// Cost info -const FETCH_COST_INFO_STARTED = 'FETCH_COST_INFO_STARTED'; -const FETCH_COST_INFO_COMPLETED = 'FETCH_COST_INFO_COMPLETED'; -const FETCH_COST_INFO_FAILED = 'FETCH_COST_INFO_FAILED'; - -// Tags -const TOGGLE_TAG_FOLLOW = 'TOGGLE_TAG_FOLLOW'; -const TAG_ADD = 'TAG_ADD'; -const TAG_DELETE = 'TAG_DELETE'; - -// Blocked Channels -const TOGGLE_BLOCK_CHANNEL = 'TOGGLE_BLOCK_CHANNEL'; - -// Sync -const USER_STATE_POPULATE = 'USER_STATE_POPULATE'; - var action_types = /*#__PURE__*/Object.freeze({ - WINDOW_FOCUSED: WINDOW_FOCUSED, - DAEMON_READY: DAEMON_READY, - DAEMON_VERSION_MATCH: DAEMON_VERSION_MATCH, - DAEMON_VERSION_MISMATCH: DAEMON_VERSION_MISMATCH, - VOLUME_CHANGED: VOLUME_CHANGED, - SET_WELCOME_VERSION: SET_WELCOME_VERSION, - SET_ALLOW_ANALYTICS: SET_ALLOW_ANALYTICS, - CHANGE_AFTER_AUTH_PATH: CHANGE_AFTER_AUTH_PATH, - WINDOW_SCROLLED: WINDOW_SCROLLED, - HISTORY_NAVIGATE: HISTORY_NAVIGATE, - UPGRADE_CANCELLED: UPGRADE_CANCELLED, - DOWNLOAD_UPGRADE: DOWNLOAD_UPGRADE, - UPGRADE_DOWNLOAD_STARTED: UPGRADE_DOWNLOAD_STARTED, - UPGRADE_DOWNLOAD_COMPLETED: UPGRADE_DOWNLOAD_COMPLETED, - UPGRADE_DOWNLOAD_PROGRESSED: UPGRADE_DOWNLOAD_PROGRESSED, - CHECK_UPGRADE_AVAILABLE: CHECK_UPGRADE_AVAILABLE, - CHECK_UPGRADE_START: CHECK_UPGRADE_START, - CHECK_UPGRADE_SUCCESS: CHECK_UPGRADE_SUCCESS, - CHECK_UPGRADE_FAIL: CHECK_UPGRADE_FAIL, - CHECK_UPGRADE_SUBSCRIBE: CHECK_UPGRADE_SUBSCRIBE, - UPDATE_VERSION: UPDATE_VERSION, - UPDATE_REMOTE_VERSION: UPDATE_REMOTE_VERSION, - SKIP_UPGRADE: SKIP_UPGRADE, - START_UPGRADE: START_UPGRADE, - AUTO_UPDATE_DECLINED: AUTO_UPDATE_DECLINED, - AUTO_UPDATE_DOWNLOADED: AUTO_UPDATE_DOWNLOADED, - CLEAR_UPGRADE_TIMER: CLEAR_UPGRADE_TIMER, - GET_NEW_ADDRESS_STARTED: GET_NEW_ADDRESS_STARTED, - GET_NEW_ADDRESS_COMPLETED: GET_NEW_ADDRESS_COMPLETED, - FETCH_TRANSACTIONS_STARTED: FETCH_TRANSACTIONS_STARTED, - FETCH_TRANSACTIONS_COMPLETED: FETCH_TRANSACTIONS_COMPLETED, - FETCH_TXO_PAGE_STARTED: FETCH_TXO_PAGE_STARTED, - FETCH_TXO_PAGE_COMPLETED: FETCH_TXO_PAGE_COMPLETED, - FETCH_TXO_PAGE_FAILED: FETCH_TXO_PAGE_FAILED, - UPDATE_TXO_FETCH_PARAMS: UPDATE_TXO_FETCH_PARAMS, - FETCH_SUPPORTS_STARTED: FETCH_SUPPORTS_STARTED, - FETCH_SUPPORTS_COMPLETED: FETCH_SUPPORTS_COMPLETED, - ABANDON_SUPPORT_STARTED: ABANDON_SUPPORT_STARTED, - ABANDON_SUPPORT_COMPLETED: ABANDON_SUPPORT_COMPLETED, - ABANDON_CLAIM_SUPPORT_STARTED: ABANDON_CLAIM_SUPPORT_STARTED, - ABANDON_CLAIM_SUPPORT_COMPLETED: ABANDON_CLAIM_SUPPORT_COMPLETED, - ABANDON_CLAIM_SUPPORT_FAILED: ABANDON_CLAIM_SUPPORT_FAILED, - ABANDON_CLAIM_SUPPORT_PREVIEW: ABANDON_CLAIM_SUPPORT_PREVIEW, - PENDING_SUPPORTS_UPDATED: PENDING_SUPPORTS_UPDATED, - UPDATE_BALANCE: UPDATE_BALANCE, - UPDATE_TOTAL_BALANCE: UPDATE_TOTAL_BALANCE, - CHECK_ADDRESS_IS_MINE_STARTED: CHECK_ADDRESS_IS_MINE_STARTED, - CHECK_ADDRESS_IS_MINE_COMPLETED: CHECK_ADDRESS_IS_MINE_COMPLETED, - SEND_TRANSACTION_STARTED: SEND_TRANSACTION_STARTED, - SEND_TRANSACTION_COMPLETED: SEND_TRANSACTION_COMPLETED, - SEND_TRANSACTION_FAILED: SEND_TRANSACTION_FAILED, - SUPPORT_TRANSACTION_STARTED: SUPPORT_TRANSACTION_STARTED, - SUPPORT_TRANSACTION_COMPLETED: SUPPORT_TRANSACTION_COMPLETED, - SUPPORT_TRANSACTION_FAILED: SUPPORT_TRANSACTION_FAILED, - CLEAR_SUPPORT_TRANSACTION: CLEAR_SUPPORT_TRANSACTION, - WALLET_ENCRYPT_START: WALLET_ENCRYPT_START, - WALLET_ENCRYPT_COMPLETED: WALLET_ENCRYPT_COMPLETED, - WALLET_ENCRYPT_FAILED: WALLET_ENCRYPT_FAILED, - WALLET_UNLOCK_START: WALLET_UNLOCK_START, - WALLET_UNLOCK_COMPLETED: WALLET_UNLOCK_COMPLETED, - WALLET_UNLOCK_FAILED: WALLET_UNLOCK_FAILED, - WALLET_DECRYPT_START: WALLET_DECRYPT_START, - WALLET_DECRYPT_COMPLETED: WALLET_DECRYPT_COMPLETED, - WALLET_DECRYPT_FAILED: WALLET_DECRYPT_FAILED, - WALLET_LOCK_START: WALLET_LOCK_START, - WALLET_LOCK_COMPLETED: WALLET_LOCK_COMPLETED, - WALLET_LOCK_FAILED: WALLET_LOCK_FAILED, - WALLET_STATUS_START: WALLET_STATUS_START, - WALLET_STATUS_COMPLETED: WALLET_STATUS_COMPLETED, - WALLET_RESTART: WALLET_RESTART, - WALLET_RESTART_COMPLETED: WALLET_RESTART_COMPLETED, - SET_TRANSACTION_LIST_FILTER: SET_TRANSACTION_LIST_FILTER, - UPDATE_CURRENT_HEIGHT: UPDATE_CURRENT_HEIGHT, - SET_DRAFT_TRANSACTION_AMOUNT: SET_DRAFT_TRANSACTION_AMOUNT, - SET_DRAFT_TRANSACTION_ADDRESS: SET_DRAFT_TRANSACTION_ADDRESS, - RESOLVE_URIS_STARTED: RESOLVE_URIS_STARTED, - RESOLVE_URIS_COMPLETED: RESOLVE_URIS_COMPLETED, - FETCH_CHANNEL_CLAIMS_STARTED: FETCH_CHANNEL_CLAIMS_STARTED, - FETCH_CHANNEL_CLAIMS_COMPLETED: FETCH_CHANNEL_CLAIMS_COMPLETED, - FETCH_CLAIM_LIST_MINE_STARTED: FETCH_CLAIM_LIST_MINE_STARTED, - FETCH_CLAIM_LIST_MINE_COMPLETED: FETCH_CLAIM_LIST_MINE_COMPLETED, - ABANDON_CLAIM_STARTED: ABANDON_CLAIM_STARTED, - ABANDON_CLAIM_SUCCEEDED: ABANDON_CLAIM_SUCCEEDED, - FETCH_CHANNEL_LIST_STARTED: FETCH_CHANNEL_LIST_STARTED, - FETCH_CHANNEL_LIST_COMPLETED: FETCH_CHANNEL_LIST_COMPLETED, - FETCH_CHANNEL_LIST_FAILED: FETCH_CHANNEL_LIST_FAILED, - CREATE_CHANNEL_STARTED: CREATE_CHANNEL_STARTED, - CREATE_CHANNEL_COMPLETED: CREATE_CHANNEL_COMPLETED, - CREATE_CHANNEL_FAILED: CREATE_CHANNEL_FAILED, - UPDATE_CHANNEL_STARTED: UPDATE_CHANNEL_STARTED, - UPDATE_CHANNEL_COMPLETED: UPDATE_CHANNEL_COMPLETED, - UPDATE_CHANNEL_FAILED: UPDATE_CHANNEL_FAILED, - IMPORT_CHANNEL_STARTED: IMPORT_CHANNEL_STARTED, - IMPORT_CHANNEL_COMPLETED: IMPORT_CHANNEL_COMPLETED, - IMPORT_CHANNEL_FAILED: IMPORT_CHANNEL_FAILED, - PUBLISH_STARTED: PUBLISH_STARTED, - PUBLISH_COMPLETED: PUBLISH_COMPLETED, - PUBLISH_FAILED: PUBLISH_FAILED, - SET_PLAYING_URI: SET_PLAYING_URI, - SET_CONTENT_POSITION: SET_CONTENT_POSITION, - SET_CONTENT_LAST_VIEWED: SET_CONTENT_LAST_VIEWED, - CLEAR_CONTENT_HISTORY_URI: CLEAR_CONTENT_HISTORY_URI, - CLEAR_CONTENT_HISTORY_ALL: CLEAR_CONTENT_HISTORY_ALL, - CLAIM_SEARCH_STARTED: CLAIM_SEARCH_STARTED, - CLAIM_SEARCH_COMPLETED: CLAIM_SEARCH_COMPLETED, - CLAIM_SEARCH_FAILED: CLAIM_SEARCH_FAILED, - CLAIM_SEARCH_BY_TAGS_STARTED: CLAIM_SEARCH_BY_TAGS_STARTED, - CLAIM_SEARCH_BY_TAGS_COMPLETED: CLAIM_SEARCH_BY_TAGS_COMPLETED, - CLAIM_SEARCH_BY_TAGS_FAILED: CLAIM_SEARCH_BY_TAGS_FAILED, - CLAIM_REPOST_STARTED: CLAIM_REPOST_STARTED, - CLAIM_REPOST_COMPLETED: CLAIM_REPOST_COMPLETED, - CLAIM_REPOST_FAILED: CLAIM_REPOST_FAILED, - CLEAR_REPOST_ERROR: CLEAR_REPOST_ERROR, - CLEAR_CHANNEL_ERRORS: CLEAR_CHANNEL_ERRORS, - CHECK_PUBLISH_NAME_STARTED: CHECK_PUBLISH_NAME_STARTED, - CHECK_PUBLISH_NAME_COMPLETED: CHECK_PUBLISH_NAME_COMPLETED, - UPDATE_PENDING_CLAIMS: UPDATE_PENDING_CLAIMS, - UPDATE_CONFIRMED_CLAIMS: UPDATE_CONFIRMED_CLAIMS, - ADD_FILES_REFLECTING: ADD_FILES_REFLECTING, - UPDATE_FILES_REFLECTING: UPDATE_FILES_REFLECTING, - TOGGLE_CHECKING_REFLECTING: TOGGLE_CHECKING_REFLECTING, - TOGGLE_CHECKING_PENDING: TOGGLE_CHECKING_PENDING, - PURCHASE_LIST_STARTED: PURCHASE_LIST_STARTED, - PURCHASE_LIST_COMPLETED: PURCHASE_LIST_COMPLETED, - PURCHASE_LIST_FAILED: PURCHASE_LIST_FAILED, - COMMENT_LIST_STARTED: COMMENT_LIST_STARTED, - COMMENT_LIST_COMPLETED: COMMENT_LIST_COMPLETED, - COMMENT_LIST_FAILED: COMMENT_LIST_FAILED, - COMMENT_CREATE_STARTED: COMMENT_CREATE_STARTED, - COMMENT_CREATE_COMPLETED: COMMENT_CREATE_COMPLETED, - COMMENT_CREATE_FAILED: COMMENT_CREATE_FAILED, - COMMENT_ABANDON_STARTED: COMMENT_ABANDON_STARTED, - COMMENT_ABANDON_COMPLETED: COMMENT_ABANDON_COMPLETED, - COMMENT_ABANDON_FAILED: COMMENT_ABANDON_FAILED, - COMMENT_UPDATE_STARTED: COMMENT_UPDATE_STARTED, - COMMENT_UPDATE_COMPLETED: COMMENT_UPDATE_COMPLETED, - COMMENT_UPDATE_FAILED: COMMENT_UPDATE_FAILED, - COMMENT_HIDE_STARTED: COMMENT_HIDE_STARTED, - COMMENT_HIDE_COMPLETED: COMMENT_HIDE_COMPLETED, - COMMENT_HIDE_FAILED: COMMENT_HIDE_FAILED, - FILE_LIST_STARTED: FILE_LIST_STARTED, - FILE_LIST_SUCCEEDED: FILE_LIST_SUCCEEDED, - FETCH_FILE_INFO_STARTED: FETCH_FILE_INFO_STARTED, - FETCH_FILE_INFO_COMPLETED: FETCH_FILE_INFO_COMPLETED, - FETCH_FILE_INFO_FAILED: FETCH_FILE_INFO_FAILED, - LOADING_VIDEO_STARTED: LOADING_VIDEO_STARTED, - LOADING_VIDEO_COMPLETED: LOADING_VIDEO_COMPLETED, - LOADING_VIDEO_FAILED: LOADING_VIDEO_FAILED, - DOWNLOADING_STARTED: DOWNLOADING_STARTED, - DOWNLOADING_PROGRESSED: DOWNLOADING_PROGRESSED, - DOWNLOADING_COMPLETED: DOWNLOADING_COMPLETED, - DOWNLOADING_CANCELED: DOWNLOADING_CANCELED, - PLAY_VIDEO_STARTED: PLAY_VIDEO_STARTED, - FETCH_AVAILABILITY_STARTED: FETCH_AVAILABILITY_STARTED, - FETCH_AVAILABILITY_COMPLETED: FETCH_AVAILABILITY_COMPLETED, - FILE_DELETE: FILE_DELETE, - SET_FILE_LIST_SORT: SET_FILE_LIST_SORT, - PURCHASE_URI_STARTED: PURCHASE_URI_STARTED, - PURCHASE_URI_COMPLETED: PURCHASE_URI_COMPLETED, - PURCHASE_URI_FAILED: PURCHASE_URI_FAILED, - CLEAR_PURCHASED_URI_SUCCESS: CLEAR_PURCHASED_URI_SUCCESS, - SEARCH_START: SEARCH_START, - SEARCH_SUCCESS: SEARCH_SUCCESS, - SEARCH_FAIL: SEARCH_FAIL, - RESOLVED_SEARCH_START: RESOLVED_SEARCH_START, - RESOLVED_SEARCH_SUCCESS: RESOLVED_SEARCH_SUCCESS, - RESOLVED_SEARCH_FAIL: RESOLVED_SEARCH_FAIL, - UPDATE_SEARCH_QUERY: UPDATE_SEARCH_QUERY, - UPDATE_SEARCH_OPTIONS: UPDATE_SEARCH_OPTIONS, - UPDATE_SEARCH_SUGGESTIONS: UPDATE_SEARCH_SUGGESTIONS, - SEARCH_FOCUS: SEARCH_FOCUS, - SEARCH_BLUR: SEARCH_BLUR, - DAEMON_SETTINGS_RECEIVED: DAEMON_SETTINGS_RECEIVED, - DAEMON_STATUS_RECEIVED: DAEMON_STATUS_RECEIVED, - SHARED_PREFERENCE_SET: SHARED_PREFERENCE_SET, - SAVE_CUSTOM_WALLET_SERVERS: SAVE_CUSTOM_WALLET_SERVERS, - CLIENT_SETTING_CHANGED: CLIENT_SETTING_CHANGED, - UPDATE_IS_NIGHT: UPDATE_IS_NIGHT, - AUTHENTICATION_STARTED: AUTHENTICATION_STARTED, - AUTHENTICATION_SUCCESS: AUTHENTICATION_SUCCESS, - AUTHENTICATION_FAILURE: AUTHENTICATION_FAILURE, - USER_EMAIL_DECLINE: USER_EMAIL_DECLINE, - USER_EMAIL_NEW_STARTED: USER_EMAIL_NEW_STARTED, - USER_EMAIL_NEW_SUCCESS: USER_EMAIL_NEW_SUCCESS, - USER_EMAIL_NEW_EXISTS: USER_EMAIL_NEW_EXISTS, - USER_EMAIL_NEW_FAILURE: USER_EMAIL_NEW_FAILURE, - USER_EMAIL_VERIFY_SET: USER_EMAIL_VERIFY_SET, - USER_EMAIL_VERIFY_STARTED: USER_EMAIL_VERIFY_STARTED, - USER_EMAIL_VERIFY_SUCCESS: USER_EMAIL_VERIFY_SUCCESS, - USER_EMAIL_VERIFY_FAILURE: USER_EMAIL_VERIFY_FAILURE, - USER_EMAIL_VERIFY_RETRY: USER_EMAIL_VERIFY_RETRY, - USER_PHONE_RESET: USER_PHONE_RESET, - USER_PHONE_NEW_STARTED: USER_PHONE_NEW_STARTED, - USER_PHONE_NEW_SUCCESS: USER_PHONE_NEW_SUCCESS, - USER_PHONE_NEW_FAILURE: USER_PHONE_NEW_FAILURE, - USER_PHONE_VERIFY_STARTED: USER_PHONE_VERIFY_STARTED, - USER_PHONE_VERIFY_SUCCESS: USER_PHONE_VERIFY_SUCCESS, - USER_PHONE_VERIFY_FAILURE: USER_PHONE_VERIFY_FAILURE, - USER_IDENTITY_VERIFY_STARTED: USER_IDENTITY_VERIFY_STARTED, - USER_IDENTITY_VERIFY_SUCCESS: USER_IDENTITY_VERIFY_SUCCESS, - USER_IDENTITY_VERIFY_FAILURE: USER_IDENTITY_VERIFY_FAILURE, - USER_FETCH_STARTED: USER_FETCH_STARTED, - USER_FETCH_SUCCESS: USER_FETCH_SUCCESS, - USER_FETCH_FAILURE: USER_FETCH_FAILURE, - USER_INVITE_STATUS_FETCH_STARTED: USER_INVITE_STATUS_FETCH_STARTED, - USER_INVITE_STATUS_FETCH_SUCCESS: USER_INVITE_STATUS_FETCH_SUCCESS, - USER_INVITE_STATUS_FETCH_FAILURE: USER_INVITE_STATUS_FETCH_FAILURE, - USER_INVITE_NEW_STARTED: USER_INVITE_NEW_STARTED, - USER_INVITE_NEW_SUCCESS: USER_INVITE_NEW_SUCCESS, - USER_INVITE_NEW_FAILURE: USER_INVITE_NEW_FAILURE, - FETCH_ACCESS_TOKEN_SUCCESS: FETCH_ACCESS_TOKEN_SUCCESS, - FETCH_REWARDS_STARTED: FETCH_REWARDS_STARTED, - FETCH_REWARDS_COMPLETED: FETCH_REWARDS_COMPLETED, - CLAIM_REWARD_STARTED: CLAIM_REWARD_STARTED, - CLAIM_REWARD_SUCCESS: CLAIM_REWARD_SUCCESS, - CLAIM_REWARD_FAILURE: CLAIM_REWARD_FAILURE, - CLAIM_REWARD_CLEAR_ERROR: CLAIM_REWARD_CLEAR_ERROR, - FETCH_REWARD_CONTENT_COMPLETED: FETCH_REWARD_CONTENT_COMPLETED, - DOWNLOAD_LANGUAGE_SUCCEEDED: DOWNLOAD_LANGUAGE_SUCCEEDED, - DOWNLOAD_LANGUAGE_FAILED: DOWNLOAD_LANGUAGE_FAILED, - CHANNEL_SUBSCRIBE: CHANNEL_SUBSCRIBE, - CHANNEL_UNSUBSCRIBE: CHANNEL_UNSUBSCRIBE, - HAS_FETCHED_SUBSCRIPTIONS: HAS_FETCHED_SUBSCRIPTIONS, - SET_SUBSCRIPTION_LATEST: SET_SUBSCRIPTION_LATEST, - SET_SUBSCRIPTION_NOTIFICATION: SET_SUBSCRIPTION_NOTIFICATION, - SET_SUBSCRIPTION_NOTIFICATIONS: SET_SUBSCRIPTION_NOTIFICATIONS, - CHECK_SUBSCRIPTION_STARTED: CHECK_SUBSCRIPTION_STARTED, - CHECK_SUBSCRIPTION_COMPLETED: CHECK_SUBSCRIPTION_COMPLETED, - CHECK_SUBSCRIPTIONS_SUBSCRIBE: CHECK_SUBSCRIPTIONS_SUBSCRIBE, - CLEAR_PUBLISH: CLEAR_PUBLISH, - UPDATE_PUBLISH_FORM: UPDATE_PUBLISH_FORM, - PUBLISH_START: PUBLISH_START, - PUBLISH_SUCCESS: PUBLISH_SUCCESS, - PUBLISH_FAIL: PUBLISH_FAIL, - CLEAR_PUBLISH_ERROR: CLEAR_PUBLISH_ERROR, - REMOVE_PENDING_PUBLISH: REMOVE_PENDING_PUBLISH, - DO_PREPARE_EDIT: DO_PREPARE_EDIT, - CREATE_NOTIFICATION: CREATE_NOTIFICATION, - EDIT_NOTIFICATION: EDIT_NOTIFICATION, - DELETE_NOTIFICATION: DELETE_NOTIFICATION, - DISMISS_NOTIFICATION: DISMISS_NOTIFICATION, - CREATE_TOAST: CREATE_TOAST, - DISMISS_TOAST: DISMISS_TOAST, - CREATE_ERROR: CREATE_ERROR, - DISMISS_ERROR: DISMISS_ERROR, - FETCH_DATE: FETCH_DATE, - FETCH_COST_INFO_STARTED: FETCH_COST_INFO_STARTED, - FETCH_COST_INFO_COMPLETED: FETCH_COST_INFO_COMPLETED, - FETCH_COST_INFO_FAILED: FETCH_COST_INFO_FAILED, - TOGGLE_TAG_FOLLOW: TOGGLE_TAG_FOLLOW, - TAG_ADD: TAG_ADD, - TAG_DELETE: TAG_DELETE, - TOGGLE_BLOCK_CHANNEL: TOGGLE_BLOCK_CHANNEL, - USER_STATE_POPULATE: USER_STATE_POPULATE + WINDOW_FOCUSED: WINDOW_FOCUSED, + DAEMON_READY: DAEMON_READY, + DAEMON_VERSION_MATCH: DAEMON_VERSION_MATCH, + DAEMON_VERSION_MISMATCH: DAEMON_VERSION_MISMATCH, + VOLUME_CHANGED: VOLUME_CHANGED, + CHANGE_AFTER_AUTH_PATH: CHANGE_AFTER_AUTH_PATH, + WINDOW_SCROLLED: WINDOW_SCROLLED, + HISTORY_NAVIGATE: HISTORY_NAVIGATE, + UPGRADE_CANCELLED: UPGRADE_CANCELLED, + DOWNLOAD_UPGRADE: DOWNLOAD_UPGRADE, + UPGRADE_DOWNLOAD_STARTED: UPGRADE_DOWNLOAD_STARTED, + UPGRADE_DOWNLOAD_COMPLETED: UPGRADE_DOWNLOAD_COMPLETED, + UPGRADE_DOWNLOAD_PROGRESSED: UPGRADE_DOWNLOAD_PROGRESSED, + CHECK_UPGRADE_AVAILABLE: CHECK_UPGRADE_AVAILABLE, + CHECK_UPGRADE_START: CHECK_UPGRADE_START, + CHECK_UPGRADE_SUCCESS: CHECK_UPGRADE_SUCCESS, + CHECK_UPGRADE_FAIL: CHECK_UPGRADE_FAIL, + CHECK_UPGRADE_SUBSCRIBE: CHECK_UPGRADE_SUBSCRIBE, + UPDATE_VERSION: UPDATE_VERSION, + UPDATE_REMOTE_VERSION: UPDATE_REMOTE_VERSION, + SKIP_UPGRADE: SKIP_UPGRADE, + START_UPGRADE: START_UPGRADE, + AUTO_UPDATE_DECLINED: AUTO_UPDATE_DECLINED, + AUTO_UPDATE_DOWNLOADED: AUTO_UPDATE_DOWNLOADED, + CLEAR_UPGRADE_TIMER: CLEAR_UPGRADE_TIMER, + GET_NEW_ADDRESS_STARTED: GET_NEW_ADDRESS_STARTED, + GET_NEW_ADDRESS_COMPLETED: GET_NEW_ADDRESS_COMPLETED, + FETCH_TRANSACTIONS_STARTED: FETCH_TRANSACTIONS_STARTED, + FETCH_TRANSACTIONS_COMPLETED: FETCH_TRANSACTIONS_COMPLETED, + UPDATE_BALANCE: UPDATE_BALANCE, + UPDATE_TOTAL_BALANCE: UPDATE_TOTAL_BALANCE, + CHECK_ADDRESS_IS_MINE_STARTED: CHECK_ADDRESS_IS_MINE_STARTED, + CHECK_ADDRESS_IS_MINE_COMPLETED: CHECK_ADDRESS_IS_MINE_COMPLETED, + SEND_TRANSACTION_STARTED: SEND_TRANSACTION_STARTED, + SEND_TRANSACTION_COMPLETED: SEND_TRANSACTION_COMPLETED, + SEND_TRANSACTION_FAILED: SEND_TRANSACTION_FAILED, + FETCH_BLOCK_SUCCESS: FETCH_BLOCK_SUCCESS, + SUPPORT_TRANSACTION_STARTED: SUPPORT_TRANSACTION_STARTED, + SUPPORT_TRANSACTION_COMPLETED: SUPPORT_TRANSACTION_COMPLETED, + SUPPORT_TRANSACTION_FAILED: SUPPORT_TRANSACTION_FAILED, + WALLET_ENCRYPT_START: WALLET_ENCRYPT_START, + WALLET_ENCRYPT_COMPLETED: WALLET_ENCRYPT_COMPLETED, + WALLET_ENCRYPT_FAILED: WALLET_ENCRYPT_FAILED, + WALLET_UNLOCK_START: WALLET_UNLOCK_START, + WALLET_UNLOCK_COMPLETED: WALLET_UNLOCK_COMPLETED, + WALLET_UNLOCK_FAILED: WALLET_UNLOCK_FAILED, + WALLET_DECRYPT_START: WALLET_DECRYPT_START, + WALLET_DECRYPT_COMPLETED: WALLET_DECRYPT_COMPLETED, + WALLET_DECRYPT_FAILED: WALLET_DECRYPT_FAILED, + WALLET_LOCK_START: WALLET_LOCK_START, + WALLET_LOCK_COMPLETED: WALLET_LOCK_COMPLETED, + WALLET_LOCK_FAILED: WALLET_LOCK_FAILED, + WALLET_STATUS_START: WALLET_STATUS_START, + WALLET_STATUS_COMPLETED: WALLET_STATUS_COMPLETED, + SET_TRANSACTION_LIST_FILTER: SET_TRANSACTION_LIST_FILTER, + UPDATE_CURRENT_HEIGHT: UPDATE_CURRENT_HEIGHT, + SET_DRAFT_TRANSACTION_AMOUNT: SET_DRAFT_TRANSACTION_AMOUNT, + SET_DRAFT_TRANSACTION_ADDRESS: SET_DRAFT_TRANSACTION_ADDRESS, + RESOLVE_URIS_STARTED: RESOLVE_URIS_STARTED, + RESOLVE_URIS_COMPLETED: RESOLVE_URIS_COMPLETED, + FETCH_CHANNEL_CLAIMS_STARTED: FETCH_CHANNEL_CLAIMS_STARTED, + FETCH_CHANNEL_CLAIMS_COMPLETED: FETCH_CHANNEL_CLAIMS_COMPLETED, + FETCH_CLAIM_LIST_MINE_STARTED: FETCH_CLAIM_LIST_MINE_STARTED, + FETCH_CLAIM_LIST_MINE_COMPLETED: FETCH_CLAIM_LIST_MINE_COMPLETED, + ABANDON_CLAIM_STARTED: ABANDON_CLAIM_STARTED, + ABANDON_CLAIM_SUCCEEDED: ABANDON_CLAIM_SUCCEEDED, + FETCH_CHANNEL_LIST_STARTED: FETCH_CHANNEL_LIST_STARTED, + FETCH_CHANNEL_LIST_COMPLETED: FETCH_CHANNEL_LIST_COMPLETED, + CREATE_CHANNEL_STARTED: CREATE_CHANNEL_STARTED, + CREATE_CHANNEL_COMPLETED: CREATE_CHANNEL_COMPLETED, + CREATE_CHANNEL_FAILED: CREATE_CHANNEL_FAILED, + PUBLISH_STARTED: PUBLISH_STARTED, + PUBLISH_COMPLETED: PUBLISH_COMPLETED, + PUBLISH_FAILED: PUBLISH_FAILED, + SET_PLAYING_URI: SET_PLAYING_URI, + SET_CONTENT_POSITION: SET_CONTENT_POSITION, + SET_CONTENT_LAST_VIEWED: SET_CONTENT_LAST_VIEWED, + CLEAR_CONTENT_HISTORY_URI: CLEAR_CONTENT_HISTORY_URI, + CLEAR_CONTENT_HISTORY_ALL: CLEAR_CONTENT_HISTORY_ALL, + FILE_LIST_STARTED: FILE_LIST_STARTED, + FILE_LIST_SUCCEEDED: FILE_LIST_SUCCEEDED, + FETCH_FILE_INFO_STARTED: FETCH_FILE_INFO_STARTED, + FETCH_FILE_INFO_COMPLETED: FETCH_FILE_INFO_COMPLETED, + LOADING_VIDEO_STARTED: LOADING_VIDEO_STARTED, + LOADING_VIDEO_COMPLETED: LOADING_VIDEO_COMPLETED, + LOADING_VIDEO_FAILED: LOADING_VIDEO_FAILED, + DOWNLOADING_STARTED: DOWNLOADING_STARTED, + DOWNLOADING_PROGRESSED: DOWNLOADING_PROGRESSED, + DOWNLOADING_COMPLETED: DOWNLOADING_COMPLETED, + DOWNLOADING_CANCELED: DOWNLOADING_CANCELED, + PLAY_VIDEO_STARTED: PLAY_VIDEO_STARTED, + FETCH_AVAILABILITY_STARTED: FETCH_AVAILABILITY_STARTED, + FETCH_AVAILABILITY_COMPLETED: FETCH_AVAILABILITY_COMPLETED, + FILE_DELETE: FILE_DELETE, + SET_FILE_LIST_SORT: SET_FILE_LIST_SORT, + SEARCH_START: SEARCH_START, + SEARCH_SUCCESS: SEARCH_SUCCESS, + SEARCH_FAIL: SEARCH_FAIL, + UPDATE_SEARCH_QUERY: UPDATE_SEARCH_QUERY, + UPDATE_SEARCH_OPTIONS: UPDATE_SEARCH_OPTIONS, + UPDATE_SEARCH_SUGGESTIONS: UPDATE_SEARCH_SUGGESTIONS, + SEARCH_FOCUS: SEARCH_FOCUS, + SEARCH_BLUR: SEARCH_BLUR, + DAEMON_SETTINGS_RECEIVED: DAEMON_SETTINGS_RECEIVED, + CLIENT_SETTING_CHANGED: CLIENT_SETTING_CHANGED, + UPDATE_IS_NIGHT: UPDATE_IS_NIGHT, + AUTHENTICATION_STARTED: AUTHENTICATION_STARTED, + AUTHENTICATION_SUCCESS: AUTHENTICATION_SUCCESS, + AUTHENTICATION_FAILURE: AUTHENTICATION_FAILURE, + USER_EMAIL_DECLINE: USER_EMAIL_DECLINE, + USER_EMAIL_NEW_STARTED: USER_EMAIL_NEW_STARTED, + USER_EMAIL_NEW_SUCCESS: USER_EMAIL_NEW_SUCCESS, + USER_EMAIL_NEW_EXISTS: USER_EMAIL_NEW_EXISTS, + USER_EMAIL_NEW_FAILURE: USER_EMAIL_NEW_FAILURE, + USER_EMAIL_VERIFY_SET: USER_EMAIL_VERIFY_SET, + USER_EMAIL_VERIFY_STARTED: USER_EMAIL_VERIFY_STARTED, + USER_EMAIL_VERIFY_SUCCESS: USER_EMAIL_VERIFY_SUCCESS, + USER_EMAIL_VERIFY_FAILURE: USER_EMAIL_VERIFY_FAILURE, + USER_EMAIL_VERIFY_RETRY: USER_EMAIL_VERIFY_RETRY, + USER_PHONE_RESET: USER_PHONE_RESET, + USER_PHONE_NEW_STARTED: USER_PHONE_NEW_STARTED, + USER_PHONE_NEW_SUCCESS: USER_PHONE_NEW_SUCCESS, + USER_PHONE_NEW_FAILURE: USER_PHONE_NEW_FAILURE, + USER_PHONE_VERIFY_STARTED: USER_PHONE_VERIFY_STARTED, + USER_PHONE_VERIFY_SUCCESS: USER_PHONE_VERIFY_SUCCESS, + USER_PHONE_VERIFY_FAILURE: USER_PHONE_VERIFY_FAILURE, + USER_IDENTITY_VERIFY_STARTED: USER_IDENTITY_VERIFY_STARTED, + USER_IDENTITY_VERIFY_SUCCESS: USER_IDENTITY_VERIFY_SUCCESS, + USER_IDENTITY_VERIFY_FAILURE: USER_IDENTITY_VERIFY_FAILURE, + USER_FETCH_STARTED: USER_FETCH_STARTED, + USER_FETCH_SUCCESS: USER_FETCH_SUCCESS, + USER_FETCH_FAILURE: USER_FETCH_FAILURE, + USER_INVITE_STATUS_FETCH_STARTED: USER_INVITE_STATUS_FETCH_STARTED, + USER_INVITE_STATUS_FETCH_SUCCESS: USER_INVITE_STATUS_FETCH_SUCCESS, + USER_INVITE_STATUS_FETCH_FAILURE: USER_INVITE_STATUS_FETCH_FAILURE, + USER_INVITE_NEW_STARTED: USER_INVITE_NEW_STARTED, + USER_INVITE_NEW_SUCCESS: USER_INVITE_NEW_SUCCESS, + USER_INVITE_NEW_FAILURE: USER_INVITE_NEW_FAILURE, + FETCH_ACCESS_TOKEN_SUCCESS: FETCH_ACCESS_TOKEN_SUCCESS, + FETCH_REWARDS_STARTED: FETCH_REWARDS_STARTED, + FETCH_REWARDS_COMPLETED: FETCH_REWARDS_COMPLETED, + CLAIM_REWARD_STARTED: CLAIM_REWARD_STARTED, + CLAIM_REWARD_SUCCESS: CLAIM_REWARD_SUCCESS, + CLAIM_REWARD_FAILURE: CLAIM_REWARD_FAILURE, + CLAIM_REWARD_CLEAR_ERROR: CLAIM_REWARD_CLEAR_ERROR, + FETCH_REWARD_CONTENT_COMPLETED: FETCH_REWARD_CONTENT_COMPLETED, + DOWNLOAD_LANGUAGE_SUCCEEDED: DOWNLOAD_LANGUAGE_SUCCEEDED, + DOWNLOAD_LANGUAGE_FAILED: DOWNLOAD_LANGUAGE_FAILED, + GET_SUPPORTED_COINS_START: GET_SUPPORTED_COINS_START, + GET_SUPPORTED_COINS_SUCCESS: GET_SUPPORTED_COINS_SUCCESS, + GET_SUPPORTED_COINS_FAIL: GET_SUPPORTED_COINS_FAIL, + GET_COIN_STATS_START: GET_COIN_STATS_START, + GET_COIN_STATS_SUCCESS: GET_COIN_STATS_SUCCESS, + GET_COIN_STATS_FAIL: GET_COIN_STATS_FAIL, + PREPARE_SHAPE_SHIFT_START: PREPARE_SHAPE_SHIFT_START, + PREPARE_SHAPE_SHIFT_SUCCESS: PREPARE_SHAPE_SHIFT_SUCCESS, + PREPARE_SHAPE_SHIFT_FAIL: PREPARE_SHAPE_SHIFT_FAIL, + GET_ACTIVE_SHIFT_START: GET_ACTIVE_SHIFT_START, + GET_ACTIVE_SHIFT_SUCCESS: GET_ACTIVE_SHIFT_SUCCESS, + GET_ACTIVE_SHIFT_FAIL: GET_ACTIVE_SHIFT_FAIL, + CLEAR_SHAPE_SHIFT: CLEAR_SHAPE_SHIFT, + CHANNEL_SUBSCRIBE: CHANNEL_SUBSCRIBE, + CHANNEL_UNSUBSCRIBE: CHANNEL_UNSUBSCRIBE, + HAS_FETCHED_SUBSCRIPTIONS: HAS_FETCHED_SUBSCRIPTIONS, + SET_SUBSCRIPTION_LATEST: SET_SUBSCRIPTION_LATEST, + SET_SUBSCRIPTION_NOTIFICATION: SET_SUBSCRIPTION_NOTIFICATION, + SET_SUBSCRIPTION_NOTIFICATIONS: SET_SUBSCRIPTION_NOTIFICATIONS, + CHECK_SUBSCRIPTION_STARTED: CHECK_SUBSCRIPTION_STARTED, + CHECK_SUBSCRIPTION_COMPLETED: CHECK_SUBSCRIPTION_COMPLETED, + CHECK_SUBSCRIPTIONS_SUBSCRIBE: CHECK_SUBSCRIPTIONS_SUBSCRIBE, + CLEAR_PUBLISH: CLEAR_PUBLISH, + UPDATE_PUBLISH_FORM: UPDATE_PUBLISH_FORM, + PUBLISH_START: PUBLISH_START, + PUBLISH_SUCCESS: PUBLISH_SUCCESS, + PUBLISH_FAIL: PUBLISH_FAIL, + CLEAR_PUBLISH_ERROR: CLEAR_PUBLISH_ERROR, + REMOVE_PENDING_PUBLISH: REMOVE_PENDING_PUBLISH, + DO_PREPARE_EDIT: DO_PREPARE_EDIT, + CREATE_NOTIFICATION: CREATE_NOTIFICATION, + EDIT_NOTIFICATION: EDIT_NOTIFICATION, + DELETE_NOTIFICATION: DELETE_NOTIFICATION, + DISMISS_NOTIFICATION: DISMISS_NOTIFICATION, + CREATE_TOAST: CREATE_TOAST, + DISMISS_TOAST: DISMISS_TOAST, + CREATE_ERROR: CREATE_ERROR, + DISMISS_ERROR: DISMISS_ERROR, + FETCH_DATE: FETCH_DATE }); -const CC_LICENSES = [{ - value: 'Creative Commons Attribution 4.0 International', - url: 'https://creativecommons.org/licenses/by/4.0/legalcode' -}, { - value: 'Creative Commons Attribution-ShareAlike 4.0 International', - url: 'https://creativecommons.org/licenses/by-sa/4.0/legalcode' -}, { - value: 'Creative Commons Attribution-NoDerivatives 4.0 International', - url: 'https://creativecommons.org/licenses/by-nd/4.0/legalcode' -}, { - value: 'Creative Commons Attribution-NonCommercial 4.0 International', - url: 'https://creativecommons.org/licenses/by-nc/4.0/legalcode' -}, { - value: 'Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International', - url: 'https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode' -}, { - value: 'Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International', - url: 'https://creativecommons.org/licenses/by-nc-nd/4.0/legalcode' -}]; +const API_DOWN = 'apiDown'; +const READY = 'ready'; +const IN_PROGRESS = 'inProgress'; +const COMPLETE = 'complete'; +const MANUAL = 'manual'; -const NONE = 'None'; -const PUBLIC_DOMAIN = 'Public Domain'; -const OTHER = 'other'; -const COPYRIGHT = 'copyright'; +var thumbnail_upload_statuses = /*#__PURE__*/Object.freeze({ + API_DOWN: API_DOWN, + READY: READY, + IN_PROGRESS: IN_PROGRESS, + COMPLETE: COMPLETE, + MANUAL: MANUAL +}); -var licenses = /*#__PURE__*/Object.freeze({ - CC_LICENSES: CC_LICENSES, - NONE: NONE, - PUBLIC_DOMAIN: PUBLIC_DOMAIN, - OTHER: OTHER, - COPYRIGHT: COPYRIGHT +/* 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 */ +const CREDIT_REQUIRED_ACKNOWLEDGED = 'credit_required_acknowledged'; +const NEW_USER_ACKNOWLEDGED = 'welcome_acknowledged'; +const EMAIL_COLLECTION_ACKNOWLEDGED = 'email_collection_acknowledged'; +const LANGUAGE = 'language'; +const SHOW_NSFW = 'showNsfw'; +const SHOW_UNAVAILABLE = 'showUnavailable'; +const INSTANT_PURCHASE_ENABLED = 'instantPurchaseEnabled'; +const INSTANT_PURCHASE_MAX = 'instantPurchaseMax'; +const THEME = 'theme'; +const THEMES = 'themes'; +const AUTOMATIC_DARK_MODE_ENABLED = 'automaticDarkModeEnabled'; + +// mobile settings +const BACKGROUND_PLAY_ENABLED = 'backgroundPlayEnabled'; +const FOREGROUND_NOTIFICATION_ENABLED = 'foregroundNotificationEnabled'; +const KEEP_DAEMON_RUNNING = 'keepDaemonRunning'; + +var settings = /*#__PURE__*/Object.freeze({ + CREDIT_REQUIRED_ACKNOWLEDGED: CREDIT_REQUIRED_ACKNOWLEDGED, + NEW_USER_ACKNOWLEDGED: NEW_USER_ACKNOWLEDGED, + EMAIL_COLLECTION_ACKNOWLEDGED: EMAIL_COLLECTION_ACKNOWLEDGED, + LANGUAGE: LANGUAGE, + SHOW_NSFW: SHOW_NSFW, + SHOW_UNAVAILABLE: SHOW_UNAVAILABLE, + INSTANT_PURCHASE_ENABLED: INSTANT_PURCHASE_ENABLED, + INSTANT_PURCHASE_MAX: INSTANT_PURCHASE_MAX, + THEME: THEME, + THEMES: THEMES, + AUTOMATIC_DARK_MODE_ENABLED: AUTOMATIC_DARK_MODE_ENABLED, + BACKGROUND_PLAY_ENABLED: BACKGROUND_PLAY_ENABLED, + FOREGROUND_NOTIFICATION_ENABLED: FOREGROUND_NOTIFICATION_ENABLED, + KEEP_DAEMON_RUNNING: KEEP_DAEMON_RUNNING +}); + +// eslint-disable-next-line import/prefer-default-export +const ALL = 'all'; +const SPEND = 'spend'; +const RECEIVE = 'receive'; +const PUBLISH = 'publish'; +const CHANNEL = 'channel'; +const TIP = 'tip'; +const SUPPORT = 'support'; +const UPDATE = 'update'; +const ABANDON = 'abandon'; + +var transaction_types = /*#__PURE__*/Object.freeze({ + ALL: ALL, + SPEND: SPEND, + RECEIVE: RECEIVE, + PUBLISH: PUBLISH, + CHANNEL: CHANNEL, + TIP: TIP, + SUPPORT: SUPPORT, + UPDATE: UPDATE, + ABANDON: ABANDON +}); + +const DATE_NEW = 'dateNew'; +const DATE_OLD = 'dateOld'; +const TITLE = 'title'; +const FILENAME = 'filename'; + +var sort_options = /*#__PURE__*/Object.freeze({ + DATE_NEW: DATE_NEW, + DATE_OLD: DATE_OLD, + TITLE: TITLE, + FILENAME: FILENAME }); const AUTH = 'auth'; const BACKUP = 'backup'; -const CHANNEL = 'channel'; +const CHANNEL$1 = 'channel'; const DISCOVER = 'discover'; const FILE = 'file'; const DOWNLOADED = 'downloaded'; @@ -613,7 +511,7 @@ const PUBLISHED = 'published'; const GET_CREDITS = 'getcredits'; const HELP = 'help'; const INVITE = 'invite'; -const PUBLISH = 'publish'; +const PUBLISH$1 = 'publish'; const REPORT = 'report'; const REWARDS = 'rewards'; const SEARCH = 'search'; @@ -626,356 +524,33 @@ const HISTORY = 'user_history'; const WALLET = 'wallet'; var pages = /*#__PURE__*/Object.freeze({ - AUTH: AUTH, - BACKUP: BACKUP, - CHANNEL: CHANNEL, - DISCOVER: DISCOVER, - FILE: FILE, - DOWNLOADED: DOWNLOADED, - PUBLISHED: PUBLISHED, - GET_CREDITS: GET_CREDITS, - HELP: HELP, - INVITE: INVITE, - PUBLISH: PUBLISH, - REPORT: REPORT, - REWARDS: REWARDS, - SEARCH: SEARCH, - SEND_CREDITS: SEND_CREDITS, - SETTINGS: SETTINGS, - SHOW: SHOW, - SUBSCRIPTIONS: SUBSCRIPTIONS, - TRANSACTION_HISTORY: TRANSACTION_HISTORY, - HISTORY: HISTORY, - WALLET: WALLET -}); - -/* 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 */ - -const SHOW_NSFW = 'showNsfw'; -const CREDIT_REQUIRED_ACKNOWLEDGED = 'credit_required_acknowledged'; -const NEW_USER_ACKNOWLEDGED = 'welcome_acknowledged'; -const EMAIL_COLLECTION_ACKNOWLEDGED = 'email_collection_acknowledged'; -const INVITE_ACKNOWLEDGED = 'invite_acknowledged'; -const LANGUAGE = 'language'; -const SHOW_MATURE = 'show_mature'; -const HIDE_REPOSTS = 'hide_reposts'; -const SHOW_ANONYMOUS = 'show_anonymous'; -const SHOW_UNAVAILABLE = 'show_unavailable'; -const INSTANT_PURCHASE_ENABLED = 'instant_purchase_enabled'; -const INSTANT_PURCHASE_MAX = 'instant_purchase_max'; -const THEME = 'theme'; -const THEMES = 'themes'; -const AUTOMATIC_DARK_MODE_ENABLED = 'automatic_dark_mode_enabled'; -const AUTOPLAY = 'autoplay'; -const OS_NOTIFICATIONS_ENABLED = 'os_notifications_enabled'; -const AUTO_DOWNLOAD = 'auto_download'; -const AUTO_LAUNCH = 'auto_launch'; -const SUPPORT_OPTION = 'support_option'; -const HIDE_BALANCE = 'hide_balance'; -const HIDE_SPLASH_ANIMATION = 'hide_splash_animation'; -const FLOATING_PLAYER = 'floating_player'; -const DARK_MODE_TIMES = 'dark_mode_times'; -const ENABLE_SYNC = 'enable_sync'; - -// mobile settings -const BACKGROUND_PLAY_ENABLED = 'backgroundPlayEnabled'; -const FOREGROUND_NOTIFICATION_ENABLED = 'foregroundNotificationEnabled'; -const KEEP_DAEMON_RUNNING = 'keepDaemonRunning'; -const SHOW_URI_BAR_SUGGESTIONS = 'showUriBarSuggestions'; -const RECEIVE_SUBSCRIPTION_NOTIFICATIONS = 'receiveSubscriptionNotifications'; -const RECEIVE_REWARD_NOTIFICATIONS = 'receiveRewardNotifications'; -const RECEIVE_INTERESTS_NOTIFICATIONS = 'receiveInterestsNotifications'; -const RECEIVE_CREATOR_NOTIFICATIONS = 'receiveCreatorNotifications'; - -var settings = /*#__PURE__*/Object.freeze({ - SHOW_NSFW: SHOW_NSFW, - CREDIT_REQUIRED_ACKNOWLEDGED: CREDIT_REQUIRED_ACKNOWLEDGED, - NEW_USER_ACKNOWLEDGED: NEW_USER_ACKNOWLEDGED, - EMAIL_COLLECTION_ACKNOWLEDGED: EMAIL_COLLECTION_ACKNOWLEDGED, - INVITE_ACKNOWLEDGED: INVITE_ACKNOWLEDGED, - LANGUAGE: LANGUAGE, - SHOW_MATURE: SHOW_MATURE, - HIDE_REPOSTS: HIDE_REPOSTS, - SHOW_ANONYMOUS: SHOW_ANONYMOUS, - SHOW_UNAVAILABLE: SHOW_UNAVAILABLE, - INSTANT_PURCHASE_ENABLED: INSTANT_PURCHASE_ENABLED, - INSTANT_PURCHASE_MAX: INSTANT_PURCHASE_MAX, - THEME: THEME, - THEMES: THEMES, - AUTOMATIC_DARK_MODE_ENABLED: AUTOMATIC_DARK_MODE_ENABLED, - AUTOPLAY: AUTOPLAY, - OS_NOTIFICATIONS_ENABLED: OS_NOTIFICATIONS_ENABLED, - AUTO_DOWNLOAD: AUTO_DOWNLOAD, - AUTO_LAUNCH: AUTO_LAUNCH, - SUPPORT_OPTION: SUPPORT_OPTION, - HIDE_BALANCE: HIDE_BALANCE, - HIDE_SPLASH_ANIMATION: HIDE_SPLASH_ANIMATION, - FLOATING_PLAYER: FLOATING_PLAYER, - DARK_MODE_TIMES: DARK_MODE_TIMES, - ENABLE_SYNC: ENABLE_SYNC, - BACKGROUND_PLAY_ENABLED: BACKGROUND_PLAY_ENABLED, - FOREGROUND_NOTIFICATION_ENABLED: FOREGROUND_NOTIFICATION_ENABLED, - KEEP_DAEMON_RUNNING: KEEP_DAEMON_RUNNING, - SHOW_URI_BAR_SUGGESTIONS: SHOW_URI_BAR_SUGGESTIONS, - RECEIVE_SUBSCRIPTION_NOTIFICATIONS: RECEIVE_SUBSCRIPTION_NOTIFICATIONS, - RECEIVE_REWARD_NOTIFICATIONS: RECEIVE_REWARD_NOTIFICATIONS, - RECEIVE_INTERESTS_NOTIFICATIONS: RECEIVE_INTERESTS_NOTIFICATIONS, - RECEIVE_CREATOR_NOTIFICATIONS: RECEIVE_CREATOR_NOTIFICATIONS -}); - -const DATE_NEW = 'dateNew'; -const DATE_OLD = 'dateOld'; -const TITLE = 'title'; -const FILENAME = 'filename'; - -var sort_options = /*#__PURE__*/Object.freeze({ - DATE_NEW: DATE_NEW, - DATE_OLD: DATE_OLD, - TITLE: TITLE, - FILENAME: FILENAME -}); - -const API_DOWN = 'apiDown'; -const READY = 'ready'; -const IN_PROGRESS = 'inProgress'; -const COMPLETE = 'complete'; -const MANUAL = 'manual'; - -var thumbnail_upload_statuses = /*#__PURE__*/Object.freeze({ - API_DOWN: API_DOWN, - READY: READY, - IN_PROGRESS: IN_PROGRESS, - COMPLETE: COMPLETE, - MANUAL: MANUAL -}); - -// eslint-disable-next-line import/prefer-default-export -const ALL = 'all'; -const SPEND = 'spend'; -const RECEIVE = 'receive'; -const PUBLISH$1 = 'publish'; -const CHANNEL$1 = 'channel'; -const TIP = 'tip'; -const SUPPORT = 'support'; -const UPDATE = 'update'; -const ABANDON = 'abandon'; - -var transaction_types = /*#__PURE__*/Object.freeze({ - ALL: ALL, - SPEND: SPEND, - RECEIVE: RECEIVE, - PUBLISH: PUBLISH$1, - CHANNEL: CHANNEL$1, - TIP: TIP, - SUPPORT: SUPPORT, - UPDATE: UPDATE, - ABANDON: ABANDON -}); - -// PAGE SIZE -const PAGE_SIZE$1 = 50; -const LATEST_PAGE_SIZE = 20; - -var transaction_list = /*#__PURE__*/Object.freeze({ - PAGE_SIZE: PAGE_SIZE$1, - LATEST_PAGE_SIZE: LATEST_PAGE_SIZE -}); - -const PENDING = 'pending'; -const DONE = 'done'; -const READY$1 = 'ready'; -const ERROR = 'error'; - -var abandon_states = /*#__PURE__*/Object.freeze({ - PENDING: PENDING, - DONE: DONE, - READY: READY$1, - ERROR: ERROR -}); - -const ACTIVE = 'active'; // spent, active, all -const TYPE = 'type'; // all, payment, support, channel, stream, repost -const SUB_TYPE = 'subtype'; // other, purchase, tip -const PAGE_SIZE$2 = 'page_size'; -const PAGE = 'page'; -const ALL$1 = 'all'; -// dropdown types -const SENT = 'sent'; -const RECEIVED = 'received'; -const SUPPORT$1 = 'support'; -const CHANNEL$2 = 'channel'; -const PUBLISH$2 = 'publish'; -const REPOST = 'repost'; -const DROPDOWN_TYPES = [ALL$1, SENT, RECEIVED, SUPPORT$1, CHANNEL$2, PUBLISH$2, REPOST]; -// dropdown subtypes -const TIP$1 = 'tip'; -const PURCHASE = 'purchase'; -const PAYMENT = 'payment'; -const DROPDOWN_SUBTYPES = [ALL$1, TIP$1, PURCHASE, PAYMENT]; - -// rpc params -const TX_TYPE = 'type'; // = other, stream, repost, channel, support, purchase -const IS_SPENT = 'is_spent'; -const IS_NOT_SPENT = 'is_not_spent'; -const IS_MY_INPUT = 'is_my_input'; -const IS_MY_OUTPUT = 'is_my_output'; -const IS_NOT_MY_INPUT = 'is_not_my_input'; -const IS_NOT_MY_OUTPUT = 'is_not_my_output'; // use to further distinguish payments to self / from self. -const IS_MY_INPUT_OR_OUTPUT = 'is_my_input_or_output'; -const EXCLUDE_INTERNAL_TRANSFERS = 'exclude_internal_transfers'; - -// sdk unique types -const OTHER$1 = 'other'; -const STREAM = 'stream'; - -const PAGE_SIZE_DEFAULT = 20; - -var txo_list = /*#__PURE__*/Object.freeze({ - ACTIVE: ACTIVE, - TYPE: TYPE, - SUB_TYPE: SUB_TYPE, - PAGE_SIZE: PAGE_SIZE$2, - PAGE: PAGE, - ALL: ALL$1, - SENT: SENT, - RECEIVED: RECEIVED, - SUPPORT: SUPPORT$1, - CHANNEL: CHANNEL$2, - PUBLISH: PUBLISH$2, - REPOST: REPOST, - DROPDOWN_TYPES: DROPDOWN_TYPES, - TIP: TIP$1, - PURCHASE: PURCHASE, - PAYMENT: PAYMENT, - DROPDOWN_SUBTYPES: DROPDOWN_SUBTYPES, - TX_TYPE: TX_TYPE, - IS_SPENT: IS_SPENT, - IS_NOT_SPENT: IS_NOT_SPENT, - IS_MY_INPUT: IS_MY_INPUT, - IS_MY_OUTPUT: IS_MY_OUTPUT, - IS_NOT_MY_INPUT: IS_NOT_MY_INPUT, - IS_NOT_MY_OUTPUT: IS_NOT_MY_OUTPUT, - IS_MY_INPUT_OR_OUTPUT: IS_MY_INPUT_OR_OUTPUT, - EXCLUDE_INTERNAL_TRANSFERS: EXCLUDE_INTERNAL_TRANSFERS, - OTHER: OTHER$1, - STREAM: STREAM, - PAGE_SIZE_DEFAULT: PAGE_SIZE_DEFAULT -}); - -const SPEECH_STATUS = 'https://spee.ch/api/config/site/publishing'; -const SPEECH_PUBLISH = 'https://spee.ch/api/claim/publish'; - -var speech_urls = /*#__PURE__*/Object.freeze({ - SPEECH_STATUS: SPEECH_STATUS, - SPEECH_PUBLISH: SPEECH_PUBLISH -}); - -const ANNOUNCE_HEAD_AND_SD_ONLY = 'announce_head_and_sd_only'; -const API = 'api'; -const BLOB_DOWNLOAD_TIMEOUT = 'blob_download_timeout'; -const BLOB_LRU_CACHE_SIZE = 'blob_lru_cache_size'; -const BLOCKCHAIN_NAME = 'blockchain_name'; -const CACHE_TIME = 'cache_time'; -const COIN_SELECTION_STRATEGY = 'coin_selection_strategy'; -const COMMENT_SERVER = 'comment_server'; -const COMPONENTS_TO_SKIP = 'components_to_skip'; -const CONCURRENT_BLOB_ANNOUNCERS = 'concurrent_blob_announcers'; -const CONCURRENT_REFLECTOR_UPLOADS = 'concurrent_reflector_uploads'; -const CONFIG = 'config'; -const DATA_DIR = 'data_dir'; -const DOWNLOAD_DIR = 'download_dir'; -const DOWNLOAD_TIMEOUT = 'download_timeout'; -const FIXED_PEER_DELAY = 'fixed_peer_delay'; -const KNOWN_DHT_NODES = 'known_dht_nodes'; -const LBRYUM_SERVERS = 'lbryum_servers'; -const MAX_CONNECTIONS_PER_DOWNLOAD = 'max_connections_per_download'; -const MAX_KEY_FEE = 'max_key_fee'; -const DEFAULT_WALLET = 'default_wallet'; -const NETWORK_INTERFACE = 'network_interface'; -const NODE_RPC_TIMEOUT = 'node_rpc_timeout'; -const PEER_CONNECT_TIMEOUT = 'peer_connect_timeout'; -const REFLECT_STREAMS = 'reflect_streams'; -const REFLECTOR_SERVERS = 'reflector_servers'; -const S3_HEADERS_DEPTH = 's3_headers_depth'; -const SAVE_BLOBS = 'save_blobs'; -const SAVE_FILES = 'save_files'; -const SHARE_USAGE_DATA = 'share_usage_data'; -const SPLIT_BUCKETS_UNDER_INDEX = 'split_buckets_under_index'; -const STREAMING_GET = 'streaming_get'; -const STREAMING_SERVER = 'streaming_server'; -const TCP_PORT = 'tcp_port'; -const TRACK_BANDWIDTH = 'track_bandwidth'; -const UDP_PORT = 'udp_port'; -const USE_UPNP = 'use_upnp'; -const WALLET_DIR = 'wallet_dir'; -const WALLETS = 'wallets'; - -var daemon_settings = /*#__PURE__*/Object.freeze({ - ANNOUNCE_HEAD_AND_SD_ONLY: ANNOUNCE_HEAD_AND_SD_ONLY, - API: API, - BLOB_DOWNLOAD_TIMEOUT: BLOB_DOWNLOAD_TIMEOUT, - BLOB_LRU_CACHE_SIZE: BLOB_LRU_CACHE_SIZE, - BLOCKCHAIN_NAME: BLOCKCHAIN_NAME, - CACHE_TIME: CACHE_TIME, - COIN_SELECTION_STRATEGY: COIN_SELECTION_STRATEGY, - COMMENT_SERVER: COMMENT_SERVER, - COMPONENTS_TO_SKIP: COMPONENTS_TO_SKIP, - CONCURRENT_BLOB_ANNOUNCERS: CONCURRENT_BLOB_ANNOUNCERS, - CONCURRENT_REFLECTOR_UPLOADS: CONCURRENT_REFLECTOR_UPLOADS, - CONFIG: CONFIG, - DATA_DIR: DATA_DIR, - DOWNLOAD_DIR: DOWNLOAD_DIR, - DOWNLOAD_TIMEOUT: DOWNLOAD_TIMEOUT, - FIXED_PEER_DELAY: FIXED_PEER_DELAY, - KNOWN_DHT_NODES: KNOWN_DHT_NODES, - LBRYUM_SERVERS: LBRYUM_SERVERS, - MAX_CONNECTIONS_PER_DOWNLOAD: MAX_CONNECTIONS_PER_DOWNLOAD, - MAX_KEY_FEE: MAX_KEY_FEE, - DEFAULT_WALLET: DEFAULT_WALLET, - NETWORK_INTERFACE: NETWORK_INTERFACE, - NODE_RPC_TIMEOUT: NODE_RPC_TIMEOUT, - PEER_CONNECT_TIMEOUT: PEER_CONNECT_TIMEOUT, - REFLECT_STREAMS: REFLECT_STREAMS, - REFLECTOR_SERVERS: REFLECTOR_SERVERS, - S3_HEADERS_DEPTH: S3_HEADERS_DEPTH, - SAVE_BLOBS: SAVE_BLOBS, - SAVE_FILES: SAVE_FILES, - SHARE_USAGE_DATA: SHARE_USAGE_DATA, - SPLIT_BUCKETS_UNDER_INDEX: SPLIT_BUCKETS_UNDER_INDEX, - STREAMING_GET: STREAMING_GET, - STREAMING_SERVER: STREAMING_SERVER, - TCP_PORT: TCP_PORT, - TRACK_BANDWIDTH: TRACK_BANDWIDTH, - UDP_PORT: UDP_PORT, - USE_UPNP: USE_UPNP, - WALLET_DIR: WALLET_DIR, - WALLETS: WALLETS -}); - -/* - * How to use this file: - * Settings exported from here will trigger the setting to be - * sent to the preference middleware when set using the - * usual setDaemonSettings and clearDaemonSettings methods. - * - * See redux/settings/actions in the app for where this is used. - */ - -const WALLET_SERVERS = LBRYUM_SERVERS; -const SHARE_USAGE_DATA$1 = SHARE_USAGE_DATA; - -var shared_preferences = /*#__PURE__*/Object.freeze({ - WALLET_SERVERS: WALLET_SERVERS, - SHARE_USAGE_DATA: SHARE_USAGE_DATA$1 + AUTH: AUTH, + BACKUP: BACKUP, + CHANNEL: CHANNEL$1, + DISCOVER: DISCOVER, + FILE: FILE, + DOWNLOADED: DOWNLOADED, + PUBLISHED: PUBLISHED, + GET_CREDITS: GET_CREDITS, + HELP: HELP, + INVITE: INVITE, + PUBLISH: PUBLISH$1, + REPORT: REPORT, + REWARDS: REWARDS, + SEARCH: SEARCH, + SEND_CREDITS: SEND_CREDITS, + SETTINGS: SETTINGS, + SHOW: SHOW, + SUBSCRIPTIONS: SUBSCRIPTIONS, + TRANSACTION_HISTORY: TRANSACTION_HISTORY, + HISTORY: HISTORY, + WALLET: WALLET }); const SEARCH_TYPES = { FILE: 'file', CHANNEL: 'channel', - SEARCH: 'search', - TAG: 'tag' + SEARCH: 'search' }; const SEARCH_OPTIONS = { @@ -991,16 +566,6 @@ const SEARCH_OPTIONS = { MEDIA_APPLICATION: 'application' }; -const DEFAULT_FOLLOWED_TAGS = ['art', 'automotive', 'blockchain', 'comedy', 'economics', 'education', 'gaming', 'music', 'news', 'science', 'sports', 'technology']; - -const MATURE_TAGS = ['porn', 'porno', 'nsfw', 'mature', 'xxx', 'sex', 'creampie', 'blowjob', 'handjob', 'vagina', 'boobs', 'big boobs', 'big dick', 'pussy', 'cumshot', 'anal', 'hard fucking', 'ass', 'fuck', 'hentai']; - -const DEFAULT_ENGLISH_KNOWN_TAGS = ['free speech', 'censorship', 'gaming', 'pop culture', 'entertainment', 'technology', 'music', 'funny', 'education', 'learning', 'news', 'gameplay', 'nature', 'beliefs', 'comedy', 'games', 'film & animation', 'game', 'weapons', 'blockchain', 'video game', 'sports', 'walkthrough', 'lbrytvpaidbeta', 'art', 'pc', 'minecraft', 'playthrough', 'economics', 'automotive', 'play', 'tutorial', 'twitch', 'how to', 'ps4', 'bitcoin', 'fortnite', 'commentary', 'lets play', 'fun', 'politics', 'travel', 'food', 'science', 'xbox', 'liberal', 'democrat', 'progressive', 'survival', 'non-profits', 'activism', 'cryptocurrency', 'playstation', 'nintendo', 'government', 'steam', 'podcast', 'gamer', 'horror', 'conservative', 'reaction', 'trailer', 'love', 'cnn', 'republican', 'political', 'hangoutsonair', 'hoa', 'msnbc', 'cbs', 'anime', 'donald trump', 'fiction', 'fox news', 'crypto', 'ethereum', 'call of duty', 'android', 'multiplayer', 'epic', 'rpg', 'adventure', 'secular talk', 'btc', 'atheist', 'atheism', 'video games', 'ps3', 'cod', 'online', 'agnostic', 'movie', 'fps', 'lets', 'mod', 'world', 'reviews', 'sharefactory', 'space', 'pokemon', 'stream', 'hilarious', 'lol', 'sony', 'god', 'dance', 'pvp', 'tech', 'strategy', 'zombies', 'fail', 'film', 'xbox360', 'animation', 'unboxing', 'money', 'wwe', 'mods', 'indie', 'pubg', 'ios', 'history', 'rap', 'mobile', 'trump', 'hack', 'flat earth', 'trap', 'humor', 'vlogging', 'fox', 'news radio', 'facebook', 'edm', 'fitness', 'vaping', 'hip hop', 'secular', 'jesus', 'song', 'vape', 'guitar', 'remix', 'mining', 'daily', 'diy', 'pets', 'videogame', 'death', 'funny moments', 'religion', 'media', 'viral', 'war', 'nbc', 'freedom', 'gold', 'family', 'meme', 'zombie', 'photography', 'chill', 'sniper', 'computer', 'iphone', 'dragon', 'bible', 'pro', 'overwatch', 'litecoin', 'gta', 'house', 'fire', 'bass', 'truth', 'crash', 'mario', 'league of legends', 'wii', 'mmorpg', 'health', 'marvel', 'racing', 'apple', 'instrumental', 'earth', 'destiny', 'satire', 'race', 'training', 'electronic', 'boss', 'roblox', 'family friendly', 'california', 'react', 'christian', 'mmo', 'twitter', 'help', 'star', 'cars', 'random', 'top 10', 'ninja', 'guns', 'linux', 'lessons', 'vegan', 'future', 'dota 2', 'studio', 'star wars', 'shooting', 'nasa', 'rock', 'league', 'subscribe', 'water', 'gta v', 'car', 'samsung', 'music video', 'skyrim', 'dog', 'comics', 'shooter game', 'bo3', 'halloween', 'liberty', 'eth', 'conspiracy', 'knife', 'fashion', 'stories', 'vapor', 'nvidia', 'cute', 'beat', 'nintendo switch', 'fantasy', 'christmas', 'world of warcraft', 'industry', 'cartoon', 'garden', 'animals', 'windows', 'happy', 'magic', 'memes', 'design', 'tactical', 'fallout 4', 'puzzle', 'parody', 'rv', 'beats', 'building', 'disney', 'drone', 'ps2', 'beach', 'metal', 'christianity', 'business', 'mix', 'bo2', 'cover', 'senate', '4k', 'united states', 'final', 'hero', 'playing', 'dlc', 'ubisoft', 'halo', 'pc gaming', 'raw', 'investing', 'online learning', 'software', 'ark', 'mojang', 'console', 'battle royale', 'canon', 'microsoft', 'camping', 'ufo', 'progressive talk', 'switch', 'fpv', 'arcade', 'school', 'driving', 'bodybuilding', 'drama', 'retro', 'science fiction', 'eggs', 'australia', 'modded', 'rainbow', 'gamers', 'resident evil', 'drawing', 'brasil', 'england', 'hillary clinton', 'singing', 'final fantasy', 'hiphop', 'video blog', 'mature', 'quad', 'noob', 'simulation', 'illuminati', 'poetry', 'dayz', 'manga', 'howto', 'insane', 'press', 'special', 'church', 'ico', 'weird', 'libertarian', 'crafting', 'level', 'comic', 'sandbox', 'daily vlog', 'outdoor', 'black ops', 'sound', 'christ', 'duty', 'juvenile fiction', 'pc game', 'how-to', 'ww2', 'creepy', 'artist', 'galaxy', 'destiny 2', 'new music', 'quest', 'lee', 'pacman', 'super smash bros', 'day', 'survival horror', 'patreon', 'bitcoin price', 'trending', 'open world', 'wii u', 'dope', 'reaper', 'sniping', 'dubstep', 'truck', 'planet', 'dc', 'amazon', 'spirituality', 'universe', 'video game culture', 'community', 'cat', 'aliens', 'tourism', 'altcoins', 'style', 'travel trailer', 'rda', 'gun', 'secret', 'far cry 5', 'auto', 'culture', 'dj', 'mw2', 'lord', 'full time rving', 'role-playing game', 'prank', 'grand theft auto', 'master', 'wrestling', 'sci-fi', 'workout', 'ghost', 'fake news', 'silly', 'season', 'bo4', 'trading', 'extreme', 'economy', 'combat', 'plays', 'muslim', 'pubg mobile', 'clips', 'bo1', 'paypal', 'sims', 'exploration', 'light', 'ripple', 'paranormal', 'football', 'capcom', 'rta', 'discord', 'batman', 'player', 'server', 'anarchy', 'military', 'playlist', 'cosplay', 'rv park', 'rant', 'edit', 'germany', 'reading', 'chris', 'flash', 'loot', 'bitcoin gratis', 'game reviews', 'movies', 'stupid', 'latest news', 'squad gameplay', 'guru', 'timelapse', 'black ops 3', 'holiday', 'soul', 'motivation', 'mw3', 'vacation', 'sega', '19th century', 'pop', 'sims 4', 'post', 'smok', 'island', 'scotland', 'paladins', 'warrior', 'creepypasta', 'role-playing', 'solar', 'vr', 'animal', 'peace', 'consciousness', 'dota', 'audio', 'mass effect', 'humour', 'first look', 'videogames', 'future bass', 'freestyle', 'hardcore', 'portugal', 'dantdm', 'teaser', 'lbry', 'coronavirus', '2020protests', 'covidcuts', 'covid-19']; - -const DEFAULT_SPANISH_KNOWN_TAGS = ['español', 'tecnología', 'criptomonedas', 'economía', 'bitcoin', 'educación', 'videojuegos', 'música', 'noticias', 'ciencia', 'deportes', 'latinoamérica', 'latam', 'conspiración', 'humor', 'política', 'tutoriales']; - -const DEFAULT_KNOWN_TAGS = [...DEFAULT_ENGLISH_KNOWN_TAGS, ...DEFAULT_SPANISH_KNOWN_TAGS]; - // const CHECK_DAEMON_STARTED_TRY_NUMBER = 200; @@ -1013,34 +578,22 @@ const Lbry = { isConnected: false, connectPromise: null, daemonConnectionString: 'http://localhost:5279', - alternateConnectionString: '', - methodsUsingAlternateConnectionString: [], - apiRequestHeaders: { 'Content-Type': 'application/json-rpc' }, // Allow overriding daemon connection string (e.g. to `/api/proxy` for lbryweb) setDaemonConnectionString: value => { Lbry.daemonConnectionString = value; }, - setApiHeader: (key, value) => { - Lbry.apiRequestHeaders = Object.assign(Lbry.apiRequestHeaders, { [key]: value }); - }, - - unsetApiHeader: key => { - Object.keys(Lbry.apiRequestHeaders).includes(key) && delete Lbry.apiRequestHeaders['key']; - }, // Allow overriding Lbry methods overrides: {}, setOverride: (methodName, newMethod) => { Lbry.overrides[methodName] = newMethod; }, - getApiRequestHeaders: () => Lbry.apiRequestHeaders, // Returns a human readable media type based on the content type or extension of a file that is returned by the sdk - getMediaType: (contentType, fileName) => { - if (fileName) { - const formats = [[/\.(mp4|m4v|webm|flv|f4v|ogv)$/i, 'video'], [/\.(mp3|m4a|aac|wav|flac|ogg|opus)$/i, 'audio'], [/\.(jpeg|jpg|png|gif|svg|webp)$/i, 'image'], [/\.(h|go|ja|java|js|jsx|c|cpp|cs|css|rb|scss|sh|php|py)$/i, 'script'], [/\.(html|json|csv|txt|log|md|markdown|docx|pdf|xml|yml|yaml)$/i, 'document'], [/\.(pdf|odf|doc|docx|epub|org|rtf)$/i, 'e-book'], [/\.(stl|obj|fbx|gcode)$/i, '3D-file'], [/\.(cbr|cbt|cbz)$/i, 'comic-book'], [/\.(lbry)$/i, 'application']]; - + getMediaType: (contentType, extname) => { + if (extname) { + const formats = [[/^(mp4|m4v|webm|flv|f4v|ogv)$/i, 'video'], [/^(mp3|m4a|aac|wav|flac|ogg|opus)$/i, 'audio'], [/^(html|htm|xml|pdf|odf|doc|docx|md|markdown|txt|epub|org)$/i, 'document'], [/^(stl|obj|fbx|gcode)$/i, '3D-file']]; const res = formats.reduce((ret, testpair) => { switch (testpair[0].test(ret)) { case true: @@ -1048,14 +601,13 @@ const Lbry = { default: return ret; } - }, fileName); - return res === fileName ? 'unknown' : res; + }, extname); + return res === extname ? 'unknown' : res; } else if (contentType) { // $FlowFixMe return (/^[^/]+/.exec(contentType)[0] ); } - return 'unknown'; }, @@ -1070,18 +622,14 @@ const Lbry = { // Claim fetching and manipulation resolve: params => daemonCallWithResult('resolve', params), get: params => daemonCallWithResult('get', params), + publish: params => daemonCallWithResult('publish', params), claim_search: params => daemonCallWithResult('claim_search', params), claim_list: params => daemonCallWithResult('claim_list', params), channel_create: params => daemonCallWithResult('channel_create', params), - channel_update: params => daemonCallWithResult('channel_update', params), - channel_import: params => daemonCallWithResult('channel_import', params), channel_list: params => daemonCallWithResult('channel_list', params), stream_abandon: params => daemonCallWithResult('stream_abandon', params), - stream_list: params => daemonCallWithResult('stream_list', params), channel_abandon: params => daemonCallWithResult('channel_abandon', params), support_create: params => daemonCallWithResult('support_create', params), - support_list: params => daemonCallWithResult('support_list', params), - stream_repost: params => daemonCallWithResult('stream_repost', params), // File fetching and manipulation file_list: (params = {}) => daemonCallWithResult('file_list', params), @@ -1091,34 +639,22 @@ const Lbry = { blob_list: (params = {}) => daemonCallWithResult('blob_list', params), // Wallet utilities - wallet_balance: (params = {}) => daemonCallWithResult('wallet_balance', params), - wallet_decrypt: () => daemonCallWithResult('wallet_decrypt', {}), - wallet_encrypt: (params = {}) => daemonCallWithResult('wallet_encrypt', params), - wallet_unlock: (params = {}) => daemonCallWithResult('wallet_unlock', params), - wallet_list: (params = {}) => daemonCallWithResult('wallet_list', params), - wallet_send: (params = {}) => daemonCallWithResult('wallet_send', params), - wallet_status: (params = {}) => daemonCallWithResult('wallet_status', params), + account_balance: (params = {}) => daemonCallWithResult('account_balance', params), + account_decrypt: () => daemonCallWithResult('account_decrypt', {}), + account_encrypt: (params = {}) => daemonCallWithResult('account_encrypt', params), + account_unlock: (params = {}) => daemonCallWithResult('account_unlock', params), + account_list: (params = {}) => daemonCallWithResult('account_list', params), + account_send: (params = {}) => daemonCallWithResult('account_send', params), address_is_mine: (params = {}) => daemonCallWithResult('address_is_mine', params), address_unused: (params = {}) => daemonCallWithResult('address_unused', params), - address_list: (params = {}) => daemonCallWithResult('address_list', params), transaction_list: (params = {}) => daemonCallWithResult('transaction_list', params), utxo_release: (params = {}) => daemonCallWithResult('utxo_release', params), - support_abandon: (params = {}) => daemonCallWithResult('support_abandon', params), - purchase_list: (params = {}) => daemonCallWithResult('purchase_list', params), sync_hash: (params = {}) => daemonCallWithResult('sync_hash', params), sync_apply: (params = {}) => daemonCallWithResult('sync_apply', params), - // Preferences - preference_get: (params = {}) => daemonCallWithResult('preference_get', params), - preference_set: (params = {}) => daemonCallWithResult('preference_set', params), - - // Comments comment_list: (params = {}) => daemonCallWithResult('comment_list', params), comment_create: (params = {}) => daemonCallWithResult('comment_create', params), - comment_hide: (params = {}) => daemonCallWithResult('comment_hide', params), - comment_abandon: (params = {}) => daemonCallWithResult('comment_abandon', params), - comment_update: (params = {}) => daemonCallWithResult('comment_update', params), // Connect to the sdk connect: () => { @@ -1144,15 +680,7 @@ const Lbry = { // Flow thinks this could be empty, but it will always reuturn a promise // $FlowFixMe return Lbry.connectPromise; - }, - - publish: (params = {}) => new Promise((resolve, reject) => { - if (Lbry.overrides.publish) { - Lbry.overrides.publish(params).then(resolve, reject); - } else { - apiCall('publish', params, resolve, reject); - } - }) + } }; function checkAndParse(response) { @@ -1175,7 +703,6 @@ function apiCall(method, params, resolve, reject) { const counter = new Date().getTime(); const options = { method: 'POST', - headers: Lbry.apiRequestHeaders, body: JSON.stringify({ jsonrpc: '2.0', method, @@ -1184,8 +711,7 @@ function apiCall(method, params, resolve, reject) { }) }; - const connectionString = Lbry.methodsUsingAlternateConnectionString.includes(method) ? Lbry.alternateConnectionString : Lbry.daemonConnectionString; - return fetch(connectionString + '?m=' + method, options).then(checkAndParse).then(response => { + return fetch(Lbry.daemonConnectionString, options).then(checkAndParse).then(response => { const error = response.error || response.result && response.result.error; if (error) { @@ -1219,169 +745,6 @@ const lbryProxy = new Proxy(Lbry, { // -const CHECK_LBRYFIRST_STARTED_TRY_NUMBER = 200; -// -// Basic LBRYFIRST connection config -// Offers a proxy to call LBRYFIRST methods - -// -const LbryFirst = { - isConnected: false, - connectPromise: null, - lbryFirstConnectionString: 'http://localhost:1337/rpc', - apiRequestHeaders: { 'Content-Type': 'application/json' }, - - // Allow overriding lbryFirst connection string (e.g. to `/api/proxy` for lbryweb) - setLbryFirstConnectionString: value => { - LbryFirst.lbryFirstConnectionString = value; - }, - - setApiHeader: (key, value) => { - LbryFirst.apiRequestHeaders = Object.assign(LbryFirst.apiRequestHeaders, { [key]: value }); - }, - - unsetApiHeader: key => { - Object.keys(LbryFirst.apiRequestHeaders).includes(key) && delete LbryFirst.apiRequestHeaders['key']; - }, - // Allow overriding Lbry methods - overrides: {}, - setOverride: (methodName, newMethod) => { - LbryFirst.overrides[methodName] = newMethod; - }, - getApiRequestHeaders: () => LbryFirst.apiRequestHeaders, - - // - // LbryFirst Methods - // - status: (params = {}) => lbryFirstCallWithResult('status', params), - stop: () => lbryFirstCallWithResult('stop', {}), - version: () => lbryFirstCallWithResult('version', {}), - - // Upload to youtube - upload: (params = {}) => { - // Only upload when originally publishing for now - if (!params.file_path) { - return Promise.resolve(); - } - - const uploadParams = { - Title: params.title, - Description: params.description, - FilePath: params.file_path, - Category: '', - Keywords: '' - }; - - return lbryFirstCallWithResult('youtube.Upload', uploadParams); - }, - - hasYTAuth: token => { - const hasYTAuthParams = {}; - hasYTAuthParams.AuthToken = token; - return lbryFirstCallWithResult('youtube.HasAuth', hasYTAuthParams); - }, - - ytSignup: () => { - const emptyParams = {}; - return lbryFirstCallWithResult('youtube.Signup', emptyParams); - }, - - remove: () => { - const emptyParams = {}; - return lbryFirstCallWithResult('youtube.Remove', emptyParams); - }, - - // Connect to lbry-first - connect: () => { - if (LbryFirst.connectPromise === null) { - LbryFirst.connectPromise = new Promise((resolve, reject) => { - let tryNum = 0; - // Check every half second to see if the lbryFirst is accepting connections - function checkLbryFirstStarted() { - tryNum += 1; - LbryFirst.status().then(resolve).catch(() => { - if (tryNum <= CHECK_LBRYFIRST_STARTED_TRY_NUMBER) { - setTimeout(checkLbryFirstStarted, tryNum < 50 ? 400 : 1000); - } else { - reject(new Error('Unable to connect to LBRY')); - } - }); - } - - checkLbryFirstStarted(); - }); - } - - // Flow thinks this could be empty, but it will always return a promise - // $FlowFixMe - return LbryFirst.connectPromise; - } -}; - -function checkAndParse$1(response) { - if (response.status >= 200 && response.status < 300) { - return response.json(); - } - return response.json().then(json => { - let error; - if (json.error) { - const errorMessage = typeof json.error === 'object' ? json.error.message : json.error; - error = new Error(errorMessage); - } else { - error = new Error('Protocol error with unknown response signature'); - } - return Promise.reject(error); - }); -} - -function apiCall$1(method, params, resolve, reject) { - const counter = new Date().getTime(); - const paramsArray = [params]; - const options = { - method: 'POST', - headers: LbryFirst.apiRequestHeaders, - body: JSON.stringify({ - jsonrpc: '2.0', - method, - params: paramsArray, - id: counter - }) - }; - - return fetch(LbryFirst.lbryFirstConnectionString, options).then(checkAndParse$1).then(response => { - const error = response.error || response.result && response.result.error; - - if (error) { - return reject(error); - } - return resolve(response.result); - }).catch(reject); -} - -function lbryFirstCallWithResult(name, params = {}) { - return new Promise((resolve, reject) => { - apiCall$1(name, params, result => { - resolve(result); - }, reject); - }); -} - -// This is only for a fallback -// If there is a LbryFirst method that is being called by an app, it should be added to /flow-typed/LbryFirst.js -const lbryFirstProxy = new Proxy(LbryFirst, { - get(target, name) { - if (name in target) { - return target[name]; - } - - return (params = {}) => new Promise((resolve, reject) => { - apiCall$1(name, params, resolve, reject); - }); - } -}); - -// - const DEFAULT_SEARCH_RESULT_FROM = 0; const DEFAULT_SEARCH_SIZE = 20; @@ -1410,167 +773,113 @@ function toQueryString(params) { return parts.join('&'); } -const getSearchQueryString = (query, options = {}) => { +const getSearchQueryString = (query, options = {}, includeUserOptions = false) => { const encodedQuery = encodeURIComponent(query); const queryParams = [`s=${encodedQuery}`, `size=${options.size || DEFAULT_SEARCH_SIZE}`, `from=${options.from || DEFAULT_SEARCH_RESULT_FROM}`]; - const { isBackgroundSearch } = options; - const includeUserOptions = typeof isBackgroundSearch === 'undefined' ? false : !isBackgroundSearch; if (includeUserOptions) { - const claimType = options[SEARCH_OPTIONS.CLAIM_TYPE]; - if (claimType) { - queryParams.push(`claimType=${claimType}`); + queryParams.push(`claimType=${options[SEARCH_OPTIONS.CLAIM_TYPE]}`); - // If they are only searching for channels, strip out the media info - if (!claimType.includes(SEARCH_OPTIONS.INCLUDE_CHANNELS)) { - queryParams.push(`mediaType=${[SEARCH_OPTIONS.MEDIA_FILE, SEARCH_OPTIONS.MEDIA_AUDIO, SEARCH_OPTIONS.MEDIA_VIDEO, SEARCH_OPTIONS.MEDIA_TEXT, SEARCH_OPTIONS.MEDIA_IMAGE, SEARCH_OPTIONS.MEDIA_APPLICATION].reduce((acc, currentOption) => options[currentOption] ? `${acc}${currentOption},` : acc, '')}`); - } + // If they are only searching for channels, strip out the media info + if (options[SEARCH_OPTIONS.CLAIM_TYPE] !== SEARCH_OPTIONS.INCLUDE_CHANNELS) { + queryParams.push(`mediaType=${[SEARCH_OPTIONS.MEDIA_FILE, SEARCH_OPTIONS.MEDIA_AUDIO, SEARCH_OPTIONS.MEDIA_VIDEO, SEARCH_OPTIONS.MEDIA_TEXT, SEARCH_OPTIONS.MEDIA_IMAGE, SEARCH_OPTIONS.MEDIA_APPLICATION].reduce((acc, currentOption) => options[currentOption] ? `${acc}${currentOption},` : acc, '')}`); } } - const additionalOptions = {}; - const { related_to } = options; - const { nsfw } = options; - if (related_to) additionalOptions['related_to'] = related_to; - if (typeof nsfw !== 'undefined') additionalOptions['nsfw'] = nsfw; - - if (additionalOptions) { - Object.keys(additionalOptions).forEach(key => { - const option = additionalOptions[key]; - queryParams.push(`${key}=${option}`); - }); - } - return queryParams.join('&'); }; var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; -function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } const channelNameMinLength = 1; const claimIdMaxLength = 40; -// see https://spec.lbry.com/#urls -const regexInvalidURI = /[ =&#:$@%?;/\\"<>%\{\}|^~[\]`\u{0000}-\u{0008}\u{000b}-\u{000c}\u{000e}-\u{001F}\u{D800}-\u{DFFF}\u{FFFE}-\u{FFFF}]/u; +const regexInvalidURI = /[^A-Za-z0-9-]/g; const regexAddress = /^(b|r)(?=[^0OIl]{32,33})[0-9A-Za-z]{32,33}$/; -const regexPartProtocol = '^((?:lbry://)?)'; -const regexPartStreamOrChannelName = '([^:$#/]*)'; -const regexPartModifierSeparator = '([:$#]?)([^/]*)'; -const queryStringBreaker = '^([\\S]+)([?][\\S]*)'; -const separateQuerystring = new RegExp(queryStringBreaker); /** * Parses a LBRY name into its component parts. Throws errors with user-friendly * messages for invalid names. * + * N.B. that "name" indicates the value in the name position of the URI. For + * claims for channel content, this will actually be the channel name, and + * the content name is in the path (e.g. lbry://@channel/content) + * + * In most situations, you'll want to use the contentName and channelName keys + * and ignore the name key. + * * Returns a dictionary with keys: - * - path (string) + * - name (string): The value in the "name" position in the URI. Note that this + * could be either content name or channel name; see above. + * - path (string, if persent) + * - claimSequence (int, if present) + * - bidPosition (int, if present) + * - claimId (string, if present) * - isChannel (boolean) - * - streamName (string, if present) - * - streamClaimId (string, if present) - * - channelName (string, if present) - * - channelClaimId (string, if present) - * - primaryClaimSequence (int, if present) - * - secondaryClaimSequence (int, if present) - * - primaryBidPosition (int, if present) - * - secondaryBidPosition (int, if present) + * - contentName (string): For anon claims, the name; for channel claims, the path + * - channelName (string, if present): Channel name without @ */ - -function parseURI(URL, requireProto = false) { +function parseURI(URI, requireProto = false) { // Break into components. Empty sub-matches are converted to null + const componentsRegex = new RegExp('^((?:lbry://)?)' + // protocol + '([^:$#/]*)' + // claim name (stops at the first separator or end) + '([:$#]?)([^/]*)' + // modifier separator, modifier (stops at the first path separator or end) + '(/?)(.*)' // path separator, path + ); + const [proto, claimName, modSep, modVal, pathSep, path] = componentsRegex.exec(URI).slice(1).map(match => match || null); - const componentsRegex = new RegExp(regexPartProtocol + // protocol - regexPartStreamOrChannelName + // stream or channel name (stops at the first separator or end) - regexPartModifierSeparator + // modifier separator, modifier (stops at the first path separator or end) - '(/?)' + // path separator, there should only be one (optional) slash to separate the stream and channel parts - regexPartStreamOrChannelName + regexPartModifierSeparator); - // chop off the querystring first - let QSStrippedURL, qs; - const qsRegexResult = separateQuerystring.exec(URL); - if (qsRegexResult) { - [QSStrippedURL, qs] = qsRegexResult.slice(1).map(match => match || null); - } - - const cleanURL = QSStrippedURL || URL; - const regexMatch = componentsRegex.exec(cleanURL) || []; - const [proto, ...rest] = regexMatch.slice(1).map(match => match || null); - const path = rest.join(''); - const [streamNameOrChannelName, primaryModSeparator, primaryModValue, pathSep, possibleStreamName, secondaryModSeparator, secondaryModValue] = rest; - const searchParams = new URLSearchParams(qs || ''); - const startTime = searchParams.get('t'); + let contentName; // Validate protocol if (requireProto && !proto) { - throw new Error(__('LBRY URLs must include a protocol prefix (lbry://).')); + throw new Error(__('LBRY URIs must include a protocol prefix (lbry://).')); } // Validate and process name - if (!streamNameOrChannelName) { - throw new Error(__('URL does not include name.')); + if (!claimName) { + throw new Error(__('URI does not include name.')); } - rest.forEach(urlPiece => { - if (urlPiece && urlPiece.includes(' ')) { - console.error('URL can not include a space'); - } - }); + const isChannel = claimName.startsWith('@'); + const channelName = isChannel ? claimName.slice(1) : claimName; - const includesChannel = streamNameOrChannelName.startsWith('@'); - const isChannel = streamNameOrChannelName.startsWith('@') && !possibleStreamName; - const channelName = includesChannel && streamNameOrChannelName.slice(1); - - if (includesChannel) { + if (isChannel) { if (!channelName) { throw new Error(__('No channel name after @.')); } if (channelName.length < channelNameMinLength) { - throw new Error(__(`Channel names must be at least %channelNameMinLength% characters.`, { - channelNameMinLength - })); + throw new Error(__(`Channel names must be at least %s characters.`, channelNameMinLength)); } + + contentName = path; } - // Validate and process modifier - const [primaryClaimId, primaryClaimSequence, primaryBidPosition] = parseURIModifier(primaryModSeparator, primaryModValue); - const [secondaryClaimId, secondaryClaimSequence, secondaryBidPosition] = parseURIModifier(secondaryModSeparator, secondaryModValue); - const streamName = includesChannel ? possibleStreamName : streamNameOrChannelName; - const streamClaimId = includesChannel ? secondaryClaimId : primaryClaimId; - const channelClaimId = includesChannel && primaryClaimId; + const nameBadChars = (channelName || claimName).match(regexInvalidURI); + if (nameBadChars) { + throw new Error(__(`Invalid character %s in name: %s.`, nameBadChars.length === 1 ? '' : 's', nameBadChars.join(', '))); + } - return _extends({ - isChannel, - path - }, streamName ? { streamName } : {}, streamClaimId ? { streamClaimId } : {}, channelName ? { channelName } : {}, channelClaimId ? { channelClaimId } : {}, primaryClaimSequence ? { primaryClaimSequence: parseInt(primaryClaimSequence, 10) } : {}, secondaryClaimSequence ? { secondaryClaimSequence: parseInt(secondaryClaimSequence, 10) } : {}, primaryBidPosition ? { primaryBidPosition: parseInt(primaryBidPosition, 10) } : {}, secondaryBidPosition ? { secondaryBidPosition: parseInt(secondaryBidPosition, 10) } : {}, startTime ? { startTime: parseInt(startTime, 10) } : {}, { - - // The values below should not be used for new uses of parseURI - // They will not work properly with canonical_urls - claimName: streamNameOrChannelName, - claimId: primaryClaimId - }, streamName ? { contentName: streamName } : {}, qs ? { queryString: qs } : {}); -} - -function parseURIModifier(modSeperator, modValue) { + // Validate and process modifier (claim ID, bid position or claim sequence) let claimId; let claimSequence; let bidPosition; - - if (modSeperator) { - if (!modValue) { - throw new Error(__(`No modifier provided after separator %modSeperator%.`, { modSeperator })); + if (modSep) { + if (!modVal) { + throw new Error(__(`No modifier provided after separator %s.`, modSep)); } - if (modSeperator === '#') { - claimId = modValue; - } else if (modSeperator === ':') { - claimSequence = modValue; - } else if (modSeperator === '$') { - bidPosition = modValue; + if (modSep === '#') { + claimId = modVal; + } else if (modSep === ':') { + claimSequence = modVal; + } else if (modSep === '$') { + bidPosition = modVal; } } if (claimId && (claimId.length > claimIdMaxLength || !claimId.match(/^[0-9a-f]+$/))) { - throw new Error(__(`Invalid claim ID %claimId%.`, { claimId })); + throw new Error(__(`Invalid claim ID %s.`, claimId)); } if (claimSequence && !claimSequence.match(/^-?[1-9][0-9]*$/)) { @@ -1581,7 +890,27 @@ function parseURIModifier(modSeperator, modValue) { throw new Error(__('Bid position must be a number.')); } - return [claimId, claimSequence, bidPosition]; + // Validate and process path + if (path) { + if (!isChannel) { + throw new Error(__('Only channel URIs may have a path.')); + } + + const pathBadChars = path.match(regexInvalidURI); + if (pathBadChars) { + throw new Error(__(`Invalid character in path: %s`, pathBadChars.join(', '))); + } + + contentName = path; + } else if (pathSep) { + throw new Error(__('No path provided after /')); + } + + return _extends({ + claimName, + path, + isChannel + }, contentName ? { contentName } : {}, channelName ? { channelName } : {}, claimSequence ? { claimSequence: parseInt(claimSequence, 10) } : {}, bidPosition ? { bidPosition: parseInt(bidPosition, 10) } : {}, claimId ? { claimId } : {}, path ? { path } : {}); } /** @@ -1589,110 +918,68 @@ function parseURIModifier(modSeperator, modValue) { * * The channelName key will accept names with or without the @ prefix. */ -function buildURI(UrlObj, includeProto = true, protoDefault = 'lbry://') { - const { - streamName, - streamClaimId, - channelName, - channelClaimId, - primaryClaimSequence, - primaryBidPosition, - secondaryClaimSequence, - secondaryBidPosition, - startTime - } = UrlObj, - deprecatedParts = _objectWithoutProperties(UrlObj, ['streamName', 'streamClaimId', 'channelName', 'channelClaimId', 'primaryClaimSequence', 'primaryBidPosition', 'secondaryClaimSequence', 'secondaryBidPosition', 'startTime']); - const { claimId, claimName, contentName } = deprecatedParts; +function buildURI(URIObj, includeProto = true, protoDefault = 'lbry://') { + const { claimId, claimSequence, bidPosition, contentName, channelName } = URIObj; - if (!claimName && !channelName && !streamName) { - console.error(__("'claimName', 'channelName', and 'streamName' are all empty. One must be present to build a url.")); + let { claimName, path } = URIObj; + + if (channelName) { + const channelNameFormatted = channelName.startsWith('@') ? channelName : `@${channelName}`; + if (!claimName) { + claimName = channelNameFormatted; + } else if (claimName !== channelNameFormatted) { + throw new Error(__('Received a channel content URI, but claim name and channelName do not match. "name" represents the value in the name position of the URI (lbry://name...), which for channel content will be the channel name. In most cases, to construct a channel URI you should just pass channelName and contentName.')); + } } - const formattedChannelName = channelName && (channelName.startsWith('@') ? channelName : `@${channelName}`); - const primaryClaimName = claimName || contentName || formattedChannelName || streamName; - const primaryClaimId = claimId || (formattedChannelName ? channelClaimId : streamClaimId); - const secondaryClaimName = !claimName && contentName || (formattedChannelName ? streamName : null); - const secondaryClaimId = secondaryClaimName && streamClaimId; - - return (includeProto ? protoDefault : '') + - // primaryClaimName will always exist here because we throw above if there is no "name" value passed in - // $FlowFixMe - primaryClaimName + (primaryClaimId ? `#${primaryClaimId}` : '') + (primaryClaimSequence ? `:${primaryClaimSequence}` : '') + (primaryBidPosition ? `${primaryBidPosition}` : '') + (secondaryClaimName ? `/${secondaryClaimName}` : '') + (secondaryClaimId ? `#${secondaryClaimId}` : '') + (secondaryClaimSequence ? `:${secondaryClaimSequence}` : '') + (secondaryBidPosition ? `${secondaryBidPosition}` : '') + (startTime ? `?t=${startTime}` : ''); -} - -/* Takes a parseable LBRY URL and converts it to standard, canonical format */ -function normalizeURI(URL) { - const { - streamName, - streamClaimId, - channelName, - channelClaimId, - primaryClaimSequence, - primaryBidPosition, - secondaryClaimSequence, - secondaryBidPosition, - startTime - } = parseURI(URL); - - return buildURI({ - streamName, - streamClaimId, - channelName, - channelClaimId, - primaryClaimSequence, - primaryBidPosition, - secondaryClaimSequence, - secondaryBidPosition, - startTime - }); -} - -function isURIValid(URL) { - try { - parseURI(normalizeURI(URL)); - } catch (error) { - return false; + if (contentName) { + if (!claimName) { + claimName = contentName; + } else if (!path) { + path = contentName; + } + if (path && path !== contentName) { + throw new Error(__('Path and contentName do not match. Only one is required; most likely you wanted contentName.')); + } } - return true; + return (includeProto ? protoDefault : '') + claimName + (claimId ? `#${claimId}` : '') + (claimSequence ? `:${claimSequence}` : '') + (bidPosition ? `${bidPosition}` : '') + (path ? `/${path}` : ''); } -function isNameValid(claimName) { - return !regexInvalidURI.test(claimName); +/* Takes a parseable LBRY URI and converts it to standard, canonical format */ +function normalizeURI(URI) { + const { claimName, path, bidPosition, claimSequence, claimId } = parseURI(URI); + return buildURI({ claimName, path, claimSequence, bidPosition, claimId }); } -function isURIClaimable(URL) { +function isURIValid(URI) { let parts; try { - parts = parseURI(normalizeURI(URL)); + parts = parseURI(normalizeURI(URI)); } catch (error) { return false; } - - return parts && parts.streamName && !parts.streamClaimId && !parts.isChannel; + return parts && parts.claimName; } -function convertToShareLink(URL) { - const { - streamName, - streamClaimId, - channelName, - channelClaimId, - primaryBidPosition, - primaryClaimSequence, - secondaryBidPosition, - secondaryClaimSequence - } = parseURI(URL); - return buildURI({ - streamName, - streamClaimId, - channelName, - channelClaimId, - primaryBidPosition, - primaryClaimSequence, - secondaryBidPosition, - secondaryClaimSequence - }, true, 'https://open.lbry.com/'); +function isNameValid(claimName, checkCase = true) { + const regexp = new RegExp('^[a-z0-9-]+$', checkCase ? '' : 'i'); + return regexp.test(claimName); +} + +function isURIClaimable(URI) { + let parts; + try { + parts = parseURI(normalizeURI(URI)); + } catch (error) { + return false; + } + return parts && parts.claimName && !parts.claimId && !parts.bidPosition && !parts.claimSequence && !parts.isChannel && !parts.path; +} + +function convertToShareLink(URI) { + const { claimName, path, bidPosition, claimSequence, claimId } = parseURI(URI); + return buildURI({ claimName, path, claimSequence, bidPosition, claimId }, true, 'https://open.lbry.io/'); } var _extends$1 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; @@ -1713,48 +1000,37 @@ const makeSelectSearchUris = query => // replace statement below is kind of ugly, and repeated in doSearch action reselect.createSelector(selectSearchUrisByQuery, byQuery => byQuery[query ? query.replace(/^lbry:\/\//i, '').replace(/\//, ' ') : query]); -const selectResolvedSearchResultsByQuery = reselect.createSelector(selectState, state => state.resolvedResultsByQuery); - -const selectResolvedSearchResultsByQueryLastPageReached = reselect.createSelector(selectState, state => state.resolvedResultsByQueryLastPageReached); - -const makeSelectResolvedSearchResults = query => -// replace statement below is kind of ugly, and repeated in doSearch action -reselect.createSelector(selectResolvedSearchResultsByQuery, byQuery => byQuery[query ? query.replace(/^lbry:\/\//i, '').replace(/\//, ' ') : query]); - -const makeSelectResolvedSearchResultsLastPageReached = query => -// replace statement below is kind of ugly, and repeated in doSearch action -reselect.createSelector(selectResolvedSearchResultsByQueryLastPageReached, byQuery => byQuery[query ? query.replace(/^lbry:\/\//i, '').replace(/\//, ' ') : query]); - const selectSearchBarFocused = reselect.createSelector(selectState, state => state.focused); const selectSearchSuggestions = reselect.createSelector(selectSearchValue, selectSuggestions, (query, suggestions) => { if (!query) { return []; } - const queryIsPrefix = query === 'lbry:' || query === 'lbry:/' || query === 'lbry://' || query === 'lbry://@'; - if (queryIsPrefix) { - // If it is a prefix, wait until something else comes to figure out what to do - return []; - } else if (query.startsWith('lbry://')) { + const queryIsPrefix = query === 'lbry:' || query === 'lbry:/' || query === 'lbry://'; + + if (query.startsWith('lbry://') && query !== 'lbry://') { // If it starts with a prefix, don't show any autocomplete results // They are probably typing/pasting in a lbry uri return [{ value: query, - type: query[7] === '@' ? SEARCH_TYPES.CHANNEL : SEARCH_TYPES.FILE + type: SEARCH_TYPES.FILE }]; + } else if (queryIsPrefix) { + // If it is a prefix, wait until something else comes to figure out what to do + return []; } let searchSuggestions = []; try { const uri = normalizeURI(query); - const { channelName, streamName, isChannel } = parseURI(uri); + const { claimName, isChannel } = parseURI(uri); searchSuggestions.push({ - value: query, + value: claimName, type: SEARCH_TYPES.SEARCH }, { value: uri, - shorthand: isChannel ? channelName : streamName, + shorthand: isChannel ? claimName.slice(1) : claimName, type: isChannel ? SEARCH_TYPES.CHANNEL : SEARCH_TYPES.FILE }); } catch (e) { @@ -1764,22 +1040,17 @@ const selectSearchSuggestions = reselect.createSelector(selectSearchValue, selec }); } - searchSuggestions.push({ - value: query, - type: SEARCH_TYPES.TAG - }); - const apiSuggestions = suggestions[query] || []; if (apiSuggestions.length) { searchSuggestions = searchSuggestions.concat(apiSuggestions.filter(suggestion => suggestion !== query).map(suggestion => { // determine if it's a channel try { const uri = normalizeURI(suggestion); - const { channelName, streamName, isChannel } = parseURI(uri); + const { claimName, isChannel } = parseURI(uri); return { value: uri, - shorthand: isChannel ? channelName : streamName, + shorthand: isChannel ? claimName.slice(1) : claimName, type: isChannel ? SEARCH_TYPES.CHANNEL : SEARCH_TYPES.FILE }; } catch (e) { @@ -1797,251 +1068,15 @@ const selectSearchSuggestions = reselect.createSelector(selectSearchValue, selec // Creates a query string based on the state in the search reducer // Can be overrided by passing in custom sizes/from values for other areas pagination +const makeSelectQueryWithOptions = (customQuery, customSize, customFrom, isBackgroundSearch = false // If it's a background search, don't use the users settings +) => reselect.createSelector(selectSearchValue, selectSearchOptions, (query, options) => { + const size = customSize || options[SEARCH_OPTIONS.RESULT_COUNT]; - -const makeSelectQueryWithOptions = (customQuery, options) => reselect.createSelector(selectSearchValue, selectSearchOptions, (query, defaultOptions) => { - const searchOptions = _extends$1({}, defaultOptions, options); - const queryString = getSearchQueryString(customQuery || query, searchOptions); + const queryString = getSearchQueryString(customQuery || query, _extends$1({}, options, { size, from: customFrom }), !isBackgroundSearch); return queryString; }); -/* eslint-disable */ -// underscore's deep equal function -// https://github.com/jashkenas/underscore/blob/master/underscore.js#L1189 - -function isEqual(a, b, aStack, bStack) { - // Identical objects are equal. `0 === -0`, but they aren't identical. - // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal). - if (a === b) return a !== 0 || 1 / a === 1 / b; - // `null` or `undefined` only equal to itself (strict comparison). - if (a == null || b == null) return false; - // `NaN`s are equivalent, but non-reflexive. - if (a !== a) return b !== b; - // Exhaust primitive checks - var type = typeof a; - if (type !== 'function' && type !== 'object' && typeof b != 'object') return false; - return deepEq(a, b, aStack, bStack); -} - -function deepEq(a, b, aStack, bStack) { - // Compare `[[Class]]` names. - var className = toString.call(a); - if (className !== toString.call(b)) return false; - switch (className) { - // Strings, numbers, regular expressions, dates, and booleans are compared by value. - case '[object RegExp]': - // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i') - case '[object String]': - // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is - // equivalent to `new String("5")`. - return '' + a === '' + b; - case '[object Number]': - // `NaN`s are equivalent, but non-reflexive. - // Object(NaN) is equivalent to NaN. - if (+a !== +a) return +b !== +b; - // An `egal` comparison is performed for other numeric values. - return +a === 0 ? 1 / +a === 1 / b : +a === +b; - case '[object Date]': - case '[object Boolean]': - // Coerce dates and booleans to numeric primitive values. Dates are compared by their - // millisecond representations. Note that invalid dates with millisecond representations - // of `NaN` are not equivalent. - return +a === +b; - case '[object Symbol]': - return SymbolProto.valueOf.call(a) === SymbolProto.valueOf.call(b); - } - - var areArrays = className === '[object Array]'; - if (!areArrays) { - if (typeof a != 'object' || typeof b != 'object') return false; - - // Objects with different constructors are not equivalent, but `Object`s or `Array`s - // from different frames are. - var aCtor = a.constructor, - bCtor = b.constructor; - if (aCtor !== bCtor && !(typeof aCtor === 'function' && aCtor instanceof aCtor && typeof bCtor === 'function' && bCtor instanceof bCtor) && 'constructor' in a && 'constructor' in b) { - return false; - } - } - // Assume equality for cyclic structures. The algorithm for detecting cyclic - // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. - - // Initializing stack of traversed objects. - // It's done here since we only need them for objects and arrays comparison. - aStack = aStack || []; - bStack = bStack || []; - var length = aStack.length; - while (length--) { - // Linear search. Performance is inversely proportional to the number of - // unique nested structures. - if (aStack[length] === a) return bStack[length] === b; - } - - // Add the first object to the stack of traversed objects. - aStack.push(a); - bStack.push(b); - - // Recursively compare objects and arrays. - if (areArrays) { - // Compare array lengths to determine if a deep comparison is necessary. - length = a.length; - if (length !== b.length) return false; - // Deep compare the contents, ignoring non-numeric properties. - while (length--) { - if (!isEqual(a[length], b[length], aStack, bStack)) return false; - } - } else { - // Deep compare objects. - var keys = Object.keys(a), - key; - length = keys.length; - // Ensure that both objects contain the same number of properties before comparing deep equality. - if (Object.keys(b).length !== length) return false; - while (length--) { - // Deep compare each member - key = keys[length]; - if (!(has(b, key) && isEqual(a[key], b[key], aStack, bStack))) return false; - } - } - // Remove the first object from the stack of traversed objects. - aStack.pop(); - bStack.pop(); - return true; -} - -function has(obj, path) { - return obj != null && hasOwnProperty.call(obj, path); -} -/* eslint-enable */ - -var _extends$2 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; - -function extractUserState(rawObj) { - if (rawObj && rawObj.version === '0.1' && rawObj.value) { - const { - subscriptions, - tags, - blocked, - settings, - app_welcome_version, - sharing_3P - } = rawObj.value; - - return _extends$2({}, subscriptions ? { subscriptions } : {}, tags ? { tags } : {}, blocked ? { blocked } : {}, settings ? { settings } : {}, app_welcome_version ? { app_welcome_version } : {}, sharing_3P ? { sharing_3P } : {}); - } - - return {}; -} - -function doPopulateSharedUserState(sharedSettings) { - return dispatch => { - const { - subscriptions, - tags, - blocked, - settings, - app_welcome_version, - sharing_3P - } = extractUserState(sharedSettings); - dispatch({ - type: USER_STATE_POPULATE, - data: { - subscriptions, - tags, - blocked, - settings, - welcomeVersion: app_welcome_version, - allowAnalytics: sharing_3P - } - }); - }; -} - -function doPreferenceSet(key, value, version, success, fail) { - const preference = { - type: typeof value, - version, - value - }; - - const options = { - key, - value: JSON.stringify(preference) - }; - - lbryProxy.preference_set(options).then(() => { - success(preference); - }).catch(() => { - if (fail) { - fail(); - } - }); -} - -function doPreferenceGet(key, success, fail) { - const options = { - key - }; - - lbryProxy.preference_get(options).then(result => { - if (result) { - const preference = result[key]; - return success(preference); - } - - return success(null); - }).catch(err => { - if (fail) { - fail(err); - } - }); -} - -// - -const SHARED_PREFERENCE_KEY = 'shared'; -const SHARED_PREFERENCE_VERSION = '0.1'; -let oldShared = {}; - -const buildSharedStateMiddleware = (actions, sharedStateFilters, sharedStateCb) => ({ getState, dispatch }) => next => action => { - const currentState = getState(); - - // We don't care if sync is disabled here, we always want to backup preferences to the wallet - if (!actions.includes(action.type)) { - return next(action); - } - - const actionResult = next(action); - // Call `getState` after calling `next` to ensure the state has updated in response to the action - const nextState = getState(); - const shared = {}; - - Object.keys(sharedStateFilters).forEach(key => { - const filter = sharedStateFilters[key]; - const { source, property, transform } = filter; - let value = nextState[source][property]; - if (transform) { - value = transform(value); - } - - shared[key] = value; - }); - - if (!isEqual(oldShared, shared)) { - // only update if the preference changed from last call in the same session - oldShared = shared; - doPreferenceSet(SHARED_PREFERENCE_KEY, shared, SHARED_PREFERENCE_VERSION); - } - - if (sharedStateCb) { - // Pass dispatch to the callback to consumers can dispatch actions in response to preference set - sharedStateCb({ dispatch, getState }); - } - - return actionResult; -}; - // function doToast(params) { @@ -2079,74 +1114,301 @@ function doDismissError() { }; } -const selectState$1 = state => state.wallet || {}; +var _extends$2 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; -const selectWalletState = selectState$1; +// -const selectWalletIsEncrypted = reselect.createSelector(selectState$1, state => state.walletIsEncrypted); +const naughtyTags = ['porn', 'nsfw', 'mature', 'xxx'].reduce((acc, tag) => _extends$2({}, acc, { [tag]: true }), {}); -const selectWalletEncryptPending = reselect.createSelector(selectState$1, state => state.walletEncryptPending); +const isClaimNsfw = claim => { + if (!claim) { + throw new Error('No claim passed to isClaimNsfw()'); + } -const selectWalletEncryptSucceeded = reselect.createSelector(selectState$1, state => state.walletEncryptSucceded); + if (!claim.value) { + return false; + } -const selectPendingSupportTransactions = reselect.createSelector(selectState$1, state => state.pendingSupportTransactions); + const tags = claim.value.tags || []; + for (let i = 0; i < tags.length; i += 1) { + const tag = tags[i].toLowerCase(); + if (naughtyTags[tag]) { + return true; + } + } -const selectAbandonClaimSupportError = reselect.createSelector(selectState$1, state => state.abandonClaimSupportError); + return false; +}; -const makeSelectPendingAmountByUri = uri => reselect.createSelector(selectClaimIdsByUri, selectPendingSupportTransactions, (claimIdsByUri, pendingSupports) => { - const uriEntry = Object.entries(claimIdsByUri).find(([u, cid]) => u === uri); - const claimId = uriEntry && uriEntry[1]; - const pendingSupport = claimId && pendingSupports[claimId]; - return pendingSupport ? pendingSupport.effective : undefined; -}); +// -const selectWalletEncryptResult = reselect.createSelector(selectState$1, state => state.walletEncryptResult); +const selectState$1 = state => state.claims || {}; -const selectWalletDecryptPending = reselect.createSelector(selectState$1, state => state.walletDecryptPending); +const selectClaimsById = reselect.createSelector(selectState$1, state => state.byId || {}); -const selectWalletDecryptSucceeded = reselect.createSelector(selectState$1, state => state.walletDecryptSucceded); +const selectCurrentChannelPage = reselect.createSelector(selectState$1, state => state.currentChannelPage || 1); -const selectWalletDecryptResult = reselect.createSelector(selectState$1, state => state.walletDecryptResult); +const selectClaimsByUri = reselect.createSelector(selectState$1, selectClaimsById, (state, byId) => { + const byUri = state.claimsByUri || {}; + const claims = {}; -const selectWalletUnlockPending = reselect.createSelector(selectState$1, state => state.walletUnlockPending); + Object.keys(byUri).forEach(uri => { + const claimId = byUri[uri]; -const selectWalletUnlockSucceeded = reselect.createSelector(selectState$1, state => state.walletUnlockSucceded); - -const selectWalletUnlockResult = reselect.createSelector(selectState$1, state => state.walletUnlockResult); - -const selectWalletLockPending = reselect.createSelector(selectState$1, state => state.walletLockPending); - -const selectWalletLockSucceeded = reselect.createSelector(selectState$1, state => state.walletLockSucceded); - -const selectWalletLockResult = reselect.createSelector(selectState$1, state => state.walletLockResult); - -const selectBalance = reselect.createSelector(selectState$1, state => state.balance); - -const selectTotalBalance = reselect.createSelector(selectState$1, state => state.totalBalance); - -const selectReservedBalance = reselect.createSelector(selectState$1, state => state.reservedBalance); - -const selectClaimsBalance = reselect.createSelector(selectState$1, state => state.claimsBalance); - -const selectSupportsBalance = reselect.createSelector(selectState$1, state => state.supportsBalance); - -const selectTipsBalance = reselect.createSelector(selectState$1, state => state.tipsBalance); - -const selectTransactionsById = reselect.createSelector(selectState$1, state => state.transactions || {}); - -const selectSupportsByOutpoint = reselect.createSelector(selectState$1, state => state.supports || {}); - -const selectTotalSupports = reselect.createSelector(selectSupportsByOutpoint, byOutpoint => { - let total = parseFloat('0.0'); - - Object.values(byOutpoint).forEach(support => { - const { amount } = support; - total = amount ? total + parseFloat(amount) : total; + // NOTE returning a null claim allows us to differentiate between an + // undefined (never fetched claim) and one which just doesn't exist. Not + // the cleanest solution but couldn't think of anything better right now + if (claimId === null) { + claims[uri] = null; + } else { + claims[uri] = byId[claimId]; + } }); - return total; + return claims; }); +const selectAllClaimsByChannel = reselect.createSelector(selectState$1, state => state.claimsByChannel || {}); + +const selectPendingById = reselect.createSelector(selectState$1, state => state.pendingById || {}); + +const selectPendingClaims = reselect.createSelector(selectState$1, state => Object.values(state.pendingById || [])); + +const makeSelectClaimIsPending = uri => reselect.createSelector(selectPendingById, pendingById => { + const { claimId } = parseURI(uri); + return Boolean(pendingById[claimId]); +}); + +const makeSelectPendingByUri = uri => reselect.createSelector(selectPendingById, pendingById => { + const { claimId } = parseURI(uri); + return pendingById[claimId]; +}); + +const makeSelectClaimForUri = uri => reselect.createSelector(selectClaimsByUri, selectPendingById, (byUri, pendingById) => { + // Check if a claim is pending first + // It won't be in claimsByUri because resolving it will return nothing + const { claimId } = parseURI(uri); + const pendingClaim = pendingById[claimId]; + if (pendingClaim) { + return pendingClaim; + } + + return byUri && byUri[normalizeURI(uri)]; +}); + +const selectMyClaimsRaw = reselect.createSelector(selectState$1, state => state.myClaims); + +const selectAbandoningIds = reselect.createSelector(selectState$1, state => Object.keys(state.abandoningById || {})); + +const selectMyActiveClaims = reselect.createSelector(selectMyClaimsRaw, selectAbandoningIds, (claims, abandoningIds) => new Set(claims && claims.map(claim => claim.claim_id).filter(claimId => Object.keys(abandoningIds).indexOf(claimId) === -1))); + +const makeSelectClaimIsMine = rawUri => { + const uri = normalizeURI(rawUri); + return reselect.createSelector(selectClaimsByUri, selectMyActiveClaims, (claims, myClaims) => claims && claims[uri] && claims[uri].claim_id && myClaims.has(claims[uri].claim_id)); +}; + +const selectAllFetchingChannelClaims = reselect.createSelector(selectState$1, state => state.fetchingChannelClaims || {}); + +const makeSelectFetchingChannelClaims = uri => reselect.createSelector(selectAllFetchingChannelClaims, fetching => fetching && fetching[uri]); + +const makeSelectClaimsInChannelForPage = (uri, page) => reselect.createSelector(selectClaimsById, selectAllClaimsByChannel, (byId, allClaims) => { + const byChannel = allClaims[uri] || {}; + const claimIds = byChannel[page || 1]; + + if (!claimIds) return claimIds; + + return claimIds.map(claimId => byId[claimId]); +}); + +const makeSelectClaimsInChannelForCurrentPageState = uri => reselect.createSelector(selectClaimsById, selectAllClaimsByChannel, selectCurrentChannelPage, (byId, allClaims, page) => { + const byChannel = allClaims[uri] || {}; + const claimIds = byChannel[page || 1]; + + if (!claimIds) return claimIds; + + return claimIds.map(claimId => byId[claimId]); +}); + +const makeSelectMetadataForUri = uri => reselect.createSelector(makeSelectClaimForUri(uri), claim => { + const metadata = claim && claim.value; + return metadata || (claim === undefined ? undefined : null); +}); + +const makeSelectTitleForUri = uri => reselect.createSelector(makeSelectMetadataForUri(uri), metadata => metadata && metadata.title); + +const makeSelectContentTypeForUri = uri => reselect.createSelector(makeSelectClaimForUri(uri), claim => { + const source = claim && claim.value && claim.value.source; + return source ? source.media_type : undefined; +}); + +const makeSelectThumbnailForUri = uri => reselect.createSelector(makeSelectClaimForUri(uri), claim => { + const thumbnail = claim && claim.value && claim.value.thumbnail; + return thumbnail ? thumbnail.url : undefined; +}); + +const selectIsFetchingClaimListMine = reselect.createSelector(selectState$1, state => state.isFetchingClaimListMine); + +const selectMyClaims = reselect.createSelector(selectMyActiveClaims, selectClaimsById, selectAbandoningIds, selectPendingClaims, (myClaimIds, byId, abandoningIds, pendingClaims) => { + const claims = []; + + myClaimIds.forEach(id => { + const claim = byId[id]; + + if (claim && abandoningIds.indexOf(id) === -1) claims.push(claim); + }); + + return [...claims, ...pendingClaims]; +}); + +const selectMyClaimsWithoutChannels = reselect.createSelector(selectMyClaims, myClaims => myClaims.filter(claim => !claim.name.match(/^@/))); + +const selectAllMyClaimsByOutpoint = reselect.createSelector(selectMyClaimsRaw, claims => new Set(claims && claims.length ? claims.map(claim => `${claim.txid}:${claim.nout}`) : null)); + +const selectMyClaimsOutpoints = reselect.createSelector(selectMyClaims, myClaims => { + const outpoints = []; + + myClaims.forEach(claim => outpoints.push(`${claim.txid}:${claim.nout}`)); + + return outpoints; +}); + +const selectFetchingMyChannels = reselect.createSelector(selectState$1, state => state.fetchingMyChannels); + +const selectMyChannelClaims = reselect.createSelector(selectState$1, selectClaimsById, (state, byId) => { + const ids = state.myChannelClaims || []; + const claims = []; + + ids.forEach(id => { + if (byId[id]) { + // I'm not sure why this check is necessary, but it ought to be a quick fix for https://github.com/lbryio/lbry-desktop/issues/544 + claims.push(byId[id]); + } + }); + + return claims; +}); + +const selectResolvingUris = reselect.createSelector(selectState$1, state => state.resolvingUris || []); + +const makeSelectIsUriResolving = uri => reselect.createSelector(selectResolvingUris, resolvingUris => resolvingUris && resolvingUris.indexOf(uri) !== -1); + +const selectPlayingUri = reselect.createSelector(selectState$1, state => state.playingUri); + +const selectChannelClaimCounts = reselect.createSelector(selectState$1, state => state.channelClaimCounts || {}); + +const makeSelectTotalItemsForChannel = uri => reselect.createSelector(selectChannelClaimCounts, byUri => byUri && byUri[uri]); + +const makeSelectTotalPagesForChannel = (uri, pageSize = 10) => reselect.createSelector(selectChannelClaimCounts, byUri => byUri && byUri[uri] && Math.ceil(byUri[uri] / pageSize)); + +const makeSelectNsfwCountFromUris = uris => reselect.createSelector(selectClaimsByUri, claims => uris.reduce((acc, uri) => { + const claim = claims[uri]; + if (claim && isClaimNsfw(claim)) { + return acc + 1; + } + return acc; +}, 0)); + +const makeSelectNsfwCountForChannel = uri => reselect.createSelector(selectClaimsById, selectAllClaimsByChannel, selectCurrentChannelPage, (byId, allClaims, page) => { + const byChannel = allClaims[uri] || {}; + const claimIds = byChannel[page || 1]; + + if (!claimIds) return 0; + + return claimIds.reduce((acc, claimId) => { + const claim = byId[claimId]; + if (isClaimNsfw(claim)) { + return acc + 1; + } + return acc; + }, 0); +}); + +const makeSelectClaimIsNsfw = uri => reselect.createSelector(makeSelectClaimForUri(uri), +// Eventually these will come from some list of tags that are considered adult +// Or possibly come from users settings of what tags they want to hide +// For now, there is just a hard coded list of tags inside `isClaimNsfw` +// selectNaughtyTags(), +claim => { + if (!claim) { + return false; + } + + return isClaimNsfw(claim); +}); + +const makeSelectRecommendedContentForUri = uri => reselect.createSelector(makeSelectClaimForUri(uri), selectSearchUrisByQuery, (claim, searchUrisByQuery) => { + const atVanityURI = !uri.includes('#'); + + let recommendedContent; + if (claim) { + // If we are at a vanity uri, build the full uri so we can properly filter + const currentUri = atVanityURI ? buildURI({ claimId: claim.claim_id, claimName: claim.name }) : uri; + + const { title } = claim.value; + + const searchQuery = getSearchQueryString(title.replace(/\//, ' ')); + + let searchUris = searchUrisByQuery[searchQuery]; + if (searchUris) { + searchUris = searchUris.filter(searchUri => searchUri !== currentUri); + recommendedContent = searchUris; + } + } + + return recommendedContent; +}); + +const makeSelectFirstRecommendedFileForUri = uri => reselect.createSelector(makeSelectRecommendedContentForUri(uri), recommendedContent => recommendedContent ? recommendedContent[0] : null); + +// Returns the associated channel uri for a given claim uri +// accepts a regular claim uri lbry://something +// returns the channel uri that created this claim lbry://@channel +const makeSelectChannelForClaimUri = (uri, includePrefix = false) => reselect.createSelector(makeSelectClaimForUri(uri), claim => { + if (!claim || !claim.signing_channel) { + return null; + } + + const { claim_id: claimId, name } = claim.signing_channel; + let channel = `${name}#${claimId}`; + return includePrefix ? `lbry://${channel}` : channel; +}); + +const selectState$2 = state => state.wallet || {}; + +const selectWalletState = selectState$2; + +const selectWalletIsEncrypted = reselect.createSelector(selectState$2, state => state.walletIsEncrypted); + +const selectWalletEncryptPending = reselect.createSelector(selectState$2, state => state.walletEncryptPending); + +const selectWalletEncryptSucceeded = reselect.createSelector(selectState$2, state => state.walletEncryptSucceded); + +const selectWalletEncryptResult = reselect.createSelector(selectState$2, state => state.walletEncryptResult); + +const selectWalletDecryptPending = reselect.createSelector(selectState$2, state => state.walletDecryptPending); + +const selectWalletDecryptSucceeded = reselect.createSelector(selectState$2, state => state.walletDecryptSucceded); + +const selectWalletDecryptResult = reselect.createSelector(selectState$2, state => state.walletDecryptResult); + +const selectWalletUnlockPending = reselect.createSelector(selectState$2, state => state.walletUnlockPending); + +const selectWalletUnlockSucceeded = reselect.createSelector(selectState$2, state => state.walletUnlockSucceded); + +const selectWalletUnlockResult = reselect.createSelector(selectState$2, state => state.walletUnlockResult); + +const selectWalletLockPending = reselect.createSelector(selectState$2, state => state.walletLockPending); + +const selectWalletLockSucceeded = reselect.createSelector(selectState$2, state => state.walletLockSucceded); + +const selectWalletLockResult = reselect.createSelector(selectState$2, state => state.walletLockResult); + +const selectBalance = reselect.createSelector(selectState$2, state => state.balance); + +const selectTotalBalance = reselect.createSelector(selectState$2, state => state.totalBalance); + +const selectTransactionsById = reselect.createSelector(selectState$2, state => state.transactions); + const selectTransactionItems = reselect.createSelector(selectTransactionsById, byId => { const items = []; @@ -2162,7 +1424,7 @@ const selectTransactionItems = reselect.createSelector(selectTransactionsById, b const append = []; append.push(...tx.claim_info.map(item => Object.assign({}, tx, item, { - type: item.claim_name[0] === '@' ? CHANNEL$1 : PUBLISH$1 + type: item.claim_name[0] === '@' ? CHANNEL : PUBLISH }))); append.push(...tx.support_info.map(item => Object.assign({}, tx, item, { type: !item.is_tip ? SUPPORT : TIP @@ -2171,9 +1433,14 @@ const selectTransactionItems = reselect.createSelector(selectTransactionsById, b append.push(...tx.abandon_info.map(item => Object.assign({}, tx, item, { type: ABANDON }))); if (!append.length) { - append.push(Object.assign({}, tx, { - type: tx.value < 0 ? SPEND : RECEIVE - })); + append.push(...tx.claim_info.map(item => Object.assign({}, tx, item, { + type: item.claim_name[0] === '@' ? CHANNEL : PUBLISH + }))); + append.push(...tx.support_info.map(item => Object.assign({}, tx, item, { + type: !item.is_tip ? SUPPORT : TIP + }))); + append.push(...tx.update_info.map(item => Object.assign({}, tx, item, { type: UPDATE }))); + append.push(...tx.abandon_info.map(item => Object.assign({}, tx, item, { type: ABANDON }))); } items.push(...append.map(item => { @@ -2226,15 +1493,15 @@ const selectRecentTransactions = reselect.createSelector(selectTransactionItems, const selectHasTransactions = reselect.createSelector(selectTransactionItems, transactions => transactions && transactions.length > 0); -const selectIsFetchingTransactions = reselect.createSelector(selectState$1, state => state.fetchingTransactions); +const selectIsFetchingTransactions = reselect.createSelector(selectState$2, state => state.fetchingTransactions); -const selectIsSendingSupport = reselect.createSelector(selectState$1, state => state.sendingSupport); +const selectIsSendingSupport = reselect.createSelector(selectState$2, state => state.sendingSupport); -const selectReceiveAddress = reselect.createSelector(selectState$1, state => state.receiveAddress); +const selectReceiveAddress = reselect.createSelector(selectState$2, state => state.receiveAddress); -const selectGettingNewAddress = reselect.createSelector(selectState$1, state => state.gettingNewAddress); +const selectGettingNewAddress = reselect.createSelector(selectState$2, state => state.gettingNewAddress); -const selectDraftTransaction = reselect.createSelector(selectState$1, state => state.draftTransaction || {}); +const selectDraftTransaction = reselect.createSelector(selectState$2, state => state.draftTransaction || {}); const selectDraftTransactionAmount = reselect.createSelector(selectDraftTransaction, draft => draft.amount); @@ -2242,611 +1509,35 @@ const selectDraftTransactionAddress = reselect.createSelector(selectDraftTransac const selectDraftTransactionError = reselect.createSelector(selectDraftTransaction, draft => draft.error); -const selectBlocks = reselect.createSelector(selectState$1, state => state.blocks); +const selectBlocks = reselect.createSelector(selectState$2, state => state.blocks); -const selectCurrentHeight = reselect.createSelector(selectState$1, state => state.latestBlock); +const selectCurrentHeight = reselect.createSelector(selectState$2, state => state.latestBlock); -const selectTransactionListFilter = reselect.createSelector(selectState$1, state => state.transactionListFilter || ''); - -const selectFilteredTransactions = reselect.createSelector(selectTransactionItems, selectTransactionListFilter, (transactions, filter) => { - return transactions.filter(transaction => { - return filter === ALL || filter === transaction.type; - }); -}); - -const selectTxoPageParams = reselect.createSelector(selectState$1, state => state.txoFetchParams); - -const selectTxoPage = reselect.createSelector(selectState$1, state => state.txoPage && state.txoPage.items || []); - -const selectTxoPageNumber = reselect.createSelector(selectState$1, state => state.txoPage && state.txoPage.page || 1); - -const selectTxoItemCount = reselect.createSelector(selectState$1, state => state.txoPage && state.txoPage.total_items || 1); - -const selectFetchingTxosError = reselect.createSelector(selectState$1, state => state.fetchingTxosError); - -const selectIsFetchingTxos = reselect.createSelector(selectState$1, state => state.fetchingTxos); - -const makeSelectFilteredTransactionsForPage = (page = 1) => reselect.createSelector(selectFilteredTransactions, filteredTransactions => { - const start = (Number(page) - 1) * Number(PAGE_SIZE$1); - const end = Number(page) * Number(PAGE_SIZE$1); - return filteredTransactions && filteredTransactions.length ? filteredTransactions.slice(start, end) : []; -}); - -const makeSelectLatestTransactions = reselect.createSelector(selectTransactionItems, transactions => { - return transactions && transactions.length ? transactions.slice(0, LATEST_PAGE_SIZE) : []; -}); - -const selectFilteredTransactionCount = reselect.createSelector(selectFilteredTransactions, filteredTransactions => filteredTransactions.length); - -const selectIsWalletReconnecting = reselect.createSelector(selectState$1, state => state.walletReconnecting); - -var _extends$3 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; - -function _objectWithoutProperties$1(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } - -const matureTagMap = MATURE_TAGS.reduce((acc, tag) => _extends$3({}, acc, { [tag]: true }), {}); - -const isClaimNsfw = claim => { - if (!claim) { - throw new Error('No claim passed to isClaimNsfw()'); +const makeSelectBlockDate = block => reselect.createSelector(selectBlocks, selectCurrentHeight, (blocks, latestBlock) => { + // If we have the block data, look at the actual date, + // If not, try to simulate it based on 2.5 minute blocks + // Adding this on 11/7/2018 because caling block_show for every claim is causing + // performance issues. + if (blocks && blocks[block]) { + return new Date(blocks[block].time * 1000); } - if (!claim.value) { - return false; - } - - const tags = claim.value.tags || []; - for (let i = 0; i < tags.length; i += 1) { - const tag = tags[i].toLowerCase(); - if (matureTagMap[tag]) { - return true; - } - } - - return false; -}; - -function createNormalizedClaimSearchKey(options) { - // Ignore page because we don't care what the last page searched was, we want everything - // Ignore release_time because that will change depending on when you call claim_search ex: release_time: ">12344567" - const rest = _objectWithoutProperties$1(options, ['page', 'release_time']); - const query = JSON.stringify(rest); - return query; -} - -function filterClaims(claims, query) { - if (query) { - const queryMatchRegExp = new RegExp(query, 'i'); - return claims.filter(claim => { - const { value } = claim; - - return value.title && value.title.match(queryMatchRegExp) || claim.signing_channel && claim.signing_channel.name.match(queryMatchRegExp) || claim.name && claim.name.match(queryMatchRegExp); - }); - } - - return claims; -} - -var _extends$4 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; - -const selectState$2 = state => state.claims || {}; - -const selectClaimsById = reselect.createSelector(selectState$2, state => state.byId || {}); - -const selectClaimIdsByUri = reselect.createSelector(selectState$2, state => state.claimsByUri || {}); - -const selectCurrentChannelPage = reselect.createSelector(selectState$2, state => state.currentChannelPage || 1); - -const selectCreatingChannel = reselect.createSelector(selectState$2, state => state.creatingChannel); - -const selectCreateChannelError = reselect.createSelector(selectState$2, state => state.createChannelError); - -const selectRepostLoading = reselect.createSelector(selectState$2, state => state.repostLoading); - -const selectRepostError = reselect.createSelector(selectState$2, state => state.repostError); - -const selectClaimsByUri = reselect.createSelector(selectClaimIdsByUri, selectClaimsById, (byUri, byId) => { - const claims = {}; - - Object.keys(byUri).forEach(uri => { - const claimId = byUri[uri]; - - // NOTE returning a null claim allows us to differentiate between an - // undefined (never fetched claim) and one which just doesn't exist. Not - // the cleanest solution but couldn't think of anything better right now - if (claimId === null) { - claims[uri] = null; - } else { - claims[uri] = byId[claimId]; - } - }); - - return claims; -}); - -const selectAllClaimsByChannel = reselect.createSelector(selectState$2, state => state.paginatedClaimsByChannel || {}); - -const selectPendingIds = reselect.createSelector(selectState$2, state => state.pendingIds || []); - -const makeSelectClaimIsPending = uri => reselect.createSelector(selectClaimIdsByUri, selectPendingIds, (idsByUri, pendingIds) => { - const claimId = idsByUri[normalizeURI(uri)]; - - if (claimId) { - return pendingIds.some(i => i === claimId); - } - return false; -}); - -const selectReflectingById = reselect.createSelector(selectState$2, state => state.reflectingById); - -const makeSelectClaimForUri = (uri, returnRepost = true) => reselect.createSelector(selectClaimIdsByUri, selectClaimsById, (byUri, byId) => { - let validUri; - let channelClaimId; - let streamClaimId; - let isChannel; - try { - ({ isChannel, channelClaimId, streamClaimId } = parseURI(uri)); - validUri = true; - } catch (e) {} - - if (validUri && byUri) { - const claimId = uri && byUri[normalizeURI(uri)]; - const claim = byId[claimId]; - - // Make sure to return the claim as is so apps can check if it's been resolved before (null) or still needs to be resolved (undefined) - if (claimId === null) { - return null; - } else if (claimId === undefined) { - return undefined; - } - - const repostedClaim = claim.reposted_claim; - if (repostedClaim && returnRepost) { - const channelUrl = claim.signing_channel && claim.signing_channel.canonical_url; - - return _extends$4({}, repostedClaim, { - repost_url: uri, - repost_channel_url: channelUrl - }); - } else { - return claim; - } - } -}); - -const selectMyClaimsRaw = reselect.createSelector(selectState$2, selectClaimsById, (state, byId) => { - const ids = state.myClaims; - if (!ids) { - return ids; - } - - const claims = []; - ids.forEach(id => { - if (byId[id]) { - // I'm not sure why this check is necessary, but it ought to be a quick fix for https://github.com/lbryio/lbry-desktop/issues/544 - claims.push(byId[id]); - } - }); - return claims; -}); - -const selectAbandoningIds = reselect.createSelector(selectState$2, state => Object.keys(state.abandoningById || {})); - -const selectMyActiveClaims = reselect.createSelector(selectMyClaimsRaw, selectAbandoningIds, (claims, abandoningIds) => new Set(claims && claims.map(claim => claim.claim_id).filter(claimId => Object.keys(abandoningIds).indexOf(claimId) === -1))); - -const makeSelectClaimIsMine = rawUri => { - let uri; - try { - uri = normalizeURI(rawUri); - } catch (e) {} - - return reselect.createSelector(selectClaimsByUri, selectMyActiveClaims, (claims, myClaims) => { - try { - parseURI(uri); - } catch (e) { - return false; - } - - return claims && claims[uri] && (claims[uri].is_my_output || claims[uri].claim_id && myClaims.has(claims[uri].claim_id)); - }); -}; - -const selectMyPurchases = reselect.createSelector(selectState$2, state => state.myPurchases); - -const selectPurchaseUriSuccess = reselect.createSelector(selectState$2, state => state.purchaseUriSuccess); - -const selectMyPurchasesCount = reselect.createSelector(selectState$2, state => state.myPurchasesPageTotalResults); - -const selectIsFetchingMyPurchases = reselect.createSelector(selectState$2, state => state.fetchingMyPurchases); - -const selectFetchingMyPurchasesError = reselect.createSelector(selectState$2, state => state.fetchingMyPurchasesError); - -const makeSelectMyPurchasesForPage = (query, page = 1) => reselect.createSelector(selectMyPurchases, selectClaimsByUri, (myPurchases, claimsByUri) => { - if (!myPurchases) { - return undefined; - } - - if (!query) { - // ensure no duplicates from double purchase bugs - return [...new Set(myPurchases)]; - } - - const fileInfos = myPurchases.map(uri => claimsByUri[uri]); - const matchingFileInfos = filterClaims(fileInfos, query); - const start = (Number(page) - 1) * Number(PAGE_SIZE); - const end = Number(page) * Number(PAGE_SIZE); - return matchingFileInfos && matchingFileInfos.length ? matchingFileInfos.slice(start, end).map(fileInfo => fileInfo.canonical_url || fileInfo.permanent_url) : []; -}); - -const makeSelectClaimWasPurchased = uri => reselect.createSelector(makeSelectClaimForUri(uri), claim => { - return claim && claim.purchase_receipt !== undefined; -}); - -const selectAllFetchingChannelClaims = reselect.createSelector(selectState$2, state => state.fetchingChannelClaims || {}); - -const makeSelectFetchingChannelClaims = uri => reselect.createSelector(selectAllFetchingChannelClaims, fetching => fetching && fetching[uri]); - -const makeSelectClaimsInChannelForPage = (uri, page) => reselect.createSelector(selectClaimsById, selectAllClaimsByChannel, (byId, allClaims) => { - const byChannel = allClaims[uri] || {}; - const claimIds = byChannel[page || 1]; - - if (!claimIds) return claimIds; - - return claimIds.map(claimId => byId[claimId]); -}); - -const makeSelectTotalClaimsInChannelSearch = uri => reselect.createSelector(selectClaimsById, selectAllClaimsByChannel, (byId, allClaims) => { - const byChannel = allClaims[uri] || {}; - return byChannel['itemCount']; -}); - -const makeSelectTotalPagesInChannelSearch = uri => reselect.createSelector(selectClaimsById, selectAllClaimsByChannel, (byId, allClaims) => { - const byChannel = allClaims[uri] || {}; - return byChannel['pageCount']; -}); - -const makeSelectClaimsInChannelForCurrentPageState = uri => reselect.createSelector(selectClaimsById, selectAllClaimsByChannel, selectCurrentChannelPage, (byId, allClaims, page) => { - const byChannel = allClaims[uri] || {}; - const claimIds = byChannel[page || 1]; - - if (!claimIds) return claimIds; - - return claimIds.map(claimId => byId[claimId]); -}); - -const makeSelectMetadataForUri = uri => reselect.createSelector(makeSelectClaimForUri(uri), claim => { - const metadata = claim && claim.value; - return metadata || (claim === undefined ? undefined : null); -}); - -const makeSelectMetadataItemForUri = (uri, key) => reselect.createSelector(makeSelectMetadataForUri(uri), metadata => { - return metadata ? metadata[key] : undefined; -}); - -const makeSelectTitleForUri = uri => reselect.createSelector(makeSelectMetadataForUri(uri), metadata => metadata && metadata.title); - -const makeSelectDateForUri = uri => reselect.createSelector(makeSelectClaimForUri(uri), claim => { - const timestamp = claim && claim.value && (claim.value.release_time ? claim.value.release_time * 1000 : claim.meta && claim.meta.creation_timestamp ? claim.meta.creation_timestamp * 1000 : null); - if (!timestamp) { - return undefined; - } - const dateObj = new Date(timestamp); - return dateObj; -}); - -const makeSelectAmountForUri = uri => reselect.createSelector(makeSelectClaimForUri(uri), claim => { - return claim && claim.amount; -}); - -const makeSelectContentTypeForUri = uri => reselect.createSelector(makeSelectClaimForUri(uri), claim => { - const source = claim && claim.value && claim.value.source; - return source ? source.media_type : undefined; -}); - -const makeSelectThumbnailForUri = uri => reselect.createSelector(makeSelectClaimForUri(uri), claim => { - const thumbnail = claim && claim.value && claim.value.thumbnail; - return thumbnail && thumbnail.url ? thumbnail.url.trim().replace(/^http:\/\//i, 'https://') : undefined; -}); - -const makeSelectCoverForUri = uri => reselect.createSelector(makeSelectClaimForUri(uri), claim => { - const cover = claim && claim.value && claim.value.cover; - return cover && cover.url ? cover.url.trim().replace(/^http:\/\//i, 'https://') : undefined; -}); - -const selectIsFetchingClaimListMine = reselect.createSelector(selectState$2, state => state.isFetchingClaimListMine); - -const selectMyClaimsPage = reselect.createSelector(selectState$2, state => state.myClaimsPageResults || []); - -const selectMyClaimsPageNumber = reselect.createSelector(selectState$2, state => state.claimListMinePage && state.claimListMinePage.items || [], state => state.txoPage && state.txoPage.page || 1); - -const selectMyClaimsPageItemCount = reselect.createSelector(selectState$2, state => state.myClaimsPageTotalResults || 1); - -const selectFetchingMyClaimsPageError = reselect.createSelector(selectState$2, state => state.fetchingClaimListMinePageError); - -const selectMyClaims = reselect.createSelector(selectMyActiveClaims, selectClaimsById, selectAbandoningIds, (myClaimIds, byId, abandoningIds) => { - const claims = []; - - myClaimIds.forEach(id => { - const claim = byId[id]; - - if (claim && abandoningIds.indexOf(id) === -1) claims.push(claim); - }); - - return [...claims]; -}); - -const selectMyClaimsWithoutChannels = reselect.createSelector(selectMyClaims, myClaims => myClaims.filter(claim => !claim.name.match(/^@/)).sort((a, b) => a.timestamp - b.timestamp)); - -const selectMyClaimUrisWithoutChannels = reselect.createSelector(selectMyClaimsWithoutChannels, myClaims => { - return myClaims.sort((a, b) => { - if (a.height < 1) { - return -1; - } else if (b.height < 1) { - return 1; - } else { - return b.timestamp - a.timestamp; - } - }).map(claim => { - return claim.canonical_url || claim.permanent_url; - }); -}); - -const selectAllMyClaimsByOutpoint = reselect.createSelector(selectMyClaimsRaw, claims => new Set(claims && claims.length ? claims.map(claim => `${claim.txid}:${claim.nout}`) : null)); - -const selectMyClaimsOutpoints = reselect.createSelector(selectMyClaims, myClaims => { - const outpoints = []; - - myClaims.forEach(claim => outpoints.push(`${claim.txid}:${claim.nout}`)); - - return outpoints; -}); - -const selectFetchingMyChannels = reselect.createSelector(selectState$2, state => state.fetchingMyChannels); - -const selectMyChannelClaims = reselect.createSelector(selectState$2, selectClaimsById, (state, byId) => { - const ids = state.myChannelClaims; - if (!ids) { - return ids; - } - - const claims = []; - ids.forEach(id => { - if (byId[id]) { - // I'm not sure why this check is necessary, but it ought to be a quick fix for https://github.com/lbryio/lbry-desktop/issues/544 - claims.push(byId[id]); - } - }); - - return claims; -}); - -const selectMyChannelUrls = reselect.createSelector(selectMyChannelClaims, claims => claims ? claims.map(claim => claim.canonical_url || claim.permanent_url) : undefined); - -const selectResolvingUris = reselect.createSelector(selectState$2, state => state.resolvingUris || []); - -const selectChannelImportPending = reselect.createSelector(selectState$2, state => state.pendingChannelImport); - -const makeSelectIsUriResolving = uri => reselect.createSelector(selectResolvingUris, resolvingUris => resolvingUris && resolvingUris.indexOf(uri) !== -1); - -const selectPlayingUri = reselect.createSelector(selectState$2, state => state.playingUri); - -const selectChannelClaimCounts = reselect.createSelector(selectState$2, state => state.channelClaimCounts || {}); - -const makeSelectTotalItemsForChannel = uri => reselect.createSelector(selectChannelClaimCounts, byUri => byUri && byUri[uri]); - -const makeSelectTotalPagesForChannel = (uri, pageSize = 10) => reselect.createSelector(selectChannelClaimCounts, byUri => byUri && byUri[uri] && Math.ceil(byUri[uri] / pageSize)); - -const makeSelectNsfwCountFromUris = uris => reselect.createSelector(selectClaimsByUri, claims => uris.reduce((acc, uri) => { - const claim = claims[uri]; - if (claim && isClaimNsfw(claim)) { - return acc + 1; - } - return acc; -}, 0)); - -const makeSelectNsfwCountForChannel = uri => reselect.createSelector(selectClaimsById, selectAllClaimsByChannel, selectCurrentChannelPage, (byId, allClaims, page) => { - const byChannel = allClaims[uri] || {}; - const claimIds = byChannel[page || 1]; - - if (!claimIds) return 0; - - return claimIds.reduce((acc, claimId) => { - const claim = byId[claimId]; - if (isClaimNsfw(claim)) { - return acc + 1; - } - return acc; - }, 0); -}); - -const makeSelectOmittedCountForChannel = uri => reselect.createSelector(makeSelectTotalItemsForChannel(uri), makeSelectTotalClaimsInChannelSearch(uri), (claimsInChannel, claimsInSearch) => { - if (claimsInChannel && typeof claimsInSearch === 'number' && claimsInSearch >= 0) { - return claimsInChannel - claimsInSearch; - } else return 0; -}); - -const makeSelectClaimIsNsfw = uri => reselect.createSelector(makeSelectClaimForUri(uri), -// Eventually these will come from some list of tags that are considered adult -// Or possibly come from users settings of what tags they want to hide -// For now, there is just a hard coded list of tags inside `isClaimNsfw` -// selectNaughtyTags(), -claim => { - if (!claim) { - return false; - } - - return isClaimNsfw(claim); -}); - -const makeSelectRecommendedContentForUri = uri => reselect.createSelector(makeSelectClaimForUri(uri), selectSearchUrisByQuery, makeSelectClaimIsNsfw(uri), (claim, searchUrisByQuery, isMature) => { - const atVanityURI = !uri.includes('#'); - - let recommendedContent; - if (claim) { - // always grab full URL - this can change once search returns canonical - const currentUri = buildURI({ streamClaimId: claim.claim_id, streamName: claim.name }); - - const { title } = claim.value; - - if (!title) { - return; - } - - const options = { related_to: claim.claim_id, isBackgroundSearch: true }; - - if (!isMature) { - options['nsfw'] = false; - } - const searchQuery = getSearchQueryString(title.replace(/\//, ' '), options); - - let searchUris = searchUrisByQuery[searchQuery]; - if (searchUris) { - searchUris = searchUris.filter(searchUri => searchUri !== currentUri); - recommendedContent = searchUris; - } - } - - return recommendedContent; -}); - -const makeSelectFirstRecommendedFileForUri = uri => reselect.createSelector(makeSelectRecommendedContentForUri(uri), recommendedContent => recommendedContent ? recommendedContent[0] : null); - -// Returns the associated channel uri for a given claim uri -// accepts a regular claim uri lbry://something -// returns the channel uri that created this claim lbry://@channel -const makeSelectChannelForClaimUri = (uri, includePrefix = false) => reselect.createSelector(makeSelectClaimForUri(uri), claim => { - if (!claim || !claim.signing_channel || !claim.is_channel_signature_valid) { + // Pending claim + if (block < 1) { return null; } - const { canonical_url: canonicalUrl, permanent_url: permanentUrl } = claim.signing_channel; - - if (canonicalUrl) { - return includePrefix ? canonicalUrl : canonicalUrl.slice('lbry://'.length); - } else { - return includePrefix ? permanentUrl : permanentUrl.slice('lbry://'.length); - } + const difference = latestBlock - block; + const msSincePublish = difference * 2.5 * 60 * 1000; // Number of blocks * 2.5 minutes in ms + const publishDate = Date.now() - msSincePublish; + return new Date(publishDate); }); -const makeSelectTagsForUri = uri => reselect.createSelector(makeSelectMetadataForUri(uri), metadata => { - return metadata && metadata.tags || []; -}); +const selectTransactionListFilter = reselect.createSelector(selectState$2, state => state.transactionListFilter || ''); -const selectFetchingClaimSearchByQuery = reselect.createSelector(selectState$2, state => state.fetchingClaimSearchByQuery || {}); - -const selectFetchingClaimSearch = reselect.createSelector(selectFetchingClaimSearchByQuery, fetchingClaimSearchByQuery => Boolean(Object.keys(fetchingClaimSearchByQuery).length)); - -const selectClaimSearchByQuery = reselect.createSelector(selectState$2, state => state.claimSearchByQuery || {}); - -const selectClaimSearchByQueryLastPageReached = reselect.createSelector(selectState$2, state => state.claimSearchByQueryLastPageReached || {}); - -const makeSelectShortUrlForUri = uri => reselect.createSelector(makeSelectClaimForUri(uri), claim => claim && claim.short_url); - -const makeSelectCanonicalUrlForUri = uri => reselect.createSelector(makeSelectClaimForUri(uri), claim => claim && claim.canonical_url); - -const makeSelectPermanentUrlForUri = uri => reselect.createSelector(makeSelectClaimForUri(uri), claim => claim && claim.permanent_url); - -const makeSelectSupportsForUri = uri => reselect.createSelector(selectSupportsByOutpoint, makeSelectClaimForUri(uri), (byOutpoint, claim) => { - if (!claim || !claim.is_my_output) { - return null; - } - - const { claim_id: claimId } = claim; - let total = 0; - - Object.values(byOutpoint).forEach(support => { - // $FlowFixMe - const { claim_id, amount } = support; - total = claim_id === claimId && amount ? total + parseFloat(amount) : total; - }); - - return total; -}); - -const selectUpdatingChannel = reselect.createSelector(selectState$2, state => state.updatingChannel); - -const selectUpdateChannelError = reselect.createSelector(selectState$2, state => state.updateChannelError); - -const makeSelectReflectingClaimForUri = uri => reselect.createSelector(selectClaimIdsByUri, selectReflectingById, (claimIdsByUri, reflectingById) => { - const claimId = claimIdsByUri[normalizeURI(uri)]; - return reflectingById[claimId]; -}); - -const makeSelectMyStreamUrlsForPage = (page = 1) => reselect.createSelector(selectMyClaimUrisWithoutChannels, urls => { - const start = (Number(page) - 1) * Number(PAGE_SIZE); - const end = Number(page) * Number(PAGE_SIZE); - - return urls && urls.length ? urls.slice(start, end) : []; -}); - -const selectMyStreamUrlsCount = reselect.createSelector(selectMyClaimUrisWithoutChannels, channels => channels.length); - -const makeSelectResolvedRecommendedContentForUri = (uri, size, claimId, claimName, claimTitle) => reselect.createSelector(makeSelectClaimForUri(uri), selectResolvedSearchResultsByQuery, makeSelectClaimIsNsfw(uri), (claim, resolvedResultsByQuery, isMature) => { - const atVanityURI = !uri.includes('#'); - - let currentUri; - let recommendedContent; - let title; - if (claim) { - // always grab full URL - this can change once search returns canonical - currentUri = buildURI({ streamClaimId: claim.claim_id, streamName: claim.name }); - title = claim.value ? claim.value.title : null; - } else { - // for cases on mobile where the claim may not have been resolved () - currentUri = buildURI({ streamClaimId: claimId, streamName: claimName }); - title = claimTitle; - } - - if (!title) { - return; - } - - const options = { related_to: claim ? claim.claim_id : claimId, size, isBackgroundSearch: false }; - - const searchQuery = getSearchQueryString(title.replace(/\//, ' '), options); - let results = resolvedResultsByQuery[searchQuery]; - if (results) { - results = results.filter(result => buildURI({ streamClaimId: result.claimId, streamName: result.name }) !== currentUri); - recommendedContent = results; - } - - return recommendedContent; -}); - -function numberWithCommas(x) { - var parts = x.toString().split('.'); - parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ','); - return parts.join('.'); -} - -function formatCredits(amount, precision, shortFormat = false) { - let actualAmount = parseFloat(amount); - let actualPrecision = parseFloat(precision); - let suffix = ''; - - if (Number.isNaN(actualAmount) || actualAmount === 0) return '0'; - - if (actualAmount >= 1000000) { - if (precision <= 7) { - if (shortFormat) { - actualAmount = actualAmount / 1000000; - suffix = 'M'; - } else { - actualPrecision -= 7; - } - } - } else if (actualAmount >= 1000) { - if (precision <= 4) { - if (shortFormat) { - actualAmount = actualAmount / 1000; - suffix = 'K'; - } else { - actualPrecision -= 4; - } - } - } - - return numberWithCommas(actualAmount.toFixed(actualPrecision >= 0 ? actualPrecision : 1).replace(/\.*0+$/, '')) + suffix; +function formatCredits(amount, precision) { + if (Number.isNaN(parseFloat(amount))) return '0'; + return parseFloat(amount).toFixed(precision || 1).replace(/\.?0+$/, ''); } function formatFullPrice(amount, precision = 1) { @@ -2872,42 +1563,43 @@ function creditsToString(amount) { return creditString; } -var _extends$5 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; - -let walletBalancePromise = null; function doUpdateBalance() { return (dispatch, getState) => { const { - wallet: { totalBalance: totalInStore } + wallet: { balance: balanceInStore } } = getState(); + lbryProxy.account_balance().then(balanceAsString => { + const balance = parseFloat(balanceAsString); + if (balanceInStore !== balance) { + dispatch({ + type: UPDATE_BALANCE, + data: { + balance + } + }); + } + }); + }; +} - if (walletBalancePromise === null) { - walletBalancePromise = lbryProxy.wallet_balance().then(response => { - walletBalancePromise = null; - - const { available, reserved, reserved_subtotals, total } = response; - const { claims, supports, tips } = reserved_subtotals; - const totalFloat = parseFloat(total); - - if (totalInStore !== totalFloat) { - dispatch({ - type: UPDATE_BALANCE, - data: { - totalBalance: totalFloat, - balance: parseFloat(available), - reservedBalance: parseFloat(reserved), - claimsBalance: parseFloat(claims), - supportsBalance: parseFloat(supports), - tipsBalance: parseFloat(tips) - } - }); - } - }).catch(() => { - walletBalancePromise = null; - }); - } - - return walletBalancePromise; +function doUpdateTotalBalance() { + return (dispatch, getState) => { + const { + wallet: { totalBalance: totalBalanceInStore } + } = getState(); + lbryProxy.account_list().then(accountList => { + const { lbc_mainnet: accounts } = accountList; + const totalSatoshis = accounts.length === 1 ? accounts[0].satoshis : accounts.reduce((a, b) => a.satoshis + b.satoshis); + const totalBalance = (Number.isNaN(totalSatoshis) ? 0 : totalSatoshis) / Math.pow(10, 8); + if (totalBalanceInStore !== totalBalance) { + dispatch({ + type: UPDATE_TOTAL_BALANCE, + data: { + totalBalance + } + }); + } + }); }; } @@ -2918,70 +1610,36 @@ function doBalanceSubscribe() { }; } -function doFetchTransactions(page = 1, pageSize = 99999) { +function doTotalBalanceSubscribe() { + return dispatch => { + dispatch(doUpdateTotalBalance()); + setInterval(() => dispatch(doUpdateTotalBalance()), 5000); + }; +} + +function doFetchTransactions() { return dispatch => { - dispatch(doFetchSupports()); dispatch({ type: FETCH_TRANSACTIONS_STARTED }); - lbryProxy.utxo_release().then(() => lbryProxy.transaction_list({ page, page_size: pageSize })).then(result => { + lbryProxy.utxo_release().then(() => lbryProxy.transaction_list()).then(results => { dispatch({ type: FETCH_TRANSACTIONS_COMPLETED, data: { - transactions: result.items + transactions: results } }); }); }; } -function doFetchTxoPage() { - return (dispatch, getState) => { - dispatch({ - type: FETCH_TXO_PAGE_STARTED - }); - - const state = getState(); - const queryParams = selectTxoPageParams(state); - - lbryProxy.utxo_release().then(() => lbryProxy.txo_list(queryParams)).then(res => { - dispatch({ - type: FETCH_TXO_PAGE_COMPLETED, - data: res - }); - }).catch(e => { - dispatch({ - type: FETCH_TXO_PAGE_COMPLETED, - data: e.message - }); - }); - }; -} - -function doUpdateTxoPageParams(params) { +function doFetchBlock(height) { return dispatch => { - dispatch({ - type: UPDATE_TXO_FETCH_PARAMS, - data: params - }); - - dispatch(doFetchTxoPage()); - }; -} - -function doFetchSupports(page = 1, pageSize = 99999) { - return dispatch => { - dispatch({ - type: FETCH_SUPPORTS_STARTED - }); - - lbryProxy.support_list({ page, page_size: pageSize }).then(result => { + lbryProxy.block_show({ height }).then(block => { dispatch({ - type: FETCH_SUPPORTS_COMPLETED, - data: { - supports: result.items - } + type: FETCH_BLOCK_SUCCESS, + data: { block } }); }); }; @@ -3025,8 +1683,8 @@ function doSendDraftTransaction(address, amount) { if (balance - amount <= 0) { dispatch(doToast({ - title: __('Insufficient credits'), - message: __('Insufficient credits') + title: 'Insufficient credits', + message: 'Insufficient credits' })); return; } @@ -3041,8 +1699,8 @@ function doSendDraftTransaction(address, amount) { type: SEND_TRANSACTION_COMPLETED }); dispatch(doToast({ - message: __(`You sent ${amount} LBC`), - linkText: __('History'), + message: `You sent ${amount} LBC`, + linkText: 'History', linkTarget: '/wallet' })); } else { @@ -3051,7 +1709,7 @@ function doSendDraftTransaction(address, amount) { data: { error: response } }); dispatch(doToast({ - message: __('Transaction failed'), + message: 'Transaction failed', isError: true })); } @@ -3063,12 +1721,12 @@ function doSendDraftTransaction(address, amount) { data: { error: error.message } }); dispatch(doToast({ - message: __('Transaction failed'), + message: 'Transaction failed', isError: true })); }; - lbryProxy.wallet_send({ + lbryProxy.account_send({ addresses: [address], amount: creditsToString(amount) }).then(successCallback, errorCallback); @@ -3089,17 +1747,14 @@ function doSetDraftTransactionAddress(address) { }; } -function doSendTip(params, isSupport, successCallback, errorCallback) { +function doSendTip(amount, claimId, uri, successCallback, errorCallback) { return (dispatch, getState) => { const state = getState(); const balance = selectBalance(state); - const myClaims = selectMyClaimsRaw(state); - const shouldSupport = isSupport || (myClaims ? myClaims.find(claim => claim.claim_id === params.claim_id) : false); - - if (balance - params.amount <= 0) { + if (balance - amount <= 0) { dispatch(doToast({ - message: __('Insufficient credits'), + message: 'Insufficient credits', isError: true })); return; @@ -3107,9 +1762,9 @@ function doSendTip(params, isSupport, successCallback, errorCallback) { const success = () => { dispatch(doToast({ - message: shouldSupport ? __('You deposited %amount% LBC as a support!', { amount: params.amount }) : __('You sent %amount% LBC as a tip, Mahalo!', { amount: params.amount }), + message: __(`You sent ${amount} LBC as a tip, Mahalo!`), linkText: __('History'), - linkTarget: '/wallet' + linkTarget: __('/wallet') })); dispatch({ @@ -3143,17 +1798,11 @@ function doSendTip(params, isSupport, successCallback, errorCallback) { type: SUPPORT_TRANSACTION_STARTED }); - lbryProxy.support_create(_extends$5({}, params, { - tip: !shouldSupport, - blocking: true, - amount: creditsToString(params.amount) - })).then(success, error); - }; -} - -function doClearSupport() { - return { - type: CLEAR_SUPPORT_TRANSACTION + lbryProxy.support_create({ + claim_id: claimId, + amount: creditsToString(amount), + tip: true + }).then(success, error); }; } @@ -3163,7 +1812,7 @@ function doWalletEncrypt(newPassword) { type: WALLET_ENCRYPT_START }); - lbryProxy.wallet_encrypt({ new_password: newPassword }).then(result => { + lbryProxy.account_encrypt({ new_password: newPassword }).then(result => { if (result === true) { dispatch({ type: WALLET_ENCRYPT_COMPLETED, @@ -3185,7 +1834,7 @@ function doWalletUnlock(password) { type: WALLET_UNLOCK_START }); - lbryProxy.wallet_unlock({ password }).then(result => { + lbryProxy.account_unlock({ password }).then(result => { if (result === true) { dispatch({ type: WALLET_UNLOCK_COMPLETED, @@ -3201,58 +1850,13 @@ function doWalletUnlock(password) { }; } -function doSupportAbandonForClaim(claimId, claimType, keep, preview) { - return dispatch => { - if (preview) { - dispatch({ - type: ABANDON_CLAIM_SUPPORT_PREVIEW - }); - } else { - dispatch({ - type: ABANDON_CLAIM_SUPPORT_STARTED - }); - } - - const params = { claim_id: claimId }; - if (preview) params['preview'] = true; - if (keep) params['keep'] = keep; - return lbryProxy.support_abandon(params).then(res => { - if (!preview) { - dispatch({ - type: ABANDON_CLAIM_SUPPORT_COMPLETED, - data: { claimId, txid: res.txid, effective: res.outputs[0].amount, type: claimType } // add to pendingSupportTransactions, - }); - dispatch(doCheckPendingTxs()); - } - return res; - }).catch(e => { - dispatch({ - type: ABANDON_CLAIM_SUPPORT_FAILED, - data: e.message - }); - }); - }; -} - -function doWalletReconnect() { - return dispatch => { - dispatch({ - type: WALLET_RESTART - }); - // this basically returns null when it's done. :( - // might be good to dispatch ACTIONS.WALLET_RESTARTED - lbryProxy.wallet_reconnect().then(() => dispatch({ - type: WALLET_RESTART_COMPLETED - })); - }; -} function doWalletDecrypt() { return dispatch => { dispatch({ type: WALLET_DECRYPT_START }); - lbryProxy.wallet_decrypt().then(result => { + lbryProxy.account_decrypt().then(result => { if (result === true) { dispatch({ type: WALLET_DECRYPT_COMPLETED, @@ -3274,11 +1878,11 @@ function doWalletStatus() { type: WALLET_STATUS_START }); - lbryProxy.wallet_status().then(status => { - if (status) { + lbryProxy.status().then(status => { + if (status && status.wallet) { dispatch({ type: WALLET_STATUS_COMPLETED, - result: status.is_encrypted + result: status.wallet.is_encrypted }); } }); @@ -3303,71 +1907,7 @@ function doUpdateBlockHeight() { }); } -// Calls transaction_show on txes until any pending txes are confirmed -const doCheckPendingTxs = () => (dispatch, getState) => { - const state = getState(); - const pendingTxsById = selectPendingSupportTransactions(state); // {} - if (!Object.keys(pendingTxsById).length) { - return; - } - let txCheckInterval; - const checkTxList = () => { - const state = getState(); - const pendingTxs = selectPendingSupportTransactions(state); // {} - const promises = []; - const newPendingTxes = {}; - const types = new Set([]); - let changed = false; - Object.entries(pendingTxs).forEach(([claim, data]) => { - promises.push(lbryProxy.transaction_show({ txid: data.txid })); - types.add(data.type); - }); - - Promise.all(promises).then(txShows => { - txShows.forEach(result => { - if (result.height <= 0) { - const entries = Object.entries(pendingTxs); - const match = entries.find(entry => entry[1].txid === result.txid); - newPendingTxes[match[0]] = match[1]; - } else { - changed = true; - } - }); - }).then(() => { - if (changed) { - dispatch({ - type: PENDING_SUPPORTS_UPDATED, - data: newPendingTxes - }); - if (types.has('channel')) { - dispatch(doFetchChannelListMine()); - } - if (types.has('stream')) { - dispatch(doFetchClaimListMine()); - } - } - if (Object.keys(newPendingTxes).length === 0) clearInterval(txCheckInterval); - }); - - if (!Object.keys(pendingTxsById).length) { - clearInterval(txCheckInterval); - } - }; - - txCheckInterval = setInterval(() => { - checkTxList(); - }, 30000); -}; - -// https://github.com/reactjs/redux/issues/911 -function batchActions(...actions) { - return { - type: 'BATCH_ACTIONS', - actions - }; -} - -var _extends$6 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; +var _extends$3 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; function doResolveUris(uris, returnCachedClaims = false) { return (dispatch, getState) => { @@ -3388,13 +1928,6 @@ function doResolveUris(uris, returnCachedClaims = false) { return; } - const options = { - include_purchase_receipt: true - }; - - if (urisToResolve.length === 1) { - options.include_is_my_output = true; - } dispatch({ type: RESOLVE_URIS_STARTED, data: { uris: normalizedUris } @@ -3402,35 +1935,23 @@ function doResolveUris(uris, returnCachedClaims = false) { const resolveInfo = {}; - return lbryProxy.resolve(_extends$6({ urls: urisToResolve }, options)).then(result => { + lbryProxy.resolve({ urls: urisToResolve }).then(result => { Object.entries(result).forEach(([uri, uriResolveInfo]) => { const fallbackResolveInfo = { - stream: null, + claim: null, claimsInChannel: null, - channel: null + certificate: null }; // Flow has terrible Object.entries support // https://github.com/facebook/flow/issues/2221 - if (uriResolveInfo) { - if (uriResolveInfo.error) { - resolveInfo[uri] = _extends$6({}, fallbackResolveInfo); - } else { - let result = {}; - if (uriResolveInfo.value_type === 'channel') { - result.channel = uriResolveInfo; - // $FlowFixMe - result.claimsInChannel = uriResolveInfo.meta.claims_in_channel; - } else { - result.stream = uriResolveInfo; - if (uriResolveInfo.signing_channel) { - result.channel = uriResolveInfo.signing_channel; - result.claimsInChannel = uriResolveInfo.signing_channel.meta && uriResolveInfo.signing_channel.meta.claims_in_channel || 0; - } - } - // $FlowFixMe - resolveInfo[uri] = result; - } + // $FlowFixMe + if (uriResolveInfo.error) { + resolveInfo[uri] = _extends$3({}, fallbackResolveInfo); + } else { + // $FlowFixMe + const { claim, certificate, claims_in_channel: claimsInChannel } = uriResolveInfo; + resolveInfo[uri] = { claim, certificate, claimsInChannel }; } }); @@ -3438,7 +1959,6 @@ function doResolveUris(uris, returnCachedClaims = false) { type: RESOLVE_URIS_COMPLETED, data: { resolveInfo } }); - return result; }); }; } @@ -3447,159 +1967,66 @@ function doResolveUri(uri) { return doResolveUris([uri]); } -function doFetchClaimListMine(page = 1, pageSize = 99999, resolve = true) { +function doFetchClaimListMine() { return dispatch => { dispatch({ type: FETCH_CLAIM_LIST_MINE_STARTED }); - // $FlowFixMe - lbryProxy.claim_list({ - page: page, - page_size: pageSize, - claim_type: ['stream', 'repost'], - resolve - }).then(result => { + lbryProxy.claim_list().then(claims => { dispatch({ type: FETCH_CLAIM_LIST_MINE_COMPLETED, data: { - result, - resolve + claims } }); }); }; } -function doAbandonTxo(txo, cb) { - return dispatch => { - if (cb) cb(PENDING); - const isClaim = txo.type === 'claim'; - const isSupport = txo.type === 'support' && txo.is_my_input === true; - const isTip = txo.type === 'support' && txo.is_my_input === false; - - const data = isClaim ? { claimId: txo.claim_id } : { outpoint: `${txo.txid}:${txo.nout}` }; - - const startedActionType = isClaim ? ABANDON_CLAIM_STARTED : ABANDON_SUPPORT_STARTED; - const completedActionType = isClaim ? ABANDON_CLAIM_SUCCEEDED : ABANDON_SUPPORT_COMPLETED; - - dispatch({ - type: startedActionType, - data - }); - - const errorCallback = () => { - if (cb) cb(ERROR); - dispatch(doToast({ - message: isClaim ? 'Error abandoning your claim/support' : 'Error unlocking your tip', - isError: true - })); - }; - - const successCallback = () => { - dispatch({ - type: completedActionType, - data - }); - - let abandonMessage; - if (isClaim) { - abandonMessage = __('Successfully abandoned your claim.'); - } else if (isSupport) { - abandonMessage = __('Successfully abandoned your support.'); - } else { - abandonMessage = __('Successfully unlocked your tip!'); - } - if (cb) cb(DONE); - - dispatch(doToast({ - message: abandonMessage - })); - }; - - const abandonParams = { - blocking: true - }; - if (isClaim) { - abandonParams['claim_id'] = txo.claim_id; - } else { - abandonParams['txid'] = txo.txid; - abandonParams['nout'] = txo.nout; - } - - let method; - if (isSupport || isTip) { - method = 'support_abandon'; - } else if (isClaim) { - const { normalized_name: claimName } = txo; - method = claimName.startsWith('@') ? 'channel_abandon' : 'stream_abandon'; - } - - if (!method) { - console.error('No "method" chosen for claim or support abandon'); - return; - } - - lbryProxy[method](abandonParams).then(successCallback, errorCallback); - }; -} - -function doAbandonClaim(txid, nout, cb) { - const outpoint = `${txid}:${nout}`; - +function doAbandonClaim(txid, nout) { return (dispatch, getState) => { const state = getState(); const myClaims = selectMyClaimsRaw(state); - const mySupports = selectSupportsByOutpoint(state); - - // A user could be trying to abandon a support or one of their claims const claimToAbandon = myClaims.find(claim => claim.txid === txid && claim.nout === nout); - const supportToAbandon = mySupports[outpoint]; - if (!claimToAbandon && !supportToAbandon) { - console.error('No associated support or claim with txid: ', txid); + if (!claimToAbandon) { + console.error('No associated claim with txid: ', txid); return; } - const data = claimToAbandon ? { claimId: claimToAbandon.claim_id } : { outpoint: `${supportToAbandon.txid}:${supportToAbandon.nout}` }; - - const isClaim = !!claimToAbandon; - const startedActionType = isClaim ? ABANDON_CLAIM_STARTED : ABANDON_SUPPORT_STARTED; - const completedActionType = isClaim ? ABANDON_CLAIM_SUCCEEDED : ABANDON_SUPPORT_COMPLETED; + const { claim_id: claimId, name: claimName } = claimToAbandon; dispatch({ - type: startedActionType, - data + type: ABANDON_CLAIM_STARTED, + data: { + claimId + } }); const errorCallback = () => { dispatch(doToast({ - message: isClaim ? 'Error abandoning your claim/support' : 'Error unlocking your tip', + message: 'Error abandoning claim', isError: true })); - if (cb) cb(ERROR); }; const successCallback = () => { dispatch({ - type: completedActionType, - data + type: ABANDON_CLAIM_SUCCEEDED, + data: { + claimId + } }); - if (cb) cb(DONE); - - let abandonMessage; - if (isClaim) { - abandonMessage = __('Successfully abandoned your claim.'); - } else if (supportToAbandon) { - abandonMessage = __('Successfully abandoned your support.'); - } else { - abandonMessage = __('Successfully unlocked your tip!'); - } dispatch(doToast({ - message: abandonMessage + message: 'Successfully abandoned your claim' })); - dispatch(doFetchTxoPage()); + + // After abandoning, call claim_list to show the claim as abandoned + // Also fetch transactions to show the new abandon transaction + dispatch(doFetchClaimListMine()); + dispatch(doFetchTransactions()); }; const abandonParams = { @@ -3608,19 +2035,7 @@ function doAbandonClaim(txid, nout, cb) { blocking: true }; - let method; - if (supportToAbandon) { - method = 'support_abandon'; - } else if (claimToAbandon) { - const { name: claimName } = claimToAbandon; - method = claimName.startsWith('@') ? 'channel_abandon' : 'stream_abandon'; - } - - if (!method) { - console.error('No "method" chosen for claim or support abandon'); - return; - } - + const method = claimName.startsWith('@') ? 'channel_abandon' : 'stream_abandon'; lbryProxy[method](abandonParams).then(successCallback, errorCallback); }; } @@ -3632,22 +2047,15 @@ function doFetchClaimsByChannel(uri, page = 1) { data: { uri, page } }); - lbryProxy.claim_search({ - channel: uri, - valid_channel_signature: true, - page: page || 1, - order_by: ['release_time'], - include_is_my_output: true, - include_purchase_receipt: true - }).then(result => { - const { items: claims, total_items: claimsInChannel, page: returnedPage } = result; + lbryProxy.claim_search({ uri, page: page || 1 }).then(result => { + const claimResult = result[uri] || {}; + const { claims_in_channel: claimsInChannel, returned_page: returnedPage } = claimResult; dispatch({ type: FETCH_CHANNEL_CLAIMS_COMPLETED, data: { uri, - claimsInChannel, - claims: claims || [], + claims: claimsInChannel || [], page: returnedPage || undefined } }); @@ -3655,49 +2063,16 @@ function doFetchClaimsByChannel(uri, page = 1) { }; } -function doClearChannelErrors() { - return { - type: CLEAR_CHANNEL_ERRORS - }; -} - -function doCreateChannel(name, amount, optionalParams, cb) { +function doCreateChannel(name, amount) { return dispatch => { dispatch({ type: CREATE_CHANNEL_STARTED }); - const createParams = { + return lbryProxy.channel_create({ name, - bid: creditsToString(amount), - blocking: true - }; - - if (optionalParams) { - if (optionalParams.title) { - createParams.title = optionalParams.title; - } - if (optionalParams.coverUrl) { - createParams.cover_url = optionalParams.coverUrl; - } - if (optionalParams.thumbnailUrl) { - createParams.thumbnail_url = optionalParams.thumbnailUrl; - } - if (optionalParams.description) { - createParams.description = optionalParams.description; - } - if (optionalParams.website) { - createParams.website_url = optionalParams.website; - } - if (optionalParams.email) { - createParams.email = optionalParams.email; - } - if (optionalParams.tags) { - createParams.tags = optionalParams.tags.map(tag => tag.name); - } - } - - return lbryProxy.channel_create(createParams) + bid: creditsToString(amount) + }) // outputs[0] is the certificate // outputs[1] is the change from the tx, not in the app currently .then(result => { @@ -3706,312 +2081,32 @@ function doCreateChannel(name, amount, optionalParams, cb) { type: CREATE_CHANNEL_COMPLETED, data: { channelClaim } }); - dispatch({ - type: UPDATE_PENDING_CLAIMS, - data: { - claims: [channelClaim] - } - }); - dispatch(doCheckPendingClaims(cb)); - return channelClaim; }).catch(error => { dispatch({ type: CREATE_CHANNEL_FAILED, - data: error.message - }); - }); - }; -} - -function doUpdateChannel(params, cb) { - return (dispatch, getState) => { - dispatch({ - type: UPDATE_CHANNEL_STARTED - }); - const state = getState(); - const myChannels = selectMyChannelClaims(state); - const channelClaim = myChannels.find(myChannel => myChannel.claim_id === params.claim_id); - - const updateParams = { - claim_id: params.claim_id, - bid: creditsToString(params.amount), - title: params.title, - cover_url: params.coverUrl, - thumbnail_url: params.thumbnailUrl, - description: params.description, - website_url: params.website, - email: params.email, - tags: [], - replace: true, - languages: [], - locations: [], - blocking: true - }; - - if (params.tags) { - updateParams.tags = params.tags.map(tag => tag.name); - } - - // we'll need to remove these once we add locations/channels to channel page edit/create options - - if (channelClaim && channelClaim.value && channelClaim.value.locations) { - updateParams.locations = channelClaim.value.locations; - } - - if (channelClaim && channelClaim.value && channelClaim.value.languages) { - updateParams.languages = channelClaim.value.languages; - } - - return lbryProxy.channel_update(updateParams).then(result => { - const channelClaim = result.outputs[0]; - dispatch({ - type: UPDATE_CHANNEL_COMPLETED, - data: { channelClaim } - }); - dispatch({ - type: UPDATE_PENDING_CLAIMS, - data: { - claims: [channelClaim] - } - }); - dispatch(doCheckPendingClaims(cb)); - return Boolean(result.outputs[0]); - }).then().catch(error => { - dispatch({ - type: UPDATE_CHANNEL_FAILED, data: error }); }); }; } -function doImportChannel(certificate) { - return dispatch => { - dispatch({ - type: IMPORT_CHANNEL_STARTED - }); - - return lbryProxy.channel_import({ channel_data: certificate }).then(result => { - dispatch({ - type: IMPORT_CHANNEL_COMPLETED - }); - }).catch(error => { - dispatch({ - type: IMPORT_CHANNEL_FAILED, - data: error - }); - }); - }; -} - -function doFetchChannelListMine(page = 1, pageSize = 99999, resolve = true) { +function doFetchChannelListMine() { return dispatch => { dispatch({ type: FETCH_CHANNEL_LIST_STARTED }); - const callback = response => { + const callback = channels => { dispatch({ type: FETCH_CHANNEL_LIST_COMPLETED, - data: { claims: response.items } + data: { claims: channels } }); }; - const failure = error => { - dispatch({ - type: FETCH_CHANNEL_LIST_FAILED, - data: error - }); - }; - - lbryProxy.channel_list({ page, page_size: pageSize, resolve }).then(callback, failure); + lbryProxy.channel_list().then(callback); }; } -function doClaimSearch(options = { - no_totals: true, - page_size: 10, - page: 1 -}) { - const query = createNormalizedClaimSearchKey(options); - return dispatch => { - dispatch({ - type: CLAIM_SEARCH_STARTED, - data: { query: query } - }); - - const success = data => { - const resolveInfo = {}; - const urls = []; - data.items.forEach(stream => { - resolveInfo[stream.canonical_url] = { stream }; - urls.push(stream.canonical_url); - }); - - dispatch({ - type: CLAIM_SEARCH_COMPLETED, - data: { - query, - resolveInfo, - urls, - append: options.page && options.page !== 1, - pageSize: options.page_size - } - }); - }; - - const failure = err => { - dispatch({ - type: CLAIM_SEARCH_FAILED, - data: { query }, - error: err - }); - }; - - lbryProxy.claim_search(_extends$6({}, options, { - include_purchase_receipt: true - })).then(success, failure); - }; -} - -function doRepost(options) { - return dispatch => { - // $FlowFixMe - return new Promise(resolve => { - dispatch({ - type: CLAIM_REPOST_STARTED - }); - - function success(response) { - const repostClaim = response.outputs[0]; - dispatch({ - type: CLAIM_REPOST_COMPLETED, - data: { - originalClaimId: options.claim_id, - repostClaim - } - }); - - dispatch(doFetchClaimListMine(1, 10)); - resolve(repostClaim); - } - - function failure(error) { - dispatch({ - type: CLAIM_REPOST_FAILED, - data: { - error: error.message - } - }); - } - - lbryProxy.stream_repost(options).then(success, failure); - }); - }; -} - -function doCheckPublishNameAvailability(name) { - return dispatch => { - dispatch({ - type: CHECK_PUBLISH_NAME_STARTED - }); - - return lbryProxy.claim_list({ name: name }).then(result => { - dispatch({ - type: CHECK_PUBLISH_NAME_COMPLETED - }); - if (result.items.length) { - dispatch({ - type: FETCH_CLAIM_LIST_MINE_COMPLETED, - data: { - result, - resolve: false - } - }); - } - return !(result && result.items && result.items.length); - }); - }; -} - -function doClearRepostError() { - return { - type: CLEAR_REPOST_ERROR - }; -} - -function doPurchaseList(page = 1, pageSize = PAGE_SIZE) { - return dispatch => { - dispatch({ - type: PURCHASE_LIST_STARTED - }); - - const success = result => { - return dispatch({ - type: PURCHASE_LIST_COMPLETED, - data: { - result - } - }); - }; - - const failure = error => { - dispatch({ - type: PURCHASE_LIST_FAILED, - data: { - error: error.message - } - }); - }; - - lbryProxy.purchase_list({ - page: page, - page_size: pageSize, - resolve: true - }).then(success, failure); - }; -} - -const doCheckPendingClaims = onConfirmed => (dispatch, getState) => { - let claimCheckInterval; - - const checkClaimList = () => { - const state = getState(); - const pendingIdSet = new Set(selectPendingIds(state)); - lbryProxy.claim_list({ page: 1, page_size: 10 }).then(result => { - const claims = result.items; - const claimsToConfirm = []; - claims.forEach(claim => { - const { claim_id: claimId } = claim; - if (claim.confirmations > 0 && pendingIdSet.has(claimId)) { - pendingIdSet.delete(claimId); - claimsToConfirm.push(claim); - if (onConfirmed) { - onConfirmed(claim); - } - } - }); - if (claimsToConfirm.length) { - dispatch({ - type: UPDATE_CONFIRMED_CLAIMS, - data: { - claims: claimsToConfirm - } - }); - } - return pendingIdSet.size; - }).then(len => { - if (!len) { - clearInterval(claimCheckInterval); - } - }); - }; - - claimCheckInterval = setInterval(() => { - checkClaimList(); - }, 30000); -}; - const selectState$3 = state => state.fileInfo || {}; const selectFileInfosByOutpoint = reselect.createSelector(selectState$3, state => state.byOutpoint || {}); @@ -4033,23 +2128,14 @@ const makeSelectDownloadingForUri = uri => reselect.createSelector(selectDownloa return byOutpoint[fileInfo.outpoint]; }); -const selectUrisLoading = reselect.createSelector(selectState$3, state => state.fetching || {}); +const selectUrisLoading = reselect.createSelector(selectState$3, state => state.urisLoading || {}); -const makeSelectLoadingForUri = uri => reselect.createSelector(selectUrisLoading, makeSelectClaimForUri(uri), (fetchingByOutpoint, claim) => { - if (!claim) { - return false; - } +const makeSelectLoadingForUri = uri => reselect.createSelector(selectUrisLoading, byUri => byUri && byUri[uri]); - const { txid, nout } = claim; - const outpoint = `${txid}:${nout}`; - const isFetching = fetchingByOutpoint[outpoint]; - return isFetching; -}); - -const selectFileInfosDownloaded = reselect.createSelector(selectFileInfosByOutpoint, selectMyClaims, (byOutpoint, myClaims) => Object.values(byOutpoint).reverse().filter(fileInfo => { +const selectFileInfosDownloaded = reselect.createSelector(selectFileInfosByOutpoint, selectMyClaims, (byOutpoint, myClaims) => Object.values(byOutpoint).filter(fileInfo => { const myClaimIds = myClaims.map(claim => claim.claim_id); - return fileInfo && myClaimIds.indexOf(fileInfo.claim_id) === -1 && (fileInfo.completed || fileInfo.written_bytes > 0 || fileInfo.blobs_completed > 0); + return fileInfo && myClaimIds.indexOf(fileInfo.claim_id) === -1 && (fileInfo.completed || fileInfo.written_bytes); })); // export const selectFileInfoForUri = (state, props) => { @@ -4087,183 +2173,101 @@ const selectTotalDownloadProgress = reselect.createSelector(selectDownloadingFil return -1; }); +const selectSearchDownloadUris = query => reselect.createSelector(selectFileInfosDownloaded, selectClaimsById, (fileInfos, claimsById) => { + if (!query || !fileInfos.length) { + return null; + } + + const queryParts = query.toLowerCase().split(' '); + const searchQueryDictionary = {}; + queryParts.forEach(subQuery => { + searchQueryDictionary[subQuery] = subQuery; + }); + + const arrayContainsQueryPart = array => { + for (let i = 0; i < array.length; i += 1) { + const subQuery = array[i]; + if (searchQueryDictionary[subQuery]) { + return true; + } + } + return false; + }; + + const downloadResultsFromQuery = []; + fileInfos.forEach(fileInfo => { + const { channel_name: channelName, claim_name: claimName, metadata } = fileInfo; + const { author, description, title } = metadata; + + if (channelName) { + const lowerCaseChannel = channelName.toLowerCase(); + const strippedOutChannelName = lowerCaseChannel.slice(1); // trim off the @ + if (searchQueryDictionary[channelName] || searchQueryDictionary[strippedOutChannelName]) { + downloadResultsFromQuery.push(fileInfo); + return; + } + } + + const nameParts = claimName.toLowerCase().split('-'); + if (arrayContainsQueryPart(nameParts)) { + downloadResultsFromQuery.push(fileInfo); + return; + } + + const titleParts = title.toLowerCase().split(' '); + if (arrayContainsQueryPart(titleParts)) { + downloadResultsFromQuery.push(fileInfo); + return; + } + + if (author) { + const authorParts = author.toLowerCase().split(' '); + if (arrayContainsQueryPart(authorParts)) { + downloadResultsFromQuery.push(fileInfo); + return; + } + } + + if (description) { + const descriptionParts = description.toLowerCase().split(' '); + if (arrayContainsQueryPart(descriptionParts)) { + downloadResultsFromQuery.push(fileInfo); + } + } + }); + + return downloadResultsFromQuery.length ? downloadResultsFromQuery.map(fileInfo => { + const { + channel_name: channelName, + claim_id: claimId, + claim_name: claimName + } = fileInfo; + + const uriParams = {}; + + if (channelName) { + const claim = claimsById[claimId]; + if (claim) { + uriParams.claimId = claim.channel_id; + } else { + uriParams.claimId = claimId; + } + uriParams.channelName = channelName; + uriParams.contentName = claimName; + } else { + uriParams.claimId = claimId; + uriParams.claimName = claimName; + } + + const uri = buildURI(uriParams); + return uri; + }) : null; +}); + const selectFileListPublishedSort = reselect.createSelector(selectState$3, state => state.fileListPublishedSort); const selectFileListDownloadedSort = reselect.createSelector(selectState$3, state => state.fileListDownloadedSort); -const selectDownloadedUris = reselect.createSelector(selectFileInfosDownloaded, -// We should use permament_url but it doesn't exist in file_list -info => info.slice().map(claim => `lbry://${claim.claim_name}#${claim.claim_id}`)); - -const makeSelectMediaTypeForUri = uri => reselect.createSelector(makeSelectFileInfoForUri(uri), makeSelectContentTypeForUri(uri), (fileInfo, contentType) => { - if (!fileInfo && !contentType) { - return undefined; - } - - const fileName = fileInfo && fileInfo.file_name; - return lbryProxy.getMediaType(contentType, fileName); -}); - -const makeSelectUriIsStreamable = uri => reselect.createSelector(makeSelectMediaTypeForUri(uri), mediaType => { - const isStreamable = ['audio', 'video', 'image'].indexOf(mediaType) !== -1; - return isStreamable; -}); - -const makeSelectDownloadPathForUri = uri => reselect.createSelector(makeSelectFileInfoForUri(uri), fileInfo => { - return fileInfo && fileInfo.download_path; -}); - -const makeSelectFilePartlyDownloaded = uri => reselect.createSelector(makeSelectFileInfoForUri(uri), fileInfo => { - if (!fileInfo) { - return false; - } - - return fileInfo.written_bytes > 0 || fileInfo.blobs_completed > 0; -}); - -const makeSelectFileNameForUri = uri => reselect.createSelector(makeSelectFileInfoForUri(uri), fileInfo => { - return fileInfo && fileInfo.file_name; -}); - -const selectDownloadUrlsCount = reselect.createSelector(selectDownloadedUris, uris => uris.length); - -function filterFileInfos(fileInfos, query) { - if (query) { - const queryMatchRegExp = new RegExp(query, 'i'); - return fileInfos.filter(fileInfo => { - const { metadata } = fileInfo; - - return metadata.title && metadata.title.match(queryMatchRegExp) || fileInfo.channel_name && fileInfo.channel_name.match(queryMatchRegExp) || fileInfo.claim_name && fileInfo.claim_name.match(queryMatchRegExp); - }); - } - - return fileInfos; -} - -const makeSelectSearchDownloadUrlsForPage = (query, page = 1) => reselect.createSelector(selectFileInfosDownloaded, fileInfos => { - const matchingFileInfos = filterFileInfos(fileInfos, query); - const start = (Number(page) - 1) * Number(PAGE_SIZE); - const end = Number(page) * Number(PAGE_SIZE); - - return matchingFileInfos && matchingFileInfos.length ? matchingFileInfos.slice(start, end).map(fileInfo => buildURI({ - streamName: fileInfo.claim_name, - channelName: fileInfo.channel_name, - channelClaimId: fileInfo.channel_claim_id - })) : []; -}); - -const makeSelectSearchDownloadUrlsCount = query => reselect.createSelector(selectFileInfosDownloaded, fileInfos => { - return fileInfos && fileInfos.length ? filterFileInfos(fileInfos, query).length : 0; -}); - -const makeSelectStreamingUrlForUri = uri => reselect.createSelector(makeSelectFileInfoForUri(uri), fileInfo => { - return fileInfo && fileInfo.streaming_url; -}); - -// - -function doFileGet(uri, saveFile = true, onSuccess) { - return (dispatch, getState) => { - const state = getState(); - const { nout, txid } = makeSelectClaimForUri(uri)(state); - const outpoint = `${txid}:${nout}`; - - dispatch({ - type: FETCH_FILE_INFO_STARTED, - data: { - outpoint - } - }); - - // set save_file argument to True to save the file (old behaviour) - lbryProxy.get({ uri, save_file: saveFile }).then(streamInfo => { - const timeout = streamInfo === null || typeof streamInfo !== 'object' || streamInfo.error === 'Timeout'; - if (timeout) { - dispatch({ - type: FETCH_FILE_INFO_FAILED, - data: { outpoint } - }); - - dispatch(doToast({ message: `File timeout for uri ${uri}`, isError: true })); - } else { - if (streamInfo.purchase_receipt || streamInfo.content_fee) { - dispatch({ - type: PURCHASE_URI_COMPLETED, - data: { uri, purchaseReceipt: streamInfo.purchase_receipt || streamInfo.content_fee } - }); - } - dispatch({ - type: FETCH_FILE_INFO_COMPLETED, - data: { - fileInfo: streamInfo, - outpoint: outpoint - } - }); - - if (onSuccess) { - onSuccess(streamInfo); - } - } - }).catch(error => { - dispatch({ - type: PURCHASE_URI_FAILED, - data: { uri, error } - }); - - dispatch({ - type: FETCH_FILE_INFO_FAILED, - data: { outpoint } - }); - - dispatch(doToast({ - message: `Failed to view ${uri}, please try again. If this problem persists, visit https://lbry.com/faq/support for support.`, - isError: true - })); - }); - }; -} - -function doPurchaseUri(uri, costInfo, saveFile = true, onSuccess) { - return (dispatch, getState) => { - dispatch({ - type: PURCHASE_URI_STARTED, - data: { uri } - }); - - const state = getState(); - const balance = selectBalance(state); - const fileInfo = makeSelectFileInfoForUri(uri)(state); - const downloadingByOutpoint = selectDownloadingByOutpoint(state); - const alreadyDownloading = fileInfo && !!downloadingByOutpoint[fileInfo.outpoint]; - const alreadyStreaming = makeSelectStreamingUrlForUri(uri)(state); - - if (!saveFile && (alreadyDownloading || alreadyStreaming)) { - dispatch({ - type: PURCHASE_URI_FAILED, - data: { uri, error: `Already fetching uri: ${uri}` } - }); - return; - } - - const { cost } = costInfo; - if (parseFloat(cost) > balance) { - dispatch({ - type: PURCHASE_URI_FAILED, - data: { uri, error: 'Insufficient credits' } - }); - return; - } - - dispatch(doFileGet(uri, saveFile, onSuccess)); - }; -} - -function doClearPurchasedUriSuccess() { - return { - type: CLEAR_PURCHASED_URI_SUCCESS - }; -} - function doFetchFileInfo(uri) { return (dispatch, getState) => { const state = getState(); @@ -4279,15 +2283,12 @@ function doFetchFileInfo(uri) { } }); - lbryProxy.file_list({ outpoint, full_status: true, page: 1, page_size: 1 }).then(result => { - const { items: fileInfos } = result; - const fileInfo = fileInfos[0]; - + lbryProxy.file_list({ outpoint, full_status: true }).then(fileInfos => { dispatch({ type: FETCH_FILE_INFO_COMPLETED, data: { outpoint, - fileInfo: fileInfo || null + fileInfo: fileInfos && fileInfos.length ? fileInfos[0] : null } }); }); @@ -4295,7 +2296,7 @@ function doFetchFileInfo(uri) { }; } -function doFileList(page = 1, pageSize = 99999) { +function doFileList() { return (dispatch, getState) => { const state = getState(); const isFetching = selectIsFetchingFileList(state); @@ -4305,12 +2306,11 @@ function doFileList(page = 1, pageSize = 99999) { type: FILE_LIST_STARTED }); - lbryProxy.file_list({ page, page_size: pageSize }).then(result => { - const { items: fileInfos } = result; + lbryProxy.file_list().then(fileInfos => { dispatch({ type: FILE_LIST_SUCCEEDED, data: { - fileInfos: fileInfos + fileInfos } }); }); @@ -4318,10 +2318,13 @@ function doFileList(page = 1, pageSize = 99999) { }; } -function doFetchFileInfos() { +function doFetchFileInfosAndPublishedClaims() { return (dispatch, getState) => { const state = getState(); + const isFetchingClaimListMine = selectIsFetchingClaimListMine(state); const isFetchingFileInfo = selectIsFetchingFileList(state); + + if (!isFetchingClaimListMine) dispatch(doFetchClaimListMine()); if (!isFetchingFileInfo) dispatch(doFileList()); }; } @@ -4333,491 +2336,13 @@ function doSetFileListSort(page, value) { }; } -var _extends$7 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; - -function _objectWithoutProperties$2(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } - -const selectState$4 = state => state.publish || {}; - -// Is the current uri the same as the uri they clicked "edit" on -const selectIsStillEditing = reselect.createSelector(selectState$4, publishState => { - const { editingURI, uri } = publishState; - - if (!editingURI || !uri) { - return false; - } - - const { - isChannel: currentIsChannel, - streamName: currentClaimName, - channelName: currentContentName - } = parseURI(uri); - const { - isChannel: editIsChannel, - streamName: editClaimName, - channelName: editContentName - } = parseURI(editingURI); - - // Depending on the previous/current use of a channel, we need to compare different things - // ex: going from a channel to anonymous, the new uri won't return contentName, so we need to use claimName - const currentName = currentIsChannel ? currentContentName : currentClaimName; - const editName = editIsChannel ? editContentName : editClaimName; - return currentName === editName; -}); - -const selectPublishFormValues = reselect.createSelector(selectState$4, selectIsStillEditing, (state, isStillEditing) => { - const { pendingPublish, language, languages } = state, - formValues = _objectWithoutProperties$2(state, ['pendingPublish', 'language', 'languages']); - - let actualLanguage; - // Sets default if editing a claim with a set language - if (!language && isStillEditing && languages && languages[0]) { - actualLanguage = languages[0]; - } else { - actualLanguage = language || 'en'; - } - return _extends$7({}, formValues, { language: actualLanguage }); -}); -const makeSelectPublishFormValue = item => reselect.createSelector(selectState$4, state => state[item]); - -const selectMyClaimForUri = reselect.createSelector(selectPublishFormValues, selectIsStillEditing, selectClaimsById, selectMyClaimsWithoutChannels, ({ editingURI, uri }, isStillEditing, claimsById, myClaims) => { - const { channelName: contentName, streamName: claimName } = parseURI(uri); - const { streamClaimId: editClaimId } = parseURI(editingURI); - - // If isStillEditing - // They clicked "edit" from the file page - // They haven't changed the channel/name after clicking edit - // Get the claim so they can edit without re-uploading a new file - return isStillEditing ? claimsById[editClaimId] : myClaims.find(claim => !contentName ? claim.name === claimName : claim.name === contentName || claim.name === claimName); -}); - -const selectIsResolvingPublishUris = reselect.createSelector(selectState$4, selectResolvingUris, ({ uri, name }, resolvingUris) => { - if (uri) { - const isResolvingUri = resolvingUris.includes(uri); - const { isChannel } = parseURI(uri); - - let isResolvingShortUri; - if (isChannel && name) { - const shortUri = buildURI({ streamName: name }); - isResolvingShortUri = resolvingUris.includes(shortUri); - } - - return isResolvingUri || isResolvingShortUri; - } - - return false; -}); - -const selectTakeOverAmount = reselect.createSelector(selectState$4, selectMyClaimForUri, selectClaimsByUri, ({ name }, myClaimForUri, claimsByUri) => { - if (!name) { - return null; - } - - // We only care about the winning claim for the short uri - const shortUri = buildURI({ streamName: name }); - const claimForShortUri = claimsByUri[shortUri]; - - if (!myClaimForUri && claimForShortUri) { - return claimForShortUri.meta.effective_amount; - } else if (myClaimForUri && claimForShortUri) { - // https://github.com/lbryio/lbry/issues/1476 - // We should check the current effective_amount on my claim to see how much additional lbc - // is needed to win the claim. Currently this is not possible during a takeover. - // With this, we could say something like, "You have x lbc in support, if you bid y additional LBC you will control the claim" - // For now just ignore supports. We will just show the winning claim's bid amount - return claimForShortUri.meta.effective_amount || claimForShortUri.amount; - } - - return null; -}); - -var _extends$8 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; - -function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } - -const doResetThumbnailStatus = () => dispatch => { - dispatch({ - type: UPDATE_PUBLISH_FORM, - data: { - thumbnailPath: '' - } - }); - - return fetch(SPEECH_STATUS).then(res => res.json()).then(status => { - if (status.disabled) { - throw Error(); - } - - return dispatch({ - type: UPDATE_PUBLISH_FORM, - data: { - uploadThumbnailStatus: READY, - thumbnail: '' - } - }); - }).catch(() => dispatch({ - type: UPDATE_PUBLISH_FORM, - data: { - uploadThumbnailStatus: API_DOWN, - thumbnail: '' - } - })); -}; - -const doClearPublish = () => dispatch => { - dispatch({ type: CLEAR_PUBLISH }); - return dispatch(doResetThumbnailStatus()); -}; - -const doUpdatePublishForm = publishFormValue => dispatch => dispatch({ - type: UPDATE_PUBLISH_FORM, - data: _extends$8({}, publishFormValue) -}); - -const doUploadThumbnail = (filePath, thumbnailBlob, fsAdapter, fs, path) => dispatch => { - let thumbnail, fileExt, fileName, fileType; - - const makeid = () => { - let text = ''; - const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; - for (let i = 0; i < 24; i += 1) text += possible.charAt(Math.floor(Math.random() * 62)); - return text; +// https://github.com/reactjs/redux/issues/911 +function batchActions(...actions) { + return { + type: 'BATCH_ACTIONS', + actions }; - - const uploadError = (error = '') => { - dispatch(batchActions({ - type: UPDATE_PUBLISH_FORM, - data: { - uploadThumbnailStatus: READY, - thumbnail: '', - nsfw: false - } - }, doError(error))); - }; - - const doUpload = data => { - return fetch(SPEECH_PUBLISH, { - method: 'POST', - body: data - }).then(res => res.text()).then(text => text.length ? JSON.parse(text) : {}).then(json => { - return json.success ? dispatch({ - type: UPDATE_PUBLISH_FORM, - data: { - uploadThumbnailStatus: COMPLETE, - thumbnail: json.data.serveUrl - } - }) : uploadError(json.message || __('Thumbnail upload service may be down, try again later.')); - }).catch(err => { - uploadError(err.message); - }); - }; - - dispatch({ - type: UPDATE_PUBLISH_FORM, - data: { uploadThumbnailStatus: IN_PROGRESS } - }); - - if (fsAdapter && fsAdapter.readFile && filePath) { - fsAdapter.readFile(filePath, 'base64').then(base64Image => { - fileExt = 'png'; - fileName = 'thumbnail.png'; - fileType = 'image/png'; - - const data = new FormData(); - const name = makeid(); - data.append('name', name); - // $FlowFixMe - data.append('file', { uri: 'file://' + filePath, type: fileType, name: fileName }); - return doUpload(data); - }); - } else { - if (filePath && fs && path) { - thumbnail = fs.readFileSync(filePath); - fileExt = path.extname(filePath); - fileName = path.basename(filePath); - fileType = `image/${fileExt.slice(1)}`; - } else if (thumbnailBlob) { - fileExt = `.${thumbnailBlob.type && thumbnailBlob.type.split('/')[1]}`; - fileName = thumbnailBlob.name; - fileType = thumbnailBlob.type; - } else { - return null; - } - - const data = new FormData(); - const name = makeid(); - const file = thumbnailBlob || thumbnail && new File([thumbnail], fileName, { type: fileType }); - data.append('name', name); - // $FlowFixMe - data.append('file', file); - return doUpload(data); - } -}; - -const doPrepareEdit = (claim, uri, fileInfo, fs) => dispatch => { - const { name, amount, value = {} } = claim; - const channelName = claim && claim.signing_channel && claim.signing_channel.name || null; - const { - author, - description, - // use same values as default state - // fee will be undefined for free content - fee = { - amount: '0', - currency: 'LBC' - }, - languages, - license, - license_url: licenseUrl, - thumbnail, - title, - tags - } = value; - - const publishData = { - name, - bid: amount, - contentIsFree: fee.amount === '0', - author, - description, - fee, - languages, - thumbnail: thumbnail ? thumbnail.url : null, - title, - uri, - uploadThumbnailStatus: thumbnail ? MANUAL : undefined, - licenseUrl, - nsfw: isClaimNsfw(claim), - tags: tags ? tags.map(tag => ({ name: tag })) : [] - }; - - // Make sure custom licenses are mapped properly - // If the license isn't one of the standard licenses, map the custom license and description/url - if (!CC_LICENSES.some(({ value }) => value === license)) { - if (!license || license === NONE || license === PUBLIC_DOMAIN) { - publishData.licenseType = license; - } else if (license && !licenseUrl && license !== NONE) { - publishData.licenseType = COPYRIGHT; - } else { - publishData.licenseType = OTHER; - } - - publishData.otherLicenseDescription = license; - } else { - publishData.licenseType = license; - } - if (channelName) { - publishData['channel'] = channelName; - } - - dispatch({ type: DO_PREPARE_EDIT, data: publishData }); -}; - -const doPublish = (success, fail) => (dispatch, getState) => { - dispatch({ type: PUBLISH_START }); - - const state = getState(); - const myClaimForUri = selectMyClaimForUri(state); - const myChannels = selectMyChannelClaims(state); - const myClaims = selectMyClaimsWithoutChannels(state); - // get redux publish form - const publishData = selectPublishFormValues(state); - - // destructure the data values - const { - name, - bid, - filePath, - description, - language, - license, - licenseUrl, - useLBRYUploader, - licenseType, - otherLicenseDescription, - thumbnail, - channel, - title, - contentIsFree, - fee, - uri, - tags, - locations, - optimize - } = publishData; - // Handle scenario where we have a claim that has the same name as a channel we are publishing with. - const myClaimForUriEditing = myClaimForUri && myClaimForUri.name === name ? myClaimForUri : null; - - let publishingLicense; - switch (licenseType) { - case COPYRIGHT: - case OTHER: - publishingLicense = otherLicenseDescription; - break; - default: - publishingLicense = licenseType; - } - - // get the claim id from the channel name, we will use that instead - const namedChannelClaim = myChannels ? myChannels.find(myChannel => myChannel.name === channel) : null; - const channelId = namedChannelClaim ? namedChannelClaim.claim_id : ''; - - const publishPayload = { - name, - title, - description, - locations: [], - bid: creditsToString(bid), - languages: [language], - tags: tags && tags.map(tag => tag.name), - thumbnail_url: thumbnail, - blocking: true - }; - // Temporary solution to keep the same publish flow with the new tags api - // Eventually we will allow users to enter their own tags on publish - // `nsfw` will probably be removed - - if (publishingLicense) { - publishPayload.license = publishingLicense; - } - - if (licenseUrl) { - publishPayload.license_url = licenseUrl; - } - - if (thumbnail) { - publishPayload.thumbnail_url = thumbnail; - } - - if (useLBRYUploader) { - publishPayload.tags.push('lbry-first'); - } - - // Set release time to curret date. On edits, keep original release/transaction time as release_time - if (myClaimForUriEditing && myClaimForUriEditing.value.release_time) { - publishPayload.release_time = Number(myClaimForUri.value.release_time); - } else if (myClaimForUriEditing && myClaimForUriEditing.timestamp) { - publishPayload.release_time = Number(myClaimForUriEditing.timestamp); - } else { - publishPayload.release_time = Number(Math.round(Date.now() / 1000)); - } - - if (channelId) { - publishPayload.channel_id = channelId; - } - - if (myClaimForUriEditing && myClaimForUriEditing.value && myClaimForUriEditing.value.locations) { - publishPayload.locations = myClaimForUriEditing.value.locations; - } - - if (!contentIsFree && fee && fee.currency && Number(fee.amount) > 0) { - publishPayload.fee_currency = fee.currency; - publishPayload.fee_amount = creditsToString(fee.amount); - } - - if (optimize) { - publishPayload.optimize_file = true; - } - - // Only pass file on new uploads, not metadata only edits. - // The sdk will figure it out - if (filePath) publishPayload.file_path = filePath; - - return lbryProxy.publish(publishPayload).then(response => { - if (!useLBRYUploader) { - return success(response); - } - - // $FlowFixMe - publishPayload.permanent_url = response.outputs[0].permanent_url; - - return lbryFirstProxy.upload(publishPayload).then(() => { - // Return original publish response so app treats it like a normal publish - return success(response); - }).catch(error => { - return success(response, error); - }); - }, fail); -}; - -// Calls file_list until any reflecting files are done -const doCheckReflectingFiles = () => (dispatch, getState) => { - const state = getState(); - const { checkingReflector } = state.claims; - let reflectorCheckInterval; - - const checkFileList = (() => { - var _ref = _asyncToGenerator(function* () { - const state = getState(); - const reflectingById = selectReflectingById(state); - const ids = Object.keys(reflectingById); - - const newReflectingById = {}; - const promises = []; - // TODO: just use file_list({claim_id: Array}) - if (Object.keys(reflectingById).length) { - ids.forEach(function (claimId) { - promises.push(lbryProxy.file_list({ claim_id: claimId })); - }); - - Promise.all(promises).then(function (results) { - results.forEach(function (res) { - if (res.items[0]) { - const fileListItem = res.items[0]; - const fileClaimId = fileListItem.claim_id; - const { - is_fully_reflected: done, - uploading_to_reflector: uploading, - reflector_progress: progress - } = fileListItem; - if (uploading) { - newReflectingById[fileClaimId] = { - fileListItem: fileListItem, - progress, - stalled: !done && !uploading - }; - } - } - }); - }).then(function () { - dispatch({ - type: UPDATE_FILES_REFLECTING, - data: newReflectingById - }); - if (!Object.keys(newReflectingById).length) { - dispatch({ - type: TOGGLE_CHECKING_REFLECTING, - data: false - }); - clearInterval(reflectorCheckInterval); - } - }); - } else { - dispatch({ - type: TOGGLE_CHECKING_REFLECTING, - data: false - }); - clearInterval(reflectorCheckInterval); - } - }); - - return function checkFileList() { - return _ref.apply(this, arguments); - }; - })(); - // do it once... - checkFileList(); - // then start the interval if it's not already started - if (!checkingReflector) { - dispatch({ - type: TOGGLE_CHECKING_REFLECTING, - data: true - }); - reflectorCheckInterval = setInterval(() => { - checkFileList(); - }, 5000); - } -}; +} // Returns a function, that, as long as it continues to be invoked, will not // be triggered. The function will be called after it stops being called for @@ -4846,12 +2371,12 @@ function handleFetchResponse(response) { return response.status === 200 ? Promise.resolve(response.json()) : Promise.reject(new Error(response.statusText)); } -var _extends$9 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; +// const DEBOUNCED_SEARCH_SUGGESTION_MS = 300; // We can't use env's because they aren't passed into node_modules -let CONNECTION_STRING = 'https://lighthouse.lbry.com/'; +let CONNECTION_STRING = 'https://lighthouse.lbry.io/'; const setSearchApi = endpoint => { CONNECTION_STRING = endpoint.replace(/\/*$/, '/'); // exactly one slash at the end; @@ -4903,10 +2428,10 @@ const doUpdateSearchQuery = (query, shouldSkipSuggestions) => dispatch => { } }; -const doSearch = (rawQuery, searchOptions) => (dispatch, getState) => { +const doSearch = (rawQuery, // pass in a query if you don't want to search for what's in the search bar +size, // only pass in if you don't want to use the users setting (ex: related content) +from, isBackgroundSearch = false) => (dispatch, getState) => { const query = rawQuery.replace(/^lbry:\/\//i, '').replace(/\//, ' '); - const resolveResults = searchOptions && searchOptions.resolveResults; - const isBackgroundSearch = searchOptions && searchOptions.isBackgroundSearch || false; if (!query) { dispatch({ @@ -4916,8 +2441,7 @@ const doSearch = (rawQuery, searchOptions) => (dispatch, getState) => { } const state = getState(); - - let queryWithOptions = makeSelectQueryWithOptions(query, searchOptions)(state); + const queryWithOptions = makeSelectQueryWithOptions(query, size, from, isBackgroundSearch)(state); // If we have already searched for something, we don't need to do anything const urisForQuery = makeSelectSearchUris(queryWithOptions)(state); @@ -4942,24 +2466,12 @@ const doSearch = (rawQuery, searchOptions) => (dispatch, getState) => { const actions = []; data.forEach(result => { - if (result) { - const { name, claimId } = result; - const urlObj = {}; - - if (name.startsWith('@')) { - urlObj.channelName = name; - urlObj.channelClaimId = claimId; - } else { - urlObj.streamName = name; - urlObj.streamClaimId = claimId; - } - - const url = buildURI(urlObj); - if (resolveResults) { - actions.push(doResolveUri(url)); - } - uris.push(url); - } + const uri = buildURI({ + claimName: result.name, + claimId: result.claimId + }); + actions.push(doResolveUri(uri)); + uris.push(uri); }); actions.push({ @@ -4970,80 +2482,13 @@ const doSearch = (rawQuery, searchOptions) => (dispatch, getState) => { } }); dispatch(batchActions(...actions)); - }).catch(e => { + }).catch(() => { dispatch({ type: SEARCH_FAIL }); }); }; -const doResolvedSearch = (rawQuery, size, // only pass in if you don't want to use the users setting (ex: related content) -from, isBackgroundSearch = false, options = {}, nsfw) => (dispatch, getState) => { - const query = rawQuery.replace(/^lbry:\/\//i, '').replace(/\//, ' '); - - if (!query) { - dispatch({ - type: RESOLVED_SEARCH_FAIL - }); - return; - } - - const optionsWithFrom = _extends$9({}, size ? { size } : {}, from ? { from } : {}, { - isBackgroundSearch - }, options); - - const optionsWithoutFrom = _extends$9({}, size ? { size } : {}, { - isBackgroundSearch - }, options); - - const state = getState(); - - let queryWithOptions = makeSelectQueryWithOptions(query, optionsWithFrom)(state); - - // make from null so that we can maintain a reference to the same query for multiple pages and simply append the found results - let queryWithoutFrom = makeSelectQueryWithOptions(query, optionsWithoutFrom)(state); - - // If we have already searched for something, we don't need to do anything - // TODO: Tweak this check for multiple page results - /* const resultsForQuery = makeSelectResolvedSearchResults(queryWithOptions)(state); - if (resultsForQuery && resultsForQuery.length && resultsForQuery.length > (from * size)) { - return; - } */ - - dispatch({ - type: RESOLVED_SEARCH_START - }); - - if (!state.search.searchQuery && !isBackgroundSearch) { - dispatch(doUpdateSearchQuery(query)); - } - - const fetchUrl = nsfw ? `${CONNECTION_STRING}search?resolve=true&${queryWithOptions}` : `${CONNECTION_STRING}search?resolve=true&nsfw=false&${queryWithOptions}`; - fetch(fetchUrl).then(handleFetchResponse).then(data => { - const results = []; - - data.forEach(result => { - if (result) { - results.push(result); - } - }); - - dispatch({ - type: RESOLVED_SEARCH_SUCCESS, - data: { - query: queryWithoutFrom, - results, - pageSize: size, - append: parseInt(from, 10) > parseInt(size, 10) - 1 - } - }); - }).catch(e => { - dispatch({ - type: RESOLVED_SEARCH_FAIL - }); - }); -}; - const doFocusSearchInput = () => dispatch => dispatch({ type: SEARCH_FOCUS }); @@ -5052,7 +2497,7 @@ const doBlurSearchInput = () => dispatch => dispatch({ type: SEARCH_BLUR }); -const doUpdateSearchOptions = (newOptions, additionalOptions) => (dispatch, getState) => { +const doUpdateSearchOptions = newOptions => (dispatch, getState) => { const state = getState(); const searchValue = selectSearchValue(state); @@ -5063,12 +2508,10 @@ const doUpdateSearchOptions = (newOptions, additionalOptions) => (dispatch, getS if (searchValue) { // After updating, perform a search with the new options - dispatch(doSearch(searchValue, additionalOptions)); + dispatch(doSearch(searchValue)); } }; -// - function savePosition(claimId, outpoint, position) { return dispatch => { dispatch({ @@ -5080,341 +2523,53 @@ function savePosition(claimId, outpoint, position) { // -const doToggleTagFollow = name => ({ - type: TOGGLE_TAG_FOLLOW, - data: { - name - } -}); - -const doAddTag = name => ({ - type: TAG_ADD, - data: { - name - } -}); - -const doDeleteTag = name => ({ - type: TAG_DELETE, - data: { - name - } -}); - -// - -function doCommentList(uri, page = 1, pageSize = 99999) { - return (dispatch, getState) => { - const state = getState(); - const claim = selectClaimsByUri(state)[uri]; - const claimId = claim ? claim.claim_id : null; - - dispatch({ - type: COMMENT_LIST_STARTED - }); - lbryProxy.comment_list({ - claim_id: claimId, - page, - page_size: pageSize - }).then(result => { - const { items: comments } = result; - dispatch({ - type: COMMENT_LIST_COMPLETED, - data: { - comments, - claimId: claimId, - uri: uri - } - }); - }).catch(error => { - console.log(error); - dispatch({ - type: COMMENT_LIST_FAILED, - data: error - }); - }); - }; -} - -function doCommentCreate(comment = '', claim_id = '', channel, parent_id) { - return (dispatch, getState) => { - const state = getState(); - dispatch({ - type: COMMENT_CREATE_STARTED - }); - - const myChannels = selectMyChannelClaims(state); - const namedChannelClaim = myChannels && myChannels.find(myChannel => myChannel.name === channel); - const channel_id = namedChannelClaim.claim_id; - - if (channel_id == null) { - dispatch({ - type: COMMENT_CREATE_FAILED, - data: {} - }); - dispatch(doToast({ - message: 'Channel cannot be anonymous, please select a channel and try again.', - isError: true - })); - return; - } - - return lbryProxy.comment_create({ - comment: comment, - claim_id: claim_id, - channel_id: channel_id, - parent_id: parent_id - }).then(result => { - dispatch({ - type: COMMENT_CREATE_COMPLETED, - data: { - comment: result, - claimId: claim_id - } - }); - }).catch(error => { - dispatch({ - type: COMMENT_CREATE_FAILED, - data: error - }); - dispatch(doToast({ - message: 'Unable to create comment, please try again later.', - isError: true - })); - }); - }; -} - -function doCommentHide(comment_id) { - return dispatch => { - dispatch({ - type: COMMENT_HIDE_STARTED - }); - return lbryProxy.comment_hide({ - comment_ids: [comment_id] - }).then(result => { - dispatch({ - type: COMMENT_HIDE_COMPLETED, - data: result - }); - }).catch(error => { - dispatch({ - type: COMMENT_HIDE_FAILED, - data: error - }); - dispatch(doToast({ - message: 'Unable to hide this comment, please try again later.', - isError: true - })); - }); - }; -} - -function doCommentAbandon(comment_id) { - return dispatch => { - dispatch({ - type: COMMENT_ABANDON_STARTED - }); - return lbryProxy.comment_abandon({ - comment_id: comment_id - }).then(result => { - // Comment may not be deleted if the signing channel can't be signed. - // This will happen if the channel was recently created or abandoned. - if (result.abandoned) { - dispatch({ - type: COMMENT_ABANDON_COMPLETED, - data: { - comment_id: comment_id - } - }); - } else { - dispatch({ - type: COMMENT_ABANDON_FAILED - }); - dispatch(doToast({ - message: 'Your channel is still being setup, try again in a few moments.', - isError: true - })); - } - }).catch(error => { - dispatch({ - type: COMMENT_ABANDON_FAILED, - data: error - }); - dispatch(doToast({ - message: 'Unable to delete this comment, please try again later.', - isError: true - })); - }); - }; -} - -function doCommentUpdate(comment_id, comment) { - // if they provided an empty string, they must have wanted to abandon - if (comment === '') { - return doCommentAbandon(comment_id); - } else { - return dispatch => { - dispatch({ - type: COMMENT_UPDATE_STARTED - }); - return lbryProxy.comment_update({ - comment_id: comment_id, - comment: comment - }).then(result => { - if (result != null) { - dispatch({ - type: COMMENT_UPDATE_COMPLETED, - data: { - comment: result - } - }); - } else { - // the result will return null - dispatch({ - type: COMMENT_UPDATE_FAILED - }); - dispatch(doToast({ - message: 'Your channel is still being setup, try again in a few moments.', - isError: true - })); - } - }).catch(error => { - dispatch({ - type: COMMENT_UPDATE_FAILED, - data: error - }); - dispatch(doToast({ - message: 'Unable to edit this comment, please try again later.', - isError: true - })); - }); - }; - } -} - -// - -const doToggleBlockChannel = uri => ({ - type: TOGGLE_BLOCK_CHANNEL, - data: { - uri - } -}); - -var _extends$a = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; - -/* -new claim = { ...maybeResolvedClaim, ...pendingClaim, meta: maybeResolvedClaim['meta'] } - */ - -function mergeClaims(maybeResolved, pending) { - return _extends$a({}, maybeResolved, pending, { meta: maybeResolved.meta }); -} - -var _extends$b = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; - -function _objectWithoutProperties$3(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } - const reducers = {}; const defaultState = { byId: {}, claimsByUri: {}, - paginatedClaimsByChannel: {}, + claimsByChannel: {}, channelClaimCounts: {}, fetchingChannelClaims: {}, resolvingUris: [], - myChannelClaims: undefined, - myClaims: undefined, - myPurchases: undefined, - myPurchasesPageNumber: undefined, - myPurchasesPageTotalResults: undefined, - purchaseUriSuccess: false, - fetchingMyPurchases: false, - fetchingMyPurchasesError: undefined, + // This should not be a Set + // Storing sets in reducers can cause issues + myChannelClaims: new Set(), fetchingMyChannels: false, abandoningById: {}, - pendingIds: [], - reflectingById: {}, - claimSearchError: false, - claimSearchByQuery: {}, - claimSearchByQueryLastPageReached: {}, - fetchingClaimSearchByQuery: {}, - updateChannelError: '', - updatingChannel: false, - creatingChannel: false, - createChannelError: undefined, - pendingChannelImport: false, - repostLoading: false, - repostError: undefined, - fetchingClaimListMinePageError: undefined, - myClaimsPageResults: [], - myClaimsPageNumber: undefined, - myClaimsPageTotalResults: undefined, - isFetchingClaimListMine: false, - isFetchingMyPurchases: false, - isCheckingNameForPublish: false, - checkingPending: false, - checkingReflecting: false + pendingById: {} }; -function handleClaimAction(state, action) { - const { - resolveInfo - } = action.data; - +reducers[RESOLVE_URIS_COMPLETED] = (state, action) => { + const { resolveInfo } = action.data; const byUri = Object.assign({}, state.claimsByUri); const byId = Object.assign({}, state.byId); const channelClaimCounts = Object.assign({}, state.channelClaimCounts); - const pendingIds = state.pendingIds; - let newResolvingUrls = new Set(state.resolvingUris); - Object.entries(resolveInfo).forEach(([url, resolveResponse]) => { + Object.entries(resolveInfo).forEach(([uri, resolveResponse]) => { // $FlowFixMe - const { claimsInChannel, stream, channel } = resolveResponse; - - if (stream) { - if (pendingIds.includes(stream.claim_id)) { - byId[stream.claim_id] = mergeClaims(stream, byId[stream.claim_id]); - } else { - byId[stream.claim_id] = stream; - } - byUri[url] = stream.claim_id; - - // If url isn't a canonical_url, make sure that is added too - byUri[stream.canonical_url] = stream.claim_id; - - // Also add the permanent_url here until lighthouse returns canonical_url for search results - byUri[stream.permanent_url] = stream.claim_id; - newResolvingUrls.delete(stream.canonical_url); - newResolvingUrls.delete(stream.permanent_url); + if (resolveResponse.certificate && !Number.isNaN(resolveResponse.claimsInChannel)) { + // $FlowFixMe + channelClaimCounts[uri] = resolveResponse.claimsInChannel; } + }); - if (channel && channel.claim_id) { - if (!stream) { - byUri[url] = channel.claim_id; - } + // $FlowFixMe + Object.entries(resolveInfo).forEach(([uri, { certificate, claim }]) => { + if (claim && !certificate) { + byId[claim.claim_id] = claim; + byUri[uri] = claim.claim_id; + } else if (claim && certificate) { + byId[claim.claim_id] = claim; + byUri[uri] = claim.claim_id; - if (claimsInChannel) { - channelClaimCounts[url] = claimsInChannel; - channelClaimCounts[channel.canonical_url] = claimsInChannel; - } - - if (pendingIds.includes(channel.claim_id)) { - byId[channel.claim_id] = mergeClaims(channel, byId[channel.claim_id]); - } else { - byId[channel.claim_id] = channel; - } - // Also add the permanent_url here until lighthouse returns canonical_url for search results - byUri[channel.permanent_url] = channel.claim_id; - byUri[channel.canonical_url] = channel.claim_id; - newResolvingUrls.delete(channel.canonical_url); - newResolvingUrls.delete(channel.permanent_url); - } - - newResolvingUrls.delete(url); - if (!stream && !channel && !pendingIds.includes(byUri[url])) { - byUri[url] = null; + byId[certificate.claim_id] = certificate; + const channelUri = `lbry://${certificate.name}#${certificate.claim_id}`; + byUri[channelUri] = certificate.claim_id; + } else if (!claim && certificate) { + byId[certificate.claim_id] = certificate; + byUri[uri] = certificate.claim_id; + } else { + byUri[uri] = null; } }); @@ -5422,29 +2577,8 @@ function handleClaimAction(state, action) { byId, claimsByUri: byUri, channelClaimCounts, - resolvingUris: Array.from(newResolvingUrls) + resolvingUris: (state.resolvingUris || []).filter(uri => !resolveInfo[uri]) }); -} - -reducers[RESOLVE_URIS_STARTED] = (state, action) => { - const { uris } = action.data; - - const oldResolving = state.resolvingUris || []; - const newResolving = oldResolving.slice(); - - uris.forEach(uri => { - if (!newResolving.includes(uri)) { - newResolving.push(uri); - } - }); - - return Object.assign({}, state, { - resolvingUris: newResolving - }); -}; - -reducers[RESOLVE_URIS_COMPLETED] = (state, action) => { - return _extends$b({}, handleClaimAction(state, action)); }; reducers[FETCH_CLAIM_LIST_MINE_STARTED] = state => Object.assign({}, state, { @@ -5452,47 +2586,40 @@ reducers[FETCH_CLAIM_LIST_MINE_STARTED] = state => Object.assign({}, state, { }); reducers[FETCH_CLAIM_LIST_MINE_COMPLETED] = (state, action) => { - const { result, resolve } = action.data; - const claims = result.items; - const page = result.page; - const totalItems = result.total_items; - + const { claims } = action.data; const byId = Object.assign({}, state.byId); const byUri = Object.assign({}, state.claimsByUri); - const pendingIds = state.pendingIds || []; - let myClaimIds = new Set(state.myClaims); - let urlsForCurrentPage = []; - - const pendingIdSet = new Set(pendingIds); + const pendingById = Object.assign({}, state.pendingById); claims.forEach(claim => { - const { permanent_url: permanentUri, claim_id: claimId } = claim; + const uri = buildURI({ claimName: claim.name, claimId: claim.claim_id }); + if (claim.type && claim.type.match(/claim|update/)) { - urlsForCurrentPage.push(permanentUri); if (claim.confirmations < 1) { - pendingIdSet.add(claimId); - } else if (!resolve && pendingIdSet.has(claimId) && claim.confirmations > 0) { - pendingIdSet.delete(claimId); - } - if (pendingIds.includes(claimId)) { - byId[claimId] = mergeClaims(claim, byId[claimId]); + pendingById[claim.claim_id] = claim; + delete byId[claim.claim_id]; + delete byUri[claim.claim_id]; } else { - byId[claimId] = claim; + byId[claim.claim_id] = claim; + byUri[uri] = claim.claim_id; } - byUri[permanentUri] = claimId; - myClaimIds.add(claimId); } }); + // Remove old pending publishes + Object.values(pendingById) + // $FlowFixMe + .filter(pendingClaim => byId[pendingClaim.claim_id]).forEach(pendingClaim => { + // $FlowFixMe + delete pendingById[pendingClaim.claim_id]; + }); + return Object.assign({}, state, { isFetchingClaimListMine: false, - myClaims: Array.from(myClaimIds), + myClaims: claims, byId, - pendingIds: Array.from(pendingIdSet), claimsByUri: byUri, - myClaimsPageResults: urlsForCurrentPage, - myClaimsPageNumber: page, - myClaimsPageTotalResults: totalItems + pendingById }); }; @@ -5500,50 +2627,18 @@ reducers[FETCH_CHANNEL_LIST_STARTED] = state => Object.assign({}, state, { fetch reducers[FETCH_CHANNEL_LIST_COMPLETED] = (state, action) => { const { claims } = action.data; - const myClaims = state.myClaims || []; - let myClaimIds = new Set(state.myClaims); - const pendingIds = state.pendingIds || []; - let myChannelClaims; + const myChannelClaims = new Set(state.myChannelClaims); const byId = Object.assign({}, state.byId); - const byUri = Object.assign({}, state.claimsByUri); - const channelClaimCounts = Object.assign({}, state.channelClaimCounts); - if (!claims.length) { - // $FlowFixMe - myChannelClaims = null; - } else { - myChannelClaims = new Set(state.myChannelClaims); - claims.forEach(claim => { - const { claims_in_channel: claimsInChannel } = claim.meta; - const { canonical_url: canonicalUrl, permanent_url: permanentUrl, claim_id: claimId } = claim; - - byUri[canonicalUrl] = claimId; - byUri[permanentUrl] = claimId; - channelClaimCounts[canonicalUrl] = claimsInChannel; - channelClaimCounts[permanentUrl] = claimsInChannel; - - // $FlowFixMe - myChannelClaims.add(claimId); - if (!pendingIds.some(c => c === claimId)) { - byId[claimId] = claim; - } - myClaimIds.add(claimId); - }); - } + claims.forEach(claim => { + myChannelClaims.add(claim.claim_id); + byId[claim.claim_id] = claim; + }); return Object.assign({}, state, { byId, - claimsByUri: byUri, - channelClaimCounts, fetchingMyChannels: false, - myChannelClaims: myChannelClaims ? Array.from(myChannelClaims) : null, - myClaims: myClaimIds ? Array.from(myClaimIds) : null - }); -}; - -reducers[FETCH_CHANNEL_LIST_FAILED] = (state, action) => { - return Object.assign({}, state, { - fetchingMyChannels: false + myChannelClaims }); }; @@ -5563,18 +2658,11 @@ reducers[FETCH_CHANNEL_CLAIMS_COMPLETED] = (state, action) => { const { uri, claims, - claimsInChannel, - page, - totalPages + page } = action.data; - // byChannel keeps claim_search relevant results by page. If the total changes, erase it. - const channelClaimCounts = Object.assign({}, state.channelClaimCounts); - - const paginatedClaimsByChannel = Object.assign({}, state.paginatedClaimsByChannel); - // check if count has changed - that means cached pagination will be wrong, so clear it - const previousCount = paginatedClaimsByChannel[uri] && paginatedClaimsByChannel[uri]['itemCount']; - const byChannel = claimsInChannel === previousCount ? Object.assign({}, paginatedClaimsByChannel[uri]) : {}; + const claimsByChannel = Object.assign({}, state.claimsByChannel); + const byChannel = Object.assign({}, claimsByChannel[uri]); const allClaimIds = new Set(byChannel.all); const currentPageClaimIds = []; const byId = Object.assign({}, state.byId); @@ -5586,23 +2674,20 @@ reducers[FETCH_CHANNEL_CLAIMS_COMPLETED] = (state, action) => { allClaimIds.add(claim.claim_id); currentPageClaimIds.push(claim.claim_id); byId[claim.claim_id] = claim; - claimsByUri[claim.canonical_url] = claim.claim_id; + claimsByUri[`lbry://${claim.name}#${claim.claim_id}`] = claim.claim_id; }); } byChannel.all = allClaimIds; - byChannel.pageCount = totalPages; - byChannel.itemCount = claimsInChannel; byChannel[page] = currentPageClaimIds; - paginatedClaimsByChannel[uri] = byChannel; + claimsByChannel[uri] = byChannel; delete fetchingChannelClaims[uri]; return Object.assign({}, state, { - paginatedClaimsByChannel, + claimsByChannel, byId, fetchingChannelClaims, claimsByUri, - channelClaimCounts, currentChannelPage: page }); }; @@ -5618,76 +2703,9 @@ reducers[ABANDON_CLAIM_STARTED] = (state, action) => { }); }; -reducers[UPDATE_PENDING_CLAIMS] = (state, action) => { - const { claims: pendingClaims } = action.data; - const byId = Object.assign({}, state.byId); - const byUri = Object.assign({}, state.claimsByUri); - const pendingIds = state.pendingIds; - const pendingIdSet = new Set(pendingIds); - let myClaimIds = new Set(state.myClaims); - const myChannelClaims = new Set(state.myChannelClaims); - - // $FlowFixMe - pendingClaims.forEach(claim => { - let newClaim; - const { permanent_url: uri, claim_id: claimId, type, value_type: valueType } = claim; - pendingIdSet.add(claimId); - const oldClaim = byId[claimId]; - if (oldClaim && oldClaim.canonical_url) { - newClaim = mergeClaims(oldClaim, claim); - } else { - newClaim = claim; - } - if (valueType === 'channel') { - myChannelClaims.add(claimId); - } - - if (type && type.match(/claim|update/)) { - byId[claimId] = newClaim; - byUri[uri] = claimId; - } - myClaimIds.add(claimId); - }); - return Object.assign({}, state, { - myClaims: Array.from(myClaimIds), - byId, - myChannelClaims: Array.from(myChannelClaims), - claimsByUri: byUri, - pendingIds: Array.from(pendingIdSet) - }); -}; - -reducers[UPDATE_CONFIRMED_CLAIMS] = (state, action) => { - const { claims: confirmedClaims } = action.data; - const byId = Object.assign({}, state.byId); - const byUri = Object.assign({}, state.claimsByUri); - const pendingIds = state.pendingIds; - const pendingIdSet = new Set(pendingIds); - - confirmedClaims.forEach(claim => { - const { permanent_url: permanentUri, claim_id: claimId, type } = claim; - let newClaim = claim; - const oldClaim = byId[claimId]; - if (oldClaim && oldClaim.canonical_url) { - newClaim = mergeClaims(oldClaim, claim); - } - if (type && type.match(/claim|update|channel/)) { - byId[claimId] = newClaim; - pendingIdSet.delete(claimId); - } - }); - return Object.assign({}, state, { - pendingIds: Array.from(pendingIdSet), - byId, - claimsByUri: byUri - }); -}; - reducers[ABANDON_CLAIM_SUCCEEDED] = (state, action) => { const { claimId } = action.data; const byId = Object.assign({}, state.byId); - const newMyClaims = state.myClaims ? state.myClaims.slice() : []; - const newMyChannelClaims = state.myChannelClaims ? state.myChannelClaims.slice() : []; const claimsByUri = Object.assign({}, state.claimsByUri); Object.keys(claimsByUri).forEach(uri => { @@ -5695,267 +2713,43 @@ reducers[ABANDON_CLAIM_SUCCEEDED] = (state, action) => { delete claimsByUri[uri]; } }); - const myClaims = newMyClaims.filter(i => i !== claimId); - const myChannelClaims = newMyChannelClaims.filter(i => i !== claimId); delete byId[claimId]; return Object.assign({}, state, { - myClaims, - myChannelClaims, byId, claimsByUri }); }; -reducers[CLEAR_CHANNEL_ERRORS] = state => _extends$b({}, state, { - createChannelError: null, - updateChannelError: null -}); - -reducers[CREATE_CHANNEL_STARTED] = state => _extends$b({}, state, { - creatingChannel: true, - createChannelError: null -}); - reducers[CREATE_CHANNEL_COMPLETED] = (state, action) => { - return Object.assign({}, state, { - creatingChannel: false - }); -}; + const channelClaim = action.data.channelClaim; + const byId = Object.assign({}, state.byId); + const myChannelClaims = new Set(state.myChannelClaims); -reducers[CREATE_CHANNEL_FAILED] = (state, action) => { - return Object.assign({}, state, { - creatingChannel: false, - createChannelError: action.data - }); -}; - -reducers[UPDATE_CHANNEL_STARTED] = (state, action) => { - return Object.assign({}, state, { - updateChannelError: '', - updatingChannel: true - }); -}; - -reducers[UPDATE_CHANNEL_COMPLETED] = (state, action) => { - return Object.assign({}, state, { - updateChannelError: '', - updatingChannel: false - }); -}; - -reducers[UPDATE_CHANNEL_FAILED] = (state, action) => { - return Object.assign({}, state, { - updateChannelError: action.data.message, - updatingChannel: false - }); -}; - -reducers[IMPORT_CHANNEL_STARTED] = state => Object.assign({}, state, { pendingChannelImports: true }); - -reducers[IMPORT_CHANNEL_COMPLETED] = state => Object.assign({}, state, { pendingChannelImports: false }); - -reducers[CLAIM_SEARCH_STARTED] = (state, action) => { - const fetchingClaimSearchByQuery = Object.assign({}, state.fetchingClaimSearchByQuery); - fetchingClaimSearchByQuery[action.data.query] = true; + byId[channelClaim.claim_id] = channelClaim; + myChannelClaims.add(channelClaim.claim_id); return Object.assign({}, state, { - fetchingClaimSearchByQuery - }); -}; - -reducers[CLAIM_SEARCH_COMPLETED] = (state, action) => { - const fetchingClaimSearchByQuery = Object.assign({}, state.fetchingClaimSearchByQuery); - const claimSearchByQuery = Object.assign({}, state.claimSearchByQuery); - const claimSearchByQueryLastPageReached = Object.assign({}, state.claimSearchByQueryLastPageReached); - const { append, query, urls, pageSize } = action.data; - - if (append) { - // todo: check for duplicate urls when concatenating? - claimSearchByQuery[query] = claimSearchByQuery[query] && claimSearchByQuery[query].length ? claimSearchByQuery[query].concat(urls) : urls; - } else { - claimSearchByQuery[query] = urls; - } - - // the returned number of urls is less than the page size, so we're on the last page - claimSearchByQueryLastPageReached[query] = urls.length < pageSize; - - delete fetchingClaimSearchByQuery[query]; - - return Object.assign({}, state, _extends$b({}, handleClaimAction(state, action), { - claimSearchByQuery, - claimSearchByQueryLastPageReached, - fetchingClaimSearchByQuery - })); -}; - -reducers[CLAIM_SEARCH_FAILED] = (state, action) => { - const { query } = action.data; - const claimSearchByQuery = Object.assign({}, state.claimSearchByQuery); - const fetchingClaimSearchByQuery = Object.assign({}, state.fetchingClaimSearchByQuery); - - delete fetchingClaimSearchByQuery[query]; - claimSearchByQuery[query] = null; - - return Object.assign({}, state, { - fetchingClaimSearchByQuery, - claimSearchByQuery - }); -}; - -reducers[CLAIM_REPOST_STARTED] = state => { - return _extends$b({}, state, { - repostLoading: true, - repostError: null - }); -}; -reducers[CLAIM_REPOST_COMPLETED] = (state, action) => { - const { originalClaimId, repostClaim } = action.data; - const byId = _extends$b({}, state.byId); - const claimsByUri = _extends$b({}, state.claimsByUri); - const claimThatWasReposted = byId[originalClaimId]; - - const repostStub = _extends$b({}, repostClaim, { reposted_claim: claimThatWasReposted }); - byId[repostStub.claim_id] = repostStub; - claimsByUri[repostStub.permanent_url] = repostStub.claim_id; - - return _extends$b({}, state, { byId, - claimsByUri, - repostLoading: false, - repostError: null - }); -}; -reducers[CLAIM_REPOST_FAILED] = (state, action) => { - const { error } = action.data; - - return _extends$b({}, state, { - repostLoading: false, - repostError: error - }); -}; -reducers[CLEAR_REPOST_ERROR] = state => { - return _extends$b({}, state, { - repostError: null - }); -}; -reducers[ADD_FILES_REFLECTING] = (state, action) => { - const pendingClaim = action.data; - const { reflectingById } = state; - const claimId = pendingClaim && pendingClaim.claim_id; - - reflectingById[claimId] = { fileListItem: pendingClaim, progress: 0, stalled: false }; - - return Object.assign({}, state, _extends$b({}, state, { - reflectingById: reflectingById - })); -}; -reducers[UPDATE_FILES_REFLECTING] = (state, action) => { - const newReflectingById = action.data; - - return Object.assign({}, state, _extends$b({}, state, { - reflectingById: newReflectingById - })); -}; -reducers[TOGGLE_CHECKING_REFLECTING] = (state, action) => { - const checkingReflecting = action.data; - - return Object.assign({}, state, _extends$b({}, state, { - checkingReflecting - })); -}; -reducers[TOGGLE_CHECKING_PENDING] = (state, action) => { - const checking = action.data; - - return Object.assign({}, state, _extends$b({}, state, { - checkingPending: checking - })); -}; - -reducers[PURCHASE_LIST_STARTED] = state => { - return _extends$b({}, state, { - fetchingMyPurchases: true, - fetchingMyPurchasesError: null + myChannelClaims }); }; -reducers[PURCHASE_LIST_COMPLETED] = (state, action) => { - const { result } = action.data; - const page = result.page; - const totalItems = result.total_items; +reducers[RESOLVE_URIS_STARTED] = (state, action) => { + const { uris } = action.data; - let byId = Object.assign({}, state.byId); - let byUri = Object.assign({}, state.claimsByUri); - let urlsForCurrentPage = []; + const oldResolving = state.resolvingUris || []; + const newResolving = oldResolving.slice(); - result.items.forEach(item => { - if (!item.claim) { - // Abandoned claim - return; + uris.forEach(uri => { + if (!newResolving.includes(uri)) { + newResolving.push(uri); } - - const { claim } = item, - purchaseInfo = _objectWithoutProperties$3(item, ['claim']); - claim.purchase_receipt = purchaseInfo; - const claimId = claim.claim_id; - const uri = claim.canonical_url; - - byId[claimId] = claim; - byUri[uri] = claimId; - urlsForCurrentPage.push(uri); }); return Object.assign({}, state, { - byId, - claimsByUri: byUri, - myPurchases: urlsForCurrentPage, - myPurchasesPageNumber: page, - myPurchasesPageTotalResults: totalItems, - fetchingMyPurchases: false - }); -}; - -reducers[PURCHASE_LIST_FAILED] = (state, action) => { - const { error } = action.data; - - return _extends$b({}, state, { - fetchingMyPurchases: false, - fetchingMyPurchasesError: error - }); -}; - -reducers[PURCHASE_URI_COMPLETED] = (state, action) => { - const { uri, purchaseReceipt } = action.data; - - let byId = Object.assign({}, state.byId); - let byUri = Object.assign({}, state.claimsByUri); - let myPurchases = state.myPurchases ? state.myPurchases.slice() : []; - - const claimId = byUri[uri]; - if (claimId) { - let claim = byId[claimId]; - claim.purchase_receipt = purchaseReceipt; - } - - myPurchases.push(uri); - - return _extends$b({}, state, { - byId, - myPurchases, - purchaseUriSuccess: true - }); -}; - -reducers[PURCHASE_URI_FAILED] = state => { - return _extends$b({}, state, { - purchaseUriSuccess: false - }); -}; - -reducers[CLEAR_PURCHASED_URI_SUCCESS] = state => { - return _extends$b({}, state, { - purchaseUriSuccess: false + resolvingUris: newResolving }); }; @@ -5965,6 +2759,195 @@ function claimsReducer(state = defaultState, action) { return state; } +var _extends$4 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +const reducers$1 = {}; +const defaultState$1 = { + fileListPublishedSort: DATE_NEW, + fileListDownloadedSort: DATE_NEW +}; + +reducers$1[FILE_LIST_STARTED] = state => Object.assign({}, state, { + isFetchingFileList: true +}); + +reducers$1[FILE_LIST_SUCCEEDED] = (state, action) => { + const { fileInfos } = action.data; + const newByOutpoint = Object.assign({}, state.byOutpoint); + const pendingByOutpoint = Object.assign({}, state.pendingByOutpoint); + + fileInfos.forEach(fileInfo => { + const { outpoint } = fileInfo; + + if (outpoint) newByOutpoint[fileInfo.outpoint] = fileInfo; + }); + + return Object.assign({}, state, { + isFetchingFileList: false, + byOutpoint: newByOutpoint, + pendingByOutpoint + }); +}; + +reducers$1[FETCH_FILE_INFO_STARTED] = (state, action) => { + const { outpoint } = action.data; + const newFetching = Object.assign({}, state.fetching); + + newFetching[outpoint] = true; + + return Object.assign({}, state, { + fetching: newFetching + }); +}; + +reducers$1[FETCH_FILE_INFO_COMPLETED] = (state, action) => { + const { fileInfo, outpoint } = action.data; + + const newByOutpoint = Object.assign({}, state.byOutpoint); + const newFetching = Object.assign({}, state.fetching); + + newByOutpoint[outpoint] = fileInfo; + delete newFetching[outpoint]; + + return Object.assign({}, state, { + byOutpoint: newByOutpoint, + fetching: newFetching + }); +}; + +reducers$1[DOWNLOADING_STARTED] = (state, action) => { + const { uri, outpoint, fileInfo } = action.data; + + const newByOutpoint = Object.assign({}, state.byOutpoint); + const newDownloading = Object.assign({}, state.downloadingByOutpoint); + const newLoading = Object.assign({}, state.urisLoading); + + newDownloading[outpoint] = true; + newByOutpoint[outpoint] = fileInfo; + delete newLoading[uri]; + + return Object.assign({}, state, { + downloadingByOutpoint: newDownloading, + urisLoading: newLoading, + byOutpoint: newByOutpoint + }); +}; + +reducers$1[DOWNLOADING_PROGRESSED] = (state, action) => { + const { outpoint, fileInfo } = action.data; + + const newByOutpoint = Object.assign({}, state.byOutpoint); + const newDownloading = Object.assign({}, state.downloadingByOutpoint); + + newByOutpoint[outpoint] = fileInfo; + newDownloading[outpoint] = true; + + return Object.assign({}, state, { + byOutpoint: newByOutpoint, + downloadingByOutpoint: newDownloading + }); +}; + +reducers$1[DOWNLOADING_CANCELED] = (state, action) => { + const { outpoint } = action.data; + + const newDownloading = Object.assign({}, state.downloadingByOutpoint); + delete newDownloading[outpoint]; + + return Object.assign({}, state, { + downloadingByOutpoint: newDownloading + }); +}; + +reducers$1[DOWNLOADING_COMPLETED] = (state, action) => { + const { outpoint, fileInfo } = action.data; + + const newByOutpoint = Object.assign({}, state.byOutpoint); + const newDownloading = Object.assign({}, state.downloadingByOutpoint); + + newByOutpoint[outpoint] = fileInfo; + delete newDownloading[outpoint]; + + return Object.assign({}, state, { + byOutpoint: newByOutpoint, + downloadingByOutpoint: newDownloading + }); +}; + +reducers$1[FILE_DELETE] = (state, action) => { + const { outpoint } = action.data; + + const newByOutpoint = Object.assign({}, state.byOutpoint); + const downloadingByOutpoint = Object.assign({}, state.downloadingByOutpoint); + + delete newByOutpoint[outpoint]; + delete downloadingByOutpoint[outpoint]; + + return Object.assign({}, state, { + byOutpoint: newByOutpoint, + downloadingByOutpoint + }); +}; + +reducers$1[LOADING_VIDEO_STARTED] = (state, action) => { + const { uri } = action.data; + + const newLoading = Object.assign({}, state.urisLoading); + newLoading[uri] = true; + + const newErrors = _extends$4({}, state.errors); + if (uri in newErrors) delete newErrors[uri]; + + return Object.assign({}, state, { + urisLoading: newLoading, + errors: _extends$4({}, newErrors) + }); +}; + +reducers$1[LOADING_VIDEO_FAILED] = (state, action) => { + const { uri } = action.data; + + const newLoading = Object.assign({}, state.urisLoading); + delete newLoading[uri]; + + const newErrors = _extends$4({}, state.errors); + newErrors[uri] = true; + + return Object.assign({}, state, { + urisLoading: newLoading, + errors: _extends$4({}, newErrors) + }); +}; + +reducers$1[FETCH_DATE] = (state, action) => { + const { time } = action.data; + if (time) { + return Object.assign({}, state, { + publishedDate: time + }); + } + return null; +}; + +reducers$1[SET_FILE_LIST_SORT] = (state, action) => { + const pageSortStates = { + [PUBLISHED]: 'fileListPublishedSort', + [DOWNLOADED]: 'fileListDownloadedSort' + }; + const pageSortState = pageSortStates[action.data.page]; + const { value } = action.data; + + return Object.assign({}, state, { + [pageSortState]: value + }); +}; + +function fileInfoReducer(state = defaultState$1, action) { + const handler = reducers$1[action.type]; + if (handler) return handler(state, action); + return state; +} + // util for creating reducers // based off of redux-actions // https://redux-actions.js.org/docs/api/handleAction.html#handleactions @@ -5983,322 +2966,9 @@ const handleActions = (actionMap, defaultState) => (state = defaultState, action return state; }; -var _extends$c = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; +var _extends$5 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; -const defaultState$1 = { - commentById: {}, // commentId -> Comment - byId: {}, // ClaimID -> list of comments - commentsByUri: {}, // URI -> claimId - isLoading: false, - myComments: undefined -}; - -const commentReducer = handleActions({ - [COMMENT_CREATE_STARTED]: (state, action) => _extends$c({}, state, { - isLoading: true - }), - - [COMMENT_CREATE_FAILED]: (state, action) => _extends$c({}, state, { - isLoading: false - }), - - [COMMENT_CREATE_COMPLETED]: (state, action) => { - const { comment, claimId } = action.data; - const commentById = Object.assign({}, state.commentById); - const byId = Object.assign({}, state.byId); - const comments = byId[claimId]; - const newCommentIds = comments.slice(); - - // add the comment by its ID - commentById[comment.comment_id] = comment; - - // push the comment_id to the top of ID list - newCommentIds.unshift(comment.comment_id); - byId[claimId] = newCommentIds; - - return _extends$c({}, state, { - commentById, - byId, - isLoading: false - }); - }, - - [COMMENT_LIST_STARTED]: state => _extends$c({}, state, { isLoading: true }), - - [COMMENT_LIST_COMPLETED]: (state, action) => { - const { comments, claimId, uri } = action.data; - - const commentById = Object.assign({}, state.commentById); - const byId = Object.assign({}, state.byId); - const commentsByUri = Object.assign({}, state.commentsByUri); - - if (comments) { - // we use an Array to preserve order of listing - // in reality this doesn't matter and we can just - // sort comments by their timestamp - const commentIds = Array(comments.length); - - // map the comment_ids to the new comments - for (let i = 0; i < comments.length; i++) { - commentIds[i] = comments[i].comment_id; - commentById[commentIds[i]] = comments[i]; - } - - byId[claimId] = commentIds; - commentsByUri[uri] = claimId; - } - return _extends$c({}, state, { - byId, - commentById, - commentsByUri, - isLoading: false - }); - }, - - [COMMENT_LIST_FAILED]: (state, action) => _extends$c({}, state, { - isLoading: false - }), - [COMMENT_ABANDON_STARTED]: (state, action) => _extends$c({}, state, { - isLoading: true - }), - [COMMENT_ABANDON_COMPLETED]: (state, action) => { - const { comment_id } = action.data; - const commentById = Object.assign({}, state.commentById); - const byId = Object.assign({}, state.byId); - - // to remove the comment and its references - const claimId = commentById[comment_id].claim_id; - for (let i = 0; i < byId[claimId].length; i++) { - if (byId[claimId][i] === comment_id) { - byId[claimId].splice(i, 1); - break; - } - } - delete commentById[comment_id]; - - return _extends$c({}, state, { - commentById, - byId, - isLoading: false - }); - }, - // do nothing - [COMMENT_ABANDON_FAILED]: (state, action) => _extends$c({}, state, { - isLoading: false - }), - // do nothing - [COMMENT_UPDATE_STARTED]: (state, action) => _extends$c({}, state, { - isLoading: true - }), - // replace existing comment with comment returned here under its comment_id - [COMMENT_UPDATE_COMPLETED]: (state, action) => { - const { comment } = action.data; - const commentById = Object.assign({}, state.commentById); - commentById[comment.comment_id] = comment; - - return _extends$c({}, state, { - commentById, - isLoading: false - }); - }, - // nothing can be done here - [COMMENT_UPDATE_FAILED]: (state, action) => _extends$c({}, state, { - isLoading: false - }), - // nothing can really be done here - [COMMENT_HIDE_STARTED]: (state, action) => _extends$c({}, state, { - isLoading: true - }), - [COMMENT_HIDE_COMPLETED]: (state, action) => _extends$c({}, state, { // todo: add HiddenComments state & create selectors - isLoading: false - }), - // nothing can be done here - [COMMENT_HIDE_FAILED]: (state, action) => _extends$c({}, state, { - isLoading: false - }) -}, defaultState$1); - -var _extends$d = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; - -const reducers$1 = {}; const defaultState$2 = { - positions: {} -}; - -reducers$1[SET_CONTENT_POSITION] = (state, action) => { - const { claimId, outpoint, position } = action.data; - return _extends$d({}, state, { - positions: _extends$d({}, state.positions, { - [claimId]: _extends$d({}, state.positions[claimId], { - [outpoint]: position - }) - }) - }); -}; - -function contentReducer(state = defaultState$2, action) { - const handler = reducers$1[action.type]; - if (handler) return handler(state, action); - return state; -} - -const reducers$2 = {}; -const defaultState$3 = { - fileListPublishedSort: DATE_NEW, - fileListDownloadedSort: DATE_NEW -}; - -reducers$2[FILE_LIST_STARTED] = state => Object.assign({}, state, { - isFetchingFileList: true -}); - -reducers$2[FILE_LIST_SUCCEEDED] = (state, action) => { - const { fileInfos } = action.data; - const newByOutpoint = Object.assign({}, state.byOutpoint); - const pendingByOutpoint = Object.assign({}, state.pendingByOutpoint); - - fileInfos.forEach(fileInfo => { - const { outpoint } = fileInfo; - - if (outpoint) newByOutpoint[fileInfo.outpoint] = fileInfo; - }); - - return Object.assign({}, state, { - isFetchingFileList: false, - byOutpoint: newByOutpoint, - pendingByOutpoint - }); -}; - -reducers$2[FETCH_FILE_INFO_STARTED] = (state, action) => { - const { outpoint } = action.data; - const newFetching = Object.assign({}, state.fetching); - - newFetching[outpoint] = true; - - return Object.assign({}, state, { - fetching: newFetching - }); -}; - -reducers$2[FETCH_FILE_INFO_COMPLETED] = (state, action) => { - const { fileInfo, outpoint } = action.data; - - const newByOutpoint = Object.assign({}, state.byOutpoint); - const newFetching = Object.assign({}, state.fetching); - - newByOutpoint[outpoint] = fileInfo; - delete newFetching[outpoint]; - - return Object.assign({}, state, { - byOutpoint: newByOutpoint, - fetching: newFetching - }); -}; - -reducers$2[FETCH_FILE_INFO_FAILED] = (state, action) => { - const { outpoint } = action.data; - const newFetching = Object.assign({}, state.fetching); - delete newFetching[outpoint]; - - return Object.assign({}, state, { - fetching: newFetching - }); -}; - -reducers$2[DOWNLOADING_STARTED] = (state, action) => { - const { uri, outpoint, fileInfo } = action.data; - - const newByOutpoint = Object.assign({}, state.byOutpoint); - const newDownloading = Object.assign({}, state.downloadingByOutpoint); - - newDownloading[outpoint] = true; - newByOutpoint[outpoint] = fileInfo; - - return Object.assign({}, state, { - downloadingByOutpoint: newDownloading, - byOutpoint: newByOutpoint - }); -}; - -reducers$2[DOWNLOADING_PROGRESSED] = (state, action) => { - const { outpoint, fileInfo } = action.data; - - const newByOutpoint = Object.assign({}, state.byOutpoint); - const newDownloading = Object.assign({}, state.downloadingByOutpoint); - - newByOutpoint[outpoint] = fileInfo; - newDownloading[outpoint] = true; - - return Object.assign({}, state, { - byOutpoint: newByOutpoint, - downloadingByOutpoint: newDownloading - }); -}; - -reducers$2[DOWNLOADING_CANCELED] = (state, action) => { - const { uri, outpoint } = action.data; - - const newDownloading = Object.assign({}, state.downloadingByOutpoint); - delete newDownloading[outpoint]; - - return Object.assign({}, state, { - downloadingByOutpoint: newDownloading - }); -}; - -reducers$2[DOWNLOADING_COMPLETED] = (state, action) => { - const { outpoint, fileInfo } = action.data; - - const newByOutpoint = Object.assign({}, state.byOutpoint); - const newDownloading = Object.assign({}, state.downloadingByOutpoint); - - newByOutpoint[outpoint] = fileInfo; - delete newDownloading[outpoint]; - - return Object.assign({}, state, { - byOutpoint: newByOutpoint, - downloadingByOutpoint: newDownloading - }); -}; - -reducers$2[FILE_DELETE] = (state, action) => { - const { outpoint } = action.data; - - const newByOutpoint = Object.assign({}, state.byOutpoint); - const downloadingByOutpoint = Object.assign({}, state.downloadingByOutpoint); - - delete newByOutpoint[outpoint]; - delete downloadingByOutpoint[outpoint]; - - return Object.assign({}, state, { - byOutpoint: newByOutpoint, - downloadingByOutpoint - }); -}; - -reducers$2[SET_FILE_LIST_SORT] = (state, action) => { - const pageSortStates = { - [PUBLISHED]: 'fileListPublishedSort', - [DOWNLOADED]: 'fileListDownloadedSort' - }; - const pageSortState = pageSortStates[action.data.page]; - const { value } = action.data; - - return Object.assign({}, state, { - [pageSortState]: value - }); -}; - -function fileInfoReducer(state = defaultState$3, action) { - const handler = reducers$2[action.type]; - if (handler) return handler(state, action); - return state; -} - -var _extends$e = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; - -const defaultState$4 = { notifications: [], toasts: [], errors: [] @@ -6311,7 +2981,7 @@ const notificationsReducer = handleActions({ const newToasts = state.toasts.slice(); newToasts.push(toast); - return _extends$e({}, state, { + return _extends$5({}, state, { toasts: newToasts }); }, @@ -6319,7 +2989,7 @@ const notificationsReducer = handleActions({ const newToasts = state.toasts.slice(); newToasts.shift(); - return _extends$e({}, state, { + return _extends$5({}, state, { toasts: newToasts }); }, @@ -6330,7 +3000,7 @@ const notificationsReducer = handleActions({ const newNotifications = state.notifications.slice(); newNotifications.push(notification); - return _extends$e({}, state, { + return _extends$5({}, state, { notifications: newNotifications }); }, @@ -6341,7 +3011,7 @@ const notificationsReducer = handleActions({ notifications = notifications.map(pastNotification => pastNotification.id === notification.id ? notification : pastNotification); - return _extends$e({}, state, { + return _extends$5({}, state, { notifications }); }, @@ -6350,7 +3020,7 @@ const notificationsReducer = handleActions({ let newNotifications = state.notifications.slice(); newNotifications = newNotifications.filter(notification => notification.id !== id); - return _extends$e({}, state, { + return _extends$5({}, state, { notifications: newNotifications }); }, @@ -6361,7 +3031,7 @@ const notificationsReducer = handleActions({ const newErrors = state.errors.slice(); newErrors.push(error); - return _extends$e({}, state, { + return _extends$5({}, state, { errors: newErrors }); }, @@ -6369,93 +3039,15 @@ const notificationsReducer = handleActions({ const newErrors = state.errors.slice(); newErrors.shift(); - return _extends$e({}, state, { + return _extends$5({}, state, { errors: newErrors }); } -}, defaultState$4); +}, defaultState$2); -var _extends$f = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; +var _extends$6 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; -function _objectWithoutProperties$4(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } - -const defaultState$5 = { - editingURI: undefined, - fileText: '', - filePath: undefined, - fileDur: 0, - fileSize: 0, - fileVid: false, - contentIsFree: true, - fee: { - amount: 1, - currency: 'LBC' - }, - title: '', - thumbnail_url: '', - thumbnailPath: '', - uploadThumbnailStatus: API_DOWN, - description: '', - language: '', - nsfw: false, - channel: CHANNEL_ANONYMOUS, - channelId: '', - name: '', - nameError: undefined, - bid: 0.1, - bidError: undefined, - licenseType: 'None', - otherLicenseDescription: 'All rights reserved', - licenseUrl: '', - tags: [], - publishing: false, - publishSuccess: false, - publishError: undefined, - optimize: false, - useLBRYUploader: false -}; - -const publishReducer = handleActions({ - [UPDATE_PUBLISH_FORM]: (state, action) => { - const { data } = action; - return _extends$f({}, state, data); - }, - [CLEAR_PUBLISH]: state => _extends$f({}, defaultState$5, { - bid: state.bid, - optimize: state.optimize - }), - [PUBLISH_START]: state => _extends$f({}, state, { - publishing: true, - publishSuccess: false - }), - [PUBLISH_FAIL]: state => _extends$f({}, state, { - publishing: false - }), - [PUBLISH_SUCCESS]: state => _extends$f({}, state, { - publishing: false, - publishSuccess: true - }), - [DO_PREPARE_EDIT]: (state, action) => { - const publishData = _objectWithoutProperties$4(action.data, []); - const { channel, name, uri } = publishData; - - // The short uri is what is presented to the user - // The editingUri is the full uri with claim id - const shortUri = buildURI({ - channelName: channel, - streamName: name - }); - - return _extends$f({}, defaultState$5, publishData, { - editingURI: uri, - uri: shortUri - }); - } -}, defaultState$5); - -var _extends$g = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; - -const defaultState$6 = { +const defaultState$3 = { isActive: false, // does the user have any typed text in the search input focused: false, // is the search input focused searchQuery: '', // needs to be an empty string for input focusing @@ -6469,64 +3061,33 @@ const defaultState$6 = { [SEARCH_OPTIONS.MEDIA_APPLICATION]: true }, suggestions: {}, - urisByQuery: {}, - resolvedResultsByQuery: {}, - resolvedResultsByQueryLastPageReached: {} + urisByQuery: {} }; const searchReducer = handleActions({ - [SEARCH_START]: state => _extends$g({}, state, { + [SEARCH_START]: state => _extends$6({}, state, { searching: true }), [SEARCH_SUCCESS]: (state, action) => { const { query, uris } = action.data; - return _extends$g({}, state, { + return _extends$6({}, state, { searching: false, urisByQuery: Object.assign({}, state.urisByQuery, { [query]: uris }) }); }, - [SEARCH_FAIL]: state => _extends$g({}, state, { + [SEARCH_FAIL]: state => _extends$6({}, state, { searching: false }), - [RESOLVED_SEARCH_START]: state => _extends$g({}, state, { - searching: true - }), - [RESOLVED_SEARCH_SUCCESS]: (state, action) => { - const resolvedResultsByQuery = Object.assign({}, state.resolvedResultsByQuery); - const resolvedResultsByQueryLastPageReached = Object.assign({}, state.resolvedResultsByQueryLastPageReached); - const { append, query, results, pageSize } = action.data; - - if (append) { - // todo: check for duplicates when concatenating? - resolvedResultsByQuery[query] = resolvedResultsByQuery[query] && resolvedResultsByQuery[query].length ? resolvedResultsByQuery[query].concat(results) : results; - } else { - resolvedResultsByQuery[query] = results; - } - - // the returned number of urls is less than the page size, so we're on the last page - resolvedResultsByQueryLastPageReached[query] = results.length < pageSize; - - return _extends$g({}, state, { - searching: false, - resolvedResultsByQuery, - resolvedResultsByQueryLastPageReached - }); - }, - - [RESOLVED_SEARCH_FAIL]: state => _extends$g({}, state, { - searching: false - }), - - [UPDATE_SEARCH_QUERY]: (state, action) => _extends$g({}, state, { + [UPDATE_SEARCH_QUERY]: (state, action) => _extends$6({}, state, { searchQuery: action.data.query, isActive: true }), - [UPDATE_SEARCH_SUGGESTIONS]: (state, action) => _extends$g({}, state, { - suggestions: _extends$g({}, state.suggestions, { + [UPDATE_SEARCH_SUGGESTIONS]: (state, action) => _extends$6({}, state, { + suggestions: _extends$6({}, state.suggestions, { [action.data.query]: action.data.suggestions }) }), @@ -6534,125 +3095,29 @@ const searchReducer = handleActions({ // sets isActive to false so the uri will be populated correctly if the // user is on a file page. The search query will still be present on any // other page - [DISMISS_NOTIFICATION]: state => _extends$g({}, state, { + [DISMISS_NOTIFICATION]: state => _extends$6({}, state, { isActive: false }), - [SEARCH_FOCUS]: state => _extends$g({}, state, { + [SEARCH_FOCUS]: state => _extends$6({}, state, { focused: true }), - [SEARCH_BLUR]: state => _extends$g({}, state, { + [SEARCH_BLUR]: state => _extends$6({}, state, { focused: false }), [UPDATE_SEARCH_OPTIONS]: (state, action) => { const { options: oldOptions } = state; const newOptions = action.data; - const options = _extends$g({}, oldOptions, newOptions); - return _extends$g({}, state, { + const options = _extends$6({}, oldOptions, newOptions); + return _extends$6({}, state, { options }); } -}, defaultState$6); +}, defaultState$3); -var _extends$h = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; - -function getDefaultKnownTags() { - return DEFAULT_FOLLOWED_TAGS.concat(DEFAULT_KNOWN_TAGS).reduce((tagsMap, tag) => _extends$h({}, tagsMap, { - [tag]: { name: tag } - }), {}); -} - -const defaultState$7 = { - followedTags: [], - knownTags: getDefaultKnownTags() -}; - -const tagsReducer = handleActions({ - [TOGGLE_TAG_FOLLOW]: (state, action) => { - const { followedTags } = state; - const { name } = action.data; - - let newFollowedTags = followedTags.slice(); - - if (newFollowedTags.includes(name)) { - newFollowedTags = newFollowedTags.filter(tag => tag !== name); - } else { - newFollowedTags.push(name); - } - - return _extends$h({}, state, { - followedTags: newFollowedTags - }); - }, - - [TAG_ADD]: (state, action) => { - const { knownTags } = state; - const { name } = action.data; - - let newKnownTags = _extends$h({}, knownTags); - newKnownTags[name] = { name }; - - return _extends$h({}, state, { - knownTags: newKnownTags - }); - }, - - [TAG_DELETE]: (state, action) => { - const { knownTags, followedTags } = state; - const { name } = action.data; - - let newKnownTags = _extends$h({}, knownTags); - delete newKnownTags[name]; - const newFollowedTags = followedTags.filter(tag => tag !== name); - - return _extends$h({}, state, { - knownTags: newKnownTags, - followedTags: newFollowedTags - }); - }, - [USER_STATE_POPULATE]: (state, action) => { - const { tags } = action.data; - if (Array.isArray(tags)) { - return _extends$h({}, state, { - followedTags: tags - }); - } - return _extends$h({}, state); - } -}, defaultState$7); - -var _extends$i = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; - -const defaultState$8 = { - blockedChannels: [] -}; - -const blockedReducer = handleActions({ - [TOGGLE_BLOCK_CHANNEL]: (state, action) => { - const { blockedChannels } = state; - const { uri } = action.data; - let newBlockedChannels = blockedChannels.slice(); - - if (newBlockedChannels.includes(uri)) { - newBlockedChannels = newBlockedChannels.filter(id => id !== uri); - } else { - newBlockedChannels.push(uri); - } - - return { - blockedChannels: newBlockedChannels - }; - }, - [USER_STATE_POPULATE]: (state, action) => { - const { blocked } = action.data; - return _extends$i({}, state, { - blockedChannels: blocked && blocked.length ? blocked : state.blockedChannels - }); - } -}, defaultState$8); - -var _extends$j = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; +// +const reducers$2 = {}; const buildDraftTransaction = () => ({ amount: undefined, address: undefined @@ -6662,20 +3127,13 @@ const buildDraftTransaction = () => ({ // See details in https://github.com/lbryio/lbry/issues/1307 -const defaultState$9 = { +const defaultState$4 = { balance: undefined, totalBalance: undefined, - reservedBalance: undefined, - claimsBalance: undefined, - supportsBalance: undefined, - tipsBalance: undefined, + blocks: {}, latestBlock: undefined, transactions: {}, fetchingTransactions: false, - fetchingTransactionsError: undefined, - supports: {}, - fetchingSupports: false, - abandoningSupportsByOutpoint: {}, gettingNewAddress: false, draftTransaction: buildDraftTransaction(), sendingSupport: false, @@ -6692,315 +3150,247 @@ const defaultState$9 = { walletLockPending: false, walletLockSucceded: null, walletLockResult: null, - transactionListFilter: 'all', - walletReconnecting: false, - txoFetchParams: {}, - txoPage: {}, - fetchingTxos: false, - fetchingTxosError: undefined, - pendingSupportTransactions: {}, - abandonClaimSupportError: undefined + transactionListFilter: 'all' }; -const walletReducer = handleActions({ - [FETCH_TRANSACTIONS_STARTED]: state => _extends$j({}, state, { - fetchingTransactions: true - }), +reducers$2[FETCH_TRANSACTIONS_STARTED] = state => Object.assign({}, state, { + fetchingTransactions: true +}); - [FETCH_TRANSACTIONS_COMPLETED]: (state, action) => { - const byId = _extends$j({}, state.transactions); +reducers$2[FETCH_TRANSACTIONS_COMPLETED] = (state, action) => { + const byId = Object.assign({}, state.transactions); - const { transactions } = action.data; - transactions.forEach(transaction => { - byId[transaction.txid] = transaction; - }); + const { transactions } = action.data; - return _extends$j({}, state, { - transactions: byId, - fetchingTransactions: false - }); - }, + transactions.forEach(transaction => { + byId[transaction.txid] = transaction; + }); - [FETCH_TXO_PAGE_STARTED]: state => { - return _extends$j({}, state, { - fetchingTxos: true, - fetchingTxosError: undefined - }); - }, + return Object.assign({}, state, { + transactions: byId, + fetchingTransactions: false + }); +}; - [FETCH_TXO_PAGE_COMPLETED]: (state, action) => { - return _extends$j({}, state, { - txoPage: action.data, - fetchingTxos: false - }); - }, +reducers$2[GET_NEW_ADDRESS_STARTED] = state => Object.assign({}, state, { + gettingNewAddress: true +}); - [FETCH_TXO_PAGE_FAILED]: (state, action) => { - return _extends$j({}, state, { - txoPage: {}, - fetchingTxos: false, - fetchingTxosError: action.data - }); - }, +reducers$2[GET_NEW_ADDRESS_COMPLETED] = (state, action) => { + const { address } = action.data; - [UPDATE_TXO_FETCH_PARAMS]: (state, action) => { - return _extends$j({}, state, { - txoFetchParams: action.data - }); - }, + // Say no to localStorage! + return Object.assign({}, state, { + gettingNewAddress: false, + receiveAddress: address + }); +}; - [FETCH_SUPPORTS_STARTED]: state => _extends$j({}, state, { - fetchingSupports: true - }), +reducers$2[UPDATE_BALANCE] = (state, action) => Object.assign({}, state, { + balance: action.data.balance +}); - [FETCH_SUPPORTS_COMPLETED]: (state, action) => { - const byOutpoint = state.supports; - const { supports } = action.data; +reducers$2[UPDATE_TOTAL_BALANCE] = (state, action) => Object.assign({}, state, { + totalBalance: action.data.totalBalance +}); - supports.forEach(transaction => { - const { txid, nout } = transaction; - byOutpoint[`${txid}:${nout}`] = transaction; - }); +reducers$2[CHECK_ADDRESS_IS_MINE_STARTED] = state => Object.assign({}, state, { + checkingAddressOwnership: true +}); - return _extends$j({}, state, { supports: byOutpoint, fetchingSupports: false }); - }, +reducers$2[CHECK_ADDRESS_IS_MINE_COMPLETED] = state => Object.assign({}, state, { + checkingAddressOwnership: false +}); - [ABANDON_SUPPORT_STARTED]: (state, action) => { - const { outpoint } = action.data; - const currentlyAbandoning = state.abandoningSupportsByOutpoint; +reducers$2[SET_DRAFT_TRANSACTION_AMOUNT] = (state, action) => { + const oldDraft = state.draftTransaction; + const newDraft = Object.assign({}, oldDraft, { + amount: parseFloat(action.data.amount) + }); - currentlyAbandoning[outpoint] = true; + return Object.assign({}, state, { + draftTransaction: newDraft + }); +}; - return _extends$j({}, state, { - abandoningSupportsByOutpoint: currentlyAbandoning - }); - }, +reducers$2[SET_DRAFT_TRANSACTION_ADDRESS] = (state, action) => { + const oldDraft = state.draftTransaction; + const newDraft = Object.assign({}, oldDraft, { + address: action.data.address + }); - [ABANDON_SUPPORT_COMPLETED]: (state, action) => { - const { outpoint } = action.data; - const byOutpoint = state.supports; - const currentlyAbandoning = state.abandoningSupportsByOutpoint; + return Object.assign({}, state, { + draftTransaction: newDraft + }); +}; - delete currentlyAbandoning[outpoint]; - delete byOutpoint[outpoint]; +reducers$2[SEND_TRANSACTION_STARTED] = state => { + const newDraftTransaction = Object.assign({}, state.draftTransaction, { + sending: true + }); - return _extends$j({}, state, { - supports: byOutpoint, - abandoningSupportsById: currentlyAbandoning - }); - }, + return Object.assign({}, state, { + draftTransaction: newDraftTransaction + }); +}; - [ABANDON_CLAIM_SUPPORT_STARTED]: (state, action) => { - return _extends$j({}, state, { - abandonClaimSupportError: undefined - }); - }, +reducers$2[SEND_TRANSACTION_COMPLETED] = state => Object.assign({}, state, { + draftTransaction: buildDraftTransaction() +}); - [ABANDON_CLAIM_SUPPORT_PREVIEW]: (state, action) => { - return _extends$j({}, state, { - abandonClaimSupportError: undefined - }); - }, +reducers$2[SEND_TRANSACTION_FAILED] = (state, action) => { + const newDraftTransaction = Object.assign({}, state.draftTransaction, { + sending: false, + error: action.data.error + }); - [ABANDON_CLAIM_SUPPORT_COMPLETED]: (state, action) => { - const { claimId, type, txid, effective } = action.data; - const pendingtxs = Object.assign({}, state.pendingSupportTransactions); + return Object.assign({}, state, { + draftTransaction: newDraftTransaction + }); +}; - pendingtxs[claimId] = { txid, type, effective }; +reducers$2[SUPPORT_TRANSACTION_STARTED] = state => Object.assign({}, state, { + sendingSupport: true +}); - return _extends$j({}, state, { - pendingSupportTransactions: pendingtxs, - abandonClaimSupportError: undefined - }); - }, +reducers$2[SUPPORT_TRANSACTION_COMPLETED] = state => Object.assign({}, state, { + sendingSupport: false +}); - [ABANDON_CLAIM_SUPPORT_FAILED]: (state, action) => { - return _extends$j({}, state, { - abandonClaimSupportError: action.data - }); - }, +reducers$2[SUPPORT_TRANSACTION_FAILED] = (state, action) => Object.assign({}, state, { + error: action.data.error, + sendingSupport: false +}); - [PENDING_SUPPORTS_UPDATED]: (state, action) => { +reducers$2[FETCH_BLOCK_SUCCESS] = (state, action) => { + const { + block, + block: { height } + } = action.data; + const blocks = Object.assign({}, state.blocks); - return _extends$j({}, state, { - pendingSupportTransactions: action.data - }); - }, + blocks[height] = block; - [GET_NEW_ADDRESS_STARTED]: state => _extends$j({}, state, { - gettingNewAddress: true - }), + return Object.assign({}, state, { blocks }); +}; - [GET_NEW_ADDRESS_COMPLETED]: (state, action) => { - const { address } = action.data; +reducers$2[WALLET_STATUS_COMPLETED] = (state, action) => Object.assign({}, state, { + walletIsEncrypted: action.result +}); - return _extends$j({}, state, { gettingNewAddress: false, receiveAddress: address }); - }, +reducers$2[WALLET_ENCRYPT_START] = state => Object.assign({}, state, { + walletEncryptPending: true, + walletEncryptSucceded: null, + walletEncryptResult: null +}); - [UPDATE_BALANCE]: (state, action) => _extends$j({}, state, { - totalBalance: action.data.totalBalance, - balance: action.data.balance, - reservedBalance: action.data.reservedBalance, - claimsBalance: action.data.claimsBalance, - supportsBalance: action.data.supportsBalance, - tipsBalance: action.data.tipsBalance - }), +reducers$2[WALLET_ENCRYPT_COMPLETED] = (state, action) => Object.assign({}, state, { + walletEncryptPending: false, + walletEncryptSucceded: true, + walletEncryptResult: action.result +}); - [CHECK_ADDRESS_IS_MINE_STARTED]: state => _extends$j({}, state, { - checkingAddressOwnership: true - }), +reducers$2[WALLET_ENCRYPT_FAILED] = (state, action) => Object.assign({}, state, { + walletEncryptPending: false, + walletEncryptSucceded: false, + walletEncryptResult: action.result +}); - [CHECK_ADDRESS_IS_MINE_COMPLETED]: state => _extends$j({}, state, { - checkingAddressOwnership: false - }), +reducers$2[WALLET_DECRYPT_START] = state => Object.assign({}, state, { + walletDecryptPending: true, + walletDecryptSucceded: null, + walletDecryptResult: null +}); - [SET_DRAFT_TRANSACTION_AMOUNT]: (state, action) => { - const oldDraft = state.draftTransaction; - const newDraft = _extends$j({}, oldDraft, { amount: parseFloat(action.data.amount) }); +reducers$2[WALLET_DECRYPT_COMPLETED] = (state, action) => Object.assign({}, state, { + walletDecryptPending: false, + walletDecryptSucceded: true, + walletDecryptResult: action.result +}); - return _extends$j({}, state, { draftTransaction: newDraft }); - }, +reducers$2[WALLET_DECRYPT_FAILED] = (state, action) => Object.assign({}, state, { + walletDecryptPending: false, + walletDecryptSucceded: false, + walletDecryptResult: action.result +}); - [SET_DRAFT_TRANSACTION_ADDRESS]: (state, action) => { - const oldDraft = state.draftTransaction; - const newDraft = _extends$j({}, oldDraft, { address: action.data.address }); +reducers$2[WALLET_UNLOCK_START] = state => Object.assign({}, state, { + walletUnlockPending: true, + walletUnlockSucceded: null, + walletUnlockResult: null +}); - return _extends$j({}, state, { draftTransaction: newDraft }); - }, +reducers$2[WALLET_UNLOCK_COMPLETED] = (state, action) => Object.assign({}, state, { + walletUnlockPending: false, + walletUnlockSucceded: true, + walletUnlockResult: action.result +}); - [SEND_TRANSACTION_STARTED]: state => { - const newDraftTransaction = _extends$j({}, state.draftTransaction, { sending: true }); +reducers$2[WALLET_UNLOCK_FAILED] = (state, action) => Object.assign({}, state, { + walletUnlockPending: false, + walletUnlockSucceded: false, + walletUnlockResult: action.result +}); - return _extends$j({}, state, { draftTransaction: newDraftTransaction }); - }, +reducers$2[WALLET_LOCK_START] = state => Object.assign({}, state, { + walletLockPending: false, + walletLockSucceded: null, + walletLockResult: null +}); - [SEND_TRANSACTION_COMPLETED]: state => Object.assign({}, state, { - draftTransaction: buildDraftTransaction() - }), +reducers$2[WALLET_LOCK_COMPLETED] = (state, action) => Object.assign({}, state, { + walletLockPending: false, + walletLockSucceded: true, + walletLockResult: action.result +}); - [SEND_TRANSACTION_FAILED]: (state, action) => { - const newDraftTransaction = Object.assign({}, state.draftTransaction, { - sending: false, - error: action.data.error - }); +reducers$2[WALLET_LOCK_FAILED] = (state, action) => Object.assign({}, state, { + walletLockPending: false, + walletLockSucceded: false, + walletLockResult: action.result +}); - return _extends$j({}, state, { draftTransaction: newDraftTransaction }); - }, +reducers$2[SET_TRANSACTION_LIST_FILTER] = (state, action) => Object.assign({}, state, { + transactionListFilter: action.data +}); - [SUPPORT_TRANSACTION_STARTED]: state => _extends$j({}, state, { - sendingSupport: true - }), +reducers$2[UPDATE_CURRENT_HEIGHT] = (state, action) => Object.assign({}, state, { + latestBlock: action.data +}); - [SUPPORT_TRANSACTION_COMPLETED]: state => _extends$j({}, state, { - sendingSupport: false - }), +function walletReducer(state = defaultState$4, action) { + const handler = reducers$2[action.type]; + if (handler) return handler(state, action); + return state; +} - [SUPPORT_TRANSACTION_FAILED]: (state, action) => _extends$j({}, state, { - error: action.data.error, - sendingSupport: false - }), +var _extends$7 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; - [CLEAR_SUPPORT_TRANSACTION]: state => _extends$j({}, state, { - sendingSupport: false - }), +const reducers$3 = {}; +const defaultState$5 = { + positions: {} +}; - [WALLET_STATUS_COMPLETED]: (state, action) => _extends$j({}, state, { - walletIsEncrypted: action.result - }), +reducers$3[SET_CONTENT_POSITION] = (state, action) => { + const { claimId, outpoint, position } = action.data; + return _extends$7({}, state, { + positions: _extends$7({}, state.positions, { + [claimId]: _extends$7({}, state.positions[claimId], { + [outpoint]: position + }) + }) + }); +}; - [WALLET_ENCRYPT_START]: state => _extends$j({}, state, { - walletEncryptPending: true, - walletEncryptSucceded: null, - walletEncryptResult: null - }), +function contentReducer(state = defaultState$5, action) { + const handler = reducers$3[action.type]; + if (handler) return handler(state, action); + return state; +} - [WALLET_ENCRYPT_COMPLETED]: (state, action) => _extends$j({}, state, { - walletEncryptPending: false, - walletEncryptSucceded: true, - walletEncryptResult: action.result - }), +const selectState$4 = state => state.content || {}; - [WALLET_ENCRYPT_FAILED]: (state, action) => _extends$j({}, state, { - walletEncryptPending: false, - walletEncryptSucceded: false, - walletEncryptResult: action.result - }), - - [WALLET_DECRYPT_START]: state => _extends$j({}, state, { - walletDecryptPending: true, - walletDecryptSucceded: null, - walletDecryptResult: null - }), - - [WALLET_DECRYPT_COMPLETED]: (state, action) => _extends$j({}, state, { - walletDecryptPending: false, - walletDecryptSucceded: true, - walletDecryptResult: action.result - }), - - [WALLET_DECRYPT_FAILED]: (state, action) => _extends$j({}, state, { - walletDecryptPending: false, - walletDecryptSucceded: false, - walletDecryptResult: action.result - }), - - [WALLET_UNLOCK_START]: state => _extends$j({}, state, { - walletUnlockPending: true, - walletUnlockSucceded: null, - walletUnlockResult: null - }), - - [WALLET_UNLOCK_COMPLETED]: (state, action) => _extends$j({}, state, { - walletUnlockPending: false, - walletUnlockSucceded: true, - walletUnlockResult: action.result - }), - - [WALLET_UNLOCK_FAILED]: (state, action) => _extends$j({}, state, { - walletUnlockPending: false, - walletUnlockSucceded: false, - walletUnlockResult: action.result - }), - - [WALLET_LOCK_START]: state => _extends$j({}, state, { - walletLockPending: false, - walletLockSucceded: null, - walletLockResult: null - }), - - [WALLET_LOCK_COMPLETED]: (state, action) => _extends$j({}, state, { - walletLockPending: false, - walletLockSucceded: true, - walletLockResult: action.result - }), - - [WALLET_LOCK_FAILED]: (state, action) => _extends$j({}, state, { - walletLockPending: false, - walletLockSucceded: false, - walletLockResult: action.result - }), - - [SET_TRANSACTION_LIST_FILTER]: (state, action) => _extends$j({}, state, { - transactionListFilter: action.data - }), - - [UPDATE_CURRENT_HEIGHT]: (state, action) => _extends$j({}, state, { - latestBlock: action.data - }), - [WALLET_RESTART]: state => _extends$j({}, state, { - walletReconnecting: true - }), - - [WALLET_RESTART_COMPLETED]: state => _extends$j({}, state, { - walletReconnecting: false - }) -}, defaultState$9); - -// - -const selectState$5 = state => state.content || {}; - -const makeSelectContentPositionForUri = uri => reselect.createSelector(selectState$5, makeSelectClaimForUri(uri), (state, claim) => { +const makeSelectContentPositionForUri = uri => reselect.createSelector(selectState$4, makeSelectClaimForUri(uri), (state, claim) => { if (!claim) { return null; } @@ -7009,14 +3399,14 @@ const makeSelectContentPositionForUri = uri => reselect.createSelector(selectSta return state.positions[id] ? state.positions[id][outpoint] : null; }); -var _extends$k = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; +var _extends$8 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; -const selectState$6 = state => state.notifications || {}; +const selectState$5 = state => state.notifications || {}; -const selectToast = reselect.createSelector(selectState$6, state => { +const selectToast = reselect.createSelector(selectState$5, state => { if (state.toasts.length) { const { id, params } = state.toasts[0]; - return _extends$k({ + return _extends$8({ id }, params); } @@ -7024,7 +3414,7 @@ const selectToast = reselect.createSelector(selectState$6, state => { return null; }); -const selectError = reselect.createSelector(selectState$6, state => { +const selectError = reselect.createSelector(selectState$5, state => { if (state.errors.length) { const { error } = state.errors[0]; return { @@ -7035,179 +3425,41 @@ const selectError = reselect.createSelector(selectState$6, state => { return null; }); -// - -const selectState$7 = state => state.comments || {}; - -const selectCommentsById = reselect.createSelector(selectState$7, state => state.commentById || {}); - -const selectIsFetchingComments = reselect.createSelector(selectState$7, state => state.isLoading); - -const selectCommentsByClaimId = reselect.createSelector(selectState$7, selectCommentsById, (state, byId) => { - const byClaimId = state.byId || {}; - const comments = {}; - - // replace every comment_id in the list with the actual comment object - Object.keys(byClaimId).forEach(claimId => { - const commentIds = byClaimId[claimId]; - - comments[claimId] = Array(commentIds === null ? 0 : commentIds.length); - for (let i = 0; i < commentIds.length; i++) { - comments[claimId][i] = byId[commentIds[i]]; - } - }); - - return comments; -}); - -// previously this used a mapping from claimId -> Array -/* export const selectCommentsById = createSelector( - selectState, - state => state.byId || {} -); */ -const selectCommentsByUri = reselect.createSelector(selectState$7, state => { - const byUri = state.commentsByUri || {}; - const comments = {}; - Object.keys(byUri).forEach(uri => { - const claimId = byUri[uri]; - if (claimId === null) { - comments[uri] = null; - } else { - comments[uri] = claimId; - } - }); - - return comments; -}); - -const makeSelectCommentsForUri = uri => reselect.createSelector(selectCommentsByClaimId, selectCommentsByUri, (byClaimId, byUri) => { - const claimId = byUri[uri]; - return byClaimId && byClaimId[claimId]; -}); - -// todo: allow SDK to retrieve user comments through comment_list -// todo: implement selectors for selecting comments owned by user - -// - -const selectState$8 = state => state.tags || {}; - -const selectKnownTagsByName = reselect.createSelector(selectState$8, state => state.knownTags); - -const selectFollowedTagsList = reselect.createSelector(selectState$8, state => state.followedTags.filter(tag => typeof tag === 'string')); - -const selectFollowedTags = reselect.createSelector(selectFollowedTagsList, followedTags => followedTags.map(tag => ({ name: tag.toLowerCase() })).sort((a, b) => a.name.localeCompare(b.name))); - -const selectUnfollowedTags = reselect.createSelector(selectKnownTagsByName, selectFollowedTagsList, (tagsByName, followedTags) => { - const followedTagsSet = new Set(followedTags); - let tagsToReturn = []; - Object.keys(tagsByName).forEach(key => { - if (!followedTagsSet.has(key)) { - const { name } = tagsByName[key]; - tagsToReturn.push({ name: name.toLowerCase() }); - } - }); - - return tagsToReturn; -}); - -const makeSelectIsFollowingTag = tag => reselect.createSelector(selectFollowedTags, followedTags => { - return followedTags.some(followedTag => followedTag.name === tag.toLowerCase()); -}); - -// - -const selectState$9 = state => state.blocked || {}; - -const selectBlockedChannels = reselect.createSelector(selectState$9, state => state.blockedChannels); - -const selectBlockedChannelsCount = reselect.createSelector(selectBlockedChannels, state => state.length); - -const selectChannelIsBlocked = uri => reselect.createSelector(selectBlockedChannels, state => { - return state.includes(uri); -}); - -exports.ABANDON_STATES = abandon_states; exports.ACTIONS = action_types; -exports.CLAIM_VALUES = claim; -exports.DAEMON_SETTINGS = daemon_settings; -exports.DEFAULT_FOLLOWED_TAGS = DEFAULT_FOLLOWED_TAGS; -exports.DEFAULT_KNOWN_TAGS = DEFAULT_KNOWN_TAGS; -exports.LICENSES = licenses; exports.Lbry = lbryProxy; -exports.LbryFirst = lbryFirstProxy; -exports.MATURE_TAGS = MATURE_TAGS; exports.PAGES = pages; exports.SEARCH_OPTIONS = SEARCH_OPTIONS; exports.SEARCH_TYPES = SEARCH_TYPES; exports.SETTINGS = settings; -exports.SHARED_PREFERENCES = shared_preferences; exports.SORT_OPTIONS = sort_options; -exports.SPEECH_URLS = speech_urls; exports.THUMBNAIL_STATUSES = thumbnail_upload_statuses; exports.TRANSACTIONS = transaction_types; -exports.TXO_LIST = txo_list; -exports.TX_LIST = transaction_list; -exports.apiCall = apiCall; exports.batchActions = batchActions; -exports.blockedReducer = blockedReducer; -exports.buildSharedStateMiddleware = buildSharedStateMiddleware; exports.buildURI = buildURI; exports.claimsReducer = claimsReducer; -exports.commentReducer = commentReducer; exports.contentReducer = contentReducer; exports.convertToShareLink = convertToShareLink; -exports.createNormalizedClaimSearchKey = createNormalizedClaimSearchKey; exports.creditsToString = creditsToString; exports.doAbandonClaim = doAbandonClaim; -exports.doAbandonTxo = doAbandonTxo; -exports.doAddTag = doAddTag; exports.doBalanceSubscribe = doBalanceSubscribe; exports.doBlurSearchInput = doBlurSearchInput; exports.doCheckAddressIsMine = doCheckAddressIsMine; -exports.doCheckPendingClaims = doCheckPendingClaims; -exports.doCheckPublishNameAvailability = doCheckPublishNameAvailability; -exports.doCheckReflectingFiles = doCheckReflectingFiles; -exports.doClaimSearch = doClaimSearch; -exports.doClearChannelErrors = doClearChannelErrors; -exports.doClearPublish = doClearPublish; -exports.doClearPurchasedUriSuccess = doClearPurchasedUriSuccess; -exports.doClearRepostError = doClearRepostError; -exports.doClearSupport = doClearSupport; -exports.doCommentAbandon = doCommentAbandon; -exports.doCommentCreate = doCommentCreate; -exports.doCommentHide = doCommentHide; -exports.doCommentList = doCommentList; -exports.doCommentUpdate = doCommentUpdate; exports.doCreateChannel = doCreateChannel; -exports.doDeleteTag = doDeleteTag; exports.doDismissError = doDismissError; exports.doDismissToast = doDismissToast; exports.doError = doError; +exports.doFetchBlock = doFetchBlock; exports.doFetchChannelListMine = doFetchChannelListMine; exports.doFetchClaimListMine = doFetchClaimListMine; exports.doFetchClaimsByChannel = doFetchClaimsByChannel; exports.doFetchFileInfo = doFetchFileInfo; -exports.doFetchFileInfos = doFetchFileInfos; +exports.doFetchFileInfosAndPublishedClaims = doFetchFileInfosAndPublishedClaims; exports.doFetchTransactions = doFetchTransactions; -exports.doFetchTxoPage = doFetchTxoPage; -exports.doFileGet = doFileGet; exports.doFileList = doFileList; exports.doFocusSearchInput = doFocusSearchInput; exports.doGetNewAddress = doGetNewAddress; -exports.doImportChannel = doImportChannel; -exports.doPopulateSharedUserState = doPopulateSharedUserState; -exports.doPreferenceGet = doPreferenceGet; -exports.doPreferenceSet = doPreferenceSet; -exports.doPrepareEdit = doPrepareEdit; -exports.doPublish = doPublish; -exports.doPurchaseList = doPurchaseList; -exports.doPurchaseUri = doPurchaseUri; -exports.doRepost = doRepost; -exports.doResetThumbnailStatus = doResetThumbnailStatus; exports.doResolveUri = doResolveUri; exports.doResolveUris = doResolveUris; -exports.doResolvedSearch = doResolvedSearch; exports.doSearch = doSearch; exports.doSendDraftTransaction = doSendDraftTransaction; exports.doSendTip = doSendTip; @@ -7215,120 +3467,68 @@ exports.doSetDraftTransactionAddress = doSetDraftTransactionAddress; exports.doSetDraftTransactionAmount = doSetDraftTransactionAmount; exports.doSetFileListSort = doSetFileListSort; exports.doSetTransactionListFilter = doSetTransactionListFilter; -exports.doSupportAbandonForClaim = doSupportAbandonForClaim; exports.doToast = doToast; -exports.doToggleBlockChannel = doToggleBlockChannel; -exports.doToggleTagFollow = doToggleTagFollow; +exports.doTotalBalanceSubscribe = doTotalBalanceSubscribe; exports.doUpdateBalance = doUpdateBalance; exports.doUpdateBlockHeight = doUpdateBlockHeight; -exports.doUpdateChannel = doUpdateChannel; -exports.doUpdatePublishForm = doUpdatePublishForm; exports.doUpdateSearchOptions = doUpdateSearchOptions; exports.doUpdateSearchQuery = doUpdateSearchQuery; -exports.doUpdateTxoPageParams = doUpdateTxoPageParams; -exports.doUploadThumbnail = doUploadThumbnail; +exports.doUpdateTotalBalance = doUpdateTotalBalance; exports.doWalletDecrypt = doWalletDecrypt; exports.doWalletEncrypt = doWalletEncrypt; -exports.doWalletReconnect = doWalletReconnect; exports.doWalletStatus = doWalletStatus; exports.doWalletUnlock = doWalletUnlock; exports.fileInfoReducer = fileInfoReducer; exports.formatCredits = formatCredits; exports.formatFullPrice = formatFullPrice; -exports.isClaimNsfw = isClaimNsfw; exports.isNameValid = isNameValid; exports.isURIClaimable = isURIClaimable; exports.isURIValid = isURIValid; -exports.makeSelectAmountForUri = makeSelectAmountForUri; -exports.makeSelectCanonicalUrlForUri = makeSelectCanonicalUrlForUri; +exports.makeSelectBlockDate = makeSelectBlockDate; exports.makeSelectChannelForClaimUri = makeSelectChannelForClaimUri; exports.makeSelectClaimForUri = makeSelectClaimForUri; exports.makeSelectClaimIsMine = makeSelectClaimIsMine; exports.makeSelectClaimIsNsfw = makeSelectClaimIsNsfw; exports.makeSelectClaimIsPending = makeSelectClaimIsPending; -exports.makeSelectClaimWasPurchased = makeSelectClaimWasPurchased; exports.makeSelectClaimsInChannelForCurrentPageState = makeSelectClaimsInChannelForCurrentPageState; exports.makeSelectClaimsInChannelForPage = makeSelectClaimsInChannelForPage; -exports.makeSelectCommentsForUri = makeSelectCommentsForUri; exports.makeSelectContentPositionForUri = makeSelectContentPositionForUri; exports.makeSelectContentTypeForUri = makeSelectContentTypeForUri; -exports.makeSelectCoverForUri = makeSelectCoverForUri; -exports.makeSelectDateForUri = makeSelectDateForUri; -exports.makeSelectDownloadPathForUri = makeSelectDownloadPathForUri; exports.makeSelectDownloadingForUri = makeSelectDownloadingForUri; exports.makeSelectFetchingChannelClaims = makeSelectFetchingChannelClaims; exports.makeSelectFileInfoForUri = makeSelectFileInfoForUri; -exports.makeSelectFileNameForUri = makeSelectFileNameForUri; -exports.makeSelectFilePartlyDownloaded = makeSelectFilePartlyDownloaded; -exports.makeSelectFilteredTransactionsForPage = makeSelectFilteredTransactionsForPage; exports.makeSelectFirstRecommendedFileForUri = makeSelectFirstRecommendedFileForUri; -exports.makeSelectIsFollowingTag = makeSelectIsFollowingTag; exports.makeSelectIsUriResolving = makeSelectIsUriResolving; -exports.makeSelectLatestTransactions = makeSelectLatestTransactions; exports.makeSelectLoadingForUri = makeSelectLoadingForUri; -exports.makeSelectMediaTypeForUri = makeSelectMediaTypeForUri; exports.makeSelectMetadataForUri = makeSelectMetadataForUri; -exports.makeSelectMetadataItemForUri = makeSelectMetadataItemForUri; -exports.makeSelectMyPurchasesForPage = makeSelectMyPurchasesForPage; -exports.makeSelectMyStreamUrlsForPage = makeSelectMyStreamUrlsForPage; exports.makeSelectNsfwCountForChannel = makeSelectNsfwCountForChannel; exports.makeSelectNsfwCountFromUris = makeSelectNsfwCountFromUris; -exports.makeSelectOmittedCountForChannel = makeSelectOmittedCountForChannel; -exports.makeSelectPendingAmountByUri = makeSelectPendingAmountByUri; -exports.makeSelectPermanentUrlForUri = makeSelectPermanentUrlForUri; -exports.makeSelectPublishFormValue = makeSelectPublishFormValue; +exports.makeSelectPendingByUri = makeSelectPendingByUri; exports.makeSelectQueryWithOptions = makeSelectQueryWithOptions; exports.makeSelectRecommendedContentForUri = makeSelectRecommendedContentForUri; -exports.makeSelectReflectingClaimForUri = makeSelectReflectingClaimForUri; -exports.makeSelectResolvedRecommendedContentForUri = makeSelectResolvedRecommendedContentForUri; -exports.makeSelectResolvedSearchResults = makeSelectResolvedSearchResults; -exports.makeSelectResolvedSearchResultsLastPageReached = makeSelectResolvedSearchResultsLastPageReached; -exports.makeSelectSearchDownloadUrlsCount = makeSelectSearchDownloadUrlsCount; -exports.makeSelectSearchDownloadUrlsForPage = makeSelectSearchDownloadUrlsForPage; exports.makeSelectSearchUris = makeSelectSearchUris; -exports.makeSelectShortUrlForUri = makeSelectShortUrlForUri; -exports.makeSelectStreamingUrlForUri = makeSelectStreamingUrlForUri; -exports.makeSelectSupportsForUri = makeSelectSupportsForUri; -exports.makeSelectTagsForUri = makeSelectTagsForUri; exports.makeSelectThumbnailForUri = makeSelectThumbnailForUri; exports.makeSelectTitleForUri = makeSelectTitleForUri; -exports.makeSelectTotalClaimsInChannelSearch = makeSelectTotalClaimsInChannelSearch; exports.makeSelectTotalItemsForChannel = makeSelectTotalItemsForChannel; exports.makeSelectTotalPagesForChannel = makeSelectTotalPagesForChannel; -exports.makeSelectTotalPagesInChannelSearch = makeSelectTotalPagesInChannelSearch; -exports.makeSelectUriIsStreamable = makeSelectUriIsStreamable; exports.normalizeURI = normalizeURI; exports.notificationsReducer = notificationsReducer; exports.parseQueryParams = parseQueryParams; exports.parseURI = parseURI; -exports.publishReducer = publishReducer; exports.regexAddress = regexAddress; exports.regexInvalidURI = regexInvalidURI; exports.savePosition = savePosition; exports.searchReducer = searchReducer; -exports.selectAbandonClaimSupportError = selectAbandonClaimSupportError; exports.selectAbandoningIds = selectAbandoningIds; exports.selectAllClaimsByChannel = selectAllClaimsByChannel; exports.selectAllFetchingChannelClaims = selectAllFetchingChannelClaims; exports.selectAllMyClaimsByOutpoint = selectAllMyClaimsByOutpoint; exports.selectBalance = selectBalance; -exports.selectBlockedChannels = selectBlockedChannels; -exports.selectBlockedChannelsCount = selectBlockedChannelsCount; exports.selectBlocks = selectBlocks; exports.selectChannelClaimCounts = selectChannelClaimCounts; -exports.selectChannelImportPending = selectChannelImportPending; -exports.selectChannelIsBlocked = selectChannelIsBlocked; -exports.selectClaimIdsByUri = selectClaimIdsByUri; -exports.selectClaimSearchByQuery = selectClaimSearchByQuery; -exports.selectClaimSearchByQueryLastPageReached = selectClaimSearchByQueryLastPageReached; -exports.selectClaimsBalance = selectClaimsBalance; exports.selectClaimsById = selectClaimsById; exports.selectClaimsByUri = selectClaimsByUri; -exports.selectCreateChannelError = selectCreateChannelError; -exports.selectCreatingChannel = selectCreatingChannel; exports.selectCurrentChannelPage = selectCurrentChannelPage; -exports.selectDownloadUrlsCount = selectDownloadUrlsCount; -exports.selectDownloadedUris = selectDownloadedUris; exports.selectDownloadingByOutpoint = selectDownloadingByOutpoint; exports.selectDownloadingFileInfos = selectDownloadingFileInfos; exports.selectDraftTransaction = selectDraftTransaction; @@ -7336,86 +3536,44 @@ exports.selectDraftTransactionAddress = selectDraftTransactionAddress; exports.selectDraftTransactionAmount = selectDraftTransactionAmount; exports.selectDraftTransactionError = selectDraftTransactionError; exports.selectError = selectError; -exports.selectFetchingClaimSearch = selectFetchingClaimSearch; -exports.selectFetchingClaimSearchByQuery = selectFetchingClaimSearchByQuery; exports.selectFetchingMyChannels = selectFetchingMyChannels; -exports.selectFetchingMyClaimsPageError = selectFetchingMyClaimsPageError; -exports.selectFetchingMyPurchasesError = selectFetchingMyPurchasesError; -exports.selectFetchingTxosError = selectFetchingTxosError; exports.selectFileInfosByOutpoint = selectFileInfosByOutpoint; exports.selectFileInfosDownloaded = selectFileInfosDownloaded; exports.selectFileListDownloadedSort = selectFileListDownloadedSort; exports.selectFileListPublishedSort = selectFileListPublishedSort; -exports.selectFilteredTransactionCount = selectFilteredTransactionCount; -exports.selectFilteredTransactions = selectFilteredTransactions; -exports.selectFollowedTags = selectFollowedTags; -exports.selectFollowedTagsList = selectFollowedTagsList; exports.selectGettingNewAddress = selectGettingNewAddress; exports.selectHasTransactions = selectHasTransactions; exports.selectIsFetchingClaimListMine = selectIsFetchingClaimListMine; -exports.selectIsFetchingComments = selectIsFetchingComments; exports.selectIsFetchingFileList = selectIsFetchingFileList; exports.selectIsFetchingFileListDownloadedOrPublished = selectIsFetchingFileListDownloadedOrPublished; -exports.selectIsFetchingMyPurchases = selectIsFetchingMyPurchases; exports.selectIsFetchingTransactions = selectIsFetchingTransactions; -exports.selectIsFetchingTxos = selectIsFetchingTxos; -exports.selectIsResolvingPublishUris = selectIsResolvingPublishUris; exports.selectIsSearching = selectIsSearching; exports.selectIsSendingSupport = selectIsSendingSupport; -exports.selectIsStillEditing = selectIsStillEditing; -exports.selectIsWalletReconnecting = selectIsWalletReconnecting; exports.selectMyActiveClaims = selectMyActiveClaims; exports.selectMyChannelClaims = selectMyChannelClaims; -exports.selectMyChannelUrls = selectMyChannelUrls; -exports.selectMyClaimForUri = selectMyClaimForUri; -exports.selectMyClaimUrisWithoutChannels = selectMyClaimUrisWithoutChannels; exports.selectMyClaims = selectMyClaims; exports.selectMyClaimsOutpoints = selectMyClaimsOutpoints; -exports.selectMyClaimsPage = selectMyClaimsPage; -exports.selectMyClaimsPageItemCount = selectMyClaimsPageItemCount; -exports.selectMyClaimsPageNumber = selectMyClaimsPageNumber; exports.selectMyClaimsRaw = selectMyClaimsRaw; exports.selectMyClaimsWithoutChannels = selectMyClaimsWithoutChannels; -exports.selectMyPurchases = selectMyPurchases; -exports.selectMyPurchasesCount = selectMyPurchasesCount; -exports.selectMyStreamUrlsCount = selectMyStreamUrlsCount; -exports.selectPendingSupportTransactions = selectPendingSupportTransactions; +exports.selectPendingById = selectPendingById; +exports.selectPendingClaims = selectPendingClaims; exports.selectPlayingUri = selectPlayingUri; -exports.selectPublishFormValues = selectPublishFormValues; -exports.selectPurchaseUriSuccess = selectPurchaseUriSuccess; exports.selectReceiveAddress = selectReceiveAddress; exports.selectRecentTransactions = selectRecentTransactions; -exports.selectReflectingById = selectReflectingById; -exports.selectRepostError = selectRepostError; -exports.selectRepostLoading = selectRepostLoading; -exports.selectReservedBalance = selectReservedBalance; -exports.selectResolvedSearchResultsByQuery = selectResolvedSearchResultsByQuery; -exports.selectResolvedSearchResultsByQueryLastPageReached = selectResolvedSearchResultsByQueryLastPageReached; exports.selectResolvingUris = selectResolvingUris; exports.selectSearchBarFocused = selectSearchBarFocused; +exports.selectSearchDownloadUris = selectSearchDownloadUris; exports.selectSearchOptions = selectSearchOptions; exports.selectSearchState = selectState; exports.selectSearchSuggestions = selectSearchSuggestions; exports.selectSearchUrisByQuery = selectSearchUrisByQuery; exports.selectSearchValue = selectSearchValue; -exports.selectSupportsBalance = selectSupportsBalance; -exports.selectSupportsByOutpoint = selectSupportsByOutpoint; -exports.selectTakeOverAmount = selectTakeOverAmount; -exports.selectTipsBalance = selectTipsBalance; exports.selectToast = selectToast; exports.selectTotalBalance = selectTotalBalance; exports.selectTotalDownloadProgress = selectTotalDownloadProgress; -exports.selectTotalSupports = selectTotalSupports; exports.selectTransactionItems = selectTransactionItems; exports.selectTransactionListFilter = selectTransactionListFilter; exports.selectTransactionsById = selectTransactionsById; -exports.selectTxoItemCount = selectTxoItemCount; -exports.selectTxoPage = selectTxoPage; -exports.selectTxoPageNumber = selectTxoPageNumber; -exports.selectTxoPageParams = selectTxoPageParams; -exports.selectUnfollowedTags = selectUnfollowedTags; -exports.selectUpdateChannelError = selectUpdateChannelError; -exports.selectUpdatingChannel = selectUpdatingChannel; exports.selectUrisLoading = selectUrisLoading; exports.selectWalletDecryptPending = selectWalletDecryptPending; exports.selectWalletDecryptResult = selectWalletDecryptResult; @@ -7429,6 +3587,5 @@ exports.selectWalletUnlockPending = selectWalletUnlockPending; exports.selectWalletUnlockResult = selectWalletUnlockResult; exports.selectWalletUnlockSucceeded = selectWalletUnlockSucceeded; exports.setSearchApi = setSearchApi; -exports.tagsReducer = tagsReducer; exports.toQueryString = toQueryString; exports.walletReducer = walletReducer; diff --git a/dist/flow-typed/Blocklist.js b/dist/flow-typed/Blocklist.js deleted file mode 100644 index 454a714..0000000 --- a/dist/flow-typed/Blocklist.js +++ /dev/null @@ -1,10 +0,0 @@ -declare type BlocklistState = { - blockedChannels: Array -}; - -declare type BlocklistAction = { - type: string, - data: { - uri: string, - }, -}; diff --git a/dist/flow-typed/Claim.js b/dist/flow-typed/Claim.js index 0b97c0e..49419bc 100644 --- a/dist/flow-typed/Claim.js +++ b/dist/flow-typed/Claim.js @@ -1,54 +1,49 @@ // @flow -declare type Claim = StreamClaim | ChannelClaim; +declare type ClaimWithPossibleCertificate = { + certificate?: ChannelClaim, + claim: StreamClaim, +}; declare type ChannelClaim = GenericClaim & { value: ChannelMetadata, }; declare type StreamClaim = GenericClaim & { + is_channel_signature_valid?: boolean, + signing_channel?: { + claim_id: string, + name: string, + value: { + public_key: string, + }, + }, value: StreamMetadata, }; declare type GenericClaim = { address: string, // address associated with tx - amount: string, // bid amount at time of tx - canonical_url: string, // URL with short id, includes channel with short id + amount: number, // bid amount at time of tx claim_id: string, // unique claim identifier - claim_sequence: number, // not being used currently + claim_sequence: number, claim_op: 'create' | 'update', - confirmations: number, - decoded_claim: boolean, // Not available currently https://github.com/lbryio/lbry/issues/2044 - timestamp?: number, // date of last transaction + confirmations: number, // This isn't the most stable atm: https://github.com/lbryio/lbry/issues/2000 + decoded_claim: boolean, // claim made in accordance with sdk protobuf types + depth: number, // confirmations since tx + effective_amount: number, // bid amount + supports + has_signature: boolean, height: number, // block height the tx was confirmed - is_channel_signature_valid?: boolean, - is_my_output: boolean, + hex: string, // `value` hex encoded name: string, + channel_name?: string, normalized_name: string, // `name` normalized via unicode NFD spec, nout: number, // index number for an output of a tx permanent_url: string, // name + claim_id - short_url: string, // permanent_url with short id, no channel + supports: Array<{}>, // TODO: add support type once we start using it txid: string, // unique tx id type: 'claim' | 'update' | 'support', + valid_at_height?: number, // BUG: this should always exist https://github.com/lbryio/lbry/issues/1728 value_type: 'stream' | 'channel', - signing_channel?: ChannelClaim, - repost_channel_url?: string, - purchase_receipt?: PurchaseReceipt, - meta: { - activation_height: number, - claims_in_channel?: number, - creation_height: number, - creation_timestamp: number, - effective_amount: string, - expiration_height: number, - is_controlling: boolean, - support_amount: string, - reposted: number, - trending_global: number, - trending_group: number, - trending_local: number, - trending_mixed: number, - }, }; declare type GenericMetadata = { @@ -64,11 +59,9 @@ declare type GenericMetadata = { declare type ChannelMetadata = GenericMetadata & { public_key: string, - public_key_id: string, cover_url?: string, - email?: string, - website_url?: string, - featured?: Array, + contact_email?: string, + homepage_url?: string, }; declare type StreamMetadata = GenericMetadata & { @@ -112,24 +105,11 @@ declare type Location = { longitude?: number, country?: string, state?: string, - city?: string, code?: string, }; declare type Fee = { - amount: string, + amount: number, // should be a string https://github.com/lbryio/lbry/issues/1576 currency: string, address: string, }; - -declare type PurchaseReceipt = { - address: string, - amount: string, - claim_id: string, - confirmations: number, - height: number, - nout: number, - timestamp: number, - txid: string, - type: 'purchase', -}; diff --git a/dist/flow-typed/Comment.js b/dist/flow-typed/Comment.js deleted file mode 100644 index 64ea974..0000000 --- a/dist/flow-typed/Comment.js +++ /dev/null @@ -1,23 +0,0 @@ -declare type Comment = { - comment: string, // comment body - comment_id: string, // sha256 digest - claim_id: string, // id linking to the claim this comment - timestamp: number, // integer representing unix-time - is_hidden: boolean, // claim owner may enable/disable this - channel_id?: string, // claimId of channel signing this comment - channel_name?: string, // name of channel claim - channel_url?: string, // full lbry url to signing channel - signature?: string, // signature of comment by originating channel - signing_ts?: string, // timestamp used when signing this comment - is_channel_signature_valid?: boolean, // whether or not the signature could be validated - parent_id?: number, // comment_id of comment this is in reply to -}; - -// todo: relate individual comments to their commentId -declare type CommentsState = { - commentsByUri: { [string]: string }, - byId: { [string]: Array }, - commentById: { [string]: Comment }, - isLoading: boolean, - myComments: ?Set, -}; diff --git a/dist/flow-typed/File.js b/dist/flow-typed/File.js index 44dc4f3..a4f8a60 100644 --- a/dist/flow-typed/File.js +++ b/dist/flow-typed/File.js @@ -2,7 +2,6 @@ declare type FileListItem = { metadata: StreamMetadata, - added_on: number, blobs_completed: number, blobs_in_stream: number, blobs_remaining: number, @@ -11,8 +10,6 @@ declare type FileListItem = { claim_id: string, claim_name: string, completed: false, - content_fee?: { txid: string }, - purchase_receipt?: { txid: string, amount: string }, download_directory: string, download_path: string, file_name: string, @@ -22,57 +19,17 @@ declare type FileListItem = { outpoint: string, points_paid: number, protobuf: string, - reflector_progress: number, sd_hash: string, status: string, stopped: false, stream_hash: string, stream_name: string, - streaming_url: string, suggested_file_name: string, total_bytes: number, total_bytes_lower_bound: number, - is_fully_reflected: boolean, // TODO: sdk plans to change `tx` // It isn't currently used by the apps tx: {}, txid: string, - uploading_to_reflector: boolean, written_bytes: number, }; - -declare type FileState = { - failedPurchaseUris: Array, - purchasedUris: Array, -}; - -declare type PurchaseUriCompleted = { - type: ACTIONS.PURCHASE_URI_COMPLETED, - data: { - uri: string, - streamingUrl: string, - }, -}; - -declare type PurchaseUriFailed = { - type: ACTIONS.PURCHASE_URI_FAILED, - data: { - uri: string, - error: any, - }, -}; - -declare type PurchaseUriStarted = { - type: ACTIONS.PURCHASE_URI_STARTED, - data: { - uri: string, - streamingUrl: string, - }, -}; - -declare type DeletePurchasedUri = { - type: ACTIONS.CLEAR_PURCHASED_URI_SUCCESS, - data: { - uri: string, - }, -}; diff --git a/dist/flow-typed/Lbry.js b/dist/flow-typed/Lbry.js index d7c0430..93ce160 100644 --- a/dist/flow-typed/Lbry.js +++ b/dist/flow-typed/Lbry.js @@ -50,8 +50,6 @@ declare type StatusResponse = { blocks_behind: number, is_encrypted: boolean, is_locked: boolean, - headers_synchronization_progress: number, - available_servers: number, }, }; @@ -65,23 +63,14 @@ declare type VersionResponse = { python_version: string, }; -declare type BalanceResponse = { - available: string, - reserved: string, - reserved_subtotals: ?{ - claims: string, - supports: string, - tips: string, - }, - total: string, -}; - declare type ResolveResponse = { // Keys are the url(s) passed to resolve - [string]: { error?: {}, stream?: StreamClaim, channel?: ChannelClaim, claimsInChannel?: number }, + [string]: + | { error: {}, certificate: ChannelClaim, claims_in_channel: number } + | { error?: {}, claim: StreamClaim, certificate?: ChannelClaim }, }; -declare type GetResponse = FileListItem & { error?: string }; +declare type GetResponse = FileListItem; declare type GenericTxResponse = { height: number, @@ -97,139 +86,50 @@ declare type GenericTxResponse = { declare type PublishResponse = GenericTxResponse & { // Only first value in outputs is a claim // That's the only value we care about - outputs: Array, + outputs: Array, }; declare type ClaimSearchResponse = { - items: Array, + items: Array, page: number, page_size: number, - total_items: number, - total_pages: number, + page_number: number, }; declare type ClaimListResponse = { - items: Array, - page: number, - page_size: number, - total_items: number, - total_pages: number, + claims: Array, }; declare type ChannelCreateResponse = GenericTxResponse & { outputs: Array, }; -declare type ChannelUpdateResponse = GenericTxResponse & { - outputs: Array, -}; +declare type ChannelListResponse = Array; -declare type CommentCreateResponse = Comment; -declare type CommentUpdateResponse = Comment; +declare type FileListResponse = Array; -declare type CommentListResponse = { - items: Array, - page: number, - page_size: number, - total_items: number, - total_pages: number, -}; +declare type TxListResponse = Array; -declare type CommentHideResponse = { - // keyed by the CommentIds entered - [string]: { hidden: boolean }, -}; +declare type BlobListResponse = Array; -declare type CommentAbandonResponse = { - // keyed by the CommentId given - abandoned: boolean, -}; - -declare type ChannelListResponse = { - items: Array, - page: number, - page_size: number, - total_items: number, - total_pages: number, -}; - -declare type FileListResponse = { - items: Array, - page: number, - page_size: number, - total_items: number, - total_pages: number, -}; - -declare type TxListResponse = { - items: Array, - page: number, - page_size: number, - total_items: number, - total_pages: number, -}; - -declare type SupportListResponse = { - items: Array, - page: number, - page_size: number, - total_items: number, - total_pages: number, -}; - -declare type BlobListResponse = { items: Array }; - -declare type WalletListResponse = Array<{ +declare type AccountListResponse = Array<{ id: string, + is_default: string, + ledger: string, name: string, + seed: string, + encrypted: string, + private_key: string, + public_key: string, + address_generator: string, + modified_on: string, }>; -declare type WalletStatusResponse = { - is_encrypted: boolean, - is_locked: boolean, - is_syncing: boolean, -}; - declare type SyncApplyResponse = { hash: string, data: string, }; -declare type SupportAbandonResponse = GenericTxResponse; - -declare type StreamListResponse = { - items: Array, - page: number, - page_size: number, - total_items: number, - total_pages: number, -}; - -declare type StreamRepostOptions = { - name: string, - bid: string, - claim_id: string, - channel_id: string, -}; - -declare type StreamRepostResponse = GenericTxResponse; - -declare type PurchaseListResponse = { - items: Array, - page: number, - page_size: number, - total_items: number, - total_pages: number, -}; - -declare type PurchaseListOptions = { - page: number, - page_size: number, - resolve: boolean, - claim_id?: string, - channel_id?: string, -}; - // // Types used in the generic Lbry object that is exported // @@ -238,12 +138,7 @@ declare type LbryTypes = { connectPromise: ?Promise, connect: () => void, daemonConnectionString: string, - alternateConnectionString: string, - methodsUsingAlternateConnectionString: Array, - apiRequestHeaders: { [key: string]: string }, setDaemonConnectionString: string => void, - setApiHeader: (string, string) => void, - unsetApiHeader: string => void, overrides: { [string]: ?Function }, setOverride: (string, Function) => void, getMediaType: (string, ?string) => string, @@ -257,19 +152,12 @@ declare type LbryTypes = { publish: (params: {}) => Promise, claim_search: (params: {}) => Promise, - claim_list: (params: {}) => Promise, + claim_list: (params?: {}) => Promise, channel_create: (params: {}) => Promise, - channel_update: (params: {}) => Promise, - channel_import: (params: {}) => Promise, - channel_list: (params: {}) => Promise, + channel_list: () => Promise, stream_abandon: (params: {}) => Promise, - stream_list: (params: {}) => Promise, channel_abandon: (params: {}) => Promise, support_create: (params: {}) => Promise, - support_list: (params: {}) => Promise, - support_abandon: (params: {}) => Promise, - stream_repost: (params: StreamRepostOptions) => Promise, - purchase_list: (params: PurchaseListOptions) => Promise, // File fetching and manipulation file_list: (params: {}) => Promise, @@ -277,28 +165,15 @@ declare type LbryTypes = { blob_delete: (params: {}) => Promise, blob_list: (params: {}) => Promise, - // Preferences - preference_get: (params: {}) => Promise, - preference_set: (params: {}) => Promise, - - // Commenting - comment_list: (params: {}) => Promise, - comment_create: (params: {}) => Promise, - comment_update: (params: {}) => Promise, - comment_hide: (params: {}) => Promise, - comment_abandon: (params: {}) => Promise, - // Wallet utilities - wallet_balance: (params: {}) => Promise, - wallet_decrypt: (prams: {}) => Promise, - wallet_encrypt: (params: {}) => Promise, - wallet_unlock: (params: {}) => Promise, - wallet_list: (params: {}) => Promise, - wallet_send: (params: {}) => Promise, - wallet_status: (params: {}) => Promise, + account_balance: (params: {}) => Promise, + account_decrypt: (prams: {}) => Promise, + account_encrypt: (params: {}) => Promise, + account_unlock: (params: {}) => Promise, + account_list: (params: {}) => Promise, + account_send: (params: {}) => Promise, address_is_mine: (params: {}) => Promise, address_unused: (params: {}) => Promise, // New address - address_list: (params: {}) => Promise, transaction_list: (params: {}) => Promise, // Sync diff --git a/dist/flow-typed/LbryFirst.js b/dist/flow-typed/LbryFirst.js deleted file mode 100644 index b068f5f..0000000 --- a/dist/flow-typed/LbryFirst.js +++ /dev/null @@ -1,99 +0,0 @@ -// @flow -declare type StatusResponse = { - Version: string, - Message: string, - Running: boolean, - Commit: string, -}; - -declare type VersionResponse = { - build: string, - lbrynet_version: string, - os_release: string, - os_system: string, - platform: string, - processor: string, - python_version: string, -}; -/* SAMPLE UPLOAD RESPONSE (FULL) -"Video": { - "etag": "\"Dn5xIderbhAnUk5TAW0qkFFir0M/xlGLrlTox7VFTRcR8F77RbKtaU4\"", - "id": "8InjtdvVmwE", - "kind": "youtube#video", - "snippet": { - "categoryId": "22", - "channelId": "UCXiVsGTU88fJjheB2rqF0rA", - "channelTitle": "Mark Beamer", - "liveBroadcastContent": "none", - "localized": { - "title": "my title" - }, - "publishedAt": "2020-05-05T04:17:53.000Z", - "thumbnails": { - "default": { - "height": 90, - "url": "https://i9.ytimg.com/vi/8InjtdvVmwE/default.jpg?sqp=CMTQw_UF&rs=AOn4CLB6dlhZMSMrazDlWRsitPgCsn8fVw", - "width": 120 - }, - "high": { - "height": 360, - "url": "https://i9.ytimg.com/vi/8InjtdvVmwE/hqdefault.jpg?sqp=CMTQw_UF&rs=AOn4CLB-Je_7l6qvASRAR_bSGWZHaXaJWQ", - "width": 480 - }, - "medium": { - "height": 180, - "url": "https://i9.ytimg.com/vi/8InjtdvVmwE/mqdefault.jpg?sqp=CMTQw_UF&rs=AOn4CLCvSnDLqVznRNMKuvJ_0misY_chPQ", - "width": 320 - } - }, - "title": "my title" - }, - "status": { - "embeddable": true, - "license": "youtube", - "privacyStatus": "private", - "publicStatsViewable": true, - "uploadStatus": "uploaded" - } - } - */ -declare type UploadResponse = { - Video: { - id: string, - snippet: { - channelId: string, - }, - status: { - uploadStatus: string, - }, - }, -}; - -declare type HasYTAuthResponse = { - HashAuth: boolean, -}; - -declare type YTSignupResponse = {}; - -// -// Types used in the generic LbryFirst object that is exported -// -declare type LbryFirstTypes = { - isConnected: boolean, - connectPromise: ?Promise, - connect: () => void, - lbryFirstConnectionString: string, - apiRequestHeaders: { [key: string]: string }, - setApiHeader: (string, string) => void, - unsetApiHeader: string => void, - overrides: { [string]: ?Function }, - setOverride: (string, Function) => void, - - // LbryFirst Methods - stop: () => Promise, - status: () => Promise, - version: () => Promise, - upload: any => Promise, - hasYTAuth: string => Promise, - ytSignup: () => Promise, -}; diff --git a/dist/flow-typed/Publish.js b/dist/flow-typed/Publish.js deleted file mode 100644 index 87955ae..0000000 --- a/dist/flow-typed/Publish.js +++ /dev/null @@ -1,27 +0,0 @@ -// @flow - -declare type UpdatePublishFormData = { - filePath?: string, - contentIsFree?: boolean, - fee?: { - amount: string, - currency: string, - }, - title?: string, - thumbnail_url?: string, - uploadThumbnailStatus?: string, - thumbnailPath?: string, - description?: string, - language?: string, - channel?: string, - channelId?: string, - name?: string, - nameError?: string, - bid?: string, - bidError?: string, - otherLicenseDescription?: string, - licenseUrl?: string, - licenseType?: string, - uri?: string, - nsfw: boolean, -}; diff --git a/dist/flow-typed/Reflector.js b/dist/flow-typed/Reflector.js deleted file mode 100644 index fc6be97..0000000 --- a/dist/flow-typed/Reflector.js +++ /dev/null @@ -1,5 +0,0 @@ -declare type ReflectingUpdate = { - fileListItem: FileListItem, - progress: number | boolean, - stalled: boolean, -}; diff --git a/dist/flow-typed/Search.js b/dist/flow-typed/Search.js index 2a2152e..5fad710 100644 --- a/dist/flow-typed/Search.js +++ b/dist/flow-typed/Search.js @@ -28,8 +28,6 @@ declare type SearchState = { options: SearchOptions, suggestions: { [string]: Array }, urisByQuery: {}, - resolvedResultsByQuery: {}, - resolvedResultsByQueryLastPageReached: {}, }; declare type SearchSuccess = { @@ -59,26 +57,3 @@ declare type UpdateSearchOptions = { type: ACTIONS.UPDATE_SEARCH_OPTIONS, data: SearchOptions, }; - -declare type ResolvedSearchResult = { - channel: string, - channel_claim_id: string, - claimId: string, - duration: number, - fee: number, - name: string, - nsfw: boolean, - release_time: string, - thumbnail_url: string, - title: string, -}; - -declare type ResolvedSearchSuccess = { - type: ACTIONS.RESOLVED_SEARCH_SUCCESS, - data: { - append: boolean, - pageSize: number, - results: Array, - query: string, - }, -}; diff --git a/dist/flow-typed/Tags.js b/dist/flow-typed/Tags.js deleted file mode 100644 index 01c58ac..0000000 --- a/dist/flow-typed/Tags.js +++ /dev/null @@ -1,21 +0,0 @@ -declare type TagState = { - followedTags: FollowedTags, - knownTags: KnownTags, -}; - -declare type Tag = { - name: string, -}; - -declare type KnownTags = { - [string]: Tag, -}; - -declare type FollowedTags = Array; - -declare type TagAction = { - type: string, - data: { - name: string, - }, -}; diff --git a/dist/flow-typed/Transaction.js b/dist/flow-typed/Transaction.js index db9e592..7953b90 100644 --- a/dist/flow-typed/Transaction.js +++ b/dist/flow-typed/Transaction.js @@ -9,20 +9,3 @@ declare type Transaction = { type: string, date: Date, }; - -declare type Support = { - address: string, - amount: string, - claim_id: string, - confirmations: number, - height: string, - is_change: string, - is_mine: string, - name: string, - normalized_name: string, - nout: string, - permanent_url: string, - timestamp: number, - txid: string, - type: string, -}; diff --git a/dist/flow-typed/Txo.js b/dist/flow-typed/Txo.js deleted file mode 100644 index 5950c99..0000000 --- a/dist/flow-typed/Txo.js +++ /dev/null @@ -1,24 +0,0 @@ -declare type Txo = { - amount: number, - claim_id: string, - normalized_name: string, - nout: number, - txid: string, - type: string, - value_type: string, - timestamp: number, - is_my_output: boolean, - is_my_input: boolean, - is_spent: boolean, -}; - -declare type TxoListParams = { - page: number, - page_size: number, - type: string, - is_my_input?: boolean, - is_my_output?: boolean, - is_not_my_input?: boolean, - is_not_my_output?: boolean, - is_spent?: boolean, -} diff --git a/dist/flow-typed/i18n.js b/dist/flow-typed/i18n.js deleted file mode 100644 index de97c0c..0000000 --- a/dist/flow-typed/i18n.js +++ /dev/null @@ -1,2 +0,0 @@ -// @flow -declare function __(a: string, b?: {}): string; diff --git a/dist/flow-typed/lbryURI.js b/dist/flow-typed/lbryURI.js deleted file mode 100644 index 549c991..0000000 --- a/dist/flow-typed/lbryURI.js +++ /dev/null @@ -1,21 +0,0 @@ -// @flow -declare type LbryUrlObj = { - // Path and channel will always exist when calling parseURI - // But they may not exist when code calls buildURI - isChannel?: boolean, - path?: string, - streamName?: string, - streamClaimId?: string, - channelName?: string, - channelClaimId?: string, - primaryClaimSequence?: number, - secondaryClaimSequence?: number, - primaryBidPosition?: number, - secondaryBidPosition?: number, - startTime?: number, - - // Below are considered deprecated and should not be used due to unreliableness with claim.canonical_url - claimName?: string, - claimId?: string, - contentName?: string, -}; diff --git a/dist/flow-typed/mime.js b/dist/flow-typed/mime.js deleted file mode 100644 index 476b179..0000000 --- a/dist/flow-typed/mime.js +++ /dev/null @@ -1,4 +0,0 @@ -// @flow -declare module 'mime' { - declare module.exports: any; -} diff --git a/flow-typed/Blocklist.js b/flow-typed/Blocklist.js deleted file mode 100644 index 454a714..0000000 --- a/flow-typed/Blocklist.js +++ /dev/null @@ -1,10 +0,0 @@ -declare type BlocklistState = { - blockedChannels: Array -}; - -declare type BlocklistAction = { - type: string, - data: { - uri: string, - }, -}; diff --git a/flow-typed/Claim.js b/flow-typed/Claim.js index 0b97c0e..49419bc 100644 --- a/flow-typed/Claim.js +++ b/flow-typed/Claim.js @@ -1,54 +1,49 @@ // @flow -declare type Claim = StreamClaim | ChannelClaim; +declare type ClaimWithPossibleCertificate = { + certificate?: ChannelClaim, + claim: StreamClaim, +}; declare type ChannelClaim = GenericClaim & { value: ChannelMetadata, }; declare type StreamClaim = GenericClaim & { + is_channel_signature_valid?: boolean, + signing_channel?: { + claim_id: string, + name: string, + value: { + public_key: string, + }, + }, value: StreamMetadata, }; declare type GenericClaim = { address: string, // address associated with tx - amount: string, // bid amount at time of tx - canonical_url: string, // URL with short id, includes channel with short id + amount: number, // bid amount at time of tx claim_id: string, // unique claim identifier - claim_sequence: number, // not being used currently + claim_sequence: number, claim_op: 'create' | 'update', - confirmations: number, - decoded_claim: boolean, // Not available currently https://github.com/lbryio/lbry/issues/2044 - timestamp?: number, // date of last transaction + confirmations: number, // This isn't the most stable atm: https://github.com/lbryio/lbry/issues/2000 + decoded_claim: boolean, // claim made in accordance with sdk protobuf types + depth: number, // confirmations since tx + effective_amount: number, // bid amount + supports + has_signature: boolean, height: number, // block height the tx was confirmed - is_channel_signature_valid?: boolean, - is_my_output: boolean, + hex: string, // `value` hex encoded name: string, + channel_name?: string, normalized_name: string, // `name` normalized via unicode NFD spec, nout: number, // index number for an output of a tx permanent_url: string, // name + claim_id - short_url: string, // permanent_url with short id, no channel + supports: Array<{}>, // TODO: add support type once we start using it txid: string, // unique tx id type: 'claim' | 'update' | 'support', + valid_at_height?: number, // BUG: this should always exist https://github.com/lbryio/lbry/issues/1728 value_type: 'stream' | 'channel', - signing_channel?: ChannelClaim, - repost_channel_url?: string, - purchase_receipt?: PurchaseReceipt, - meta: { - activation_height: number, - claims_in_channel?: number, - creation_height: number, - creation_timestamp: number, - effective_amount: string, - expiration_height: number, - is_controlling: boolean, - support_amount: string, - reposted: number, - trending_global: number, - trending_group: number, - trending_local: number, - trending_mixed: number, - }, }; declare type GenericMetadata = { @@ -64,11 +59,9 @@ declare type GenericMetadata = { declare type ChannelMetadata = GenericMetadata & { public_key: string, - public_key_id: string, cover_url?: string, - email?: string, - website_url?: string, - featured?: Array, + contact_email?: string, + homepage_url?: string, }; declare type StreamMetadata = GenericMetadata & { @@ -112,24 +105,11 @@ declare type Location = { longitude?: number, country?: string, state?: string, - city?: string, code?: string, }; declare type Fee = { - amount: string, + amount: number, // should be a string https://github.com/lbryio/lbry/issues/1576 currency: string, address: string, }; - -declare type PurchaseReceipt = { - address: string, - amount: string, - claim_id: string, - confirmations: number, - height: number, - nout: number, - timestamp: number, - txid: string, - type: 'purchase', -}; diff --git a/flow-typed/Comment.js b/flow-typed/Comment.js deleted file mode 100644 index 64ea974..0000000 --- a/flow-typed/Comment.js +++ /dev/null @@ -1,23 +0,0 @@ -declare type Comment = { - comment: string, // comment body - comment_id: string, // sha256 digest - claim_id: string, // id linking to the claim this comment - timestamp: number, // integer representing unix-time - is_hidden: boolean, // claim owner may enable/disable this - channel_id?: string, // claimId of channel signing this comment - channel_name?: string, // name of channel claim - channel_url?: string, // full lbry url to signing channel - signature?: string, // signature of comment by originating channel - signing_ts?: string, // timestamp used when signing this comment - is_channel_signature_valid?: boolean, // whether or not the signature could be validated - parent_id?: number, // comment_id of comment this is in reply to -}; - -// todo: relate individual comments to their commentId -declare type CommentsState = { - commentsByUri: { [string]: string }, - byId: { [string]: Array }, - commentById: { [string]: Comment }, - isLoading: boolean, - myComments: ?Set, -}; diff --git a/flow-typed/File.js b/flow-typed/File.js index 44dc4f3..a4f8a60 100644 --- a/flow-typed/File.js +++ b/flow-typed/File.js @@ -2,7 +2,6 @@ declare type FileListItem = { metadata: StreamMetadata, - added_on: number, blobs_completed: number, blobs_in_stream: number, blobs_remaining: number, @@ -11,8 +10,6 @@ declare type FileListItem = { claim_id: string, claim_name: string, completed: false, - content_fee?: { txid: string }, - purchase_receipt?: { txid: string, amount: string }, download_directory: string, download_path: string, file_name: string, @@ -22,57 +19,17 @@ declare type FileListItem = { outpoint: string, points_paid: number, protobuf: string, - reflector_progress: number, sd_hash: string, status: string, stopped: false, stream_hash: string, stream_name: string, - streaming_url: string, suggested_file_name: string, total_bytes: number, total_bytes_lower_bound: number, - is_fully_reflected: boolean, // TODO: sdk plans to change `tx` // It isn't currently used by the apps tx: {}, txid: string, - uploading_to_reflector: boolean, written_bytes: number, }; - -declare type FileState = { - failedPurchaseUris: Array, - purchasedUris: Array, -}; - -declare type PurchaseUriCompleted = { - type: ACTIONS.PURCHASE_URI_COMPLETED, - data: { - uri: string, - streamingUrl: string, - }, -}; - -declare type PurchaseUriFailed = { - type: ACTIONS.PURCHASE_URI_FAILED, - data: { - uri: string, - error: any, - }, -}; - -declare type PurchaseUriStarted = { - type: ACTIONS.PURCHASE_URI_STARTED, - data: { - uri: string, - streamingUrl: string, - }, -}; - -declare type DeletePurchasedUri = { - type: ACTIONS.CLEAR_PURCHASED_URI_SUCCESS, - data: { - uri: string, - }, -}; diff --git a/flow-typed/Lbry.js b/flow-typed/Lbry.js index d7c0430..93ce160 100644 --- a/flow-typed/Lbry.js +++ b/flow-typed/Lbry.js @@ -50,8 +50,6 @@ declare type StatusResponse = { blocks_behind: number, is_encrypted: boolean, is_locked: boolean, - headers_synchronization_progress: number, - available_servers: number, }, }; @@ -65,23 +63,14 @@ declare type VersionResponse = { python_version: string, }; -declare type BalanceResponse = { - available: string, - reserved: string, - reserved_subtotals: ?{ - claims: string, - supports: string, - tips: string, - }, - total: string, -}; - declare type ResolveResponse = { // Keys are the url(s) passed to resolve - [string]: { error?: {}, stream?: StreamClaim, channel?: ChannelClaim, claimsInChannel?: number }, + [string]: + | { error: {}, certificate: ChannelClaim, claims_in_channel: number } + | { error?: {}, claim: StreamClaim, certificate?: ChannelClaim }, }; -declare type GetResponse = FileListItem & { error?: string }; +declare type GetResponse = FileListItem; declare type GenericTxResponse = { height: number, @@ -97,139 +86,50 @@ declare type GenericTxResponse = { declare type PublishResponse = GenericTxResponse & { // Only first value in outputs is a claim // That's the only value we care about - outputs: Array, + outputs: Array, }; declare type ClaimSearchResponse = { - items: Array, + items: Array, page: number, page_size: number, - total_items: number, - total_pages: number, + page_number: number, }; declare type ClaimListResponse = { - items: Array, - page: number, - page_size: number, - total_items: number, - total_pages: number, + claims: Array, }; declare type ChannelCreateResponse = GenericTxResponse & { outputs: Array, }; -declare type ChannelUpdateResponse = GenericTxResponse & { - outputs: Array, -}; +declare type ChannelListResponse = Array; -declare type CommentCreateResponse = Comment; -declare type CommentUpdateResponse = Comment; +declare type FileListResponse = Array; -declare type CommentListResponse = { - items: Array, - page: number, - page_size: number, - total_items: number, - total_pages: number, -}; +declare type TxListResponse = Array; -declare type CommentHideResponse = { - // keyed by the CommentIds entered - [string]: { hidden: boolean }, -}; +declare type BlobListResponse = Array; -declare type CommentAbandonResponse = { - // keyed by the CommentId given - abandoned: boolean, -}; - -declare type ChannelListResponse = { - items: Array, - page: number, - page_size: number, - total_items: number, - total_pages: number, -}; - -declare type FileListResponse = { - items: Array, - page: number, - page_size: number, - total_items: number, - total_pages: number, -}; - -declare type TxListResponse = { - items: Array, - page: number, - page_size: number, - total_items: number, - total_pages: number, -}; - -declare type SupportListResponse = { - items: Array, - page: number, - page_size: number, - total_items: number, - total_pages: number, -}; - -declare type BlobListResponse = { items: Array }; - -declare type WalletListResponse = Array<{ +declare type AccountListResponse = Array<{ id: string, + is_default: string, + ledger: string, name: string, + seed: string, + encrypted: string, + private_key: string, + public_key: string, + address_generator: string, + modified_on: string, }>; -declare type WalletStatusResponse = { - is_encrypted: boolean, - is_locked: boolean, - is_syncing: boolean, -}; - declare type SyncApplyResponse = { hash: string, data: string, }; -declare type SupportAbandonResponse = GenericTxResponse; - -declare type StreamListResponse = { - items: Array, - page: number, - page_size: number, - total_items: number, - total_pages: number, -}; - -declare type StreamRepostOptions = { - name: string, - bid: string, - claim_id: string, - channel_id: string, -}; - -declare type StreamRepostResponse = GenericTxResponse; - -declare type PurchaseListResponse = { - items: Array, - page: number, - page_size: number, - total_items: number, - total_pages: number, -}; - -declare type PurchaseListOptions = { - page: number, - page_size: number, - resolve: boolean, - claim_id?: string, - channel_id?: string, -}; - // // Types used in the generic Lbry object that is exported // @@ -238,12 +138,7 @@ declare type LbryTypes = { connectPromise: ?Promise, connect: () => void, daemonConnectionString: string, - alternateConnectionString: string, - methodsUsingAlternateConnectionString: Array, - apiRequestHeaders: { [key: string]: string }, setDaemonConnectionString: string => void, - setApiHeader: (string, string) => void, - unsetApiHeader: string => void, overrides: { [string]: ?Function }, setOverride: (string, Function) => void, getMediaType: (string, ?string) => string, @@ -257,19 +152,12 @@ declare type LbryTypes = { publish: (params: {}) => Promise, claim_search: (params: {}) => Promise, - claim_list: (params: {}) => Promise, + claim_list: (params?: {}) => Promise, channel_create: (params: {}) => Promise, - channel_update: (params: {}) => Promise, - channel_import: (params: {}) => Promise, - channel_list: (params: {}) => Promise, + channel_list: () => Promise, stream_abandon: (params: {}) => Promise, - stream_list: (params: {}) => Promise, channel_abandon: (params: {}) => Promise, support_create: (params: {}) => Promise, - support_list: (params: {}) => Promise, - support_abandon: (params: {}) => Promise, - stream_repost: (params: StreamRepostOptions) => Promise, - purchase_list: (params: PurchaseListOptions) => Promise, // File fetching and manipulation file_list: (params: {}) => Promise, @@ -277,28 +165,15 @@ declare type LbryTypes = { blob_delete: (params: {}) => Promise, blob_list: (params: {}) => Promise, - // Preferences - preference_get: (params: {}) => Promise, - preference_set: (params: {}) => Promise, - - // Commenting - comment_list: (params: {}) => Promise, - comment_create: (params: {}) => Promise, - comment_update: (params: {}) => Promise, - comment_hide: (params: {}) => Promise, - comment_abandon: (params: {}) => Promise, - // Wallet utilities - wallet_balance: (params: {}) => Promise, - wallet_decrypt: (prams: {}) => Promise, - wallet_encrypt: (params: {}) => Promise, - wallet_unlock: (params: {}) => Promise, - wallet_list: (params: {}) => Promise, - wallet_send: (params: {}) => Promise, - wallet_status: (params: {}) => Promise, + account_balance: (params: {}) => Promise, + account_decrypt: (prams: {}) => Promise, + account_encrypt: (params: {}) => Promise, + account_unlock: (params: {}) => Promise, + account_list: (params: {}) => Promise, + account_send: (params: {}) => Promise, address_is_mine: (params: {}) => Promise, address_unused: (params: {}) => Promise, // New address - address_list: (params: {}) => Promise, transaction_list: (params: {}) => Promise, // Sync diff --git a/flow-typed/LbryFirst.js b/flow-typed/LbryFirst.js deleted file mode 100644 index b068f5f..0000000 --- a/flow-typed/LbryFirst.js +++ /dev/null @@ -1,99 +0,0 @@ -// @flow -declare type StatusResponse = { - Version: string, - Message: string, - Running: boolean, - Commit: string, -}; - -declare type VersionResponse = { - build: string, - lbrynet_version: string, - os_release: string, - os_system: string, - platform: string, - processor: string, - python_version: string, -}; -/* SAMPLE UPLOAD RESPONSE (FULL) -"Video": { - "etag": "\"Dn5xIderbhAnUk5TAW0qkFFir0M/xlGLrlTox7VFTRcR8F77RbKtaU4\"", - "id": "8InjtdvVmwE", - "kind": "youtube#video", - "snippet": { - "categoryId": "22", - "channelId": "UCXiVsGTU88fJjheB2rqF0rA", - "channelTitle": "Mark Beamer", - "liveBroadcastContent": "none", - "localized": { - "title": "my title" - }, - "publishedAt": "2020-05-05T04:17:53.000Z", - "thumbnails": { - "default": { - "height": 90, - "url": "https://i9.ytimg.com/vi/8InjtdvVmwE/default.jpg?sqp=CMTQw_UF&rs=AOn4CLB6dlhZMSMrazDlWRsitPgCsn8fVw", - "width": 120 - }, - "high": { - "height": 360, - "url": "https://i9.ytimg.com/vi/8InjtdvVmwE/hqdefault.jpg?sqp=CMTQw_UF&rs=AOn4CLB-Je_7l6qvASRAR_bSGWZHaXaJWQ", - "width": 480 - }, - "medium": { - "height": 180, - "url": "https://i9.ytimg.com/vi/8InjtdvVmwE/mqdefault.jpg?sqp=CMTQw_UF&rs=AOn4CLCvSnDLqVznRNMKuvJ_0misY_chPQ", - "width": 320 - } - }, - "title": "my title" - }, - "status": { - "embeddable": true, - "license": "youtube", - "privacyStatus": "private", - "publicStatsViewable": true, - "uploadStatus": "uploaded" - } - } - */ -declare type UploadResponse = { - Video: { - id: string, - snippet: { - channelId: string, - }, - status: { - uploadStatus: string, - }, - }, -}; - -declare type HasYTAuthResponse = { - HashAuth: boolean, -}; - -declare type YTSignupResponse = {}; - -// -// Types used in the generic LbryFirst object that is exported -// -declare type LbryFirstTypes = { - isConnected: boolean, - connectPromise: ?Promise, - connect: () => void, - lbryFirstConnectionString: string, - apiRequestHeaders: { [key: string]: string }, - setApiHeader: (string, string) => void, - unsetApiHeader: string => void, - overrides: { [string]: ?Function }, - setOverride: (string, Function) => void, - - // LbryFirst Methods - stop: () => Promise, - status: () => Promise, - version: () => Promise, - upload: any => Promise, - hasYTAuth: string => Promise, - ytSignup: () => Promise, -}; diff --git a/flow-typed/Publish.js b/flow-typed/Publish.js deleted file mode 100644 index 87955ae..0000000 --- a/flow-typed/Publish.js +++ /dev/null @@ -1,27 +0,0 @@ -// @flow - -declare type UpdatePublishFormData = { - filePath?: string, - contentIsFree?: boolean, - fee?: { - amount: string, - currency: string, - }, - title?: string, - thumbnail_url?: string, - uploadThumbnailStatus?: string, - thumbnailPath?: string, - description?: string, - language?: string, - channel?: string, - channelId?: string, - name?: string, - nameError?: string, - bid?: string, - bidError?: string, - otherLicenseDescription?: string, - licenseUrl?: string, - licenseType?: string, - uri?: string, - nsfw: boolean, -}; diff --git a/flow-typed/Reflector.js b/flow-typed/Reflector.js deleted file mode 100644 index fc6be97..0000000 --- a/flow-typed/Reflector.js +++ /dev/null @@ -1,5 +0,0 @@ -declare type ReflectingUpdate = { - fileListItem: FileListItem, - progress: number | boolean, - stalled: boolean, -}; diff --git a/flow-typed/Search.js b/flow-typed/Search.js index 2a2152e..5fad710 100644 --- a/flow-typed/Search.js +++ b/flow-typed/Search.js @@ -28,8 +28,6 @@ declare type SearchState = { options: SearchOptions, suggestions: { [string]: Array }, urisByQuery: {}, - resolvedResultsByQuery: {}, - resolvedResultsByQueryLastPageReached: {}, }; declare type SearchSuccess = { @@ -59,26 +57,3 @@ declare type UpdateSearchOptions = { type: ACTIONS.UPDATE_SEARCH_OPTIONS, data: SearchOptions, }; - -declare type ResolvedSearchResult = { - channel: string, - channel_claim_id: string, - claimId: string, - duration: number, - fee: number, - name: string, - nsfw: boolean, - release_time: string, - thumbnail_url: string, - title: string, -}; - -declare type ResolvedSearchSuccess = { - type: ACTIONS.RESOLVED_SEARCH_SUCCESS, - data: { - append: boolean, - pageSize: number, - results: Array, - query: string, - }, -}; diff --git a/flow-typed/Tags.js b/flow-typed/Tags.js deleted file mode 100644 index 01c58ac..0000000 --- a/flow-typed/Tags.js +++ /dev/null @@ -1,21 +0,0 @@ -declare type TagState = { - followedTags: FollowedTags, - knownTags: KnownTags, -}; - -declare type Tag = { - name: string, -}; - -declare type KnownTags = { - [string]: Tag, -}; - -declare type FollowedTags = Array; - -declare type TagAction = { - type: string, - data: { - name: string, - }, -}; diff --git a/flow-typed/Transaction.js b/flow-typed/Transaction.js index db9e592..7953b90 100644 --- a/flow-typed/Transaction.js +++ b/flow-typed/Transaction.js @@ -9,20 +9,3 @@ declare type Transaction = { type: string, date: Date, }; - -declare type Support = { - address: string, - amount: string, - claim_id: string, - confirmations: number, - height: string, - is_change: string, - is_mine: string, - name: string, - normalized_name: string, - nout: string, - permanent_url: string, - timestamp: number, - txid: string, - type: string, -}; diff --git a/flow-typed/Txo.js b/flow-typed/Txo.js deleted file mode 100644 index 5950c99..0000000 --- a/flow-typed/Txo.js +++ /dev/null @@ -1,24 +0,0 @@ -declare type Txo = { - amount: number, - claim_id: string, - normalized_name: string, - nout: number, - txid: string, - type: string, - value_type: string, - timestamp: number, - is_my_output: boolean, - is_my_input: boolean, - is_spent: boolean, -}; - -declare type TxoListParams = { - page: number, - page_size: number, - type: string, - is_my_input?: boolean, - is_my_output?: boolean, - is_not_my_input?: boolean, - is_not_my_output?: boolean, - is_spent?: boolean, -} diff --git a/flow-typed/i18n.js b/flow-typed/i18n.js deleted file mode 100644 index de97c0c..0000000 --- a/flow-typed/i18n.js +++ /dev/null @@ -1,2 +0,0 @@ -// @flow -declare function __(a: string, b?: {}): string; diff --git a/flow-typed/lbryURI.js b/flow-typed/lbryURI.js deleted file mode 100644 index 549c991..0000000 --- a/flow-typed/lbryURI.js +++ /dev/null @@ -1,21 +0,0 @@ -// @flow -declare type LbryUrlObj = { - // Path and channel will always exist when calling parseURI - // But they may not exist when code calls buildURI - isChannel?: boolean, - path?: string, - streamName?: string, - streamClaimId?: string, - channelName?: string, - channelClaimId?: string, - primaryClaimSequence?: number, - secondaryClaimSequence?: number, - primaryBidPosition?: number, - secondaryBidPosition?: number, - startTime?: number, - - // Below are considered deprecated and should not be used due to unreliableness with claim.canonical_url - claimName?: string, - claimId?: string, - contentName?: string, -}; diff --git a/package.json b/package.json index b8214b4..0ed595a 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "lbry" ], "license": "MIT", - "homepage": "https://lbry.com/", + "homepage": "https://lbry.io/", "bugs": { "url": "https://github.com/lbryio/lbry-redux/issues" }, @@ -16,12 +16,12 @@ }, "author": { "name": "LBRY Inc.", - "email": "hello@lbry.com" + "email": "hello@lbry.io" }, - "main": "dist/bundle.es.js", + "main": "dist/bundle.js", "module": "dist/bundle.es.js", "scripts": { - "build": "cross-env NODE_ENV=production rollup --config", + "build": "rollup --config", "dev": "rollup --config --watch", "precommit": "flow check && lint-staged", "lint": "eslint 'src/**/*.js' --fix", @@ -40,7 +40,6 @@ "babel-plugin-transform-flow-comments": "^6.17.0", "babel-preset-env": "^1.6.1", "babel-preset-stage-2": "^6.18.0", - "cross-env": "^5.2.0", "eslint": "^5.16.0", "eslint-config-standard": "^12.0.0", "eslint-config-standard-jsx": "^6.0.2", @@ -60,8 +59,7 @@ "rollup-plugin-copy": "^1.1.0", "rollup-plugin-eslint": "^5.1.0", "rollup-plugin-flow": "^1.1.1", - "rollup-plugin-includepaths": "^0.2.3", - "rollup-plugin-replace": "^2.2.0" + "rollup-plugin-includepaths": "^0.2.3" }, "engines": { "yarn": "^1.3" diff --git a/rollup.config.js b/rollup.config.js index 2b898d6..30de832 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -2,7 +2,6 @@ import babel from 'rollup-plugin-babel'; import flow from 'rollup-plugin-flow'; import includePaths from 'rollup-plugin-includepaths'; import copy from 'rollup-plugin-copy'; -import replace from 'rollup-plugin-replace'; let includePathOptions = { include: {}, @@ -11,8 +10,6 @@ let includePathOptions = { extensions: ['.js'], }; -const production = process.env.NODE_ENV === 'production'; - export default { input: 'src/index.js', output: { @@ -27,10 +24,5 @@ export default { presets: ['stage-2'], }), copy({ targets: ['flow-typed'] }), - replace({ - 'process.env.NODE_ENV': production - ? JSON.stringify('production') - : JSON.stringify('development'), - }), ], }; diff --git a/src/constants/abandon_states.js b/src/constants/abandon_states.js deleted file mode 100644 index 3761c9e..0000000 --- a/src/constants/abandon_states.js +++ /dev/null @@ -1,4 +0,0 @@ -export const PENDING = 'pending'; -export const DONE = 'done'; -export const READY = 'ready'; -export const ERROR = 'error'; diff --git a/src/constants/action_types.js b/src/constants/action_types.js index 87e4295..a01c6ef 100644 --- a/src/constants/action_types.js +++ b/src/constants/action_types.js @@ -3,8 +3,6 @@ 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'; -export const SET_WELCOME_VERSION = 'SET_WELCOME_VERSION'; -export const SET_ALLOW_ANALYTICS = 'SET_ALLOW_ANALYTICS'; // Navigation export const CHANGE_AFTER_AUTH_PATH = 'CHANGE_AFTER_AUTH_PATH'; @@ -35,19 +33,6 @@ 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 FETCH_TXO_PAGE_STARTED = 'FETCH_TXO_PAGE_STARTED'; -export const FETCH_TXO_PAGE_COMPLETED = 'FETCH_TXO_PAGE_COMPLETED'; -export const FETCH_TXO_PAGE_FAILED = 'FETCH_TXO_PAGE_FAILED'; -export const UPDATE_TXO_FETCH_PARAMS = 'UPDATE_TXO_FETCH_PARAMS'; -export const FETCH_SUPPORTS_STARTED = 'FETCH_SUPPORTS_STARTED'; -export const FETCH_SUPPORTS_COMPLETED = 'FETCH_SUPPORTS_COMPLETED'; -export const ABANDON_SUPPORT_STARTED = 'ABANDON_SUPPORT_STARTED'; -export const ABANDON_SUPPORT_COMPLETED = 'ABANDON_SUPPORT_COMPLETED'; -export const ABANDON_CLAIM_SUPPORT_STARTED = 'ABANDON_CLAIM_SUPPORT_STARTED'; -export const ABANDON_CLAIM_SUPPORT_COMPLETED = 'ABANDON_CLAIM_SUPPORT_COMPLETED'; -export const ABANDON_CLAIM_SUPPORT_FAILED = 'ABANDON_CLAIM_SUPPORT_FAILED'; -export const ABANDON_CLAIM_SUPPORT_PREVIEW = 'ABANDON_CLAIM_SUPPORT_PREVIEW'; -export const PENDING_SUPPORTS_UPDATED = 'PENDING_SUPPORTS_UPDATED'; export const UPDATE_BALANCE = 'UPDATE_BALANCE'; export const UPDATE_TOTAL_BALANCE = 'UPDATE_TOTAL_BALANCE'; export const CHECK_ADDRESS_IS_MINE_STARTED = 'CHECK_ADDRESS_IS_MINE_STARTED'; @@ -55,10 +40,10 @@ export const CHECK_ADDRESS_IS_MINE_COMPLETED = 'CHECK_ADDRESS_IS_MINE_COMPLETED' 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'; -export const CLEAR_SUPPORT_TRANSACTION = 'CLEAR_SUPPORT_TRANSACTION'; export const WALLET_ENCRYPT_START = 'WALLET_ENCRYPT_START'; export const WALLET_ENCRYPT_COMPLETED = 'WALLET_ENCRYPT_COMPLETED'; export const WALLET_ENCRYPT_FAILED = 'WALLET_ENCRYPT_FAILED'; @@ -73,8 +58,6 @@ export const WALLET_LOCK_COMPLETED = 'WALLET_LOCK_COMPLETED'; export const WALLET_LOCK_FAILED = 'WALLET_LOCK_FAILED'; export const WALLET_STATUS_START = 'WALLET_STATUS_START'; export const WALLET_STATUS_COMPLETED = 'WALLET_STATUS_COMPLETED'; -export const WALLET_RESTART = 'WALLET_RESTART'; -export const WALLET_RESTART_COMPLETED = 'WALLET_RESTART_COMPLETED'; export const SET_TRANSACTION_LIST_FILTER = 'SET_TRANSACTION_LIST_FILTER'; export const UPDATE_CURRENT_HEIGHT = 'UPDATE_CURRENT_HEIGHT'; export const SET_DRAFT_TRANSACTION_AMOUNT = 'SET_DRAFT_TRANSACTION_AMOUNT'; @@ -91,16 +74,9 @@ export const ABANDON_CLAIM_STARTED = 'ABANDON_CLAIM_STARTED'; export const ABANDON_CLAIM_SUCCEEDED = 'ABANDON_CLAIM_SUCCEEDED'; export const FETCH_CHANNEL_LIST_STARTED = 'FETCH_CHANNEL_LIST_STARTED'; export const FETCH_CHANNEL_LIST_COMPLETED = 'FETCH_CHANNEL_LIST_COMPLETED'; -export const FETCH_CHANNEL_LIST_FAILED = 'FETCH_CHANNEL_LIST_FAILED'; export const CREATE_CHANNEL_STARTED = 'CREATE_CHANNEL_STARTED'; export const CREATE_CHANNEL_COMPLETED = 'CREATE_CHANNEL_COMPLETED'; export const CREATE_CHANNEL_FAILED = 'CREATE_CHANNEL_FAILED'; -export const UPDATE_CHANNEL_STARTED = 'UPDATE_CHANNEL_STARTED'; -export const UPDATE_CHANNEL_COMPLETED = 'UPDATE_CHANNEL_COMPLETED'; -export const UPDATE_CHANNEL_FAILED = 'UPDATE_CHANNEL_FAILED'; -export const IMPORT_CHANNEL_STARTED = 'IMPORT_CHANNEL_STARTED'; -export const IMPORT_CHANNEL_COMPLETED = 'IMPORT_CHANNEL_COMPLETED'; -export const IMPORT_CHANNEL_FAILED = 'IMPORT_CHANNEL_FAILED'; export const PUBLISH_STARTED = 'PUBLISH_STARTED'; export const PUBLISH_COMPLETED = 'PUBLISH_COMPLETED'; export const PUBLISH_FAILED = 'PUBLISH_FAILED'; @@ -109,52 +85,12 @@ export const SET_CONTENT_POSITION = 'SET_CONTENT_POSITION'; export const SET_CONTENT_LAST_VIEWED = 'SET_CONTENT_LAST_VIEWED'; export const CLEAR_CONTENT_HISTORY_URI = 'CLEAR_CONTENT_HISTORY_URI'; export const CLEAR_CONTENT_HISTORY_ALL = 'CLEAR_CONTENT_HISTORY_ALL'; -export const CLAIM_SEARCH_STARTED = 'CLAIM_SEARCH_STARTED'; -export const CLAIM_SEARCH_COMPLETED = 'CLAIM_SEARCH_COMPLETED'; -export const CLAIM_SEARCH_FAILED = 'CLAIM_SEARCH_FAILED'; -export const CLAIM_SEARCH_BY_TAGS_STARTED = 'CLAIM_SEARCH_BY_TAGS_STARTED'; -export const CLAIM_SEARCH_BY_TAGS_COMPLETED = 'CLAIM_SEARCH_BY_TAGS_COMPLETED'; -export const CLAIM_SEARCH_BY_TAGS_FAILED = 'CLAIM_SEARCH_BY_TAGS_FAILED'; -export const CLAIM_REPOST_STARTED = 'CLAIM_REPOST_STARTED'; -export const CLAIM_REPOST_COMPLETED = 'CLAIM_REPOST_COMPLETED'; -export const CLAIM_REPOST_FAILED = 'CLAIM_REPOST_FAILED'; -export const CLEAR_REPOST_ERROR = 'CLEAR_REPOST_ERROR'; -export const CLEAR_CHANNEL_ERRORS = 'CLEAR_CHANNEL_ERRORS'; -export const CHECK_PUBLISH_NAME_STARTED = 'CHECK_PUBLISH_NAME_STARTED'; -export const CHECK_PUBLISH_NAME_COMPLETED = 'CHECK_PUBLISH_NAME_COMPLETED'; -export const UPDATE_PENDING_CLAIMS = 'UPDATE_PENDING_CLAIMS'; -export const UPDATE_CONFIRMED_CLAIMS = 'UPDATE_CONFIRMED_CLAIMS'; -export const ADD_FILES_REFLECTING = 'ADD_FILES_REFLECTING'; -export const UPDATE_FILES_REFLECTING = 'UPDATE_FILES_REFLECTING'; -export const TOGGLE_CHECKING_REFLECTING = 'TOGGLE_CHECKING_REFLECTING'; -export const TOGGLE_CHECKING_PENDING = 'TOGGLE_CHECKING_PENDING'; -export const PURCHASE_LIST_STARTED = 'PURCHASE_LIST_STARTED'; -export const PURCHASE_LIST_COMPLETED = 'PURCHASE_LIST_COMPLETED'; -export const PURCHASE_LIST_FAILED = 'PURCHASE_LIST_FAILED'; - -// Comments -export const COMMENT_LIST_STARTED = 'COMMENT_LIST_STARTED'; -export const COMMENT_LIST_COMPLETED = 'COMMENT_LIST_COMPLETED'; -export const COMMENT_LIST_FAILED = 'COMMENT_LIST_FAILED'; -export const COMMENT_CREATE_STARTED = 'COMMENT_CREATE_STARTED'; -export const COMMENT_CREATE_COMPLETED = 'COMMENT_CREATE_COMPLETED'; -export const COMMENT_CREATE_FAILED = 'COMMENT_CREATE_FAILED'; -export const COMMENT_ABANDON_STARTED = 'COMMENT_ABANDON_STARTED'; -export const COMMENT_ABANDON_COMPLETED = 'COMMENT_ABANDON_COMPLETED'; -export const COMMENT_ABANDON_FAILED = 'COMMENT_ABANDON_FAILED'; -export const COMMENT_UPDATE_STARTED = 'COMMENT_UPDATE_STARTED'; -export const COMMENT_UPDATE_COMPLETED = 'COMMENT_UPDATE_COMPLETED'; -export const COMMENT_UPDATE_FAILED = 'COMMENT_UPDATE_FAILED'; -export const COMMENT_HIDE_STARTED = 'COMMENT_HIDE_STARTED'; -export const COMMENT_HIDE_COMPLETED = 'COMMENT_HIDE_COMPLETED'; -export const COMMENT_HIDE_FAILED = 'COMMENT_HIDE_FAILED'; // 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_FILE_INFO_FAILED = 'FETCH_FILE_INFO_FAILED'; export const LOADING_VIDEO_STARTED = 'LOADING_VIDEO_STARTED'; export const LOADING_VIDEO_COMPLETED = 'LOADING_VIDEO_COMPLETED'; export const LOADING_VIDEO_FAILED = 'LOADING_VIDEO_FAILED'; @@ -167,18 +103,11 @@ export const FETCH_AVAILABILITY_STARTED = 'FETCH_AVAILABILITY_STARTED'; export const FETCH_AVAILABILITY_COMPLETED = 'FETCH_AVAILABILITY_COMPLETED'; export const FILE_DELETE = 'FILE_DELETE'; export const SET_FILE_LIST_SORT = 'SET_FILE_LIST_SORT'; -export const PURCHASE_URI_STARTED = 'PURCHASE_URI_STARTED'; -export const PURCHASE_URI_COMPLETED = 'PURCHASE_URI_COMPLETED'; -export const PURCHASE_URI_FAILED = 'PURCHASE_URI_FAILED'; -export const CLEAR_PURCHASED_URI_SUCCESS = 'CLEAR_PURCHASED_URI_SUCCESS'; // Search export const SEARCH_START = 'SEARCH_START'; export const SEARCH_SUCCESS = 'SEARCH_SUCCESS'; export const SEARCH_FAIL = 'SEARCH_FAIL'; -export const RESOLVED_SEARCH_START = 'RESOLVED_SEARCH_START'; -export const RESOLVED_SEARCH_SUCCESS = 'RESOLVED_SEARCH_SUCCESS'; -export const RESOLVED_SEARCH_FAIL = 'RESOLVED_SEARCH_FAIL'; export const UPDATE_SEARCH_QUERY = 'UPDATE_SEARCH_QUERY'; export const UPDATE_SEARCH_OPTIONS = 'UPDATE_SEARCH_OPTIONS'; export const UPDATE_SEARCH_SUGGESTIONS = 'UPDATE_SEARCH_SUGGESTIONS'; @@ -187,9 +116,6 @@ export const SEARCH_BLUR = 'SEARCH_BLUR'; // Settings export const DAEMON_SETTINGS_RECEIVED = 'DAEMON_SETTINGS_RECEIVED'; -export const DAEMON_STATUS_RECEIVED = 'DAEMON_STATUS_RECEIVED'; -export const SHARED_PREFERENCE_SET = 'SHARED_PREFERENCE_SET'; -export const SAVE_CUSTOM_WALLET_SERVERS = 'SAVE_CUSTOM_WALLET_SERVERS'; export const CLIENT_SETTING_CHANGED = 'CLIENT_SETTING_CHANGED'; export const UPDATE_IS_NIGHT = 'UPDATE_IS_NIGHT'; @@ -241,6 +167,21 @@ export const FETCH_REWARD_CONTENT_COMPLETED = 'FETCH_REWARD_CONTENT_COMPLETED'; 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'; @@ -273,19 +214,3 @@ export const CREATE_ERROR = 'CREATE_ERROR'; export const DISMISS_ERROR = 'DISMISS_ERROR'; export const FETCH_DATE = 'FETCH_DATE'; - -// Cost info -export const FETCH_COST_INFO_STARTED = 'FETCH_COST_INFO_STARTED'; -export const FETCH_COST_INFO_COMPLETED = 'FETCH_COST_INFO_COMPLETED'; -export const FETCH_COST_INFO_FAILED = 'FETCH_COST_INFO_FAILED'; - -// Tags -export const TOGGLE_TAG_FOLLOW = 'TOGGLE_TAG_FOLLOW'; -export const TAG_ADD = 'TAG_ADD'; -export const TAG_DELETE = 'TAG_DELETE'; - -// Blocked Channels -export const TOGGLE_BLOCK_CHANNEL = 'TOGGLE_BLOCK_CHANNEL'; - -// Sync -export const USER_STATE_POPULATE = 'USER_STATE_POPULATE'; diff --git a/src/constants/claim.js b/src/constants/claim.js deleted file mode 100644 index 4cf33ce..0000000 --- a/src/constants/claim.js +++ /dev/null @@ -1,5 +0,0 @@ -export const MINIMUM_PUBLISH_BID = 0.00000001; - -export const CHANNEL_ANONYMOUS = 'anonymous'; -export const CHANNEL_NEW = 'new'; -export const PAGE_SIZE = 20; diff --git a/src/constants/daemon_settings.js b/src/constants/daemon_settings.js deleted file mode 100644 index 04e4fd2..0000000 --- a/src/constants/daemon_settings.js +++ /dev/null @@ -1,39 +0,0 @@ -export const ANNOUNCE_HEAD_AND_SD_ONLY = 'announce_head_and_sd_only'; -export const API = 'api'; -export const BLOB_DOWNLOAD_TIMEOUT = 'blob_download_timeout'; -export const BLOB_LRU_CACHE_SIZE = 'blob_lru_cache_size'; -export const BLOCKCHAIN_NAME = 'blockchain_name'; -export const CACHE_TIME = 'cache_time'; -export const COIN_SELECTION_STRATEGY = 'coin_selection_strategy'; -export const COMMENT_SERVER = 'comment_server'; -export const COMPONENTS_TO_SKIP = 'components_to_skip'; -export const CONCURRENT_BLOB_ANNOUNCERS = 'concurrent_blob_announcers'; -export const CONCURRENT_REFLECTOR_UPLOADS = 'concurrent_reflector_uploads'; -export const CONFIG = 'config'; -export const DATA_DIR = 'data_dir'; -export const DOWNLOAD_DIR = 'download_dir'; -export const DOWNLOAD_TIMEOUT = 'download_timeout'; -export const FIXED_PEER_DELAY = 'fixed_peer_delay'; -export const KNOWN_DHT_NODES = 'known_dht_nodes'; -export const LBRYUM_SERVERS = 'lbryum_servers'; -export const MAX_CONNECTIONS_PER_DOWNLOAD = 'max_connections_per_download'; -export const MAX_KEY_FEE = 'max_key_fee'; -export const DEFAULT_WALLET = 'default_wallet'; -export const NETWORK_INTERFACE = 'network_interface'; -export const NODE_RPC_TIMEOUT = 'node_rpc_timeout'; -export const PEER_CONNECT_TIMEOUT = 'peer_connect_timeout'; -export const REFLECT_STREAMS = 'reflect_streams'; -export const REFLECTOR_SERVERS = 'reflector_servers'; -export const S3_HEADERS_DEPTH = 's3_headers_depth'; -export const SAVE_BLOBS = 'save_blobs'; -export const SAVE_FILES = 'save_files'; -export const SHARE_USAGE_DATA = 'share_usage_data'; -export const SPLIT_BUCKETS_UNDER_INDEX = 'split_buckets_under_index'; -export const STREAMING_GET = 'streaming_get'; -export const STREAMING_SERVER = 'streaming_server'; -export const TCP_PORT = 'tcp_port'; -export const TRACK_BANDWIDTH = 'track_bandwidth'; -export const UDP_PORT = 'udp_port'; -export const USE_UPNP = 'use_upnp'; -export const WALLET_DIR = 'wallet_dir'; -export const WALLETS = 'wallets'; diff --git a/src/constants/licenses.js b/src/constants/licenses.js deleted file mode 100644 index fbcc7e6..0000000 --- a/src/constants/licenses.js +++ /dev/null @@ -1,31 +0,0 @@ -export const CC_LICENSES = [ - { - value: 'Creative Commons Attribution 4.0 International', - url: 'https://creativecommons.org/licenses/by/4.0/legalcode', - }, - { - value: 'Creative Commons Attribution-ShareAlike 4.0 International', - url: 'https://creativecommons.org/licenses/by-sa/4.0/legalcode', - }, - { - value: 'Creative Commons Attribution-NoDerivatives 4.0 International', - url: 'https://creativecommons.org/licenses/by-nd/4.0/legalcode', - }, - { - value: 'Creative Commons Attribution-NonCommercial 4.0 International', - url: 'https://creativecommons.org/licenses/by-nc/4.0/legalcode', - }, - { - value: 'Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International', - url: 'https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode', - }, - { - value: 'Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International', - url: 'https://creativecommons.org/licenses/by-nc-nd/4.0/legalcode', - }, -]; - -export const NONE = 'None'; -export const PUBLIC_DOMAIN = 'Public Domain'; -export const OTHER = 'other'; -export const COPYRIGHT = 'copyright'; diff --git a/src/constants/search.js b/src/constants/search.js index 16b3620..80d291f 100644 --- a/src/constants/search.js +++ b/src/constants/search.js @@ -2,7 +2,6 @@ export const SEARCH_TYPES = { FILE: 'file', CHANNEL: 'channel', SEARCH: 'search', - TAG: 'tag', }; export const SEARCH_OPTIONS = { diff --git a/src/constants/settings.js b/src/constants/settings.js index 6d10806..0c5f88b 100644 --- a/src/constants/settings.js +++ b/src/constants/settings.js @@ -1,39 +1,19 @@ /* 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 SHOW_NSFW = 'showNsfw'; 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 INVITE_ACKNOWLEDGED = 'invite_acknowledged'; export const LANGUAGE = 'language'; -export const SHOW_MATURE = 'show_mature'; -export const HIDE_REPOSTS = 'hide_reposts'; -export const SHOW_ANONYMOUS = 'show_anonymous'; -export const SHOW_UNAVAILABLE = 'show_unavailable'; -export const INSTANT_PURCHASE_ENABLED = 'instant_purchase_enabled'; -export const INSTANT_PURCHASE_MAX = 'instant_purchase_max'; +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'; -export const AUTOMATIC_DARK_MODE_ENABLED = 'automatic_dark_mode_enabled'; -export const AUTOPLAY = 'autoplay'; -export const OS_NOTIFICATIONS_ENABLED = 'os_notifications_enabled'; -export const AUTO_DOWNLOAD = 'auto_download'; -export const AUTO_LAUNCH = 'auto_launch'; -export const SUPPORT_OPTION = 'support_option'; -export const HIDE_BALANCE = 'hide_balance'; -export const HIDE_SPLASH_ANIMATION = 'hide_splash_animation'; -export const FLOATING_PLAYER = 'floating_player'; -export const DARK_MODE_TIMES = 'dark_mode_times'; -export const ENABLE_SYNC = 'enable_sync'; +export const AUTOMATIC_DARK_MODE_ENABLED = 'automaticDarkModeEnabled'; // mobile settings export const BACKGROUND_PLAY_ENABLED = 'backgroundPlayEnabled'; export const FOREGROUND_NOTIFICATION_ENABLED = 'foregroundNotificationEnabled'; export const KEEP_DAEMON_RUNNING = 'keepDaemonRunning'; -export const SHOW_URI_BAR_SUGGESTIONS = 'showUriBarSuggestions'; -export const RECEIVE_SUBSCRIPTION_NOTIFICATIONS = 'receiveSubscriptionNotifications'; -export const RECEIVE_REWARD_NOTIFICATIONS = 'receiveRewardNotifications'; -export const RECEIVE_INTERESTS_NOTIFICATIONS = 'receiveInterestsNotifications'; -export const RECEIVE_CREATOR_NOTIFICATIONS = 'receiveCreatorNotifications'; diff --git a/src/constants/shared_preferences.js b/src/constants/shared_preferences.js deleted file mode 100644 index 58bee93..0000000 --- a/src/constants/shared_preferences.js +++ /dev/null @@ -1,13 +0,0 @@ -/* - * How to use this file: - * Settings exported from here will trigger the setting to be - * sent to the preference middleware when set using the - * usual setDaemonSettings and clearDaemonSettings methods. - * - * See redux/settings/actions in the app for where this is used. - */ - -import * as DAEMON_SETTINGS from './daemon_settings'; - -export const WALLET_SERVERS = DAEMON_SETTINGS.LBRYUM_SERVERS; -export const SHARE_USAGE_DATA = DAEMON_SETTINGS.SHARE_USAGE_DATA; diff --git a/src/constants/speech_urls.js b/src/constants/speech_urls.js deleted file mode 100644 index d61abab..0000000 --- a/src/constants/speech_urls.js +++ /dev/null @@ -1,2 +0,0 @@ -export const SPEECH_STATUS = 'https://spee.ch/api/config/site/publishing'; -export const SPEECH_PUBLISH = 'https://spee.ch/api/claim/publish'; diff --git a/src/constants/tags.js b/src/constants/tags.js deleted file mode 100644 index 2af4f94..0000000 --- a/src/constants/tags.js +++ /dev/null @@ -1,545 +0,0 @@ -export const DEFAULT_FOLLOWED_TAGS = [ - 'art', - 'automotive', - 'blockchain', - 'comedy', - 'economics', - 'education', - 'gaming', - 'music', - 'news', - 'science', - 'sports', - 'technology', -]; - -export const MATURE_TAGS = [ - 'porn', - 'porno', - 'nsfw', - 'mature', - 'xxx', - 'sex', - 'creampie', - 'blowjob', - 'handjob', - 'vagina', - 'boobs', - 'big boobs', - 'big dick', - 'pussy', - 'cumshot', - 'anal', - 'hard fucking', - 'ass', - 'fuck', - 'hentai', -]; - -const DEFAULT_ENGLISH_KNOWN_TAGS = [ - 'free speech', - 'censorship', - 'gaming', - 'pop culture', - 'entertainment', - 'technology', - 'music', - 'funny', - 'education', - 'learning', - 'news', - 'gameplay', - 'nature', - 'beliefs', - 'comedy', - 'games', - 'film & animation', - 'game', - 'weapons', - 'blockchain', - 'video game', - 'sports', - 'walkthrough', - 'lbrytvpaidbeta', - 'art', - 'pc', - 'minecraft', - 'playthrough', - 'economics', - 'automotive', - 'play', - 'tutorial', - 'twitch', - 'how to', - 'ps4', - 'bitcoin', - 'fortnite', - 'commentary', - 'lets play', - 'fun', - 'politics', - 'travel', - 'food', - 'science', - 'xbox', - 'liberal', - 'democrat', - 'progressive', - 'survival', - 'non-profits', - 'activism', - 'cryptocurrency', - 'playstation', - 'nintendo', - 'government', - 'steam', - 'podcast', - 'gamer', - 'horror', - 'conservative', - 'reaction', - 'trailer', - 'love', - 'cnn', - 'republican', - 'political', - 'hangoutsonair', - 'hoa', - 'msnbc', - 'cbs', - 'anime', - 'donald trump', - 'fiction', - 'fox news', - 'crypto', - 'ethereum', - 'call of duty', - 'android', - 'multiplayer', - 'epic', - 'rpg', - 'adventure', - 'secular talk', - 'btc', - 'atheist', - 'atheism', - 'video games', - 'ps3', - 'cod', - 'online', - 'agnostic', - 'movie', - 'fps', - 'lets', - 'mod', - 'world', - 'reviews', - 'sharefactory', - 'space', - 'pokemon', - 'stream', - 'hilarious', - 'lol', - 'sony', - 'god', - 'dance', - 'pvp', - 'tech', - 'strategy', - 'zombies', - 'fail', - 'film', - 'xbox360', - 'animation', - 'unboxing', - 'money', - 'wwe', - 'mods', - 'indie', - 'pubg', - 'ios', - 'history', - 'rap', - 'mobile', - 'trump', - 'hack', - 'flat earth', - 'trap', - 'humor', - 'vlogging', - 'fox', - 'news radio', - 'facebook', - 'edm', - 'fitness', - 'vaping', - 'hip hop', - 'secular', - 'jesus', - 'song', - 'vape', - 'guitar', - 'remix', - 'mining', - 'daily', - 'diy', - 'pets', - 'videogame', - 'death', - 'funny moments', - 'religion', - 'media', - 'viral', - 'war', - 'nbc', - 'freedom', - 'gold', - 'family', - 'meme', - 'zombie', - 'photography', - 'chill', - 'sniper', - 'computer', - 'iphone', - 'dragon', - 'bible', - 'pro', - 'overwatch', - 'litecoin', - 'gta', - 'house', - 'fire', - 'bass', - 'truth', - 'crash', - 'mario', - 'league of legends', - 'wii', - 'mmorpg', - 'health', - 'marvel', - 'racing', - 'apple', - 'instrumental', - 'earth', - 'destiny', - 'satire', - 'race', - 'training', - 'electronic', - 'boss', - 'roblox', - 'family friendly', - 'california', - 'react', - 'christian', - 'mmo', - 'twitter', - 'help', - 'star', - 'cars', - 'random', - 'top 10', - 'ninja', - 'guns', - 'linux', - 'lessons', - 'vegan', - 'future', - 'dota 2', - 'studio', - 'star wars', - 'shooting', - 'nasa', - 'rock', - 'league', - 'subscribe', - 'water', - 'gta v', - 'car', - 'samsung', - 'music video', - 'skyrim', - 'dog', - 'comics', - 'shooter game', - 'bo3', - 'halloween', - 'liberty', - 'eth', - 'conspiracy', - 'knife', - 'fashion', - 'stories', - 'vapor', - 'nvidia', - 'cute', - 'beat', - 'nintendo switch', - 'fantasy', - 'christmas', - 'world of warcraft', - 'industry', - 'cartoon', - 'garden', - 'animals', - 'windows', - 'happy', - 'magic', - 'memes', - 'design', - 'tactical', - 'fallout 4', - 'puzzle', - 'parody', - 'rv', - 'beats', - 'building', - 'disney', - 'drone', - 'ps2', - 'beach', - 'metal', - 'christianity', - 'business', - 'mix', - 'bo2', - 'cover', - 'senate', - '4k', - 'united states', - 'final', - 'hero', - 'playing', - 'dlc', - 'ubisoft', - 'halo', - 'pc gaming', - 'raw', - 'investing', - 'online learning', - 'software', - 'ark', - 'mojang', - 'console', - 'battle royale', - 'canon', - 'microsoft', - 'camping', - 'ufo', - 'progressive talk', - 'switch', - 'fpv', - 'arcade', - 'school', - 'driving', - 'bodybuilding', - 'drama', - 'retro', - 'science fiction', - 'eggs', - 'australia', - 'modded', - 'rainbow', - 'gamers', - 'resident evil', - 'drawing', - 'brasil', - 'england', - 'hillary clinton', - 'singing', - 'final fantasy', - 'hiphop', - 'video blog', - 'mature', - 'quad', - 'noob', - 'simulation', - 'illuminati', - 'poetry', - 'dayz', - 'manga', - 'howto', - 'insane', - 'press', - 'special', - 'church', - 'ico', - 'weird', - 'libertarian', - 'crafting', - 'level', - 'comic', - 'sandbox', - 'daily vlog', - 'outdoor', - 'black ops', - 'sound', - 'christ', - 'duty', - 'juvenile fiction', - 'pc game', - 'how-to', - 'ww2', - 'creepy', - 'artist', - 'galaxy', - 'destiny 2', - 'new music', - 'quest', - 'lee', - 'pacman', - 'super smash bros', - 'day', - 'survival horror', - 'patreon', - 'bitcoin price', - 'trending', - 'open world', - 'wii u', - 'dope', - 'reaper', - 'sniping', - 'dubstep', - 'truck', - 'planet', - 'dc', - 'amazon', - 'spirituality', - 'universe', - 'video game culture', - 'community', - 'cat', - 'aliens', - 'tourism', - 'altcoins', - 'style', - 'travel trailer', - 'rda', - 'gun', - 'secret', - 'far cry 5', - 'auto', - 'culture', - 'dj', - 'mw2', - 'lord', - 'full time rving', - 'role-playing game', - 'prank', - 'grand theft auto', - 'master', - 'wrestling', - 'sci-fi', - 'workout', - 'ghost', - 'fake news', - 'silly', - 'season', - 'bo4', - 'trading', - 'extreme', - 'economy', - 'combat', - 'plays', - 'muslim', - 'pubg mobile', - 'clips', - 'bo1', - 'paypal', - 'sims', - 'exploration', - 'light', - 'ripple', - 'paranormal', - 'football', - 'capcom', - 'rta', - 'discord', - 'batman', - 'player', - 'server', - 'anarchy', - 'military', - 'playlist', - 'cosplay', - 'rv park', - 'rant', - 'edit', - 'germany', - 'reading', - 'chris', - 'flash', - 'loot', - 'bitcoin gratis', - 'game reviews', - 'movies', - 'stupid', - 'latest news', - 'squad gameplay', - 'guru', - 'timelapse', - 'black ops 3', - 'holiday', - 'soul', - 'motivation', - 'mw3', - 'vacation', - 'sega', - '19th century', - 'pop', - 'sims 4', - 'post', - 'smok', - 'island', - 'scotland', - 'paladins', - 'warrior', - 'creepypasta', - 'role-playing', - 'solar', - 'vr', - 'animal', - 'peace', - 'consciousness', - 'dota', - 'audio', - 'mass effect', - 'humour', - 'first look', - 'videogames', - 'future bass', - 'freestyle', - 'hardcore', - 'portugal', - 'dantdm', - 'teaser', - 'lbry', - 'coronavirus', - '2020protests', - 'covidcuts', - 'covid-19', -]; - -const DEFAULT_SPANISH_KNOWN_TAGS = [ - 'español', - 'tecnología', - 'criptomonedas', - 'economía', - 'bitcoin', - 'educación', - 'videojuegos', - 'música', - 'noticias', - 'ciencia', - 'deportes', - 'latinoamérica', - 'latam', - 'conspiración', - 'humor', - 'política', - 'tutoriales', -]; - -export const DEFAULT_KNOWN_TAGS = [...DEFAULT_ENGLISH_KNOWN_TAGS, ...DEFAULT_SPANISH_KNOWN_TAGS]; diff --git a/src/constants/transaction_list.js b/src/constants/transaction_list.js deleted file mode 100644 index aabba4b..0000000 --- a/src/constants/transaction_list.js +++ /dev/null @@ -1,3 +0,0 @@ -// PAGE SIZE -export const PAGE_SIZE = 50; -export const LATEST_PAGE_SIZE = 20; diff --git a/src/constants/txo_list.js b/src/constants/txo_list.js deleted file mode 100644 index b702f34..0000000 --- a/src/constants/txo_list.js +++ /dev/null @@ -1,36 +0,0 @@ -export const ACTIVE = 'active'; // spent, active, all -export const TYPE = 'type'; // all, payment, support, channel, stream, repost -export const SUB_TYPE = 'subtype'; // other, purchase, tip -export const PAGE_SIZE = 'page_size'; -export const PAGE = 'page'; -export const ALL = 'all'; -// dropdown types -export const SENT = 'sent'; -export const RECEIVED = 'received'; -export const SUPPORT = 'support'; -export const CHANNEL = 'channel'; -export const PUBLISH = 'publish'; -export const REPOST = 'repost'; -export const DROPDOWN_TYPES = [ALL, SENT, RECEIVED, SUPPORT, CHANNEL, PUBLISH, REPOST]; -// dropdown subtypes -export const TIP = 'tip'; -export const PURCHASE = 'purchase'; -export const PAYMENT = 'payment'; -export const DROPDOWN_SUBTYPES = [ALL, TIP, PURCHASE, PAYMENT]; - -// rpc params -export const TX_TYPE = 'type'; // = other, stream, repost, channel, support, purchase -export const IS_SPENT = 'is_spent'; -export const IS_NOT_SPENT = 'is_not_spent'; -export const IS_MY_INPUT = 'is_my_input'; -export const IS_MY_OUTPUT = 'is_my_output'; -export const IS_NOT_MY_INPUT = 'is_not_my_input'; -export const IS_NOT_MY_OUTPUT = 'is_not_my_output'; // use to further distinguish payments to self / from self. -export const IS_MY_INPUT_OR_OUTPUT = 'is_my_input_or_output'; -export const EXCLUDE_INTERNAL_TRANSFERS = 'exclude_internal_transfers'; - -// sdk unique types -export const OTHER = 'other'; -export const STREAM = 'stream'; - -export const PAGE_SIZE_DEFAULT = 20; diff --git a/src/index.js b/src/index.js index e994dae..46467c4 100644 --- a/src/index.js +++ b/src/index.js @@ -1,49 +1,27 @@ -import * as CLAIM_VALUES from 'constants/claim'; import * as ACTIONS from 'constants/action_types'; -import * as LICENSES from 'constants/licenses'; -import * as PAGES from 'constants/pages'; -import * as SETTINGS from 'constants/settings'; -import * as SORT_OPTIONS from 'constants/sort_options'; import * as THUMBNAIL_STATUSES from 'constants/thumbnail_upload_statuses'; +import * as SETTINGS from 'constants/settings'; import * as TRANSACTIONS from 'constants/transaction_types'; -import * as TX_LIST from 'constants/transaction_list'; -import * as ABANDON_STATES from 'constants/abandon_states'; -import * as TXO_LIST from 'constants/txo_list'; -import * as SPEECH_URLS from 'constants/speech_urls'; -import * as DAEMON_SETTINGS from 'constants/daemon_settings'; -import * as SHARED_PREFERENCES from 'constants/shared_preferences'; +import * as SORT_OPTIONS from 'constants/sort_options'; +import * as PAGES from 'constants/pages'; import { SEARCH_TYPES, SEARCH_OPTIONS } from 'constants/search'; -import { DEFAULT_KNOWN_TAGS, DEFAULT_FOLLOWED_TAGS, MATURE_TAGS } from 'constants/tags'; -import Lbry, { apiCall } from 'lbry'; -import LbryFirst from 'lbry-first'; +import Lbry from 'lbry'; import { selectState as selectSearchState } from 'redux/selectors/search'; // constants export { ACTIONS, - CLAIM_VALUES, - LICENSES, THUMBNAIL_STATUSES, SEARCH_TYPES, SEARCH_OPTIONS, SETTINGS, - DAEMON_SETTINGS, TRANSACTIONS, - TX_LIST, - TXO_LIST, - ABANDON_STATES, SORT_OPTIONS, PAGES, - DEFAULT_KNOWN_TAGS, - DEFAULT_FOLLOWED_TAGS, - MATURE_TAGS, - SPEECH_URLS, - SHARED_PREFERENCES, }; // common -export { Lbry, apiCall }; -export { LbryFirst }; +export { Lbry }; export { regexInvalidURI, regexAddress, @@ -56,9 +34,6 @@ export { convertToShareLink, } from 'lbryURI'; -// middlware -export { buildSharedStateMiddleware } from 'redux/middleware/shared-state'; - // actions export { doToast, doDismissToast, doError, doDismissError } from 'redux/actions/notifications'; @@ -66,44 +41,21 @@ export { doFetchClaimsByChannel, doFetchClaimListMine, doAbandonClaim, - doAbandonTxo, doResolveUris, doResolveUri, doFetchChannelListMine, doCreateChannel, - doUpdateChannel, - doClaimSearch, - doImportChannel, - doRepost, - doClearRepostError, - doClearChannelErrors, - doCheckPublishNameAvailability, - doPurchaseList, - doCheckPendingClaims, } from 'redux/actions/claims'; -export { doClearPurchasedUriSuccess, doPurchaseUri, doFileGet } from 'redux/actions/file'; - export { doFetchFileInfo, doFileList, - doFetchFileInfos, + doFetchFileInfosAndPublishedClaims, doSetFileListSort, } from 'redux/actions/file_info'; -export { - doResetThumbnailStatus, - doClearPublish, - doUpdatePublishForm, - doUploadThumbnail, - doPrepareEdit, - doPublish, - doCheckReflectingFiles, -} from 'redux/actions/publish'; - export { doSearch, - doResolvedSearch, doUpdateSearchQuery, doFocusSearchInput, doBlurSearchInput, @@ -116,9 +68,10 @@ export { savePosition } from 'redux/actions/content'; export { doUpdateBalance, doBalanceSubscribe, + doUpdateTotalBalance, + doTotalBalanceSubscribe, doFetchTransactions, - doFetchTxoPage, - doUpdateTxoPageParams, + doFetchBlock, doGetNewAddress, doCheckAddressIsMine, doSendDraftTransaction, @@ -129,44 +82,22 @@ export { doWalletDecrypt, doWalletUnlock, doWalletStatus, - doWalletReconnect, doSetTransactionListFilter, doUpdateBlockHeight, - doClearSupport, - doSupportAbandonForClaim, } from 'redux/actions/wallet'; -export { doToggleTagFollow, doAddTag, doDeleteTag } from 'redux/actions/tags'; - -export { - doCommentList, - doCommentCreate, - doCommentAbandon, - doCommentHide, - doCommentUpdate, -} from 'redux/actions/comments'; - -export { doToggleBlockChannel } from 'redux/actions/blocked'; - -export { doPopulateSharedUserState, doPreferenceGet, doPreferenceSet } from 'redux/actions/sync'; - // utils -export { batchActions } from 'util/batch-actions'; -export { parseQueryParams, toQueryString } from 'util/query-params'; -export { formatCredits, formatFullPrice, creditsToString } from 'util/format-credits'; -export { isClaimNsfw, createNormalizedClaimSearchKey } from 'util/claim'; +export { batchActions } from 'util/batchActions'; +export { parseQueryParams, toQueryString } from 'util/query_params'; +export { formatCredits, formatFullPrice, creditsToString } from 'util/formatCredits'; // reducers export { claimsReducer } from 'redux/reducers/claims'; -export { commentReducer } from 'redux/reducers/comments'; -export { contentReducer } from 'redux/reducers/content'; export { fileInfoReducer } from 'redux/reducers/file_info'; export { notificationsReducer } from 'redux/reducers/notifications'; -export { publishReducer } from 'redux/reducers/publish'; export { searchReducer } from 'redux/reducers/search'; -export { tagsReducer } from 'redux/reducers/tags'; -export { blockedReducer } from 'redux/reducers/blocked'; export { walletReducer } from 'redux/reducers/wallet'; +export { contentReducer } from 'redux/reducers/content'; // selectors export { makeSelectContentPositionForUri } from 'redux/selectors/content'; @@ -178,38 +109,22 @@ export { makeSelectClaimIsMine, makeSelectFetchingChannelClaims, makeSelectClaimsInChannelForPage, - makeSelectTotalPagesInChannelSearch, - makeSelectTotalClaimsInChannelSearch, makeSelectMetadataForUri, - makeSelectMetadataItemForUri, - makeSelectThumbnailForUri, - makeSelectCoverForUri, makeSelectTitleForUri, - makeSelectDateForUri, - makeSelectAmountForUri, - makeSelectTagsForUri, makeSelectContentTypeForUri, makeSelectIsUriResolving, makeSelectTotalItemsForChannel, makeSelectTotalPagesForChannel, makeSelectNsfwCountFromUris, makeSelectNsfwCountForChannel, - makeSelectOmittedCountForChannel, makeSelectClaimIsNsfw, makeSelectRecommendedContentForUri, - makeSelectResolvedRecommendedContentForUri, makeSelectFirstRecommendedFileForUri, makeSelectChannelForClaimUri, makeSelectClaimIsPending, - makeSelectReflectingClaimForUri, + makeSelectPendingByUri, makeSelectClaimsInChannelForCurrentPageState, - makeSelectShortUrlForUri, - makeSelectCanonicalUrlForUri, - makeSelectPermanentUrlForUri, - makeSelectSupportsForUri, - makeSelectMyPurchasesForPage, - makeSelectClaimWasPurchased, - selectReflectingById, + selectPendingById, selectClaimsById, selectClaimsByUri, selectAllClaimsByChannel, @@ -218,10 +133,9 @@ export { selectMyActiveClaims, selectAllFetchingChannelClaims, selectIsFetchingClaimListMine, + selectPendingClaims, selectMyClaims, selectMyClaimsWithoutChannels, - selectMyChannelUrls, - selectMyClaimUrisWithoutChannels, selectAllMyClaimsByOutpoint, selectMyClaimsOutpoints, selectFetchingMyChannels, @@ -230,33 +144,9 @@ export { selectPlayingUri, selectChannelClaimCounts, selectCurrentChannelPage, - selectFetchingClaimSearch, - selectFetchingClaimSearchByQuery, - selectClaimSearchByQuery, - selectClaimSearchByQueryLastPageReached, - selectUpdatingChannel, - selectUpdateChannelError, - selectCreatingChannel, - selectCreateChannelError, - selectChannelImportPending, - makeSelectMyStreamUrlsForPage, - selectMyStreamUrlsCount, - selectRepostError, - selectRepostLoading, - selectClaimIdsByUri, - selectMyClaimsPage, - selectMyClaimsPageNumber, - selectMyClaimsPageItemCount, - selectFetchingMyClaimsPageError, - selectMyPurchases, - selectIsFetchingMyPurchases, - selectFetchingMyPurchasesError, - selectMyPurchasesCount, - selectPurchaseUriSuccess, + makeSelectThumbnailForUri, } from 'redux/selectors/claims'; -export { makeSelectCommentsForUri, selectIsFetchingComments } from 'redux/selectors/comments'; - export { makeSelectFileInfoForUri, makeSelectDownloadingForUri, @@ -269,39 +159,17 @@ export { selectFileInfosDownloaded, selectDownloadingFileInfos, selectTotalDownloadProgress, + selectSearchDownloadUris, selectFileListDownloadedSort, selectFileListPublishedSort, - selectDownloadedUris, - makeSelectMediaTypeForUri, - makeSelectUriIsStreamable, - makeSelectDownloadPathForUri, - makeSelectFileNameForUri, - makeSelectFilePartlyDownloaded, - makeSelectSearchDownloadUrlsForPage, - makeSelectSearchDownloadUrlsCount, - selectDownloadUrlsCount, - makeSelectStreamingUrlForUri, } from 'redux/selectors/file_info'; -export { - makeSelectPublishFormValue, - selectPublishFormValues, - selectIsStillEditing, - selectMyClaimForUri, - selectIsResolvingPublishUris, - selectTakeOverAmount, -} from 'redux/selectors/publish'; - export { selectSearchState }; export { makeSelectSearchUris, - makeSelectResolvedSearchResults, - makeSelectResolvedSearchResultsLastPageReached, selectSearchValue, selectSearchOptions, selectIsSearching, - selectResolvedSearchResultsByQuery, - selectResolvedSearchResultsByQueryLastPageReached, selectSearchUrisByQuery, selectSearchBarFocused, selectSearchSuggestions, @@ -309,15 +177,10 @@ export { } from 'redux/selectors/search'; export { + makeSelectBlockDate, selectBalance, selectTotalBalance, - selectReservedBalance, - selectClaimsBalance, - selectSupportsBalance, - selectTipsBalance, selectTransactionsById, - selectSupportsByOutpoint, - selectTotalSupports, selectTransactionItems, selectRecentTransactions, selectHasTransactions, @@ -342,31 +205,4 @@ export { selectWalletUnlockSucceeded, selectWalletUnlockResult, selectTransactionListFilter, - selectFilteredTransactions, - selectTxoPageParams, - selectTxoPage, - selectTxoPageNumber, - selectTxoItemCount, - selectIsFetchingTxos, - selectFetchingTxosError, - makeSelectLatestTransactions, - makeSelectFilteredTransactionsForPage, - selectFilteredTransactionCount, - selectIsWalletReconnecting, - selectPendingSupportTransactions, - selectAbandonClaimSupportError, - makeSelectPendingAmountByUri, } from 'redux/selectors/wallet'; - -export { - selectFollowedTags, - selectFollowedTagsList, - selectUnfollowedTags, - makeSelectIsFollowingTag, -} from 'redux/selectors/tags'; - -export { - selectBlockedChannels, - selectChannelIsBlocked, - selectBlockedChannelsCount, -} from 'redux/selectors/blocked'; diff --git a/src/lbry-first.js b/src/lbry-first.js deleted file mode 100644 index 4dcb39e..0000000 --- a/src/lbry-first.js +++ /dev/null @@ -1,183 +0,0 @@ -// @flow -import 'proxy-polyfill'; - -const CHECK_LBRYFIRST_STARTED_TRY_NUMBER = 200; -// -// Basic LBRYFIRST connection config -// Offers a proxy to call LBRYFIRST methods - -// -const LbryFirst: LbryFirstTypes = { - isConnected: false, - connectPromise: null, - lbryFirstConnectionString: 'http://localhost:1337/rpc', - apiRequestHeaders: { 'Content-Type': 'application/json' }, - - // Allow overriding lbryFirst connection string (e.g. to `/api/proxy` for lbryweb) - setLbryFirstConnectionString: (value: string) => { - LbryFirst.lbryFirstConnectionString = value; - }, - - setApiHeader: (key: string, value: string) => { - LbryFirst.apiRequestHeaders = Object.assign(LbryFirst.apiRequestHeaders, { [key]: value }); - }, - - unsetApiHeader: key => { - Object.keys(LbryFirst.apiRequestHeaders).includes(key) && - delete LbryFirst.apiRequestHeaders['key']; - }, - // Allow overriding Lbry methods - overrides: {}, - setOverride: (methodName, newMethod) => { - LbryFirst.overrides[methodName] = newMethod; - }, - getApiRequestHeaders: () => LbryFirst.apiRequestHeaders, - - // - // LbryFirst Methods - // - status: (params = {}) => lbryFirstCallWithResult('status', params), - stop: () => lbryFirstCallWithResult('stop', {}), - version: () => lbryFirstCallWithResult('version', {}), - - // Upload to youtube - upload: (params: { title: string, description: string, file_path: ?string } = {}) => { - // Only upload when originally publishing for now - if (!params.file_path) { - return Promise.resolve(); - } - - const uploadParams: { - Title: string, - Description: string, - FilePath: string, - Category: string, - Keywords: string, - } = { - Title: params.title, - Description: params.description, - FilePath: params.file_path, - Category: '', - Keywords: '', - }; - - return lbryFirstCallWithResult('youtube.Upload', uploadParams); - }, - - hasYTAuth: (token: string) => { - const hasYTAuthParams = {}; - hasYTAuthParams.AuthToken = token; - return lbryFirstCallWithResult('youtube.HasAuth', hasYTAuthParams); - }, - - ytSignup: () => { - const emptyParams = {}; - return lbryFirstCallWithResult('youtube.Signup', emptyParams); - }, - - remove: () => { - const emptyParams = {}; - return lbryFirstCallWithResult('youtube.Remove', emptyParams); - }, - - // Connect to lbry-first - connect: () => { - if (LbryFirst.connectPromise === null) { - LbryFirst.connectPromise = new Promise((resolve, reject) => { - let tryNum = 0; - // Check every half second to see if the lbryFirst is accepting connections - function checkLbryFirstStarted() { - tryNum += 1; - LbryFirst.status() - .then(resolve) - .catch(() => { - if (tryNum <= CHECK_LBRYFIRST_STARTED_TRY_NUMBER) { - setTimeout(checkLbryFirstStarted, tryNum < 50 ? 400 : 1000); - } else { - reject(new Error('Unable to connect to LBRY')); - } - }); - } - - checkLbryFirstStarted(); - }); - } - - // Flow thinks this could be empty, but it will always return a promise - // $FlowFixMe - return LbryFirst.connectPromise; - }, -}; - -function checkAndParse(response) { - if (response.status >= 200 && response.status < 300) { - return response.json(); - } - return response.json().then(json => { - let error; - if (json.error) { - const errorMessage = typeof json.error === 'object' ? json.error.message : json.error; - error = new Error(errorMessage); - } else { - error = new Error('Protocol error with unknown response signature'); - } - return Promise.reject(error); - }); -} - -export function apiCall(method: string, params: ?{}, resolve: Function, reject: Function) { - const counter = new Date().getTime(); - const paramsArray = [params]; - const options = { - method: 'POST', - headers: LbryFirst.apiRequestHeaders, - body: JSON.stringify({ - jsonrpc: '2.0', - method, - params: paramsArray, - id: counter, - }), - }; - - return fetch(LbryFirst.lbryFirstConnectionString, options) - .then(checkAndParse) - .then(response => { - const error = response.error || (response.result && response.result.error); - - if (error) { - return reject(error); - } - return resolve(response.result); - }) - .catch(reject); -} - -function lbryFirstCallWithResult(name: string, params: ?{} = {}) { - return new Promise((resolve, reject) => { - apiCall( - name, - params, - result => { - resolve(result); - }, - reject - ); - }); -} - -// This is only for a fallback -// If there is a LbryFirst method that is being called by an app, it should be added to /flow-typed/LbryFirst.js -const lbryFirstProxy = new Proxy(LbryFirst, { - get(target: LbryFirstTypes, name: string) { - if (name in target) { - return target[name]; - } - - return (params = {}) => - new Promise((resolve, reject) => { - apiCall(name, params, resolve, reject); - }); - }, -}); - -export default lbryFirstProxy; diff --git a/src/lbry.js b/src/lbry.js index 51f4111..093f4fb 100644 --- a/src/lbry.js +++ b/src/lbry.js @@ -11,44 +11,27 @@ const Lbry: LbryTypes = { isConnected: false, connectPromise: null, daemonConnectionString: 'http://localhost:5279', - alternateConnectionString: '', - methodsUsingAlternateConnectionString: [], - apiRequestHeaders: { 'Content-Type': 'application/json-rpc' }, // Allow overriding daemon connection string (e.g. to `/api/proxy` for lbryweb) setDaemonConnectionString: (value: string) => { Lbry.daemonConnectionString = value; }, - setApiHeader: (key: string, value: string) => { - Lbry.apiRequestHeaders = Object.assign(Lbry.apiRequestHeaders, { [key]: value }); - }, - - unsetApiHeader: key => { - Object.keys(Lbry.apiRequestHeaders).includes(key) && delete Lbry.apiRequestHeaders['key']; - }, // Allow overriding Lbry methods overrides: {}, setOverride: (methodName, newMethod) => { Lbry.overrides[methodName] = newMethod; }, - getApiRequestHeaders: () => Lbry.apiRequestHeaders, // Returns a human readable media type based on the content type or extension of a file that is returned by the sdk - getMediaType: (contentType?: string, fileName: ?string) => { - if (fileName) { + getMediaType: (contentType: string, extname: ?string) => { + if (extname) { const formats = [ - [/\.(mp4|m4v|webm|flv|f4v|ogv)$/i, 'video'], - [/\.(mp3|m4a|aac|wav|flac|ogg|opus)$/i, 'audio'], - [/\.(jpeg|jpg|png|gif|svg|webp)$/i, 'image'], - [/\.(h|go|ja|java|js|jsx|c|cpp|cs|css|rb|scss|sh|php|py)$/i, 'script'], - [/\.(html|json|csv|txt|log|md|markdown|docx|pdf|xml|yml|yaml)$/i, 'document'], - [/\.(pdf|odf|doc|docx|epub|org|rtf)$/i, 'e-book'], - [/\.(stl|obj|fbx|gcode)$/i, '3D-file'], - [/\.(cbr|cbt|cbz)$/i, 'comic-book'], - [/\.(lbry)$/i, 'application'], + [/^(mp4|m4v|webm|flv|f4v|ogv)$/i, 'video'], + [/^(mp3|m4a|aac|wav|flac|ogg|opus)$/i, 'audio'], + [/^(html|htm|xml|pdf|odf|doc|docx|md|markdown|txt|epub|org)$/i, 'document'], + [/^(stl|obj|fbx|gcode)$/i, '3D-file'], ]; - const res = formats.reduce((ret, testpair) => { switch (testpair[0].test(ret)) { case true: @@ -56,13 +39,12 @@ const Lbry: LbryTypes = { default: return ret; } - }, fileName); - return res === fileName ? 'unknown' : res; + }, extname); + return res === extname ? 'unknown' : res; } else if (contentType) { // $FlowFixMe return /^[^/]+/.exec(contentType)[0]; } - return 'unknown'; }, @@ -77,18 +59,14 @@ const Lbry: LbryTypes = { // Claim fetching and manipulation resolve: params => daemonCallWithResult('resolve', params), get: params => daemonCallWithResult('get', params), + publish: params => daemonCallWithResult('publish', params), claim_search: params => daemonCallWithResult('claim_search', params), claim_list: params => daemonCallWithResult('claim_list', params), channel_create: params => daemonCallWithResult('channel_create', params), - channel_update: params => daemonCallWithResult('channel_update', params), - channel_import: params => daemonCallWithResult('channel_import', params), channel_list: params => daemonCallWithResult('channel_list', params), stream_abandon: params => daemonCallWithResult('stream_abandon', params), - stream_list: params => daemonCallWithResult('stream_list', params), channel_abandon: params => daemonCallWithResult('channel_abandon', params), support_create: params => daemonCallWithResult('support_create', params), - support_list: params => daemonCallWithResult('support_list', params), - stream_repost: params => daemonCallWithResult('stream_repost', params), // File fetching and manipulation file_list: (params = {}) => daemonCallWithResult('file_list', params), @@ -98,34 +76,22 @@ const Lbry: LbryTypes = { blob_list: (params = {}) => daemonCallWithResult('blob_list', params), // Wallet utilities - wallet_balance: (params = {}) => daemonCallWithResult('wallet_balance', params), - wallet_decrypt: () => daemonCallWithResult('wallet_decrypt', {}), - wallet_encrypt: (params = {}) => daemonCallWithResult('wallet_encrypt', params), - wallet_unlock: (params = {}) => daemonCallWithResult('wallet_unlock', params), - wallet_list: (params = {}) => daemonCallWithResult('wallet_list', params), - wallet_send: (params = {}) => daemonCallWithResult('wallet_send', params), - wallet_status: (params = {}) => daemonCallWithResult('wallet_status', params), + account_balance: (params = {}) => daemonCallWithResult('account_balance', params), + account_decrypt: () => daemonCallWithResult('account_decrypt', {}), + account_encrypt: (params = {}) => daemonCallWithResult('account_encrypt', params), + account_unlock: (params = {}) => daemonCallWithResult('account_unlock', params), + account_list: (params = {}) => daemonCallWithResult('account_list', params), + account_send: (params = {}) => daemonCallWithResult('account_send', params), address_is_mine: (params = {}) => daemonCallWithResult('address_is_mine', params), address_unused: (params = {}) => daemonCallWithResult('address_unused', params), - address_list: (params = {}) => daemonCallWithResult('address_list', params), transaction_list: (params = {}) => daemonCallWithResult('transaction_list', params), utxo_release: (params = {}) => daemonCallWithResult('utxo_release', params), - support_abandon: (params = {}) => daemonCallWithResult('support_abandon', params), - purchase_list: (params = {}) => daemonCallWithResult('purchase_list', params), sync_hash: (params = {}) => daemonCallWithResult('sync_hash', params), sync_apply: (params = {}) => daemonCallWithResult('sync_apply', params), - // Preferences - preference_get: (params = {}) => daemonCallWithResult('preference_get', params), - preference_set: (params = {}) => daemonCallWithResult('preference_set', params), - - // Comments comment_list: (params = {}) => daemonCallWithResult('comment_list', params), comment_create: (params = {}) => daemonCallWithResult('comment_create', params), - comment_hide: (params = {}) => daemonCallWithResult('comment_hide', params), - comment_abandon: (params = {}) => daemonCallWithResult('comment_abandon', params), - comment_update: (params = {}) => daemonCallWithResult('comment_update', params), // Connect to the sdk connect: () => { @@ -154,15 +120,6 @@ const Lbry: LbryTypes = { // $FlowFixMe return Lbry.connectPromise; }, - - publish: (params = {}) => - new Promise((resolve, reject) => { - if (Lbry.overrides.publish) { - Lbry.overrides.publish(params).then(resolve, reject); - } else { - apiCall('publish', params, resolve, reject); - } - }), }; function checkAndParse(response) { @@ -181,11 +138,10 @@ function checkAndParse(response) { }); } -export function apiCall(method: string, params: ?{}, resolve: Function, reject: Function) { +function apiCall(method: string, params: ?{}, resolve: Function, reject: Function) { const counter = new Date().getTime(); const options = { method: 'POST', - headers: Lbry.apiRequestHeaders, body: JSON.stringify({ jsonrpc: '2.0', method, @@ -194,10 +150,7 @@ export function apiCall(method: string, params: ?{}, resolve: Function, reject: }), }; - const connectionString = Lbry.methodsUsingAlternateConnectionString.includes(method) - ? Lbry.alternateConnectionString - : Lbry.daemonConnectionString; - return fetch(connectionString + '?m=' + method, options) + return fetch(Lbry.daemonConnectionString, options) .then(checkAndParse) .then(response => { const error = response.error || (response.result && response.result.error); diff --git a/src/lbryURI.js b/src/lbryURI.js index 9b871d7..260df9a 100644 --- a/src/lbryURI.js +++ b/src/lbryURI.js @@ -1,160 +1,102 @@ -// @flow -const isProduction = process.env.NODE_ENV === 'production'; const channelNameMinLength = 1; const claimIdMaxLength = 40; -// see https://spec.lbry.com/#urls -export const regexInvalidURI = /[ =&#:$@%?;/\\"<>%\{\}|^~[\]`\u{0000}-\u{0008}\u{000b}-\u{000c}\u{000e}-\u{001F}\u{D800}-\u{DFFF}\u{FFFE}-\u{FFFF}]/u; +export const regexInvalidURI = /[^A-Za-z0-9-]/g; export const regexAddress = /^(b|r)(?=[^0OIl]{32,33})[0-9A-Za-z]{32,33}$/; -const regexPartProtocol = '^((?:lbry://)?)'; -const regexPartStreamOrChannelName = '([^:$#/]*)'; -const regexPartModifierSeparator = '([:$#]?)([^/]*)'; -const queryStringBreaker = '^([\\S]+)([?][\\S]*)'; -const separateQuerystring = new RegExp(queryStringBreaker); /** * Parses a LBRY name into its component parts. Throws errors with user-friendly * messages for invalid names. * + * N.B. that "name" indicates the value in the name position of the URI. For + * claims for channel content, this will actually be the channel name, and + * the content name is in the path (e.g. lbry://@channel/content) + * + * In most situations, you'll want to use the contentName and channelName keys + * and ignore the name key. + * * Returns a dictionary with keys: - * - path (string) + * - name (string): The value in the "name" position in the URI. Note that this + * could be either content name or channel name; see above. + * - path (string, if persent) + * - claimSequence (int, if present) + * - bidPosition (int, if present) + * - claimId (string, if present) * - isChannel (boolean) - * - streamName (string, if present) - * - streamClaimId (string, if present) - * - channelName (string, if present) - * - channelClaimId (string, if present) - * - primaryClaimSequence (int, if present) - * - secondaryClaimSequence (int, if present) - * - primaryBidPosition (int, if present) - * - secondaryBidPosition (int, if present) + * - contentName (string): For anon claims, the name; for channel claims, the path + * - channelName (string, if present): Channel name without @ */ - -export function parseURI(URL: string, requireProto: boolean = false): LbryUrlObj { +export function parseURI(URI, requireProto = false) { // Break into components. Empty sub-matches are converted to null - const componentsRegex = new RegExp( - regexPartProtocol + // protocol - regexPartStreamOrChannelName + // stream or channel name (stops at the first separator or end) - regexPartModifierSeparator + // modifier separator, modifier (stops at the first path separator or end) - '(/?)' + // path separator, there should only be one (optional) slash to separate the stream and channel parts - regexPartStreamOrChannelName + - regexPartModifierSeparator + '^((?:lbry://)?)' + // protocol + '([^:$#/]*)' + // claim name (stops at the first separator or end) + '([:$#]?)([^/]*)' + // modifier separator, modifier (stops at the first path separator or end) + '(/?)(.*)' // path separator, path ); - // chop off the querystring first - let QSStrippedURL, qs; - const qsRegexResult = separateQuerystring.exec(URL); - if (qsRegexResult) { - [QSStrippedURL, qs] = qsRegexResult.slice(1).map(match => match || null); - } + const [proto, claimName, modSep, modVal, pathSep, path] = componentsRegex + .exec(URI) + .slice(1) + .map(match => match || null); - const cleanURL = QSStrippedURL || URL; - const regexMatch = componentsRegex.exec(cleanURL) || []; - const [proto, ...rest] = regexMatch.slice(1).map(match => match || null); - const path = rest.join(''); - const [ - streamNameOrChannelName, - primaryModSeparator, - primaryModValue, - pathSep, - possibleStreamName, - secondaryModSeparator, - secondaryModValue, - ] = rest; - const searchParams = new URLSearchParams(qs || ''); - const startTime = searchParams.get('t'); + let contentName; // Validate protocol if (requireProto && !proto) { - throw new Error(__('LBRY URLs must include a protocol prefix (lbry://).')); + throw new Error(__('LBRY URIs must include a protocol prefix (lbry://).')); } // Validate and process name - if (!streamNameOrChannelName) { - throw new Error(__('URL does not include name.')); + if (!claimName) { + throw new Error(__('URI does not include name.')); } - rest.forEach(urlPiece => { - if (urlPiece && urlPiece.includes(' ')) { - console.error('URL can not include a space'); - } - }); + const isChannel = claimName.startsWith('@'); + const channelName = isChannel ? claimName.slice(1) : claimName; - const includesChannel = streamNameOrChannelName.startsWith('@'); - const isChannel = streamNameOrChannelName.startsWith('@') && !possibleStreamName; - const channelName = includesChannel && streamNameOrChannelName.slice(1); - - if (includesChannel) { + if (isChannel) { if (!channelName) { throw new Error(__('No channel name after @.')); } if (channelName.length < channelNameMinLength) { - throw new Error( - __(`Channel names must be at least %channelNameMinLength% characters.`, { - channelNameMinLength, - }) - ); + throw new Error(__(`Channel names must be at least %s characters.`, channelNameMinLength)); } + + contentName = path; } - // Validate and process modifier - const [primaryClaimId, primaryClaimSequence, primaryBidPosition] = parseURIModifier( - primaryModSeparator, - primaryModValue - ); - const [secondaryClaimId, secondaryClaimSequence, secondaryBidPosition] = parseURIModifier( - secondaryModSeparator, - secondaryModValue - ); - const streamName = includesChannel ? possibleStreamName : streamNameOrChannelName; - const streamClaimId = includesChannel ? secondaryClaimId : primaryClaimId; - const channelClaimId = includesChannel && primaryClaimId; + const nameBadChars = (channelName || claimName).match(regexInvalidURI); + if (nameBadChars) { + throw new Error( + __( + `Invalid character %s in name: %s.`, + nameBadChars.length === 1 ? '' : 's', + nameBadChars.join(', ') + ) + ); + } - return { - isChannel, - path, - ...(streamName ? { streamName } : {}), - ...(streamClaimId ? { streamClaimId } : {}), - ...(channelName ? { channelName } : {}), - ...(channelClaimId ? { channelClaimId } : {}), - ...(primaryClaimSequence ? { primaryClaimSequence: parseInt(primaryClaimSequence, 10) } : {}), - ...(secondaryClaimSequence - ? { secondaryClaimSequence: parseInt(secondaryClaimSequence, 10) } - : {}), - ...(primaryBidPosition ? { primaryBidPosition: parseInt(primaryBidPosition, 10) } : {}), - ...(secondaryBidPosition ? { secondaryBidPosition: parseInt(secondaryBidPosition, 10) } : {}), - ...(startTime ? { startTime: parseInt(startTime, 10) } : {}), - - // The values below should not be used for new uses of parseURI - // They will not work properly with canonical_urls - claimName: streamNameOrChannelName, - claimId: primaryClaimId, - ...(streamName ? { contentName: streamName } : {}), - ...(qs ? { queryString: qs } : {}), - }; -} - -function parseURIModifier(modSeperator: ?string, modValue: ?string) { + // Validate and process modifier (claim ID, bid position or claim sequence) let claimId; let claimSequence; let bidPosition; - - if (modSeperator) { - if (!modValue) { - throw new Error(__(`No modifier provided after separator %modSeperator%.`, { modSeperator })); + if (modSep) { + if (!modVal) { + throw new Error(__(`No modifier provided after separator %s.`, modSep)); } - if (modSeperator === '#') { - claimId = modValue; - } else if (modSeperator === ':') { - claimSequence = modValue; - } else if (modSeperator === '$') { - bidPosition = modValue; + if (modSep === '#') { + claimId = modVal; + } else if (modSep === ':') { + claimSequence = modVal; + } else if (modSep === '$') { + bidPosition = modVal; } } if (claimId && (claimId.length > claimIdMaxLength || !claimId.match(/^[0-9a-f]+$/))) { - throw new Error(__(`Invalid claim ID %claimId%.`, { claimId })); + throw new Error(__(`Invalid claim ID %s.`, claimId)); } if (claimSequence && !claimSequence.match(/^-?[1-9][0-9]*$/)) { @@ -165,7 +107,33 @@ function parseURIModifier(modSeperator: ?string, modValue: ?string) { throw new Error(__('Bid position must be a number.')); } - return [claimId, claimSequence, bidPosition]; + // Validate and process path + if (path) { + if (!isChannel) { + throw new Error(__('Only channel URIs may have a path.')); + } + + const pathBadChars = path.match(regexInvalidURI); + if (pathBadChars) { + throw new Error(__(`Invalid character in path: %s`, pathBadChars.join(', '))); + } + + contentName = path; + } else if (pathSep) { + throw new Error(__('No path provided after /')); + } + + return { + claimName, + path, + isChannel, + ...(contentName ? { contentName } : {}), + ...(channelName ? { channelName } : {}), + ...(claimSequence ? { claimSequence: parseInt(claimSequence, 10) } : {}), + ...(bidPosition ? { bidPosition: parseInt(bidPosition, 10) } : {}), + ...(claimId ? { claimId } : {}), + ...(path ? { path } : {}), + }; } /** @@ -173,150 +141,93 @@ function parseURIModifier(modSeperator: ?string, modValue: ?string) { * * The channelName key will accept names with or without the @ prefix. */ -export function buildURI( - UrlObj: LbryUrlObj, - includeProto: boolean = true, - protoDefault: string = 'lbry://' -): string { - const { - streamName, - streamClaimId, - channelName, - channelClaimId, - primaryClaimSequence, - primaryBidPosition, - secondaryClaimSequence, - secondaryBidPosition, - startTime, - ...deprecatedParts - } = UrlObj; - const { claimId, claimName, contentName } = deprecatedParts; +export function buildURI(URIObj, includeProto = true, protoDefault = 'lbry://') { + const { claimId, claimSequence, bidPosition, contentName, channelName } = URIObj; - if (!isProduction) { - if (claimId) { - console.error( - __("'claimId' should no longer be used. Use 'streamClaimId' or 'channelClaimId' instead") - ); - } - if (claimName) { - console.error( + let { claimName, path } = URIObj; + + if (channelName) { + const channelNameFormatted = channelName.startsWith('@') ? channelName : `@${channelName}`; + if (!claimName) { + claimName = channelNameFormatted; + } else if (claimName !== channelNameFormatted) { + throw new Error( __( - "'claimName' should no longer be used. Use 'streamClaimName' or 'channelClaimName' instead" + 'Received a channel content URI, but claim name and channelName do not match. "name" represents the value in the name position of the URI (lbry://name...), which for channel content will be the channel name. In most cases, to construct a channel URI you should just pass channelName and contentName.' ) ); } - if (contentName) { - console.error(__("'contentName' should no longer be used. Use 'streamName' instead")); + } + + if (contentName) { + if (!claimName) { + claimName = contentName; + } else if (!path) { + path = contentName; + } + if (path && path !== contentName) { + throw new Error( + __( + 'Path and contentName do not match. Only one is required; most likely you wanted contentName.' + ) + ); } } - if (!claimName && !channelName && !streamName) { - console.error( - __( - "'claimName', 'channelName', and 'streamName' are all empty. One must be present to build a url." - ) - ); - } - - const formattedChannelName = - channelName && (channelName.startsWith('@') ? channelName : `@${channelName}`); - const primaryClaimName = claimName || contentName || formattedChannelName || streamName; - const primaryClaimId = claimId || (formattedChannelName ? channelClaimId : streamClaimId); - const secondaryClaimName = - (!claimName && contentName) || (formattedChannelName ? streamName : null); - const secondaryClaimId = secondaryClaimName && streamClaimId; - return ( (includeProto ? protoDefault : '') + - // primaryClaimName will always exist here because we throw above if there is no "name" value passed in - // $FlowFixMe - primaryClaimName + - (primaryClaimId ? `#${primaryClaimId}` : '') + - (primaryClaimSequence ? `:${primaryClaimSequence}` : '') + - (primaryBidPosition ? `${primaryBidPosition}` : '') + - (secondaryClaimName ? `/${secondaryClaimName}` : '') + - (secondaryClaimId ? `#${secondaryClaimId}` : '') + - (secondaryClaimSequence ? `:${secondaryClaimSequence}` : '') + - (secondaryBidPosition ? `${secondaryBidPosition}` : '') + - (startTime ? `?t=${startTime}` : '') + claimName + + (claimId ? `#${claimId}` : '') + + (claimSequence ? `:${claimSequence}` : '') + + (bidPosition ? `${bidPosition}` : '') + + (path ? `/${path}` : '') ); } -/* Takes a parseable LBRY URL and converts it to standard, canonical format */ -export function normalizeURI(URL: string) { - const { - streamName, - streamClaimId, - channelName, - channelClaimId, - primaryClaimSequence, - primaryBidPosition, - secondaryClaimSequence, - secondaryBidPosition, - startTime, - } = parseURI(URL); - - return buildURI({ - streamName, - streamClaimId, - channelName, - channelClaimId, - primaryClaimSequence, - primaryBidPosition, - secondaryClaimSequence, - secondaryBidPosition, - startTime, - }); +/* Takes a parseable LBRY URI and converts it to standard, canonical format */ +export function normalizeURI(URI) { + const { claimName, path, bidPosition, claimSequence, claimId } = parseURI(URI); + return buildURI({ claimName, path, claimSequence, bidPosition, claimId }); } -export function isURIValid(URL: string): boolean { - try { - parseURI(normalizeURI(URL)); - } catch (error) { - return false; - } - - return true; -} - -export function isNameValid(claimName: string) { - return !regexInvalidURI.test(claimName); -} - -export function isURIClaimable(URL: string) { +export function isURIValid(URI) { let parts; try { - parts = parseURI(normalizeURI(URL)); + parts = parseURI(normalizeURI(URI)); } catch (error) { return false; } - - return parts && parts.streamName && !parts.streamClaimId && !parts.isChannel; + return parts && parts.claimName; } -export function convertToShareLink(URL: string) { - const { - streamName, - streamClaimId, - channelName, - channelClaimId, - primaryBidPosition, - primaryClaimSequence, - secondaryBidPosition, - secondaryClaimSequence, - } = parseURI(URL); - return buildURI( - { - streamName, - streamClaimId, - channelName, - channelClaimId, - primaryBidPosition, - primaryClaimSequence, - secondaryBidPosition, - secondaryClaimSequence, - }, - true, - 'https://open.lbry.com/' +export function isNameValid(claimName, checkCase = true) { + const regexp = new RegExp('^[a-z0-9-]+$', checkCase ? '' : 'i'); + return regexp.test(claimName); +} + +export function isURIClaimable(URI) { + let parts; + try { + parts = parseURI(normalizeURI(URI)); + } catch (error) { + return false; + } + return ( + parts && + parts.claimName && + !parts.claimId && + !parts.bidPosition && + !parts.claimSequence && + !parts.isChannel && + !parts.path + ); +} + +export function convertToShareLink(URI) { + const { claimName, path, bidPosition, claimSequence, claimId } = parseURI(URI); + return buildURI( + { claimName, path, claimSequence, bidPosition, claimId }, + true, + 'https://open.lbry.io/' ); } diff --git a/src/redux/actions/blocked.js b/src/redux/actions/blocked.js deleted file mode 100644 index 1e96563..0000000 --- a/src/redux/actions/blocked.js +++ /dev/null @@ -1,9 +0,0 @@ -// @flow -import * as ACTIONS from 'constants/action_types'; - -export const doToggleBlockChannel = (uri: string) => ({ - type: ACTIONS.TOGGLE_BLOCK_CHANNEL, - data: { - uri, - }, -}); diff --git a/src/redux/actions/claims.js b/src/redux/actions/claims.js index d74cb32..5541dc0 100644 --- a/src/redux/actions/claims.js +++ b/src/redux/actions/claims.js @@ -1,22 +1,11 @@ // @flow import * as ACTIONS from 'constants/action_types'; -import * as ABANDON_STATES from 'constants/abandon_states'; import Lbry from 'lbry'; import { normalizeURI } from 'lbryURI'; import { doToast } from 'redux/actions/notifications'; -import { - selectMyClaimsRaw, - selectResolvingUris, - selectClaimsByUri, - selectMyChannelClaims, - selectPendingIds, -} from 'redux/selectors/claims'; -import { doFetchTxoPage } from 'redux/actions/wallet'; -import { selectSupportsByOutpoint } from 'redux/selectors/wallet'; -import { creditsToString } from 'util/format-credits'; -import { batchActions } from 'util/batch-actions'; -import { createNormalizedClaimSearchKey } from 'util/claim'; -import { PAGE_SIZE } from 'constants/claim'; +import { selectMyClaimsRaw, selectResolvingUris, selectClaimsByUri } from 'redux/selectors/claims'; +import { doFetchTransactions } from 'redux/actions/wallet'; +import { creditsToString } from 'util/formatCredits'; export function doResolveUris(uris: Array, returnCachedClaims: boolean = false) { return (dispatch: Dispatch, getState: GetState) => { @@ -37,13 +26,6 @@ export function doResolveUris(uris: Array, returnCachedClaims: boolean = return; } - const options: { include_is_my_output?: boolean, include_purchase_receipt: boolean } = { - include_purchase_receipt: true, - }; - - if (urisToResolve.length === 1) { - options.include_is_my_output = true; - } dispatch({ type: ACTIONS.RESOLVE_URIS_STARTED, data: { uris: normalizedUris }, @@ -51,44 +33,29 @@ export function doResolveUris(uris: Array, returnCachedClaims: boolean = const resolveInfo: { [string]: { - stream: ?StreamClaim, - channel: ?ChannelClaim, + claim: ?StreamClaim, + certificate: ?ChannelClaim, claimsInChannel: ?number, }, } = {}; - return Lbry.resolve({ urls: urisToResolve, ...options }).then((result: ResolveResponse) => { + Lbry.resolve({ urls: urisToResolve }).then((result: ResolveResponse) => { Object.entries(result).forEach(([uri, uriResolveInfo]) => { const fallbackResolveInfo = { - stream: null, + claim: null, claimsInChannel: null, - channel: null, + certificate: null, }; // Flow has terrible Object.entries support // https://github.com/facebook/flow/issues/2221 - if (uriResolveInfo) { - if (uriResolveInfo.error) { - resolveInfo[uri] = { ...fallbackResolveInfo }; - } else { - let result = {}; - if (uriResolveInfo.value_type === 'channel') { - result.channel = uriResolveInfo; - // $FlowFixMe - result.claimsInChannel = uriResolveInfo.meta.claims_in_channel; - } else { - result.stream = uriResolveInfo; - if (uriResolveInfo.signing_channel) { - result.channel = uriResolveInfo.signing_channel; - result.claimsInChannel = - (uriResolveInfo.signing_channel.meta && - uriResolveInfo.signing_channel.meta.claims_in_channel) || - 0; - } - } - // $FlowFixMe - resolveInfo[uri] = result; - } + // $FlowFixMe + if (uriResolveInfo.error) { + resolveInfo[uri] = { ...fallbackResolveInfo }; + } else { + // $FlowFixMe + const { claim, certificate, claims_in_channel: claimsInChannel } = uriResolveInfo; + resolveInfo[uri] = { claim, certificate, claimsInChannel }; } }); @@ -96,7 +63,6 @@ export function doResolveUris(uris: Array, returnCachedClaims: boolean = type: ACTIONS.RESOLVE_URIS_COMPLETED, data: { resolveInfo }, }); - return result; }); }; } @@ -105,185 +71,70 @@ export function doResolveUri(uri: string) { return doResolveUris([uri]); } -export function doFetchClaimListMine( - page: number = 1, - pageSize: number = 99999, - resolve: boolean = true -) { +export function doFetchClaimListMine() { return (dispatch: Dispatch) => { dispatch({ type: ACTIONS.FETCH_CLAIM_LIST_MINE_STARTED, }); - // $FlowFixMe - Lbry.claim_list({ - page: page, - page_size: pageSize, - claim_type: ['stream', 'repost'], - resolve, - }).then((result: StreamListResponse) => { + Lbry.claim_list().then((claims: ClaimListResponse) => { dispatch({ type: ACTIONS.FETCH_CLAIM_LIST_MINE_COMPLETED, data: { - result, - resolve, + claims, }, }); }); }; } -export function doAbandonTxo(txo: Txo, cb: string => void) { - return (dispatch: Dispatch) => { - if (cb) cb(ABANDON_STATES.PENDING); - const isClaim = txo.type === 'claim'; - const isSupport = txo.type === 'support' && txo.is_my_input === true; - const isTip = txo.type === 'support' && txo.is_my_input === false; - - const data = isClaim ? { claimId: txo.claim_id } : { outpoint: `${txo.txid}:${txo.nout}` }; - - const startedActionType = isClaim - ? ACTIONS.ABANDON_CLAIM_STARTED - : ACTIONS.ABANDON_SUPPORT_STARTED; - const completedActionType = isClaim - ? ACTIONS.ABANDON_CLAIM_SUCCEEDED - : ACTIONS.ABANDON_SUPPORT_COMPLETED; - - dispatch({ - type: startedActionType, - data, - }); - - const errorCallback = () => { - if (cb) cb(ABANDON_STATES.ERROR); - dispatch( - doToast({ - message: isClaim ? 'Error abandoning your claim/support' : 'Error unlocking your tip', - isError: true, - }) - ); - }; - - const successCallback = () => { - dispatch({ - type: completedActionType, - data, - }); - - let abandonMessage; - if (isClaim) { - abandonMessage = __('Successfully abandoned your claim.'); - } else if (isSupport) { - abandonMessage = __('Successfully abandoned your support.'); - } else { - abandonMessage = __('Successfully unlocked your tip!'); - } - if (cb) cb(ABANDON_STATES.DONE); - - dispatch( - doToast({ - message: abandonMessage, - }) - ); - }; - - const abandonParams: { - claim_id?: string, - txid?: string, - nout?: number, - } = { - blocking: true, - }; - if (isClaim) { - abandonParams['claim_id'] = txo.claim_id; - } else { - abandonParams['txid'] = txo.txid; - abandonParams['nout'] = txo.nout; - } - - let method; - if (isSupport || isTip) { - method = 'support_abandon'; - } else if (isClaim) { - const { normalized_name: claimName } = txo; - method = claimName.startsWith('@') ? 'channel_abandon' : 'stream_abandon'; - } - - if (!method) { - console.error('No "method" chosen for claim or support abandon'); - return; - } - - Lbry[method](abandonParams).then(successCallback, errorCallback); - }; -} - -export function doAbandonClaim(txid: string, nout: number, cb: string => void) { - const outpoint = `${txid}:${nout}`; - +export function doAbandonClaim(txid: string, nout: number) { return (dispatch: Dispatch, getState: GetState) => { const state = getState(); - const myClaims: Array = selectMyClaimsRaw(state); - const mySupports: { [string]: Support } = selectSupportsByOutpoint(state); - - // A user could be trying to abandon a support or one of their claims + const myClaims: Array = selectMyClaimsRaw(state); const claimToAbandon = myClaims.find(claim => claim.txid === txid && claim.nout === nout); - const supportToAbandon = mySupports[outpoint]; - if (!claimToAbandon && !supportToAbandon) { - console.error('No associated support or claim with txid: ', txid); + if (!claimToAbandon) { + console.error('No associated claim with txid: ', txid); return; } - const data = claimToAbandon - ? { claimId: claimToAbandon.claim_id } - : { outpoint: `${supportToAbandon.txid}:${supportToAbandon.nout}` }; - - const isClaim = !!claimToAbandon; - const startedActionType = isClaim - ? ACTIONS.ABANDON_CLAIM_STARTED - : ACTIONS.ABANDON_SUPPORT_STARTED; - const completedActionType = isClaim - ? ACTIONS.ABANDON_CLAIM_SUCCEEDED - : ACTIONS.ABANDON_SUPPORT_COMPLETED; + const { claim_id: claimId, name: claimName } = claimToAbandon; dispatch({ - type: startedActionType, - data, + type: ACTIONS.ABANDON_CLAIM_STARTED, + data: { + claimId, + }, }); const errorCallback = () => { dispatch( doToast({ - message: isClaim ? 'Error abandoning your claim/support' : 'Error unlocking your tip', + message: 'Error abandoning claim', isError: true, }) ); - if (cb) cb(ABANDON_STATES.ERROR); }; const successCallback = () => { dispatch({ - type: completedActionType, - data, + type: ACTIONS.ABANDON_CLAIM_SUCCEEDED, + data: { + claimId, + }, }); - if (cb) cb(ABANDON_STATES.DONE); - - let abandonMessage; - if (isClaim) { - abandonMessage = __('Successfully abandoned your claim.'); - } else if (supportToAbandon) { - abandonMessage = __('Successfully abandoned your support.'); - } else { - abandonMessage = __('Successfully unlocked your tip!'); - } dispatch( doToast({ - message: abandonMessage, + message: 'Successfully abandoned your claim', }) ); - dispatch(doFetchTxoPage()); + + // After abandoning, call claim_list to show the claim as abandoned + // Also fetch transactions to show the new abandon transaction + dispatch(doFetchClaimListMine()); + dispatch(doFetchTransactions()); }; const abandonParams = { @@ -292,19 +143,7 @@ export function doAbandonClaim(txid: string, nout: number, cb: string => void) { blocking: true, }; - let method; - if (supportToAbandon) { - method = 'support_abandon'; - } else if (claimToAbandon) { - const { name: claimName } = claimToAbandon; - method = claimName.startsWith('@') ? 'channel_abandon' : 'stream_abandon'; - } - - if (!method) { - console.error('No "method" chosen for claim or support abandon'); - return; - } - + const method = claimName.startsWith('@') ? 'channel_abandon' : 'stream_abandon'; Lbry[method](abandonParams).then(successCallback, errorCallback); }; } @@ -316,22 +155,15 @@ export function doFetchClaimsByChannel(uri: string, page: number = 1) { data: { uri, page }, }); - Lbry.claim_search({ - channel: uri, - valid_channel_signature: true, - page: page || 1, - order_by: ['release_time'], - include_is_my_output: true, - include_purchase_receipt: true, - }).then((result: ClaimSearchResponse) => { - const { items: claims, total_items: claimsInChannel, page: returnedPage } = result; + Lbry.claim_search({ uri, page: page || 1 }).then((result: ClaimSearchResponse) => { + const claimResult = result[uri] || {}; + const { claims_in_channel: claimsInChannel, returned_page: returnedPage } = claimResult; dispatch({ type: ACTIONS.FETCH_CHANNEL_CLAIMS_COMPLETED, data: { uri, - claimsInChannel, - claims: claims || [], + claims: claimsInChannel || [], page: returnedPage || undefined, }, }); @@ -339,61 +171,17 @@ export function doFetchClaimsByChannel(uri: string, page: number = 1) { }; } -export function doClearChannelErrors() { - return { - type: ACTIONS.CLEAR_CHANNEL_ERRORS, - }; -} - -export function doCreateChannel(name: string, amount: number, optionalParams: any, cb: any) { +export function doCreateChannel(name: string, amount: number) { return (dispatch: Dispatch) => { dispatch({ type: ACTIONS.CREATE_CHANNEL_STARTED, }); - const createParams: { - name: string, - bid: string, - blocking: true, - title?: string, - cover_url?: string, - thumbnail_url?: string, - description?: string, - website_url?: string, - email?: string, - tags?: Array, - } = { - name, - bid: creditsToString(amount), - blocking: true, - }; - - if (optionalParams) { - if (optionalParams.title) { - createParams.title = optionalParams.title; - } - if (optionalParams.coverUrl) { - createParams.cover_url = optionalParams.coverUrl; - } - if (optionalParams.thumbnailUrl) { - createParams.thumbnail_url = optionalParams.thumbnailUrl; - } - if (optionalParams.description) { - createParams.description = optionalParams.description; - } - if (optionalParams.website) { - createParams.website_url = optionalParams.website; - } - if (optionalParams.email) { - createParams.email = optionalParams.email; - } - if (optionalParams.tags) { - createParams.tags = optionalParams.tags.map(tag => tag.name); - } - } - return ( - Lbry.channel_create(createParams) + Lbry.channel_create({ + name, + bid: creditsToString(amount), + }) // outputs[0] is the certificate // outputs[1] is the change from the tx, not in the app currently .then((result: ChannelCreateResponse) => { @@ -402,337 +190,30 @@ export function doCreateChannel(name: string, amount: number, optionalParams: an type: ACTIONS.CREATE_CHANNEL_COMPLETED, data: { channelClaim }, }); - dispatch({ - type: ACTIONS.UPDATE_PENDING_CLAIMS, - data: { - claims: [channelClaim], - }, - }); - dispatch(doCheckPendingClaims(cb)); - return channelClaim; }) .catch(error => { dispatch({ type: ACTIONS.CREATE_CHANNEL_FAILED, - data: error.message, + data: error, }); }) ); }; } -export function doUpdateChannel(params: any, cb: any) { - return (dispatch: Dispatch, getState: GetState) => { - dispatch({ - type: ACTIONS.UPDATE_CHANNEL_STARTED, - }); - const state = getState(); - const myChannels = selectMyChannelClaims(state); - const channelClaim = myChannels.find(myChannel => myChannel.claim_id === params.claim_id); - - const updateParams = { - claim_id: params.claim_id, - bid: creditsToString(params.amount), - title: params.title, - cover_url: params.coverUrl, - thumbnail_url: params.thumbnailUrl, - description: params.description, - website_url: params.website, - email: params.email, - tags: [], - replace: true, - languages: [], - locations: [], - blocking: true, - }; - - if (params.tags) { - updateParams.tags = params.tags.map(tag => tag.name); - } - - // we'll need to remove these once we add locations/channels to channel page edit/create options - - if (channelClaim && channelClaim.value && channelClaim.value.locations) { - updateParams.locations = channelClaim.value.locations; - } - - if (channelClaim && channelClaim.value && channelClaim.value.languages) { - updateParams.languages = channelClaim.value.languages; - } - - return Lbry.channel_update(updateParams) - .then((result: ChannelUpdateResponse) => { - const channelClaim = result.outputs[0]; - dispatch({ - type: ACTIONS.UPDATE_CHANNEL_COMPLETED, - data: { channelClaim }, - }); - dispatch({ - type: ACTIONS.UPDATE_PENDING_CLAIMS, - data: { - claims: [channelClaim], - }, - }); - dispatch(doCheckPendingClaims(cb)); - return Boolean(result.outputs[0]); - }) - .then() - .catch(error => { - dispatch({ - type: ACTIONS.UPDATE_CHANNEL_FAILED, - data: error, - }); - }); - }; -} - -export function doImportChannel(certificate: string) { - return (dispatch: Dispatch) => { - dispatch({ - type: ACTIONS.IMPORT_CHANNEL_STARTED, - }); - - return Lbry.channel_import({ channel_data: certificate }) - .then((result: string) => { - dispatch({ - type: ACTIONS.IMPORT_CHANNEL_COMPLETED, - }); - }) - .catch(error => { - dispatch({ - type: ACTIONS.IMPORT_CHANNEL_FAILED, - data: error, - }); - }); - }; -} - -export function doFetchChannelListMine( - page: number = 1, - pageSize: number = 99999, - resolve: boolean = true -) { +export function doFetchChannelListMine() { return (dispatch: Dispatch) => { dispatch({ type: ACTIONS.FETCH_CHANNEL_LIST_STARTED, }); - const callback = (response: ChannelListResponse) => { + const callback = (channels: Array) => { dispatch({ type: ACTIONS.FETCH_CHANNEL_LIST_COMPLETED, - data: { claims: response.items }, + data: { claims: channels }, }); }; - const failure = error => { - dispatch({ - type: ACTIONS.FETCH_CHANNEL_LIST_FAILED, - data: error, - }); - }; - - Lbry.channel_list({ page, page_size: pageSize, resolve }).then(callback, failure); + Lbry.channel_list().then(callback); }; } - -export function doClaimSearch( - options: { - page_size: number, - page: number, - no_totals: boolean, - any_tags?: Array, - channel_ids?: Array, - not_channel_ids?: Array, - not_tags?: Array, - order_by?: Array, - release_time?: string, - } = { - no_totals: true, - page_size: 10, - page: 1, - } -) { - const query = createNormalizedClaimSearchKey(options); - return (dispatch: Dispatch) => { - dispatch({ - type: ACTIONS.CLAIM_SEARCH_STARTED, - data: { query: query }, - }); - - const success = (data: ClaimSearchResponse) => { - const resolveInfo = {}; - const urls = []; - data.items.forEach((stream: Claim) => { - resolveInfo[stream.canonical_url] = { stream }; - urls.push(stream.canonical_url); - }); - - dispatch({ - type: ACTIONS.CLAIM_SEARCH_COMPLETED, - data: { - query, - resolveInfo, - urls, - append: options.page && options.page !== 1, - pageSize: options.page_size, - }, - }); - }; - - const failure = err => { - dispatch({ - type: ACTIONS.CLAIM_SEARCH_FAILED, - data: { query }, - error: err, - }); - }; - - Lbry.claim_search({ - ...options, - include_purchase_receipt: true, - }).then(success, failure); - }; -} - -export function doRepost(options: StreamRepostOptions) { - return (dispatch: Dispatch) => { - // $FlowFixMe - return new Promise(resolve => { - dispatch({ - type: ACTIONS.CLAIM_REPOST_STARTED, - }); - - function success(response) { - const repostClaim = response.outputs[0]; - dispatch({ - type: ACTIONS.CLAIM_REPOST_COMPLETED, - data: { - originalClaimId: options.claim_id, - repostClaim, - }, - }); - - dispatch(doFetchClaimListMine(1, 10)); - resolve(repostClaim); - } - - function failure(error) { - dispatch({ - type: ACTIONS.CLAIM_REPOST_FAILED, - data: { - error: error.message, - }, - }); - } - - Lbry.stream_repost(options).then(success, failure); - }); - }; -} - -export function doCheckPublishNameAvailability(name: string) { - return (dispatch: Dispatch) => { - dispatch({ - type: ACTIONS.CHECK_PUBLISH_NAME_STARTED, - }); - - return Lbry.claim_list({ name: name }).then(result => { - dispatch({ - type: ACTIONS.CHECK_PUBLISH_NAME_COMPLETED, - }); - if (result.items.length) { - dispatch({ - type: ACTIONS.FETCH_CLAIM_LIST_MINE_COMPLETED, - data: { - result, - resolve: false, - }, - }); - } - return !(result && result.items && result.items.length); - }); - }; -} - -export function doClearRepostError() { - return { - type: ACTIONS.CLEAR_REPOST_ERROR, - }; -} - -export function doPurchaseList(page: number = 1, pageSize: number = PAGE_SIZE) { - return (dispatch: Dispatch) => { - dispatch({ - type: ACTIONS.PURCHASE_LIST_STARTED, - }); - - const success = (result: PurchaseListResponse) => { - return dispatch({ - type: ACTIONS.PURCHASE_LIST_COMPLETED, - data: { - result, - }, - }); - }; - - const failure = error => { - dispatch({ - type: ACTIONS.PURCHASE_LIST_FAILED, - data: { - error: error.message, - }, - }); - }; - - Lbry.purchase_list({ - page: page, - page_size: pageSize, - resolve: true, - }).then(success, failure); - }; -} - -export const doCheckPendingClaims = (onConfirmed: Function) => ( - dispatch: Dispatch, - getState: GetState -) => { - let claimCheckInterval; - - const checkClaimList = () => { - const state = getState(); - const pendingIdSet = new Set(selectPendingIds(state)); - Lbry.claim_list({ page: 1, page_size: 10 }) - .then(result => { - const claims = result.items; - const claimsToConfirm = []; - claims.forEach(claim => { - const { claim_id: claimId } = claim; - if (claim.confirmations > 0 && pendingIdSet.has(claimId)) { - pendingIdSet.delete(claimId); - claimsToConfirm.push(claim); - if (onConfirmed) { - onConfirmed(claim); - } - } - }); - if (claimsToConfirm.length) { - dispatch({ - type: ACTIONS.UPDATE_CONFIRMED_CLAIMS, - data: { - claims: claimsToConfirm, - }, - }); - } - return pendingIdSet.size; - }) - .then(len => { - if (!len) { - clearInterval(claimCheckInterval); - } - }); - }; - - claimCheckInterval = setInterval(() => { - checkClaimList(); - }, 30000); -}; diff --git a/src/redux/actions/comments.js b/src/redux/actions/comments.js deleted file mode 100644 index 22b38e4..0000000 --- a/src/redux/actions/comments.js +++ /dev/null @@ -1,225 +0,0 @@ -// @flow -import * as ACTIONS from 'constants/action_types'; -import Lbry from 'lbry'; -import { selectClaimsByUri, selectMyChannelClaims } from 'redux/selectors/claims'; -import { doToast } from 'redux/actions/notifications'; - -export function doCommentList(uri: string, page: number = 1, pageSize: number = 99999) { - return (dispatch: Dispatch, getState: GetState) => { - const state = getState(); - const claim = selectClaimsByUri(state)[uri]; - const claimId = claim ? claim.claim_id : null; - - dispatch({ - type: ACTIONS.COMMENT_LIST_STARTED, - }); - Lbry.comment_list({ - claim_id: claimId, - page, - page_size: pageSize, - }) - .then((result: CommentListResponse) => { - const { items: comments } = result; - dispatch({ - type: ACTIONS.COMMENT_LIST_COMPLETED, - data: { - comments, - claimId: claimId, - uri: uri, - }, - }); - }) - .catch(error => { - console.log(error); - dispatch({ - type: ACTIONS.COMMENT_LIST_FAILED, - data: error, - }); - }); - }; -} - -export function doCommentCreate( - comment: string = '', - claim_id: string = '', - channel: string, - parent_id?: string -) { - return (dispatch: Dispatch, getState: GetState) => { - const state = getState(); - dispatch({ - type: ACTIONS.COMMENT_CREATE_STARTED, - }); - - const myChannels = selectMyChannelClaims(state); - const namedChannelClaim = - myChannels && myChannels.find(myChannel => myChannel.name === channel); - const channel_id = namedChannelClaim.claim_id; - - if (channel_id == null) { - dispatch({ - type: ACTIONS.COMMENT_CREATE_FAILED, - data: {}, - }); - dispatch( - doToast({ - message: 'Channel cannot be anonymous, please select a channel and try again.', - isError: true, - }) - ); - return; - } - - return Lbry.comment_create({ - comment: comment, - claim_id: claim_id, - channel_id: channel_id, - parent_id: parent_id, - }) - .then((result: CommentCreateResponse) => { - dispatch({ - type: ACTIONS.COMMENT_CREATE_COMPLETED, - data: { - comment: result, - claimId: claim_id, - }, - }); - }) - .catch(error => { - dispatch({ - type: ACTIONS.COMMENT_CREATE_FAILED, - data: error, - }); - dispatch( - doToast({ - message: 'Unable to create comment, please try again later.', - isError: true, - }) - ); - }); - }; -} - -export function doCommentHide(comment_id: string) { - return (dispatch: Dispatch) => { - dispatch({ - type: ACTIONS.COMMENT_HIDE_STARTED, - }); - return Lbry.comment_hide({ - comment_ids: [comment_id], - }) - .then((result: CommentHideResponse) => { - dispatch({ - type: ACTIONS.COMMENT_HIDE_COMPLETED, - data: result, - }); - }) - .catch(error => { - dispatch({ - type: ACTIONS.COMMENT_HIDE_FAILED, - data: error, - }); - dispatch( - doToast({ - message: 'Unable to hide this comment, please try again later.', - isError: true, - }) - ); - }); - }; -} - -export function doCommentAbandon(comment_id: string) { - return (dispatch: Dispatch) => { - dispatch({ - type: ACTIONS.COMMENT_ABANDON_STARTED, - }); - return Lbry.comment_abandon({ - comment_id: comment_id, - }) - .then((result: CommentAbandonResponse) => { - // Comment may not be deleted if the signing channel can't be signed. - // This will happen if the channel was recently created or abandoned. - if (result.abandoned) { - dispatch({ - type: ACTIONS.COMMENT_ABANDON_COMPLETED, - data: { - comment_id: comment_id, - }, - }); - } else { - dispatch({ - type: ACTIONS.COMMENT_ABANDON_FAILED, - }); - dispatch( - doToast({ - message: 'Your channel is still being setup, try again in a few moments.', - isError: true, - }) - ); - } - }) - .catch(error => { - dispatch({ - type: ACTIONS.COMMENT_ABANDON_FAILED, - data: error, - }); - dispatch( - doToast({ - message: 'Unable to delete this comment, please try again later.', - isError: true, - }) - ); - }); - }; -} - -export function doCommentUpdate(comment_id: string, comment: string) { - // if they provided an empty string, they must have wanted to abandon - if (comment === '') { - return doCommentAbandon(comment_id); - } else { - return (dispatch: Dispatch) => { - dispatch({ - type: ACTIONS.COMMENT_UPDATE_STARTED, - }); - return Lbry.comment_update({ - comment_id: comment_id, - comment: comment, - }) - .then((result: CommentUpdateResponse) => { - if (result != null) { - dispatch({ - type: ACTIONS.COMMENT_UPDATE_COMPLETED, - data: { - comment: result, - }, - }); - } else { - // the result will return null - dispatch({ - type: ACTIONS.COMMENT_UPDATE_FAILED, - }); - dispatch( - doToast({ - message: 'Your channel is still being setup, try again in a few moments.', - isError: true, - }) - ); - } - }) - .catch(error => { - dispatch({ - type: ACTIONS.COMMENT_UPDATE_FAILED, - data: error, - }); - dispatch( - doToast({ - message: 'Unable to edit this comment, please try again later.', - isError: true, - }) - ); - }); - }; - } -} diff --git a/src/redux/actions/content.js b/src/redux/actions/content.js index 2654f74..fff0f11 100644 --- a/src/redux/actions/content.js +++ b/src/redux/actions/content.js @@ -1,8 +1,7 @@ -// @flow import * as ACTIONS from 'constants/action_types'; export function savePosition(claimId: string, outpoint: string, position: number) { - return (dispatch: Dispatch) => { + return dispatch => { dispatch({ type: ACTIONS.SET_CONTENT_POSITION, data: { claimId, outpoint, position }, diff --git a/src/redux/actions/file.js b/src/redux/actions/file.js deleted file mode 100644 index b7dc699..0000000 --- a/src/redux/actions/file.js +++ /dev/null @@ -1,130 +0,0 @@ -// @flow -import * as ACTIONS from 'constants/action_types'; -import Lbry from 'lbry'; -import { doToast } from 'redux/actions/notifications'; -import { selectBalance } from 'redux/selectors/wallet'; -import { - makeSelectFileInfoForUri, - selectDownloadingByOutpoint, - makeSelectStreamingUrlForUri, -} from 'redux/selectors/file_info'; -import { makeSelectClaimForUri } from 'redux/selectors/claims'; - -type Dispatch = (action: any) => any; -type GetState = () => { file: FileState }; - -export function doFileGet(uri: string, saveFile: boolean = true, onSuccess?: GetResponse => any) { - return (dispatch: Dispatch, getState: () => any) => { - const state = getState(); - const { nout, txid } = makeSelectClaimForUri(uri)(state); - const outpoint = `${txid}:${nout}`; - - dispatch({ - type: ACTIONS.FETCH_FILE_INFO_STARTED, - data: { - outpoint, - }, - }); - - // set save_file argument to True to save the file (old behaviour) - Lbry.get({ uri, save_file: saveFile }) - .then((streamInfo: GetResponse) => { - const timeout = - streamInfo === null || typeof streamInfo !== 'object' || streamInfo.error === 'Timeout'; - if (timeout) { - dispatch({ - type: ACTIONS.FETCH_FILE_INFO_FAILED, - data: { outpoint }, - }); - - dispatch(doToast({ message: `File timeout for uri ${uri}`, isError: true })); - } else { - if (streamInfo.purchase_receipt || streamInfo.content_fee) { - dispatch({ - type: ACTIONS.PURCHASE_URI_COMPLETED, - data: { uri, purchaseReceipt: streamInfo.purchase_receipt || streamInfo.content_fee }, - }); - } - dispatch({ - type: ACTIONS.FETCH_FILE_INFO_COMPLETED, - data: { - fileInfo: streamInfo, - outpoint: outpoint, - }, - }); - - if (onSuccess) { - onSuccess(streamInfo); - } - } - }) - .catch(error => { - dispatch({ - type: ACTIONS.PURCHASE_URI_FAILED, - data: { uri, error }, - }); - - dispatch({ - type: ACTIONS.FETCH_FILE_INFO_FAILED, - data: { outpoint }, - }); - - dispatch( - doToast({ - message: `Failed to view ${uri}, please try again. If this problem persists, visit https://lbry.com/faq/support for support.`, - isError: true, - }) - ); - }); - }; -} - -export function doPurchaseUri( - uri: string, - costInfo: { cost: number }, - saveFile: boolean = true, - onSuccess?: GetResponse => any -) { - return (dispatch: Dispatch, getState: GetState) => { - dispatch({ - type: ACTIONS.PURCHASE_URI_STARTED, - data: { uri }, - }); - - const state = getState(); - const balance = selectBalance(state); - const fileInfo = makeSelectFileInfoForUri(uri)(state); - const downloadingByOutpoint = selectDownloadingByOutpoint(state); - const alreadyDownloading = fileInfo && !!downloadingByOutpoint[fileInfo.outpoint]; - const alreadyStreaming = makeSelectStreamingUrlForUri(uri)(state); - - if (!saveFile && (alreadyDownloading || alreadyStreaming)) { - dispatch({ - type: ACTIONS.PURCHASE_URI_FAILED, - data: { uri, error: `Already fetching uri: ${uri}` }, - }); - - Promise.resolve(); - return; - } - - const { cost } = costInfo; - if (parseFloat(cost) > balance) { - dispatch({ - type: ACTIONS.PURCHASE_URI_FAILED, - data: { uri, error: 'Insufficient credits' }, - }); - - Promise.resolve(); - return; - } - - dispatch(doFileGet(uri, saveFile, onSuccess)); - }; -} - -export function doClearPurchasedUriSuccess() { - return { - type: ACTIONS.CLEAR_PURCHASED_URI_SUCCESS, - }; -} diff --git a/src/redux/actions/file_info.js b/src/redux/actions/file_info.js index 99b4da0..7177183 100644 --- a/src/redux/actions/file_info.js +++ b/src/redux/actions/file_info.js @@ -1,6 +1,7 @@ import * as ACTIONS from 'constants/action_types'; import Lbry from 'lbry'; -import { selectClaimsByUri } from 'redux/selectors/claims'; +import { doFetchClaimListMine } from 'redux/actions/claims'; +import { selectClaimsByUri, selectIsFetchingClaimListMine } from 'redux/selectors/claims'; import { selectIsFetchingFileList, selectUrisLoading } from 'redux/selectors/file_info'; export function doFetchFileInfo(uri) { @@ -18,15 +19,12 @@ export function doFetchFileInfo(uri) { }, }); - Lbry.file_list({ outpoint, full_status: true, page: 1, page_size: 1 }).then(result => { - const { items: fileInfos } = result; - const fileInfo = fileInfos[0]; - + Lbry.file_list({ outpoint, full_status: true }).then(fileInfos => { dispatch({ type: ACTIONS.FETCH_FILE_INFO_COMPLETED, data: { outpoint, - fileInfo: fileInfo || null, + fileInfo: fileInfos && fileInfos.length ? fileInfos[0] : null, }, }); }); @@ -34,7 +32,7 @@ export function doFetchFileInfo(uri) { }; } -export function doFileList(page = 1, pageSize = 99999) { +export function doFileList() { return (dispatch, getState) => { const state = getState(); const isFetching = selectIsFetchingFileList(state); @@ -44,12 +42,11 @@ export function doFileList(page = 1, pageSize = 99999) { type: ACTIONS.FILE_LIST_STARTED, }); - Lbry.file_list({ page, page_size: pageSize }).then(result => { - const { items: fileInfos } = result; + Lbry.file_list().then(fileInfos => { dispatch({ type: ACTIONS.FILE_LIST_SUCCEEDED, data: { - fileInfos: fileInfos, + fileInfos, }, }); }); @@ -57,10 +54,13 @@ export function doFileList(page = 1, pageSize = 99999) { }; } -export function doFetchFileInfos() { +export function doFetchFileInfosAndPublishedClaims() { return (dispatch, getState) => { const state = getState(); + const isFetchingClaimListMine = selectIsFetchingClaimListMine(state); const isFetchingFileInfo = selectIsFetchingFileList(state); + + if (!isFetchingClaimListMine) dispatch(doFetchClaimListMine()); if (!isFetchingFileInfo) dispatch(doFileList()); }; } diff --git a/src/redux/actions/publish.js b/src/redux/actions/publish.js deleted file mode 100644 index 8c52098..0000000 --- a/src/redux/actions/publish.js +++ /dev/null @@ -1,452 +0,0 @@ -// @flow -import { CC_LICENSES, COPYRIGHT, OTHER, NONE, PUBLIC_DOMAIN } from 'constants/licenses'; -import { SPEECH_STATUS, SPEECH_PUBLISH } from 'constants/speech_urls'; -import * as ACTIONS from 'constants/action_types'; -import * as THUMBNAIL_STATUSES from 'constants/thumbnail_upload_statuses'; -import Lbry from 'lbry'; -import LbryFirst from 'lbry-first'; -import { batchActions } from 'util/batch-actions'; -import { creditsToString } from 'util/format-credits'; -import { doError } from 'redux/actions/notifications'; -import { isClaimNsfw } from 'util/claim'; -import { - selectMyChannelClaims, - selectMyClaimsWithoutChannels, - selectReflectingById, -} from 'redux/selectors/claims'; -import { selectPublishFormValues, selectMyClaimForUri } from 'redux/selectors/publish'; - -export const doResetThumbnailStatus = () => (dispatch: Dispatch) => { - dispatch({ - type: ACTIONS.UPDATE_PUBLISH_FORM, - data: { - thumbnailPath: '', - }, - }); - - return fetch(SPEECH_STATUS) - .then(res => res.json()) - .then(status => { - if (status.disabled) { - throw Error(); - } - - return dispatch({ - type: ACTIONS.UPDATE_PUBLISH_FORM, - data: { - uploadThumbnailStatus: THUMBNAIL_STATUSES.READY, - thumbnail: '', - }, - }); - }) - .catch(() => - dispatch({ - type: ACTIONS.UPDATE_PUBLISH_FORM, - data: { - uploadThumbnailStatus: THUMBNAIL_STATUSES.API_DOWN, - thumbnail: '', - }, - }) - ); -}; - -export const doClearPublish = () => (dispatch: Dispatch) => { - dispatch({ type: ACTIONS.CLEAR_PUBLISH }); - return dispatch(doResetThumbnailStatus()); -}; - -export const doUpdatePublishForm = (publishFormValue: UpdatePublishFormData) => ( - dispatch: Dispatch -) => - dispatch({ - type: ACTIONS.UPDATE_PUBLISH_FORM, - data: { ...publishFormValue }, - }); - -export const doUploadThumbnail = ( - filePath?: string, - thumbnailBlob?: File, - fsAdapter?: any, - fs?: any, - path?: any -) => (dispatch: Dispatch) => { - let thumbnail, fileExt, fileName, fileType; - - const makeid = () => { - let text = ''; - const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; - for (let i = 0; i < 24; i += 1) text += possible.charAt(Math.floor(Math.random() * 62)); - return text; - }; - - const uploadError = (error = '') => { - dispatch( - batchActions( - { - type: ACTIONS.UPDATE_PUBLISH_FORM, - data: { - uploadThumbnailStatus: THUMBNAIL_STATUSES.READY, - thumbnail: '', - nsfw: false, - }, - }, - doError(error) - ) - ); - }; - - const doUpload = data => { - return fetch(SPEECH_PUBLISH, { - method: 'POST', - body: data, - }) - .then(res => res.text()) - .then(text => (text.length ? JSON.parse(text) : {})) - .then(json => { - return json.success - ? dispatch({ - type: ACTIONS.UPDATE_PUBLISH_FORM, - data: { - uploadThumbnailStatus: THUMBNAIL_STATUSES.COMPLETE, - thumbnail: json.data.serveUrl, - }, - }) - : uploadError( - json.message || __('Thumbnail upload service may be down, try again later.') - ); - }) - .catch(err => { - uploadError(err.message); - }); - }; - - dispatch({ - type: ACTIONS.UPDATE_PUBLISH_FORM, - data: { uploadThumbnailStatus: THUMBNAIL_STATUSES.IN_PROGRESS }, - }); - - if (fsAdapter && fsAdapter.readFile && filePath) { - fsAdapter.readFile(filePath, 'base64').then(base64Image => { - fileExt = 'png'; - fileName = 'thumbnail.png'; - fileType = 'image/png'; - - const data = new FormData(); - const name = makeid(); - data.append('name', name); - // $FlowFixMe - data.append('file', { uri: 'file://' + filePath, type: fileType, name: fileName }); - return doUpload(data); - }); - } else { - if (filePath && fs && path) { - thumbnail = fs.readFileSync(filePath); - fileExt = path.extname(filePath); - fileName = path.basename(filePath); - fileType = `image/${fileExt.slice(1)}`; - } else if (thumbnailBlob) { - fileExt = `.${thumbnailBlob.type && thumbnailBlob.type.split('/')[1]}`; - fileName = thumbnailBlob.name; - fileType = thumbnailBlob.type; - } else { - return null; - } - - const data = new FormData(); - const name = makeid(); - const file = - thumbnailBlob || (thumbnail && new File([thumbnail], fileName, { type: fileType })); - data.append('name', name); - // $FlowFixMe - data.append('file', file); - return doUpload(data); - } -}; - -export const doPrepareEdit = (claim: StreamClaim, uri: string, fileInfo: FileListItem, fs: any) => ( - dispatch: Dispatch -) => { - const { name, amount, value = {} } = claim; - const channelName = (claim && claim.signing_channel && claim.signing_channel.name) || null; - const { - author, - description, - // use same values as default state - // fee will be undefined for free content - fee = { - amount: '0', - currency: 'LBC', - }, - languages, - license, - license_url: licenseUrl, - thumbnail, - title, - tags, - } = value; - - const publishData: UpdatePublishFormData = { - name, - bid: amount, - contentIsFree: fee.amount === '0', - author, - description, - fee, - languages, - thumbnail: thumbnail ? thumbnail.url : null, - title, - uri, - uploadThumbnailStatus: thumbnail ? THUMBNAIL_STATUSES.MANUAL : undefined, - licenseUrl, - nsfw: isClaimNsfw(claim), - tags: tags ? tags.map(tag => ({ name: tag })) : [], - }; - - // Make sure custom licenses are mapped properly - // If the license isn't one of the standard licenses, map the custom license and description/url - if (!CC_LICENSES.some(({ value }) => value === license)) { - if (!license || license === NONE || license === PUBLIC_DOMAIN) { - publishData.licenseType = license; - } else if (license && !licenseUrl && license !== NONE) { - publishData.licenseType = COPYRIGHT; - } else { - publishData.licenseType = OTHER; - } - - publishData.otherLicenseDescription = license; - } else { - publishData.licenseType = license; - } - if (channelName) { - publishData['channel'] = channelName; - } - - dispatch({ type: ACTIONS.DO_PREPARE_EDIT, data: publishData }); -}; - -export const doPublish = (success: Function, fail: Function) => ( - dispatch: Dispatch, - getState: () => {} -) => { - dispatch({ type: ACTIONS.PUBLISH_START }); - - const state = getState(); - const myClaimForUri = selectMyClaimForUri(state); - const myChannels = selectMyChannelClaims(state); - const myClaims = selectMyClaimsWithoutChannels(state); - // get redux publish form - const publishData = selectPublishFormValues(state); - - // destructure the data values - const { - name, - bid, - filePath, - description, - language, - license, - licenseUrl, - useLBRYUploader, - licenseType, - otherLicenseDescription, - thumbnail, - channel, - title, - contentIsFree, - fee, - uri, - tags, - locations, - optimize, - } = publishData; - // Handle scenario where we have a claim that has the same name as a channel we are publishing with. - const myClaimForUriEditing = myClaimForUri && myClaimForUri.name === name ? myClaimForUri : null; - - let publishingLicense; - switch (licenseType) { - case COPYRIGHT: - case OTHER: - publishingLicense = otherLicenseDescription; - break; - default: - publishingLicense = licenseType; - } - - // get the claim id from the channel name, we will use that instead - const namedChannelClaim = myChannels - ? myChannels.find(myChannel => myChannel.name === channel) - : null; - const channelId = namedChannelClaim ? namedChannelClaim.claim_id : ''; - - const publishPayload: { - name: ?string, - bid: string, - description?: string, - channel_id?: string, - file_path?: string, - - license_url?: string, - license?: string, - thumbnail_url?: string, - release_time?: number, - fee_currency?: string, - fee_amount?: string, - languages?: Array, - tags: Array, - locations?: Array, - blocking: boolean, - optimize_file?: boolean, - } = { - name, - title, - description, - locations: [], - bid: creditsToString(bid), - languages: [language], - tags: tags && tags.map(tag => tag.name), - thumbnail_url: thumbnail, - blocking: true, - }; - // Temporary solution to keep the same publish flow with the new tags api - // Eventually we will allow users to enter their own tags on publish - // `nsfw` will probably be removed - - if (publishingLicense) { - publishPayload.license = publishingLicense; - } - - if (licenseUrl) { - publishPayload.license_url = licenseUrl; - } - - if (thumbnail) { - publishPayload.thumbnail_url = thumbnail; - } - - if (useLBRYUploader) { - publishPayload.tags.push('lbry-first'); - } - - // Set release time to curret date. On edits, keep original release/transaction time as release_time - if (myClaimForUriEditing && myClaimForUriEditing.value.release_time) { - publishPayload.release_time = Number(myClaimForUri.value.release_time); - } else if (myClaimForUriEditing && myClaimForUriEditing.timestamp) { - publishPayload.release_time = Number(myClaimForUriEditing.timestamp); - } else { - publishPayload.release_time = Number(Math.round(Date.now() / 1000)); - } - - if (channelId) { - publishPayload.channel_id = channelId; - } - - if (myClaimForUriEditing && myClaimForUriEditing.value && myClaimForUriEditing.value.locations) { - publishPayload.locations = myClaimForUriEditing.value.locations; - } - - if (!contentIsFree && fee && (fee.currency && Number(fee.amount) > 0)) { - publishPayload.fee_currency = fee.currency; - publishPayload.fee_amount = creditsToString(fee.amount); - } - - if (optimize) { - publishPayload.optimize_file = true; - } - - // Only pass file on new uploads, not metadata only edits. - // The sdk will figure it out - if (filePath) publishPayload.file_path = filePath; - - return Lbry.publish(publishPayload).then((response: PublishResponse) => { - if (!useLBRYUploader) { - return success(response); - } - - // $FlowFixMe - publishPayload.permanent_url = response.outputs[0].permanent_url; - - return LbryFirst.upload(publishPayload) - .then(() => { - // Return original publish response so app treats it like a normal publish - return success(response); - }) - .catch(error => { - return success(response, error); - }); - }, fail); -}; - -// Calls file_list until any reflecting files are done -export const doCheckReflectingFiles = () => (dispatch: Dispatch, getState: GetState) => { - const state = getState(); - const { checkingReflector } = state.claims; - let reflectorCheckInterval; - - const checkFileList = async() => { - const state = getState(); - const reflectingById = selectReflectingById(state); - const ids = Object.keys(reflectingById); - - const newReflectingById = {}; - const promises = []; - // TODO: just use file_list({claim_id: Array}) - if (Object.keys(reflectingById).length) { - ids.forEach(claimId => { - promises.push(Lbry.file_list({ claim_id: claimId })); - }); - - Promise.all(promises) - .then(results => { - results.forEach(res => { - if (res.items[0]) { - const fileListItem = res.items[0]; - const fileClaimId = fileListItem.claim_id; - const { - is_fully_reflected: done, - uploading_to_reflector: uploading, - reflector_progress: progress, - } = fileListItem; - if (uploading) { - newReflectingById[fileClaimId] = { - fileListItem: fileListItem, - progress, - stalled: !done && !uploading, - }; - } - } - }); - }) - .then(() => { - dispatch({ - type: ACTIONS.UPDATE_FILES_REFLECTING, - data: newReflectingById, - }); - if (!Object.keys(newReflectingById).length) { - dispatch({ - type: ACTIONS.TOGGLE_CHECKING_REFLECTING, - data: false, - }); - clearInterval(reflectorCheckInterval); - } - }); - } else { - dispatch({ - type: ACTIONS.TOGGLE_CHECKING_REFLECTING, - data: false, - }); - clearInterval(reflectorCheckInterval); - } - }; - // do it once... - checkFileList(); - // then start the interval if it's not already started - if (!checkingReflector) { - dispatch({ - type: ACTIONS.TOGGLE_CHECKING_REFLECTING, - data: true, - }); - reflectorCheckInterval = setInterval(() => { - checkFileList(); - }, 5000); - } -}; diff --git a/src/redux/actions/search.js b/src/redux/actions/search.js index 37618eb..d81c592 100644 --- a/src/redux/actions/search.js +++ b/src/redux/actions/search.js @@ -4,12 +4,11 @@ import { buildURI } from 'lbryURI'; import { doResolveUri } from 'redux/actions/claims'; import { makeSelectSearchUris, - makeSelectResolvedSearchResults, selectSuggestions, makeSelectQueryWithOptions, selectSearchValue, } from 'redux/selectors/search'; -import { batchActions } from 'util/batch-actions'; +import { batchActions } from 'util/batchActions'; import debounce from 'util/debounce'; import handleFetchResponse from 'util/handle-fetch'; @@ -17,17 +16,8 @@ const DEBOUNCED_SEARCH_SUGGESTION_MS = 300; type Dispatch = (action: any) => any; type GetState = () => { search: SearchState }; -type SearchOptions = { - size?: number, - from?: number, - related_to?: string, - nsfw?: boolean, - isBackgroundSearch?: boolean, - resolveResults?: boolean, -}; - // We can't use env's because they aren't passed into node_modules -let CONNECTION_STRING = 'https://lighthouse.lbry.com/'; +let CONNECTION_STRING = 'https://lighthouse.lbry.io/'; export const setSearchApi = (endpoint: string) => { CONNECTION_STRING = endpoint.replace(/\/*$/, '/'); // exactly one slash at the end; @@ -84,13 +74,13 @@ export const doUpdateSearchQuery = (query: string, shouldSkipSuggestions: ?boole } }; -export const doSearch = (rawQuery: string, searchOptions: SearchOptions) => ( - dispatch: Dispatch, - getState: GetState -) => { +export const doSearch = ( + rawQuery: string, // pass in a query if you don't want to search for what's in the search bar + size: ?number, // only pass in if you don't want to use the users setting (ex: related content) + from: ?number, + isBackgroundSearch: boolean = false +) => (dispatch: Dispatch, getState: GetState) => { const query = rawQuery.replace(/^lbry:\/\//i, '').replace(/\//, ' '); - const resolveResults = searchOptions && searchOptions.resolveResults; - const isBackgroundSearch = (searchOptions && searchOptions.isBackgroundSearch) || false; if (!query) { dispatch({ @@ -100,8 +90,7 @@ export const doSearch = (rawQuery: string, searchOptions: SearchOptions) => ( } const state = getState(); - - let queryWithOptions = makeSelectQueryWithOptions(query, searchOptions)(state); + const queryWithOptions = makeSelectQueryWithOptions(query, size, from, isBackgroundSearch)(state); // If we have already searched for something, we don't need to do anything const urisForQuery = makeSelectSearchUris(queryWithOptions)(state); @@ -123,29 +112,17 @@ export const doSearch = (rawQuery: string, searchOptions: SearchOptions) => ( fetch(`${CONNECTION_STRING}search?${queryWithOptions}`) .then(handleFetchResponse) - .then((data: Array<{ name: string, claimId: string }>) => { + .then((data: Array<{ name: String, claimId: string }>) => { const uris = []; const actions = []; data.forEach(result => { - if (result) { - const { name, claimId } = result; - const urlObj: LbryUrlObj = {}; - - if (name.startsWith('@')) { - urlObj.channelName = name; - urlObj.channelClaimId = claimId; - } else { - urlObj.streamName = name; - urlObj.streamClaimId = claimId; - } - - const url = buildURI(urlObj); - if (resolveResults) { - actions.push(doResolveUri(url)); - } - uris.push(url); - } + const uri = buildURI({ + claimName: result.name, + claimId: result.claimId, + }); + actions.push(doResolveUri(uri)); + uris.push(uri); }); actions.push({ @@ -157,98 +134,13 @@ export const doSearch = (rawQuery: string, searchOptions: SearchOptions) => ( }); dispatch(batchActions(...actions)); }) - .catch(e => { + .catch(() => { dispatch({ type: ACTIONS.SEARCH_FAIL, }); }); }; -export const doResolvedSearch = ( - rawQuery: string, - size: ?number, // only pass in if you don't want to use the users setting (ex: related content) - from: ?number, - isBackgroundSearch: boolean = false, - options: { - related_to?: string, - } = {}, - nsfw: boolean -) => (dispatch: Dispatch, getState: GetState) => { - const query = rawQuery.replace(/^lbry:\/\//i, '').replace(/\//, ' '); - - if (!query) { - dispatch({ - type: ACTIONS.RESOLVED_SEARCH_FAIL, - }); - return; - } - - const optionsWithFrom: SearchOptions = { - ...(size ? { size } : {}), - ...(from ? { from } : {}), - isBackgroundSearch, - ...options, - }; - - const optionsWithoutFrom: SearchOptions = { - ...(size ? { size } : {}), - isBackgroundSearch, - ...options, - }; - - const state = getState(); - - let queryWithOptions = makeSelectQueryWithOptions(query, optionsWithFrom)(state); - - // make from null so that we can maintain a reference to the same query for multiple pages and simply append the found results - let queryWithoutFrom = makeSelectQueryWithOptions(query, optionsWithoutFrom)(state); - - // If we have already searched for something, we don't need to do anything - // TODO: Tweak this check for multiple page results - /* const resultsForQuery = makeSelectResolvedSearchResults(queryWithOptions)(state); - if (resultsForQuery && resultsForQuery.length && resultsForQuery.length > (from * size)) { - return; - } */ - - dispatch({ - type: ACTIONS.RESOLVED_SEARCH_START, - }); - - if (!state.search.searchQuery && !isBackgroundSearch) { - dispatch(doUpdateSearchQuery(query)); - } - - const fetchUrl = nsfw - ? `${CONNECTION_STRING}search?resolve=true&${queryWithOptions}` - : `${CONNECTION_STRING}search?resolve=true&nsfw=false&${queryWithOptions}`; - fetch(fetchUrl) - .then(handleFetchResponse) - .then((data: Array) => { - const results = []; - - data.forEach(result => { - if (result) { - results.push(result); - } - }); - - dispatch({ - type: ACTIONS.RESOLVED_SEARCH_SUCCESS, - data: { - query: queryWithoutFrom, - results, - pageSize: size, - append: parseInt(from, 10) > parseInt(size, 10) - 1, - }, - }); - }) - .catch(e => { - dispatch({ - type: ACTIONS.RESOLVED_SEARCH_FAIL, - }); - }); -}; - export const doFocusSearchInput = () => (dispatch: Dispatch) => dispatch({ type: ACTIONS.SEARCH_FOCUS, @@ -259,10 +151,10 @@ export const doBlurSearchInput = () => (dispatch: Dispatch) => type: ACTIONS.SEARCH_BLUR, }); -export const doUpdateSearchOptions = ( - newOptions: SearchOptions, - additionalOptions: SearchOptions -) => (dispatch: Dispatch, getState: GetState) => { +export const doUpdateSearchOptions = (newOptions: SearchOptions) => ( + dispatch: Dispatch, + getState: GetState +) => { const state = getState(); const searchValue = selectSearchValue(state); @@ -273,6 +165,6 @@ export const doUpdateSearchOptions = ( if (searchValue) { // After updating, perform a search with the new options - dispatch(doSearch(searchValue, additionalOptions)); + dispatch(doSearch(searchValue)); } }; diff --git a/src/redux/actions/sync.js b/src/redux/actions/sync.js deleted file mode 100644 index 2fc7a1e..0000000 --- a/src/redux/actions/sync.js +++ /dev/null @@ -1,113 +0,0 @@ -// @flow -import * as ACTIONS from 'constants/action_types'; -import Lbry from 'lbry'; - -type SharedData = { - version: '0.1', - value: { - subscriptions?: Array, - tags?: Array, - blocked?: Array, - settings?: any, - app_welcome_version?: number, - sharing_3P?: boolean, - }, -}; - -function extractUserState(rawObj: SharedData) { - if (rawObj && rawObj.version === '0.1' && rawObj.value) { - const { - subscriptions, - tags, - blocked, - settings, - app_welcome_version, - sharing_3P, - } = rawObj.value; - - return { - ...(subscriptions ? { subscriptions } : {}), - ...(tags ? { tags } : {}), - ...(blocked ? { blocked } : {}), - ...(settings ? { settings } : {}), - ...(app_welcome_version ? { app_welcome_version } : {}), - ...(sharing_3P ? { sharing_3P } : {}), - }; - } - - return {}; -} - -export function doPopulateSharedUserState(sharedSettings: any) { - return (dispatch: Dispatch) => { - const { - subscriptions, - tags, - blocked, - settings, - app_welcome_version, - sharing_3P, - } = extractUserState(sharedSettings); - dispatch({ - type: ACTIONS.USER_STATE_POPULATE, - data: { - subscriptions, - tags, - blocked, - settings, - welcomeVersion: app_welcome_version, - allowAnalytics: sharing_3P, - }, - }); - }; -} - -export function doPreferenceSet( - key: string, - value: any, - version: string, - success: Function, - fail: Function -) { - const preference = { - type: typeof value, - version, - value, - }; - - const options = { - key, - value: JSON.stringify(preference), - }; - - Lbry.preference_set(options) - .then(() => { - success(preference); - }) - .catch(() => { - if (fail) { - fail(); - } - }); -} - -export function doPreferenceGet(key: string, success: Function, fail?: Function) { - const options = { - key, - }; - - Lbry.preference_get(options) - .then(result => { - if (result) { - const preference = result[key]; - return success(preference); - } - - return success(null); - }) - .catch(err => { - if (fail) { - fail(err); - } - }); -} diff --git a/src/redux/actions/tags.js b/src/redux/actions/tags.js deleted file mode 100644 index cd7568b..0000000 --- a/src/redux/actions/tags.js +++ /dev/null @@ -1,24 +0,0 @@ -// @flow -import * as ACTIONS from 'constants/action_types'; -import Lbry from 'lbry'; - -export const doToggleTagFollow = (name: string) => ({ - type: ACTIONS.TOGGLE_TAG_FOLLOW, - data: { - name, - }, -}); - -export const doAddTag = (name: string) => ({ - type: ACTIONS.TAG_ADD, - data: { - name, - }, -}); - -export const doDeleteTag = (name: string) => ({ - type: ACTIONS.TAG_DELETE, - data: { - name, - }, -}); diff --git a/src/redux/actions/wallet.js b/src/redux/actions/wallet.js index 949ada5..74aa062 100644 --- a/src/redux/actions/wallet.js +++ b/src/redux/actions/wallet.js @@ -1,51 +1,49 @@ import * as ACTIONS from 'constants/action_types'; import Lbry from 'lbry'; import { doToast } from 'redux/actions/notifications'; -import { - selectBalance, - selectPendingSupportTransactions, - selectTxoPageParams, -} from 'redux/selectors/wallet'; -import { creditsToString } from 'util/format-credits'; -import { selectMyClaimsRaw } from 'redux/selectors/claims'; -import { doFetchChannelListMine, doFetchClaimListMine } from 'redux/actions/claims'; +import { selectBalance } from 'redux/selectors/wallet'; +import { creditsToString } from 'util/formatCredits'; -let walletBalancePromise = null; export function doUpdateBalance() { return (dispatch, getState) => { const { - wallet: { totalBalance: totalInStore }, + wallet: { balance: balanceInStore }, } = getState(); - - if (walletBalancePromise === null) { - walletBalancePromise = Lbry.wallet_balance() - .then(response => { - walletBalancePromise = null; - - const { available, reserved, reserved_subtotals, total } = response; - const { claims, supports, tips } = reserved_subtotals; - const totalFloat = parseFloat(total); - - if (totalInStore !== totalFloat) { - dispatch({ - type: ACTIONS.UPDATE_BALANCE, - data: { - totalBalance: totalFloat, - balance: parseFloat(available), - reservedBalance: parseFloat(reserved), - claimsBalance: parseFloat(claims), - supportsBalance: parseFloat(supports), - tipsBalance: parseFloat(tips), - }, - }); - } - }) - .catch(() => { - walletBalancePromise = null; + Lbry.account_balance().then(balanceAsString => { + const balance = parseFloat(balanceAsString); + if (balanceInStore !== balance) { + dispatch({ + type: ACTIONS.UPDATE_BALANCE, + data: { + balance, + }, }); - } + } + }); + }; +} - return walletBalancePromise; +export function doUpdateTotalBalance() { + return (dispatch, getState) => { + const { + wallet: { totalBalance: totalBalanceInStore }, + } = getState(); + Lbry.account_list().then(accountList => { + const { lbc_mainnet: accounts } = accountList; + const totalSatoshis = + accounts.length === 1 + ? accounts[0].satoshis + : accounts.reduce((a, b) => a.satoshis + b.satoshis); + const totalBalance = (Number.isNaN(totalSatoshis) ? 0 : totalSatoshis) / 10 ** 8; + if (totalBalanceInStore !== totalBalance) { + dispatch({ + type: ACTIONS.UPDATE_TOTAL_BALANCE, + data: { + totalBalance, + }, + }); + } + }); }; } @@ -56,75 +54,38 @@ export function doBalanceSubscribe() { }; } -export function doFetchTransactions(page = 1, pageSize = 99999) { +export function doTotalBalanceSubscribe() { + return dispatch => { + dispatch(doUpdateTotalBalance()); + setInterval(() => dispatch(doUpdateTotalBalance()), 5000); + }; +} + +export function doFetchTransactions() { return dispatch => { - dispatch(doFetchSupports()); dispatch({ type: ACTIONS.FETCH_TRANSACTIONS_STARTED, }); Lbry.utxo_release() - .then(() => Lbry.transaction_list({ page, page_size: pageSize })) - .then(result => { + .then(() => Lbry.transaction_list()) + .then(results => { dispatch({ type: ACTIONS.FETCH_TRANSACTIONS_COMPLETED, data: { - transactions: result.items, + transactions: results, }, }); }); }; } -export function doFetchTxoPage() { - return (dispatch, getState) => { - dispatch({ - type: ACTIONS.FETCH_TXO_PAGE_STARTED, - }); - - const state = getState(); - const queryParams = selectTxoPageParams(state); - - Lbry.utxo_release() - .then(() => Lbry.txo_list(queryParams)) - .then(res => { - dispatch({ - type: ACTIONS.FETCH_TXO_PAGE_COMPLETED, - data: res, - }); - }) - .catch(e => { - dispatch({ - type: ACTIONS.FETCH_TXO_PAGE_COMPLETED, - data: e.message, - }); - }); - }; -} - -export function doUpdateTxoPageParams(params) { +export function doFetchBlock(height) { return dispatch => { - dispatch({ - type: ACTIONS.UPDATE_TXO_FETCH_PARAMS, - data: params, - }); - - dispatch(doFetchTxoPage()); - }; -} - -export function doFetchSupports(page = 1, pageSize = 99999) { - return dispatch => { - dispatch({ - type: ACTIONS.FETCH_SUPPORTS_STARTED, - }); - - Lbry.support_list({ page, page_size: pageSize }).then(result => { + Lbry.block_show({ height }).then(block => { dispatch({ - type: ACTIONS.FETCH_SUPPORTS_COMPLETED, - data: { - supports: result.items, - }, + type: ACTIONS.FETCH_BLOCK_SUCCESS, + data: { block }, }); }); }; @@ -169,8 +130,8 @@ export function doSendDraftTransaction(address, amount) { if (balance - amount <= 0) { dispatch( doToast({ - title: __('Insufficient credits'), - message: __('Insufficient credits'), + title: 'Insufficient credits', + message: 'Insufficient credits', }) ); return; @@ -187,8 +148,8 @@ export function doSendDraftTransaction(address, amount) { }); dispatch( doToast({ - message: __(`You sent ${amount} LBC`), - linkText: __('History'), + message: `You sent ${amount} LBC`, + linkText: 'History', linkTarget: '/wallet', }) ); @@ -199,7 +160,7 @@ export function doSendDraftTransaction(address, amount) { }); dispatch( doToast({ - message: __('Transaction failed'), + message: 'Transaction failed', isError: true, }) ); @@ -213,13 +174,13 @@ export function doSendDraftTransaction(address, amount) { }); dispatch( doToast({ - message: __('Transaction failed'), + message: 'Transaction failed', isError: true, }) ); }; - Lbry.wallet_send({ + Lbry.account_send({ addresses: [address], amount: creditsToString(amount), }).then(successCallback, errorCallback); @@ -240,19 +201,15 @@ export function doSetDraftTransactionAddress(address) { }; } -export function doSendTip(params, isSupport, successCallback, errorCallback) { +export function doSendTip(amount, claimId, uri, successCallback, errorCallback) { return (dispatch, getState) => { const state = getState(); const balance = selectBalance(state); - const myClaims = selectMyClaimsRaw(state); - const shouldSupport = - isSupport || (myClaims ? myClaims.find(claim => claim.claim_id === params.claim_id) : false); - - if (balance - params.amount <= 0) { + if (balance - amount <= 0) { dispatch( doToast({ - message: __('Insufficient credits'), + message: 'Insufficient credits', isError: true, }) ); @@ -262,11 +219,9 @@ export function doSendTip(params, isSupport, successCallback, errorCallback) { const success = () => { dispatch( doToast({ - message: shouldSupport - ? __('You deposited %amount% LBC as a support!', { amount: params.amount }) - : __('You sent %amount% LBC as a tip, Mahalo!', { amount: params.amount }), + message: __(`You sent ${amount} LBC as a tip, Mahalo!`), linkText: __('History'), - linkTarget: '/wallet', + linkTarget: __('/wallet'), }) ); @@ -304,27 +259,20 @@ export function doSendTip(params, isSupport, successCallback, errorCallback) { }); Lbry.support_create({ - ...params, - tip: !shouldSupport, - blocking: true, - amount: creditsToString(params.amount), + claim_id: claimId, + amount: creditsToString(amount), + tip: true, }).then(success, error); }; } -export function doClearSupport() { - return { - type: ACTIONS.CLEAR_SUPPORT_TRANSACTION, - }; -} - export function doWalletEncrypt(newPassword) { return dispatch => { dispatch({ type: ACTIONS.WALLET_ENCRYPT_START, }); - Lbry.wallet_encrypt({ new_password: newPassword }).then(result => { + Lbry.account_encrypt({ new_password: newPassword }).then(result => { if (result === true) { dispatch({ type: ACTIONS.WALLET_ENCRYPT_COMPLETED, @@ -346,7 +294,7 @@ export function doWalletUnlock(password) { type: ACTIONS.WALLET_UNLOCK_START, }); - Lbry.wallet_unlock({ password }).then(result => { + Lbry.account_unlock({ password }).then(result => { if (result === true) { dispatch({ type: ACTIONS.WALLET_UNLOCK_COMPLETED, @@ -384,62 +332,13 @@ export function doWalletLock() { }; } -export function doSupportAbandonForClaim(claimId, claimType, keep, preview) { - return dispatch => { - if (preview) { - dispatch({ - type: ACTIONS.ABANDON_CLAIM_SUPPORT_PREVIEW, - }); - } else { - dispatch({ - type: ACTIONS.ABANDON_CLAIM_SUPPORT_STARTED, - }); - } - - const params = { claim_id: claimId }; - if (preview) params['preview'] = true; - if (keep) params['keep'] = keep; - return Lbry.support_abandon(params) - .then(res => { - if (!preview) { - dispatch({ - type: ACTIONS.ABANDON_CLAIM_SUPPORT_COMPLETED, - data: { claimId, txid: res.txid, effective: res.outputs[0].amount, type: claimType }, // add to pendingSupportTransactions, - }); - dispatch(doCheckPendingTxs()); - } - return res; - }) - .catch(e => { - dispatch({ - type: ACTIONS.ABANDON_CLAIM_SUPPORT_FAILED, - data: e.message, - }); - }); - }; -} - -export function doWalletReconnect() { - return dispatch => { - dispatch({ - type: ACTIONS.WALLET_RESTART, - }); - // this basically returns null when it's done. :( - // might be good to dispatch ACTIONS.WALLET_RESTARTED - Lbry.wallet_reconnect().then(() => - dispatch({ - type: ACTIONS.WALLET_RESTART_COMPLETED, - }) - ); - }; -} export function doWalletDecrypt() { return dispatch => { dispatch({ type: ACTIONS.WALLET_DECRYPT_START, }); - Lbry.wallet_decrypt().then(result => { + Lbry.account_decrypt().then(result => { if (result === true) { dispatch({ type: ACTIONS.WALLET_DECRYPT_COMPLETED, @@ -461,11 +360,11 @@ export function doWalletStatus() { type: ACTIONS.WALLET_STATUS_START, }); - Lbry.wallet_status().then(status => { - if (status) { + Lbry.status().then(status => { + if (status && status.wallet) { dispatch({ type: ACTIONS.WALLET_STATUS_COMPLETED, - result: status.is_encrypted, + result: status.wallet.is_encrypted, }); } }); @@ -490,61 +389,3 @@ export function doUpdateBlockHeight() { } }); } - -// Calls transaction_show on txes until any pending txes are confirmed -export const doCheckPendingTxs = () => (dispatch, getState) => { - const state = getState(); - const pendingTxsById = selectPendingSupportTransactions(state); // {} - if (!Object.keys(pendingTxsById).length) { - return; - } - let txCheckInterval; - const checkTxList = () => { - const state = getState(); - const pendingTxs = selectPendingSupportTransactions(state); // {} - const promises = []; - const newPendingTxes = {}; - const types = new Set([]); - let changed = false; - Object.entries(pendingTxs).forEach(([claim, data]) => { - promises.push(Lbry.transaction_show({ txid: data.txid })); - types.add(data.type); - }); - - Promise.all(promises) - .then(txShows => { - txShows.forEach(result => { - if (result.height <= 0) { - const entries = Object.entries(pendingTxs); - const match = entries.find(entry => entry[1].txid === result.txid); - newPendingTxes[match[0]] = match[1]; - } else { - changed = true; - } - }); - }) - .then(() => { - if (changed) { - dispatch({ - type: ACTIONS.PENDING_SUPPORTS_UPDATED, - data: newPendingTxes, - }); - if (types.has('channel')) { - dispatch(doFetchChannelListMine()); - } - if (types.has('stream')) { - dispatch(doFetchClaimListMine()); - } - } - if (Object.keys(newPendingTxes).length === 0) clearInterval(txCheckInterval); - }); - - if (!Object.keys(pendingTxsById).length) { - clearInterval(txCheckInterval); - } - }; - - txCheckInterval = setInterval(() => { - checkTxList(); - }, 30000); -}; diff --git a/src/redux/middleware/shared-state.js b/src/redux/middleware/shared-state.js deleted file mode 100644 index a211b16..0000000 --- a/src/redux/middleware/shared-state.js +++ /dev/null @@ -1,51 +0,0 @@ -// @flow -import isEqual from 'util/deep-equal'; -import { doPreferenceSet } from 'redux/actions/sync'; - -const SHARED_PREFERENCE_KEY = 'shared'; -const SHARED_PREFERENCE_VERSION = '0.1'; -let oldShared = {}; - -export const buildSharedStateMiddleware = ( - actions: Array, - sharedStateFilters: {}, - sharedStateCb?: any => void -) => ({ getState, dispatch }: { getState: () => {}, dispatch: any => void }) => ( - next: ({}) => void -) => (action: { type: string, data: any }) => { - const currentState = getState(); - - // We don't care if sync is disabled here, we always want to backup preferences to the wallet - if (!actions.includes(action.type)) { - return next(action); - } - - const actionResult = next(action); - // Call `getState` after calling `next` to ensure the state has updated in response to the action - const nextState = getState(); - const shared = {}; - - Object.keys(sharedStateFilters).forEach(key => { - const filter = sharedStateFilters[key]; - const { source, property, transform } = filter; - let value = nextState[source][property]; - if (transform) { - value = transform(value); - } - - shared[key] = value; - }); - - if (!isEqual(oldShared, shared)) { - // only update if the preference changed from last call in the same session - oldShared = shared; - doPreferenceSet(SHARED_PREFERENCE_KEY, shared, SHARED_PREFERENCE_VERSION); - } - - if (sharedStateCb) { - // Pass dispatch to the callback to consumers can dispatch actions in response to preference set - sharedStateCb({ dispatch, getState }); - } - - return actionResult; -}; diff --git a/src/redux/reducers/blocked.js b/src/redux/reducers/blocked.js deleted file mode 100644 index c688936..0000000 --- a/src/redux/reducers/blocked.js +++ /dev/null @@ -1,41 +0,0 @@ -// @flow -import * as ACTIONS from 'constants/action_types'; -import { handleActions } from 'util/redux-utils'; - -const defaultState: BlocklistState = { - blockedChannels: [], -}; - -export const blockedReducer = handleActions( - { - [ACTIONS.TOGGLE_BLOCK_CHANNEL]: ( - state: BlocklistState, - action: BlocklistAction - ): BlocklistState => { - const { blockedChannels } = state; - const { uri } = action.data; - let newBlockedChannels = blockedChannels.slice(); - - if (newBlockedChannels.includes(uri)) { - newBlockedChannels = newBlockedChannels.filter(id => id !== uri); - } else { - newBlockedChannels.push(uri); - } - - return { - blockedChannels: newBlockedChannels, - }; - }, - [ACTIONS.USER_STATE_POPULATE]: ( - state: BlocklistState, - action: { data: { blocked: ?Array } } - ) => { - const { blocked } = action.data; - return { - ...state, - blockedChannels: blocked && blocked.length ? blocked : state.blockedChannels, - }; - }, - }, - defaultState -); diff --git a/src/redux/reducers/claims.js b/src/redux/reducers/claims.js index 1de07d5..b4a81e9 100644 --- a/src/redux/reducers/claims.js +++ b/src/redux/reducers/claims.js @@ -9,159 +9,75 @@ // - Sean import * as ACTIONS from 'constants/action_types'; -import mergeClaim from 'util/merge-claim'; +import { buildURI, parseURI } from 'lbryURI'; type State = { - createChannelError: ?string, channelClaimCounts: { [string]: number }, claimsByUri: { [string]: string }, - byId: { [string]: Claim }, + byId: { [string]: StreamClaim | ChannelClaim }, resolvingUris: Array, - pendingIds: Array, - reflectingById: { [string]: ReflectingUpdate }, - myClaims: ?Array, - myChannelClaims: ?Array, + pendingById: { [string]: StreamClaim | ChannelClaim }, + myChannelClaims: Set, abandoningById: { [string]: boolean }, fetchingChannelClaims: { [string]: number }, fetchingMyChannels: boolean, - fetchingClaimSearchByQuery: { [string]: boolean }, - purchaseUriSuccess: boolean, - myPurchases: ?Array, - myPurchasesPageNumber: ?number, - myPurchasesPageTotalResults: ?number, - fetchingMyPurchases: boolean, - fetchingMyPurchasesError: ?string, - claimSearchByQuery: { [string]: Array }, - claimSearchByQueryLastPageReached: { [string]: Array }, - creatingChannel: boolean, - paginatedClaimsByChannel: { + claimsByChannel: { [string]: { all: Array, - pageCount: number, - itemCount: number, [number]: Array, }, }, - updateChannelError: ?string, - updatingChannel: boolean, - pendingChannelImport: string | boolean, - repostLoading: boolean, - repostError: ?string, - fetchingClaimListMinePageError: ?string, - myClaimsPageResults: Array, - myClaimsPageNumber: ?number, - myClaimsPageTotalResults: ?number, - isFetchingClaimListMine: boolean, - isCheckingNameForPublish: boolean, - checkingPending: boolean, - checkingReflecting: boolean, }; const reducers = {}; const defaultState = { byId: {}, claimsByUri: {}, - paginatedClaimsByChannel: {}, + claimsByChannel: {}, channelClaimCounts: {}, fetchingChannelClaims: {}, resolvingUris: [], - myChannelClaims: undefined, - myClaims: undefined, - myPurchases: undefined, - myPurchasesPageNumber: undefined, - myPurchasesPageTotalResults: undefined, - purchaseUriSuccess: false, - fetchingMyPurchases: false, - fetchingMyPurchasesError: undefined, + // This should not be a Set + // Storing sets in reducers can cause issues + myChannelClaims: new Set(), fetchingMyChannels: false, abandoningById: {}, - pendingIds: [], - reflectingById: {}, - claimSearchError: false, - claimSearchByQuery: {}, - claimSearchByQueryLastPageReached: {}, - fetchingClaimSearchByQuery: {}, - updateChannelError: '', - updatingChannel: false, - creatingChannel: false, - createChannelError: undefined, - pendingChannelImport: false, - repostLoading: false, - repostError: undefined, - fetchingClaimListMinePageError: undefined, - myClaimsPageResults: [], - myClaimsPageNumber: undefined, - myClaimsPageTotalResults: undefined, - isFetchingClaimListMine: false, - isFetchingMyPurchases: false, - isCheckingNameForPublish: false, - checkingPending: false, - checkingReflecting: false, + pendingById: {}, }; -function handleClaimAction(state: State, action: any): State { - const { - resolveInfo, - }: { - [string]: { - stream: ?StreamClaim, - channel: ?ChannelClaim, - claimsInChannel: ?number, - }, - } = action.data; - +reducers[ACTIONS.RESOLVE_URIS_COMPLETED] = (state: State, action: any): State => { + const { resolveInfo }: { [string]: ClaimWithPossibleCertificate } = action.data; const byUri = Object.assign({}, state.claimsByUri); const byId = Object.assign({}, state.byId); const channelClaimCounts = Object.assign({}, state.channelClaimCounts); - const pendingIds = state.pendingIds; - let newResolvingUrls = new Set(state.resolvingUris); - Object.entries(resolveInfo).forEach(([url: string, resolveResponse: ResolveResponse]) => { - // $FlowFixMe - const { claimsInChannel, stream, channel } = resolveResponse; - - if (stream) { - if (pendingIds.includes(stream.claim_id)) { - byId[stream.claim_id] = mergeClaim(stream, byId[stream.claim_id]); - } else { - byId[stream.claim_id] = stream; + Object.entries(resolveInfo).forEach( + ([uri: string, resolveResponse: ClaimWithPossibleCertificate]) => { + // $FlowFixMe + if (resolveResponse.certificate && !Number.isNaN(resolveResponse.claimsInChannel)) { + // $FlowFixMe + channelClaimCounts[uri] = resolveResponse.claimsInChannel; } - byUri[url] = stream.claim_id; - - // If url isn't a canonical_url, make sure that is added too - byUri[stream.canonical_url] = stream.claim_id; - - // Also add the permanent_url here until lighthouse returns canonical_url for search results - byUri[stream.permanent_url] = stream.claim_id; - newResolvingUrls.delete(stream.canonical_url); - newResolvingUrls.delete(stream.permanent_url); } + ); - if (channel && channel.claim_id) { - if (!stream) { - byUri[url] = channel.claim_id; - } + // $FlowFixMe + Object.entries(resolveInfo).forEach(([uri, { certificate, claim }]) => { + if (claim && !certificate) { + byId[claim.claim_id] = claim; + byUri[uri] = claim.claim_id; + } else if (claim && certificate) { + byId[claim.claim_id] = claim; + byUri[uri] = claim.claim_id; - if (claimsInChannel) { - channelClaimCounts[url] = claimsInChannel; - channelClaimCounts[channel.canonical_url] = claimsInChannel; - } - - if (pendingIds.includes(channel.claim_id)) { - byId[channel.claim_id] = mergeClaim(channel, byId[channel.claim_id]); - } else { - byId[channel.claim_id] = channel; - } - // Also add the permanent_url here until lighthouse returns canonical_url for search results - byUri[channel.permanent_url] = channel.claim_id; - byUri[channel.canonical_url] = channel.claim_id; - newResolvingUrls.delete(channel.canonical_url); - newResolvingUrls.delete(channel.permanent_url); - } - - newResolvingUrls.delete(url); - if (!stream && !channel && !pendingIds.includes(byUri[url])) { - byUri[url] = null; + byId[certificate.claim_id] = certificate; + const channelUri = `lbry://${certificate.name}#${certificate.claim_id}`; + byUri[channelUri] = certificate.claim_id; + } else if (!claim && certificate) { + byId[certificate.claim_id] = certificate; + byUri[uri] = certificate.claim_id; + } else { + byUri[uri] = null; } }); @@ -169,31 +85,8 @@ function handleClaimAction(state: State, action: any): State { byId, claimsByUri: byUri, channelClaimCounts, - resolvingUris: Array.from(newResolvingUrls), + resolvingUris: (state.resolvingUris || []).filter(uri => !resolveInfo[uri]), }); -} - -reducers[ACTIONS.RESOLVE_URIS_STARTED] = (state: State, action: any): State => { - const { uris }: { uris: Array } = action.data; - - const oldResolving = state.resolvingUris || []; - const newResolving = oldResolving.slice(); - - uris.forEach(uri => { - if (!newResolving.includes(uri)) { - newResolving.push(uri); - } - }); - - return Object.assign({}, state, { - resolvingUris: newResolving, - }); -}; - -reducers[ACTIONS.RESOLVE_URIS_COMPLETED] = (state: State, action: any): State => { - return { - ...handleClaimAction(state, action), - }; }; reducers[ACTIONS.FETCH_CLAIM_LIST_MINE_STARTED] = (state: State): State => @@ -202,47 +95,44 @@ reducers[ACTIONS.FETCH_CLAIM_LIST_MINE_STARTED] = (state: State): State => }); reducers[ACTIONS.FETCH_CLAIM_LIST_MINE_COMPLETED] = (state: State, action: any): State => { - const { result, resolve }: { result: ClaimListResponse, resolve: boolean } = action.data; - const claims = result.items; - const page = result.page; - const totalItems = result.total_items; - + const { claims }: { claims: Array } = action.data; const byId = Object.assign({}, state.byId); const byUri = Object.assign({}, state.claimsByUri); - const pendingIds = state.pendingIds || []; - let myClaimIds = new Set(state.myClaims); - let urlsForCurrentPage = []; + const pendingById: { [string]: StreamClaim | ChannelClaim } = Object.assign( + {}, + state.pendingById + ); - const pendingIdSet = new Set(pendingIds); + claims.forEach((claim: StreamClaim | ChannelClaim) => { + const uri = buildURI({ claimName: claim.name, claimId: claim.claim_id }); - claims.forEach((claim: Claim) => { - const { permanent_url: permanentUri, claim_id: claimId } = claim; if (claim.type && claim.type.match(/claim|update/)) { - urlsForCurrentPage.push(permanentUri); if (claim.confirmations < 1) { - pendingIdSet.add(claimId); - } else if (!resolve && pendingIdSet.has(claimId) && claim.confirmations > 0) { - pendingIdSet.delete(claimId); - } - if (pendingIds.includes(claimId)) { - byId[claimId] = mergeClaim(claim, byId[claimId]); + pendingById[claim.claim_id] = claim; + delete byId[claim.claim_id]; + delete byUri[claim.claim_id]; } else { - byId[claimId] = claim; + byId[claim.claim_id] = claim; + byUri[uri] = claim.claim_id; } - byUri[permanentUri] = claimId; - myClaimIds.add(claimId); } }); + // Remove old pending publishes + Object.values(pendingById) + // $FlowFixMe + .filter(pendingClaim => byId[pendingClaim.claim_id]) + .forEach(pendingClaim => { + // $FlowFixMe + delete pendingById[pendingClaim.claim_id]; + }); + return Object.assign({}, state, { isFetchingClaimListMine: false, - myClaims: Array.from(myClaimIds), + myClaims: claims, byId, - pendingIds: Array.from(pendingIdSet), claimsByUri: byUri, - myClaimsPageResults: urlsForCurrentPage, - myClaimsPageNumber: page, - myClaimsPageTotalResults: totalItems, + pendingById, }); }; @@ -251,51 +141,18 @@ reducers[ACTIONS.FETCH_CHANNEL_LIST_STARTED] = (state: State): State => reducers[ACTIONS.FETCH_CHANNEL_LIST_COMPLETED] = (state: State, action: any): State => { const { claims }: { claims: Array } = action.data; - const myClaims = state.myClaims || []; - let myClaimIds = new Set(state.myClaims); - const pendingIds = state.pendingIds || []; - let myChannelClaims; + const myChannelClaims = new Set(state.myChannelClaims); const byId = Object.assign({}, state.byId); - const byUri = Object.assign({}, state.claimsByUri); - const channelClaimCounts = Object.assign({}, state.channelClaimCounts); - if (!claims.length) { - // $FlowFixMe - myChannelClaims = null; - } else { - myChannelClaims = new Set(state.myChannelClaims); - claims.forEach(claim => { - const { meta } = claim; - const { claims_in_channel: claimsInChannel } = claim.meta; - const { canonical_url: canonicalUrl, permanent_url: permanentUrl, claim_id: claimId } = claim; - - byUri[canonicalUrl] = claimId; - byUri[permanentUrl] = claimId; - channelClaimCounts[canonicalUrl] = claimsInChannel; - channelClaimCounts[permanentUrl] = claimsInChannel; - - // $FlowFixMe - myChannelClaims.add(claimId); - if (!pendingIds.some(c => c === claimId)) { - byId[claimId] = claim; - } - myClaimIds.add(claimId); - }); - } + claims.forEach(claim => { + myChannelClaims.add(claim.claim_id); + byId[claim.claim_id] = claim; + }); return Object.assign({}, state, { byId, - claimsByUri: byUri, - channelClaimCounts, - fetchingMyChannels: false, - myChannelClaims: myChannelClaims ? Array.from(myChannelClaims) : null, - myClaims: myClaimIds ? Array.from(myClaimIds) : null, - }); -}; - -reducers[ACTIONS.FETCH_CHANNEL_LIST_FAILED] = (state: State, action: any): State => { - return Object.assign({}, state, { fetchingMyChannels: false, + myChannelClaims, }); }; @@ -315,25 +172,11 @@ reducers[ACTIONS.FETCH_CHANNEL_CLAIMS_COMPLETED] = (state: State, action: any): const { uri, claims, - claimsInChannel, page, - totalPages, - }: { - uri: string, - claims: Array, - claimsInChannel?: number, - page: number, - totalPages: number, - } = action.data; + }: { uri: string, claims: Array, page: number } = action.data; - // byChannel keeps claim_search relevant results by page. If the total changes, erase it. - const channelClaimCounts = Object.assign({}, state.channelClaimCounts); - - const paginatedClaimsByChannel = Object.assign({}, state.paginatedClaimsByChannel); - // check if count has changed - that means cached pagination will be wrong, so clear it - const previousCount = paginatedClaimsByChannel[uri] && paginatedClaimsByChannel[uri]['itemCount']; - const byChannel = - claimsInChannel === previousCount ? Object.assign({}, paginatedClaimsByChannel[uri]) : {}; + const claimsByChannel = Object.assign({}, state.claimsByChannel); + const byChannel = Object.assign({}, claimsByChannel[uri]); const allClaimIds = new Set(byChannel.all); const currentPageClaimIds = []; const byId = Object.assign({}, state.byId); @@ -345,23 +188,20 @@ reducers[ACTIONS.FETCH_CHANNEL_CLAIMS_COMPLETED] = (state: State, action: any): allClaimIds.add(claim.claim_id); currentPageClaimIds.push(claim.claim_id); byId[claim.claim_id] = claim; - claimsByUri[claim.canonical_url] = claim.claim_id; + claimsByUri[`lbry://${claim.name}#${claim.claim_id}`] = claim.claim_id; }); } byChannel.all = allClaimIds; - byChannel.pageCount = totalPages; - byChannel.itemCount = claimsInChannel; byChannel[page] = currentPageClaimIds; - paginatedClaimsByChannel[uri] = byChannel; + claimsByChannel[uri] = byChannel; delete fetchingChannelClaims[uri]; return Object.assign({}, state, { - paginatedClaimsByChannel, + claimsByChannel, byId, fetchingChannelClaims, claimsByUri, - channelClaimCounts, currentChannelPage: page, }); }; @@ -377,76 +217,9 @@ reducers[ACTIONS.ABANDON_CLAIM_STARTED] = (state: State, action: any): State => }); }; -reducers[ACTIONS.UPDATE_PENDING_CLAIMS] = (state: State, action: any): State => { - const { claims: pendingClaims }: { claims: Array } = action.data; - const byId = Object.assign({}, state.byId); - const byUri = Object.assign({}, state.claimsByUri); - const pendingIds = state.pendingIds; - const pendingIdSet = new Set(pendingIds); - let myClaimIds = new Set(state.myClaims); - const myChannelClaims = new Set(state.myChannelClaims); - - // $FlowFixMe - pendingClaims.forEach((claim: Claim) => { - let newClaim; - const { permanent_url: uri, claim_id: claimId, type, value_type: valueType } = claim; - pendingIdSet.add(claimId); - const oldClaim = byId[claimId]; - if (oldClaim && oldClaim.canonical_url) { - newClaim = mergeClaim(oldClaim, claim); - } else { - newClaim = claim; - } - if (valueType === 'channel') { - myChannelClaims.add(claimId); - } - - if (type && type.match(/claim|update/)) { - byId[claimId] = newClaim; - byUri[uri] = claimId; - } - myClaimIds.add(claimId); - }); - return Object.assign({}, state, { - myClaims: Array.from(myClaimIds), - byId, - myChannelClaims: Array.from(myChannelClaims), - claimsByUri: byUri, - pendingIds: Array.from(pendingIdSet), - }); -}; - -reducers[ACTIONS.UPDATE_CONFIRMED_CLAIMS] = (state: State, action: any): State => { - const { claims: confirmedClaims }: { claims: Array } = action.data; - const byId = Object.assign({}, state.byId); - const byUri = Object.assign({}, state.claimsByUri); - const pendingIds = state.pendingIds; - const pendingIdSet = new Set(pendingIds); - - confirmedClaims.forEach((claim: GenericClaim) => { - const { permanent_url: permanentUri, claim_id: claimId, type } = claim; - let newClaim = claim; - const oldClaim = byId[claimId]; - if (oldClaim && oldClaim.canonical_url) { - newClaim = mergeClaim(oldClaim, claim); - } - if (type && type.match(/claim|update|channel/)) { - byId[claimId] = newClaim; - pendingIdSet.delete(claimId); - } - }); - return Object.assign({}, state, { - pendingIds: Array.from(pendingIdSet), - byId, - claimsByUri: byUri, - }); -}; - reducers[ACTIONS.ABANDON_CLAIM_SUCCEEDED] = (state: State, action: any): State => { const { claimId }: { claimId: string } = action.data; const byId = Object.assign({}, state.byId); - const newMyClaims = state.myClaims ? state.myClaims.slice() : []; - const newMyChannelClaims = state.myChannelClaims ? state.myChannelClaims.slice() : []; const claimsByUri = Object.assign({}, state.claimsByUri); Object.keys(claimsByUri).forEach(uri => { @@ -454,294 +227,46 @@ reducers[ACTIONS.ABANDON_CLAIM_SUCCEEDED] = (state: State, action: any): State = delete claimsByUri[uri]; } }); - const myClaims = newMyClaims.filter(i => i !== claimId); - const myChannelClaims = newMyChannelClaims.filter(i => i !== claimId); delete byId[claimId]; return Object.assign({}, state, { - myClaims, - myChannelClaims, byId, claimsByUri, }); }; -reducers[ACTIONS.CLEAR_CHANNEL_ERRORS] = (state: State): State => ({ - ...state, - createChannelError: null, - updateChannelError: null, -}); - -reducers[ACTIONS.CREATE_CHANNEL_STARTED] = (state: State): State => ({ - ...state, - creatingChannel: true, - createChannelError: null, -}); - reducers[ACTIONS.CREATE_CHANNEL_COMPLETED] = (state: State, action: any): State => { - return Object.assign({}, state, { - creatingChannel: false, - }); -}; + const channelClaim: ChannelClaim = action.data.channelClaim; + const byId = Object.assign({}, state.byId); + const myChannelClaims = new Set(state.myChannelClaims); -reducers[ACTIONS.CREATE_CHANNEL_FAILED] = (state: State, action: any): State => { - return Object.assign({}, state, { - creatingChannel: false, - createChannelError: action.data, - }); -}; - -reducers[ACTIONS.UPDATE_CHANNEL_STARTED] = (state: State, action: any): State => { - return Object.assign({}, state, { - updateChannelError: '', - updatingChannel: true, - }); -}; - -reducers[ACTIONS.UPDATE_CHANNEL_COMPLETED] = (state: State, action: any): State => { - return Object.assign({}, state, { - updateChannelError: '', - updatingChannel: false, - }); -}; - -reducers[ACTIONS.UPDATE_CHANNEL_FAILED] = (state: State, action: any): State => { - return Object.assign({}, state, { - updateChannelError: action.data.message, - updatingChannel: false, - }); -}; - -reducers[ACTIONS.IMPORT_CHANNEL_STARTED] = (state: State): State => - Object.assign({}, state, { pendingChannelImports: true }); - -reducers[ACTIONS.IMPORT_CHANNEL_COMPLETED] = (state: State): State => - Object.assign({}, state, { pendingChannelImports: false }); - -reducers[ACTIONS.CLAIM_SEARCH_STARTED] = (state: State, action: any): State => { - const fetchingClaimSearchByQuery = Object.assign({}, state.fetchingClaimSearchByQuery); - fetchingClaimSearchByQuery[action.data.query] = true; + byId[channelClaim.claim_id] = channelClaim; + myChannelClaims.add(channelClaim.claim_id); return Object.assign({}, state, { - fetchingClaimSearchByQuery, - }); -}; - -reducers[ACTIONS.CLAIM_SEARCH_COMPLETED] = (state: State, action: any): State => { - const fetchingClaimSearchByQuery = Object.assign({}, state.fetchingClaimSearchByQuery); - const claimSearchByQuery = Object.assign({}, state.claimSearchByQuery); - const claimSearchByQueryLastPageReached = Object.assign( - {}, - state.claimSearchByQueryLastPageReached - ); - const { append, query, urls, pageSize } = action.data; - - if (append) { - // todo: check for duplicate urls when concatenating? - claimSearchByQuery[query] = - claimSearchByQuery[query] && claimSearchByQuery[query].length - ? claimSearchByQuery[query].concat(urls) - : urls; - } else { - claimSearchByQuery[query] = urls; - } - - // the returned number of urls is less than the page size, so we're on the last page - claimSearchByQueryLastPageReached[query] = urls.length < pageSize; - - delete fetchingClaimSearchByQuery[query]; - - return Object.assign({}, state, { - ...handleClaimAction(state, action), - claimSearchByQuery, - claimSearchByQueryLastPageReached, - fetchingClaimSearchByQuery, - }); -}; - -reducers[ACTIONS.CLAIM_SEARCH_FAILED] = (state: State, action: any): State => { - const { query } = action.data; - const claimSearchByQuery = Object.assign({}, state.claimSearchByQuery); - const fetchingClaimSearchByQuery = Object.assign({}, state.fetchingClaimSearchByQuery); - - delete fetchingClaimSearchByQuery[query]; - claimSearchByQuery[query] = null; - - return Object.assign({}, state, { - fetchingClaimSearchByQuery, - claimSearchByQuery, - }); -}; - -reducers[ACTIONS.CLAIM_REPOST_STARTED] = (state: State): State => { - return { - ...state, - repostLoading: true, - repostError: null, - }; -}; -reducers[ACTIONS.CLAIM_REPOST_COMPLETED] = (state: State, action: any): State => { - const { originalClaimId, repostClaim } = action.data; - const byId = { ...state.byId }; - const claimsByUri = { ...state.claimsByUri }; - const claimThatWasReposted = byId[originalClaimId]; - - const repostStub = { ...repostClaim, reposted_claim: claimThatWasReposted }; - byId[repostStub.claim_id] = repostStub; - claimsByUri[repostStub.permanent_url] = repostStub.claim_id; - - return { - ...state, byId, - claimsByUri, - repostLoading: false, - repostError: null, - }; -}; -reducers[ACTIONS.CLAIM_REPOST_FAILED] = (state: State, action: any): State => { - const { error } = action.data; - - return { - ...state, - repostLoading: false, - repostError: error, - }; -}; -reducers[ACTIONS.CLEAR_REPOST_ERROR] = (state: State): State => { - return { - ...state, - repostError: null, - }; -}; -reducers[ACTIONS.ADD_FILES_REFLECTING] = (state: State, action): State => { - const pendingClaim = action.data; - const { reflectingById } = state; - const claimId = pendingClaim && pendingClaim.claim_id; - - reflectingById[claimId] = { fileListItem: pendingClaim, progress: 0, stalled: false }; - - return Object.assign({}, state, { - ...state, - reflectingById: reflectingById, - }); -}; -reducers[ACTIONS.UPDATE_FILES_REFLECTING] = (state: State, action): State => { - const newReflectingById = action.data; - - return Object.assign({}, state, { - ...state, - reflectingById: newReflectingById, - }); -}; -reducers[ACTIONS.TOGGLE_CHECKING_REFLECTING] = (state: State, action): State => { - const checkingReflecting = action.data; - - return Object.assign({}, state, { - ...state, - checkingReflecting, - }); -}; -reducers[ACTIONS.TOGGLE_CHECKING_PENDING] = (state: State, action): State => { - const checking = action.data; - - return Object.assign({}, state, { - ...state, - checkingPending: checking, + myChannelClaims, }); }; -reducers[ACTIONS.PURCHASE_LIST_STARTED] = (state: State): State => { - return { - ...state, - fetchingMyPurchases: true, - fetchingMyPurchasesError: null, - }; -}; +reducers[ACTIONS.RESOLVE_URIS_STARTED] = (state: State, action: any): State => { + const { uris }: { uris: Array } = action.data; -reducers[ACTIONS.PURCHASE_LIST_COMPLETED] = (state: State, action: any): State => { - const { result }: { result: PurchaseListResponse, resolve: boolean } = action.data; - const page = result.page; - const totalItems = result.total_items; + const oldResolving = state.resolvingUris || []; + const newResolving = oldResolving.slice(); - let byId = Object.assign({}, state.byId); - let byUri = Object.assign({}, state.claimsByUri); - let urlsForCurrentPage = []; - - result.items.forEach(item => { - if (!item.claim) { - // Abandoned claim - return; + uris.forEach(uri => { + if (!newResolving.includes(uri)) { + newResolving.push(uri); } - - const { claim, ...purchaseInfo } = item; - claim.purchase_receipt = purchaseInfo; - const claimId = claim.claim_id; - const uri = claim.canonical_url; - - byId[claimId] = claim; - byUri[uri] = claimId; - urlsForCurrentPage.push(uri); }); return Object.assign({}, state, { - byId, - claimsByUri: byUri, - myPurchases: urlsForCurrentPage, - myPurchasesPageNumber: page, - myPurchasesPageTotalResults: totalItems, - fetchingMyPurchases: false, + resolvingUris: newResolving, }); }; -reducers[ACTIONS.PURCHASE_LIST_FAILED] = (state: State, action: any): State => { - const { error } = action.data; - - return { - ...state, - fetchingMyPurchases: false, - fetchingMyPurchasesError: error, - }; -}; - -reducers[ACTIONS.PURCHASE_URI_COMPLETED] = (state: State, action: any): State => { - const { uri, purchaseReceipt } = action.data; - - let byId = Object.assign({}, state.byId); - let byUri = Object.assign({}, state.claimsByUri); - let myPurchases = state.myPurchases ? state.myPurchases.slice() : []; - let urlsForCurrentPage = []; - - const claimId = byUri[uri]; - if (claimId) { - let claim = byId[claimId]; - claim.purchase_receipt = purchaseReceipt; - } - - myPurchases.push(uri); - - return { - ...state, - byId, - myPurchases, - purchaseUriSuccess: true, - }; -}; - -reducers[ACTIONS.PURCHASE_URI_FAILED] = (state: State): State => { - return { - ...state, - purchaseUriSuccess: false, - }; -}; - -reducers[ACTIONS.CLEAR_PURCHASED_URI_SUCCESS] = (state: State): State => { - return { - ...state, - purchaseUriSuccess: false, - }; -}; - export function claimsReducer(state: State = defaultState, action: any) { const handler = reducers[action.type]; if (handler) return handler(state, action); diff --git a/src/redux/reducers/comments.js b/src/redux/reducers/comments.js deleted file mode 100644 index 46d08d8..0000000 --- a/src/redux/reducers/comments.js +++ /dev/null @@ -1,153 +0,0 @@ -// @flow -import * as ACTIONS from 'constants/action_types'; -import { handleActions } from 'util/redux-utils'; - -const defaultState: CommentsState = { - commentById: {}, // commentId -> Comment - byId: {}, // ClaimID -> list of comments - commentsByUri: {}, // URI -> claimId - isLoading: false, - myComments: undefined, -}; - -export const commentReducer = handleActions( - { - [ACTIONS.COMMENT_CREATE_STARTED]: (state: CommentsState, action: any): CommentsState => ({ - ...state, - isLoading: true, - }), - - [ACTIONS.COMMENT_CREATE_FAILED]: (state: CommentsState, action: any) => ({ - ...state, - isLoading: false, - }), - - [ACTIONS.COMMENT_CREATE_COMPLETED]: (state: CommentsState, action: any): CommentsState => { - const { comment, claimId }: { comment: Comment, claimId: string } = action.data; - const commentById = Object.assign({}, state.commentById); - const byId = Object.assign({}, state.byId); - const comments = byId[claimId]; - const newCommentIds = comments.slice(); - - // add the comment by its ID - commentById[comment.comment_id] = comment; - - // push the comment_id to the top of ID list - newCommentIds.unshift(comment.comment_id); - byId[claimId] = newCommentIds; - - return { - ...state, - commentById, - byId, - isLoading: false, - }; - }, - - [ACTIONS.COMMENT_LIST_STARTED]: state => ({ ...state, isLoading: true }), - - [ACTIONS.COMMENT_LIST_COMPLETED]: (state: CommentsState, action: any) => { - const { comments, claimId, uri } = action.data; - - const commentById = Object.assign({}, state.commentById); - const byId = Object.assign({}, state.byId); - const commentsByUri = Object.assign({}, state.commentsByUri); - - if (comments) { - // we use an Array to preserve order of listing - // in reality this doesn't matter and we can just - // sort comments by their timestamp - const commentIds = Array(comments.length); - - // map the comment_ids to the new comments - for (let i = 0; i < comments.length; i++) { - commentIds[i] = comments[i].comment_id; - commentById[commentIds[i]] = comments[i]; - } - - byId[claimId] = commentIds; - commentsByUri[uri] = claimId; - } - return { - ...state, - byId, - commentById, - commentsByUri, - isLoading: false, - }; - }, - - [ACTIONS.COMMENT_LIST_FAILED]: (state: CommentsState, action: any) => ({ - ...state, - isLoading: false, - }), - [ACTIONS.COMMENT_ABANDON_STARTED]: (state: CommentsState, action: any) => ({ - ...state, - isLoading: true, - }), - [ACTIONS.COMMENT_ABANDON_COMPLETED]: (state: CommentsState, action: any) => { - const { comment_id } = action.data; - const commentById = Object.assign({}, state.commentById); - const byId = Object.assign({}, state.byId); - - // to remove the comment and its references - const claimId = commentById[comment_id].claim_id; - for (let i = 0; i < byId[claimId].length; i++) { - if (byId[claimId][i] === comment_id) { - byId[claimId].splice(i, 1); - break; - } - } - delete commentById[comment_id]; - - return { - ...state, - commentById, - byId, - isLoading: false, - }; - }, - // do nothing - [ACTIONS.COMMENT_ABANDON_FAILED]: (state: CommentsState, action: any) => ({ - ...state, - isLoading: false, - }), - // do nothing - [ACTIONS.COMMENT_UPDATE_STARTED]: (state: CommentsState, action: any) => ({ - ...state, - isLoading: true, - }), - // replace existing comment with comment returned here under its comment_id - [ACTIONS.COMMENT_UPDATE_COMPLETED]: (state: CommentsState, action: any) => { - const { comment } = action.data; - const commentById = Object.assign({}, state.commentById); - commentById[comment.comment_id] = comment; - - return { - ...state, - commentById, - isLoading: false, - }; - }, - // nothing can be done here - [ACTIONS.COMMENT_UPDATE_FAILED]: (state: CommentsState, action: any) => ({ - ...state, - isLoading: false, - }), - // nothing can really be done here - [ACTIONS.COMMENT_HIDE_STARTED]: (state: CommentsState, action: any) => ({ - ...state, - isLoading: true, - }), - [ACTIONS.COMMENT_HIDE_COMPLETED]: (state: CommentsState, action: any) => ({ - ...state, // todo: add HiddenComments state & create selectors - isLoading: false, - }), - // nothing can be done here - [ACTIONS.COMMENT_HIDE_FAILED]: (state: CommentsState, action: any) => ({ - ...state, - isLoading: false, - }), - }, - defaultState -); diff --git a/src/redux/reducers/file_info.js b/src/redux/reducers/file_info.js index cb86718..1d9f950 100644 --- a/src/redux/reducers/file_info.js +++ b/src/redux/reducers/file_info.js @@ -57,27 +57,20 @@ reducers[ACTIONS.FETCH_FILE_INFO_COMPLETED] = (state, action) => { }); }; -reducers[ACTIONS.FETCH_FILE_INFO_FAILED] = (state, action) => { - const { outpoint } = action.data; - const newFetching = Object.assign({}, state.fetching); - delete newFetching[outpoint]; - - return Object.assign({}, state, { - fetching: newFetching, - }); -}; - reducers[ACTIONS.DOWNLOADING_STARTED] = (state, action) => { const { uri, outpoint, fileInfo } = action.data; const newByOutpoint = Object.assign({}, state.byOutpoint); const newDownloading = Object.assign({}, state.downloadingByOutpoint); + const newLoading = Object.assign({}, state.urisLoading); newDownloading[outpoint] = true; newByOutpoint[outpoint] = fileInfo; + delete newLoading[uri]; return Object.assign({}, state, { downloadingByOutpoint: newDownloading, + urisLoading: newLoading, byOutpoint: newByOutpoint, }); }; @@ -98,7 +91,7 @@ reducers[ACTIONS.DOWNLOADING_PROGRESSED] = (state, action) => { }; reducers[ACTIONS.DOWNLOADING_CANCELED] = (state, action) => { - const { uri, outpoint } = action.data; + const { outpoint } = action.data; const newDownloading = Object.assign({}, state.downloadingByOutpoint); delete newDownloading[outpoint]; @@ -138,6 +131,46 @@ reducers[ACTIONS.FILE_DELETE] = (state, action) => { }); }; +reducers[ACTIONS.LOADING_VIDEO_STARTED] = (state, action) => { + const { uri } = action.data; + + const newLoading = Object.assign({}, state.urisLoading); + newLoading[uri] = true; + + const newErrors = { ...state.errors }; + if (uri in newErrors) delete newErrors[uri]; + + return Object.assign({}, state, { + urisLoading: newLoading, + errors: { ...newErrors }, + }); +}; + +reducers[ACTIONS.LOADING_VIDEO_FAILED] = (state, action) => { + const { uri } = action.data; + + const newLoading = Object.assign({}, state.urisLoading); + delete newLoading[uri]; + + const newErrors = { ...state.errors }; + newErrors[uri] = true; + + return Object.assign({}, state, { + urisLoading: newLoading, + errors: { ...newErrors }, + }); +}; + +reducers[ACTIONS.FETCH_DATE] = (state, action) => { + const { time } = action.data; + if (time) { + return Object.assign({}, state, { + publishedDate: time, + }); + } + return null; +}; + reducers[ACTIONS.SET_FILE_LIST_SORT] = (state, action) => { const pageSortStates = { [PAGES.PUBLISHED]: 'fileListPublishedSort', diff --git a/src/redux/reducers/publish.js b/src/redux/reducers/publish.js deleted file mode 100644 index 2104675..0000000 --- a/src/redux/reducers/publish.js +++ /dev/null @@ -1,123 +0,0 @@ -// @flow -import { handleActions } from 'util/redux-utils'; -import { buildURI } from 'lbryURI'; -import * as ACTIONS from 'constants/action_types'; -import * as THUMBNAIL_STATUSES from 'constants/thumbnail_upload_statuses'; -import { CHANNEL_ANONYMOUS } from 'constants/claim'; - -type PublishState = { - editingURI: ?string, - fileText: ?string, - filePath: ?string, - contentIsFree: boolean, - fileDur: number, - fileSize: number, - fileVid: boolean, - fee: { - amount: number, - currency: string, - }, - title: string, - thumbnail_url: string, - thumbnailPath: string, - uploadThumbnailStatus: string, - description: string, - language: string, - channel: string, - channelId: ?string, - name: string, - nameError: ?string, - bid: number, - bidError: ?string, - otherLicenseDescription: string, - licenseUrl: string, - tags: Array, - optimize: boolean, - useLBRYUploader: boolean, -}; - -const defaultState: PublishState = { - editingURI: undefined, - fileText: '', - filePath: undefined, - fileDur: 0, - fileSize: 0, - fileVid: false, - contentIsFree: true, - fee: { - amount: 1, - currency: 'LBC', - }, - title: '', - thumbnail_url: '', - thumbnailPath: '', - uploadThumbnailStatus: THUMBNAIL_STATUSES.API_DOWN, - description: '', - language: '', - nsfw: false, - channel: CHANNEL_ANONYMOUS, - channelId: '', - name: '', - nameError: undefined, - bid: 0.1, - bidError: undefined, - licenseType: 'None', - otherLicenseDescription: 'All rights reserved', - licenseUrl: '', - tags: [], - publishing: false, - publishSuccess: false, - publishError: undefined, - optimize: false, - useLBRYUploader: false, -}; - -export const publishReducer = handleActions( - { - [ACTIONS.UPDATE_PUBLISH_FORM]: (state, action): PublishState => { - const { data } = action; - return { - ...state, - ...data, - }; - }, - [ACTIONS.CLEAR_PUBLISH]: (state: PublishState): PublishState => ({ - ...defaultState, - bid: state.bid, - optimize: state.optimize, - }), - [ACTIONS.PUBLISH_START]: (state: PublishState): PublishState => ({ - ...state, - publishing: true, - publishSuccess: false, - }), - [ACTIONS.PUBLISH_FAIL]: (state: PublishState): PublishState => ({ - ...state, - publishing: false, - }), - [ACTIONS.PUBLISH_SUCCESS]: (state: PublishState): PublishState => ({ - ...state, - publishing: false, - publishSuccess: true, - }), - [ACTIONS.DO_PREPARE_EDIT]: (state: PublishState, action) => { - const { ...publishData } = action.data; - const { channel, name, uri } = publishData; - - // The short uri is what is presented to the user - // The editingUri is the full uri with claim id - const shortUri = buildURI({ - channelName: channel, - streamName: name, - }); - - return { - ...defaultState, - ...publishData, - editingURI: uri, - uri: shortUri, - }; - }, - }, - defaultState -); diff --git a/src/redux/reducers/search.js b/src/redux/reducers/search.js index 27e1013..ee0bd8b 100644 --- a/src/redux/reducers/search.js +++ b/src/redux/reducers/search.js @@ -18,8 +18,6 @@ const defaultState = { }, suggestions: {}, urisByQuery: {}, - resolvedResultsByQuery: {}, - resolvedResultsByQueryLastPageReached: {}, }; export const searchReducer = handleActions( @@ -43,47 +41,6 @@ export const searchReducer = handleActions( searching: false, }), - [ACTIONS.RESOLVED_SEARCH_START]: (state: SearchState): SearchState => ({ - ...state, - searching: true, - }), - [ACTIONS.RESOLVED_SEARCH_SUCCESS]: ( - state: SearchState, - action: ResolvedSearchSuccess - ): SearchState => { - const resolvedResultsByQuery = Object.assign({}, state.resolvedResultsByQuery); - const resolvedResultsByQueryLastPageReached = Object.assign( - {}, - state.resolvedResultsByQueryLastPageReached - ); - const { append, query, results, pageSize } = action.data; - - if (append) { - // todo: check for duplicates when concatenating? - resolvedResultsByQuery[query] = - resolvedResultsByQuery[query] && resolvedResultsByQuery[query].length - ? resolvedResultsByQuery[query].concat(results) - : results; - } else { - resolvedResultsByQuery[query] = results; - } - - // the returned number of urls is less than the page size, so we're on the last page - resolvedResultsByQueryLastPageReached[query] = results.length < pageSize; - - return { - ...state, - searching: false, - resolvedResultsByQuery, - resolvedResultsByQueryLastPageReached, - }; - }, - - [ACTIONS.RESOLVED_SEARCH_FAIL]: (state: SearchState): SearchState => ({ - ...state, - searching: false, - }), - [ACTIONS.UPDATE_SEARCH_QUERY]: ( state: SearchState, action: UpdateSearchQuery diff --git a/src/redux/reducers/tags.js b/src/redux/reducers/tags.js deleted file mode 100644 index b465376..0000000 --- a/src/redux/reducers/tags.js +++ /dev/null @@ -1,86 +0,0 @@ -// @flow -import * as ACTIONS from 'constants/action_types'; -import { handleActions } from 'util/redux-utils'; -import { DEFAULT_KNOWN_TAGS, DEFAULT_FOLLOWED_TAGS } from 'constants/tags'; - -function getDefaultKnownTags() { - return DEFAULT_FOLLOWED_TAGS.concat(DEFAULT_KNOWN_TAGS).reduce( - (tagsMap, tag) => ({ - ...tagsMap, - [tag]: { name: tag }, - }), - {} - ); -} - -const defaultState: TagState = { - followedTags: [], - knownTags: getDefaultKnownTags(), -}; - -export const tagsReducer = handleActions( - { - [ACTIONS.TOGGLE_TAG_FOLLOW]: (state: TagState, action: TagAction): TagState => { - const { followedTags } = state; - const { name } = action.data; - - let newFollowedTags = followedTags.slice(); - - if (newFollowedTags.includes(name)) { - newFollowedTags = newFollowedTags.filter(tag => tag !== name); - } else { - newFollowedTags.push(name); - } - - return { - ...state, - followedTags: newFollowedTags, - }; - }, - - [ACTIONS.TAG_ADD]: (state: TagState, action: TagAction) => { - const { knownTags } = state; - const { name } = action.data; - - let newKnownTags = { ...knownTags }; - newKnownTags[name] = { name }; - - return { - ...state, - knownTags: newKnownTags, - }; - }, - - [ACTIONS.TAG_DELETE]: (state: TagState, action: TagAction) => { - const { knownTags, followedTags } = state; - const { name } = action.data; - - let newKnownTags = { ...knownTags }; - delete newKnownTags[name]; - const newFollowedTags = followedTags.filter(tag => tag !== name); - - return { - ...state, - knownTags: newKnownTags, - followedTags: newFollowedTags, - }; - }, - [ACTIONS.USER_STATE_POPULATE]: ( - state: TagState, - action: { data: { tags: ?Array } } - ) => { - const { tags } = action.data; - if (Array.isArray(tags)) { - return { - ...state, - followedTags: tags, - }; - } - return { - ...state, - }; - - }, - }, - defaultState -); diff --git a/src/redux/reducers/wallet.js b/src/redux/reducers/wallet.js index d4e894b..308c5e7 100644 --- a/src/redux/reducers/wallet.js +++ b/src/redux/reducers/wallet.js @@ -1,7 +1,7 @@ // @flow import * as ACTIONS from 'constants/action_types'; -import { handleActions } from 'util/redux-utils'; +const reducers = {}; const buildDraftTransaction = () => ({ amount: undefined, address: undefined, @@ -16,17 +16,10 @@ type ActionResult = { type WalletState = { balance: any, - totalBalance: any, - reservedBalance: any, - claimsBalance: any, - supportsBalance: any, - tipsBalance: any, + blocks: any, latestBlock: ?number, - transactions: { [string]: Transaction }, - supports: { [string]: Support }, - abandoningSupportsByOutpoint: { [string]: boolean }, + transactions: any, fetchingTransactions: boolean, - fetchingTransactionsError: string, gettingNewAddress: boolean, draftTransaction: any, sendingSupport: boolean, @@ -43,29 +36,15 @@ type WalletState = { walletLockPending: boolean, walletLockSucceded: ?boolean, walletLockResult: ?boolean, - walletReconnecting: boolean, - txoFetchParams: {}, - txoPage: any, - fetchingTxos: boolean, - fetchingTxosError?: string, - pendingSupportTransactions: {}, // { claimId: {txid: 123, amount 12.3}, } - abandonClaimSupportError?: string, }; const defaultState = { balance: undefined, totalBalance: undefined, - reservedBalance: undefined, - claimsBalance: undefined, - supportsBalance: undefined, - tipsBalance: undefined, + blocks: {}, latestBlock: undefined, transactions: {}, fetchingTransactions: false, - fetchingTransactionsError: undefined, - supports: {}, - fetchingSupports: false, - abandoningSupportsByOutpoint: {}, gettingNewAddress: false, draftTransaction: buildDraftTransaction(), sendingSupport: false, @@ -83,348 +62,240 @@ const defaultState = { walletLockSucceded: null, walletLockResult: null, transactionListFilter: 'all', - walletReconnecting: false, - txoFetchParams: {}, - txoPage: {}, - fetchingTxos: false, - fetchingTxosError: undefined, - pendingSupportTransactions: {}, - abandonClaimSupportError: undefined, }; -export const walletReducer = handleActions( - { - [ACTIONS.FETCH_TRANSACTIONS_STARTED]: (state: WalletState) => ({ - ...state, - fetchingTransactions: true, - }), +reducers[ACTIONS.FETCH_TRANSACTIONS_STARTED] = (state: WalletState) => + Object.assign({}, state, { + fetchingTransactions: true, + }); - [ACTIONS.FETCH_TRANSACTIONS_COMPLETED]: (state: WalletState, action) => { - const byId = { ...state.transactions }; +reducers[ACTIONS.FETCH_TRANSACTIONS_COMPLETED] = (state: WalletState, action) => { + const byId = Object.assign({}, state.transactions); - const { transactions } = action.data; - transactions.forEach(transaction => { - byId[transaction.txid] = transaction; - }); + const { transactions } = action.data; - return { - ...state, - transactions: byId, - fetchingTransactions: false, - }; - }, + transactions.forEach(transaction => { + byId[transaction.txid] = transaction; + }); - [ACTIONS.FETCH_TXO_PAGE_STARTED]: (state: WalletState) => { - return { - ...state, - fetchingTxos: true, - fetchingTxosError: undefined, - }; - }, + return Object.assign({}, state, { + transactions: byId, + fetchingTransactions: false, + }); +}; - [ACTIONS.FETCH_TXO_PAGE_COMPLETED]: (state: WalletState, action) => { - return { - ...state, - txoPage: action.data, - fetchingTxos: false, - }; - }, +reducers[ACTIONS.GET_NEW_ADDRESS_STARTED] = (state: WalletState) => + Object.assign({}, state, { + gettingNewAddress: true, + }); - [ACTIONS.FETCH_TXO_PAGE_FAILED]: (state: WalletState, action) => { - return { - ...state, - txoPage: {}, - fetchingTxos: false, - fetchingTxosError: action.data, - }; - }, +reducers[ACTIONS.GET_NEW_ADDRESS_COMPLETED] = (state: WalletState, action) => { + const { address } = action.data; - [ACTIONS.UPDATE_TXO_FETCH_PARAMS]: (state: WalletState, action) => { - return { - ...state, - txoFetchParams: action.data, - }; - }, + // Say no to localStorage! + return Object.assign({}, state, { + gettingNewAddress: false, + receiveAddress: address, + }); +}; - [ACTIONS.FETCH_SUPPORTS_STARTED]: (state: WalletState) => ({ - ...state, - fetchingSupports: true, - }), +reducers[ACTIONS.UPDATE_BALANCE] = (state: WalletState, action) => + Object.assign({}, state, { + balance: action.data.balance, + }); - [ACTIONS.FETCH_SUPPORTS_COMPLETED]: (state: WalletState, action) => { - const byOutpoint = state.supports; - const { supports } = action.data; +reducers[ACTIONS.UPDATE_TOTAL_BALANCE] = (state: WalletState, action) => + Object.assign({}, state, { + totalBalance: action.data.totalBalance, + }); - supports.forEach(transaction => { - const { txid, nout } = transaction; - byOutpoint[`${txid}:${nout}`] = transaction; - }); +reducers[ACTIONS.CHECK_ADDRESS_IS_MINE_STARTED] = (state: WalletState) => + Object.assign({}, state, { + checkingAddressOwnership: true, + }); - return { ...state, supports: byOutpoint, fetchingSupports: false }; - }, +reducers[ACTIONS.CHECK_ADDRESS_IS_MINE_COMPLETED] = (state: WalletState) => + Object.assign({}, state, { + checkingAddressOwnership: false, + }); - [ACTIONS.ABANDON_SUPPORT_STARTED]: (state: WalletState, action: any): WalletState => { - const { outpoint }: { outpoint: string } = action.data; - const currentlyAbandoning = state.abandoningSupportsByOutpoint; +reducers[ACTIONS.SET_DRAFT_TRANSACTION_AMOUNT] = (state: WalletState, action) => { + const oldDraft = state.draftTransaction; + const newDraft = Object.assign({}, oldDraft, { + amount: parseFloat(action.data.amount), + }); - currentlyAbandoning[outpoint] = true; + return Object.assign({}, state, { + draftTransaction: newDraft, + }); +}; - return { - ...state, - abandoningSupportsByOutpoint: currentlyAbandoning, - }; - }, +reducers[ACTIONS.SET_DRAFT_TRANSACTION_ADDRESS] = (state: WalletState, action) => { + const oldDraft = state.draftTransaction; + const newDraft = Object.assign({}, oldDraft, { + address: action.data.address, + }); - [ACTIONS.ABANDON_SUPPORT_COMPLETED]: (state: WalletState, action: any): WalletState => { - const { outpoint }: { outpoint: string } = action.data; - const byOutpoint = state.supports; - const currentlyAbandoning = state.abandoningSupportsByOutpoint; + return Object.assign({}, state, { + draftTransaction: newDraft, + }); +}; - delete currentlyAbandoning[outpoint]; - delete byOutpoint[outpoint]; +reducers[ACTIONS.SEND_TRANSACTION_STARTED] = (state: WalletState) => { + const newDraftTransaction = Object.assign({}, state.draftTransaction, { + sending: true, + }); - return { - ...state, - supports: byOutpoint, - abandoningSupportsById: currentlyAbandoning, - }; - }, + return Object.assign({}, state, { + draftTransaction: newDraftTransaction, + }); +}; - [ACTIONS.ABANDON_CLAIM_SUPPORT_STARTED]: (state: WalletState, action: any): WalletState => { - return { - ...state, - abandonClaimSupportError: undefined, - }; - }, +reducers[ACTIONS.SEND_TRANSACTION_COMPLETED] = (state: WalletState) => + Object.assign({}, state, { + draftTransaction: buildDraftTransaction(), + }); - [ACTIONS.ABANDON_CLAIM_SUPPORT_PREVIEW]: (state: WalletState, action: any): WalletState => { - return { - ...state, - abandonClaimSupportError: undefined, - }; - }, +reducers[ACTIONS.SEND_TRANSACTION_FAILED] = (state: WalletState, action) => { + const newDraftTransaction = Object.assign({}, state.draftTransaction, { + sending: false, + error: action.data.error, + }); - [ACTIONS.ABANDON_CLAIM_SUPPORT_COMPLETED]: (state: WalletState, action: any): WalletState => { - const { claimId, type, txid, effective }: { claimId: string, type: string, txid: string, effective: string } = action.data; - const pendingtxs = Object.assign({}, state.pendingSupportTransactions); + return Object.assign({}, state, { + draftTransaction: newDraftTransaction, + }); +}; - pendingtxs[claimId] = {txid, type, effective}; +reducers[ACTIONS.SUPPORT_TRANSACTION_STARTED] = (state: WalletState) => + Object.assign({}, state, { + sendingSupport: true, + }); - return { - ...state, - pendingSupportTransactions: pendingtxs, - abandonClaimSupportError: undefined, - }; - }, +reducers[ACTIONS.SUPPORT_TRANSACTION_COMPLETED] = (state: WalletState) => + Object.assign({}, state, { + sendingSupport: false, + }); - [ACTIONS.ABANDON_CLAIM_SUPPORT_FAILED]: (state: WalletState, action: any): WalletState => { - return { - ...state, - abandonClaimSupportError: action.data, - }; - }, +reducers[ACTIONS.SUPPORT_TRANSACTION_FAILED] = (state: WalletState, action) => + Object.assign({}, state, { + error: action.data.error, + sendingSupport: false, + }); - [ACTIONS.PENDING_SUPPORTS_UPDATED]: (state: WalletState, action: any): WalletState => { +reducers[ACTIONS.FETCH_BLOCK_SUCCESS] = (state: WalletState, action) => { + const { + block, + block: { height }, + } = action.data; + const blocks = Object.assign({}, state.blocks); - return { - ...state, - pendingSupportTransactions: action.data, - }; - }, + blocks[height] = block; - [ACTIONS.GET_NEW_ADDRESS_STARTED]: (state: WalletState) => ({ - ...state, - gettingNewAddress: true, - }), + return Object.assign({}, state, { blocks }); +}; - [ACTIONS.GET_NEW_ADDRESS_COMPLETED]: (state: WalletState, action) => { - const { address } = action.data; +reducers[ACTIONS.WALLET_STATUS_COMPLETED] = (state: WalletState, action) => + Object.assign({}, state, { + walletIsEncrypted: action.result, + }); - return { ...state, gettingNewAddress: false, receiveAddress: address }; - }, +reducers[ACTIONS.WALLET_ENCRYPT_START] = (state: WalletState) => + Object.assign({}, state, { + walletEncryptPending: true, + walletEncryptSucceded: null, + walletEncryptResult: null, + }); - [ACTIONS.UPDATE_BALANCE]: (state: WalletState, action) => ({ - ...state, - totalBalance: action.data.totalBalance, - balance: action.data.balance, - reservedBalance: action.data.reservedBalance, - claimsBalance: action.data.claimsBalance, - supportsBalance: action.data.supportsBalance, - tipsBalance: action.data.tipsBalance, - }), +reducers[ACTIONS.WALLET_ENCRYPT_COMPLETED] = (state: WalletState, action: ActionResult) => + Object.assign({}, state, { + walletEncryptPending: false, + walletEncryptSucceded: true, + walletEncryptResult: action.result, + }); - [ACTIONS.CHECK_ADDRESS_IS_MINE_STARTED]: (state: WalletState) => ({ - ...state, - checkingAddressOwnership: true, - }), +reducers[ACTIONS.WALLET_ENCRYPT_FAILED] = (state: WalletState, action: ActionResult) => + Object.assign({}, state, { + walletEncryptPending: false, + walletEncryptSucceded: false, + walletEncryptResult: action.result, + }); - [ACTIONS.CHECK_ADDRESS_IS_MINE_COMPLETED]: (state: WalletState) => ({ - ...state, - checkingAddressOwnership: false, - }), +reducers[ACTIONS.WALLET_DECRYPT_START] = (state: WalletState) => + Object.assign({}, state, { + walletDecryptPending: true, + walletDecryptSucceded: null, + walletDecryptResult: null, + }); - [ACTIONS.SET_DRAFT_TRANSACTION_AMOUNT]: (state: WalletState, action) => { - const oldDraft = state.draftTransaction; - const newDraft = { ...oldDraft, amount: parseFloat(action.data.amount) }; +reducers[ACTIONS.WALLET_DECRYPT_COMPLETED] = (state: WalletState, action: ActionResult) => + Object.assign({}, state, { + walletDecryptPending: false, + walletDecryptSucceded: true, + walletDecryptResult: action.result, + }); - return { ...state, draftTransaction: newDraft }; - }, +reducers[ACTIONS.WALLET_DECRYPT_FAILED] = (state: WalletState, action: ActionResult) => + Object.assign({}, state, { + walletDecryptPending: false, + walletDecryptSucceded: false, + walletDecryptResult: action.result, + }); - [ACTIONS.SET_DRAFT_TRANSACTION_ADDRESS]: (state: WalletState, action) => { - const oldDraft = state.draftTransaction; - const newDraft = { ...oldDraft, address: action.data.address }; +reducers[ACTIONS.WALLET_UNLOCK_START] = (state: WalletState) => + Object.assign({}, state, { + walletUnlockPending: true, + walletUnlockSucceded: null, + walletUnlockResult: null, + }); - return { ...state, draftTransaction: newDraft }; - }, +reducers[ACTIONS.WALLET_UNLOCK_COMPLETED] = (state: WalletState, action: ActionResult) => + Object.assign({}, state, { + walletUnlockPending: false, + walletUnlockSucceded: true, + walletUnlockResult: action.result, + }); - [ACTIONS.SEND_TRANSACTION_STARTED]: (state: WalletState) => { - const newDraftTransaction = { ...state.draftTransaction, sending: true }; +reducers[ACTIONS.WALLET_UNLOCK_FAILED] = (state: WalletState, action: ActionResult) => + Object.assign({}, state, { + walletUnlockPending: false, + walletUnlockSucceded: false, + walletUnlockResult: action.result, + }); - return { ...state, draftTransaction: newDraftTransaction }; - }, +reducers[ACTIONS.WALLET_LOCK_START] = (state: WalletState) => + Object.assign({}, state, { + walletLockPending: false, + walletLockSucceded: null, + walletLockResult: null, + }); - [ACTIONS.SEND_TRANSACTION_COMPLETED]: (state: WalletState) => - Object.assign({}, state, { - draftTransaction: buildDraftTransaction(), - }), +reducers[ACTIONS.WALLET_LOCK_COMPLETED] = (state: WalletState, action: ActionResult) => + Object.assign({}, state, { + walletLockPending: false, + walletLockSucceded: true, + walletLockResult: action.result, + }); - [ACTIONS.SEND_TRANSACTION_FAILED]: (state: WalletState, action) => { - const newDraftTransaction = Object.assign({}, state.draftTransaction, { - sending: false, - error: action.data.error, - }); +reducers[ACTIONS.WALLET_LOCK_FAILED] = (state: WalletState, action: ActionResult) => + Object.assign({}, state, { + walletLockPending: false, + walletLockSucceded: false, + walletLockResult: action.result, + }); - return { ...state, draftTransaction: newDraftTransaction }; - }, +reducers[ACTIONS.SET_TRANSACTION_LIST_FILTER] = (state: WalletState, action: { data: string }) => + Object.assign({}, state, { + transactionListFilter: action.data, + }); - [ACTIONS.SUPPORT_TRANSACTION_STARTED]: (state: WalletState) => ({ - ...state, - sendingSupport: true, - }), +reducers[ACTIONS.UPDATE_CURRENT_HEIGHT] = (state: WalletState, action: { data: number }) => + Object.assign({}, state, { + latestBlock: action.data, + }); - [ACTIONS.SUPPORT_TRANSACTION_COMPLETED]: (state: WalletState) => ({ - ...state, - sendingSupport: false, - }), - - [ACTIONS.SUPPORT_TRANSACTION_FAILED]: (state: WalletState, action) => ({ - ...state, - error: action.data.error, - sendingSupport: false, - }), - - [ACTIONS.CLEAR_SUPPORT_TRANSACTION]: (state: WalletState) => ({ - ...state, - sendingSupport: false, - }), - - [ACTIONS.WALLET_STATUS_COMPLETED]: (state: WalletState, action) => ({ - ...state, - walletIsEncrypted: action.result, - }), - - [ACTIONS.WALLET_ENCRYPT_START]: (state: WalletState) => ({ - ...state, - walletEncryptPending: true, - walletEncryptSucceded: null, - walletEncryptResult: null, - }), - - [ACTIONS.WALLET_ENCRYPT_COMPLETED]: (state: WalletState, action: ActionResult) => ({ - ...state, - walletEncryptPending: false, - walletEncryptSucceded: true, - walletEncryptResult: action.result, - }), - - [ACTIONS.WALLET_ENCRYPT_FAILED]: (state: WalletState, action: ActionResult) => ({ - ...state, - walletEncryptPending: false, - walletEncryptSucceded: false, - walletEncryptResult: action.result, - }), - - [ACTIONS.WALLET_DECRYPT_START]: (state: WalletState) => ({ - ...state, - walletDecryptPending: true, - walletDecryptSucceded: null, - walletDecryptResult: null, - }), - - [ACTIONS.WALLET_DECRYPT_COMPLETED]: (state: WalletState, action: ActionResult) => ({ - ...state, - walletDecryptPending: false, - walletDecryptSucceded: true, - walletDecryptResult: action.result, - }), - - [ACTIONS.WALLET_DECRYPT_FAILED]: (state: WalletState, action: ActionResult) => ({ - ...state, - walletDecryptPending: false, - walletDecryptSucceded: false, - walletDecryptResult: action.result, - }), - - [ACTIONS.WALLET_UNLOCK_START]: (state: WalletState) => ({ - ...state, - walletUnlockPending: true, - walletUnlockSucceded: null, - walletUnlockResult: null, - }), - - [ACTIONS.WALLET_UNLOCK_COMPLETED]: (state: WalletState, action: ActionResult) => ({ - ...state, - walletUnlockPending: false, - walletUnlockSucceded: true, - walletUnlockResult: action.result, - }), - - [ACTIONS.WALLET_UNLOCK_FAILED]: (state: WalletState, action: ActionResult) => ({ - ...state, - walletUnlockPending: false, - walletUnlockSucceded: false, - walletUnlockResult: action.result, - }), - - [ACTIONS.WALLET_LOCK_START]: (state: WalletState) => ({ - ...state, - walletLockPending: false, - walletLockSucceded: null, - walletLockResult: null, - }), - - [ACTIONS.WALLET_LOCK_COMPLETED]: (state: WalletState, action: ActionResult) => ({ - ...state, - walletLockPending: false, - walletLockSucceded: true, - walletLockResult: action.result, - }), - - [ACTIONS.WALLET_LOCK_FAILED]: (state: WalletState, action: ActionResult) => ({ - ...state, - walletLockPending: false, - walletLockSucceded: false, - walletLockResult: action.result, - }), - - [ACTIONS.SET_TRANSACTION_LIST_FILTER]: (state: WalletState, action: { data: string }) => ({ - ...state, - transactionListFilter: action.data, - }), - - [ACTIONS.UPDATE_CURRENT_HEIGHT]: (state: WalletState, action: { data: number }) => ({ - ...state, - latestBlock: action.data, - }), - [ACTIONS.WALLET_RESTART]: (state: WalletState) => ({ - ...state, - walletReconnecting: true, - }), - - [ACTIONS.WALLET_RESTART_COMPLETED]: (state: WalletState) => ({ - ...state, - walletReconnecting: false, - }), - }, - defaultState -); +export function walletReducer(state: WalletState = defaultState, action: ActionResult) { + const handler = reducers[action.type]; + if (handler) return handler(state, action); + return state; +} diff --git a/src/redux/selectors/blocked.js b/src/redux/selectors/blocked.js deleted file mode 100644 index 424ea89..0000000 --- a/src/redux/selectors/blocked.js +++ /dev/null @@ -1,22 +0,0 @@ -// @flow -import { createSelector } from 'reselect'; - -const selectState = (state: { blocked: BlocklistState }) => state.blocked || {}; - -export const selectBlockedChannels = createSelector( - selectState, - (state: BlocklistState) => state.blockedChannels -); - -export const selectBlockedChannelsCount = createSelector( - selectBlockedChannels, - (state: Array) => state.length -); - -export const selectChannelIsBlocked = (uri: string) => - createSelector( - selectBlockedChannels, - (state: Array) => { - return state.includes(uri); - } - ); diff --git a/src/redux/selectors/claims.js b/src/redux/selectors/claims.js index eadd945..477dfac 100644 --- a/src/redux/selectors/claims.js +++ b/src/redux/selectors/claims.js @@ -1,14 +1,9 @@ // @flow import { normalizeURI, buildURI, parseURI } from 'lbryURI'; -import { - selectResolvedSearchResultsByQuery, - selectSearchUrisByQuery, -} from 'redux/selectors/search'; -import { selectSupportsByOutpoint } from 'redux/selectors/wallet'; +import { selectSearchUrisByQuery } from 'redux/selectors/search'; import { createSelector } from 'reselect'; -import { isClaimNsfw, filterClaims } from 'util/claim'; -import { getSearchQueryString } from 'util/query-params'; -import { PAGE_SIZE } from 'constants/claim'; +import { isClaimNsfw } from 'util/claim'; +import { getSearchQueryString } from 'util/query_params'; const selectState = state => state.claims || {}; @@ -17,40 +12,16 @@ export const selectClaimsById = createSelector( state => state.byId || {} ); -export const selectClaimIdsByUri = createSelector( - selectState, - state => state.claimsByUri || {} -); - export const selectCurrentChannelPage = createSelector( selectState, state => state.currentChannelPage || 1 ); -export const selectCreatingChannel = createSelector( - selectState, - state => state.creatingChannel -); - -export const selectCreateChannelError = createSelector( - selectState, - state => state.createChannelError -); - -export const selectRepostLoading = createSelector( - selectState, - state => state.repostLoading -); - -export const selectRepostError = createSelector( - selectState, - state => state.repostError -); - export const selectClaimsByUri = createSelector( - selectClaimIdsByUri, + selectState, selectClaimsById, - (byUri, byId) => { + (state, byId) => { + const byUri = state.claimsByUri || {}; const claims = {}; Object.keys(byUri).forEach(uri => { @@ -72,92 +43,57 @@ export const selectClaimsByUri = createSelector( export const selectAllClaimsByChannel = createSelector( selectState, - state => state.paginatedClaimsByChannel || {} + state => state.claimsByChannel || {} ); -export const selectPendingIds = createSelector( +export const selectPendingById = createSelector( selectState, - state => state.pendingIds || [] + state => state.pendingById || {} +); + +export const selectPendingClaims = createSelector( + selectState, + state => Object.values(state.pendingById || []) ); export const makeSelectClaimIsPending = (uri: string) => createSelector( - selectClaimIdsByUri, - selectPendingIds, - (idsByUri, pendingIds) => { - const claimId = idsByUri[normalizeURI(uri)]; - - if (claimId) { - return pendingIds.some(i => i === claimId); - } - return false; + selectPendingById, + pendingById => { + const { claimId } = parseURI(uri); + return Boolean(pendingById[claimId]); } ); -export const selectReflectingById = createSelector( - selectState, - state => state.reflectingById -); - -export const makeSelectClaimForUri = (uri: string, returnRepost: boolean = true) => +export const makeSelectPendingByUri = (uri: string) => createSelector( - selectClaimIdsByUri, - selectClaimsById, - (byUri, byId) => { - let validUri; - let channelClaimId; - let streamClaimId; - let isChannel; - try { - ({ isChannel, channelClaimId, streamClaimId } = parseURI(uri)); - validUri = true; - } catch (e) {} + selectPendingById, + pendingById => { + const { claimId } = parseURI(uri); + return pendingById[claimId]; + } + ); - if (validUri && byUri) { - const claimId = uri && byUri[normalizeURI(uri)]; - const claim = byId[claimId]; - - // Make sure to return the claim as is so apps can check if it's been resolved before (null) or still needs to be resolved (undefined) - if (claimId === null) { - return null; - } else if (claimId === undefined) { - return undefined; - } - - const repostedClaim = claim.reposted_claim; - if (repostedClaim && returnRepost) { - const channelUrl = claim.signing_channel && claim.signing_channel.canonical_url; - - return { - ...repostedClaim, - repost_url: uri, - repost_channel_url: channelUrl, - }; - } else { - return claim; - } +export const makeSelectClaimForUri = (uri: string) => + createSelector( + selectClaimsByUri, + selectPendingById, + (byUri, pendingById) => { + // Check if a claim is pending first + // It won't be in claimsByUri because resolving it will return nothing + const { claimId } = parseURI(uri); + const pendingClaim = pendingById[claimId]; + if (pendingClaim) { + return pendingClaim; } + + return byUri && byUri[normalizeURI(uri)]; } ); export const selectMyClaimsRaw = createSelector( selectState, - selectClaimsById, - (state, byId) => { - const ids = state.myClaims; - if (!ids) { - return ids; - } - - const claims = []; - ids.forEach(id => { - if (byId[id]) { - // I'm not sure why this check is necessary, but it ought to be a quick fix for https://github.com/lbryio/lbry-desktop/issues/544 - claims.push(byId[id]); - } - }); - return claims; - } + state => state.myClaims ); export const selectAbandoningIds = createSelector( @@ -178,89 +114,15 @@ export const selectMyActiveClaims = createSelector( ); export const makeSelectClaimIsMine = (rawUri: string) => { - let uri; - try { - uri = normalizeURI(rawUri); - } catch (e) {} - + const uri = normalizeURI(rawUri); return createSelector( selectClaimsByUri, selectMyActiveClaims, - (claims, myClaims) => { - try { - parseURI(uri); - } catch (e) { - return false; - } - - return ( - claims && - claims[uri] && - (claims[uri].is_my_output || (claims[uri].claim_id && myClaims.has(claims[uri].claim_id))) - ); - } + (claims, myClaims) => + claims && claims[uri] && claims[uri].claim_id && myClaims.has(claims[uri].claim_id) ); }; -export const selectMyPurchases = createSelector( - selectState, - state => state.myPurchases -); - -export const selectPurchaseUriSuccess = createSelector( - selectState, - state => state.purchaseUriSuccess -); - -export const selectMyPurchasesCount = createSelector( - selectState, - state => state.myPurchasesPageTotalResults -); - -export const selectIsFetchingMyPurchases = createSelector( - selectState, - state => state.fetchingMyPurchases -); - -export const selectFetchingMyPurchasesError = createSelector( - selectState, - state => state.fetchingMyPurchasesError -); - -export const makeSelectMyPurchasesForPage = (query: ?string, page: number = 1) => - createSelector( - selectMyPurchases, - selectClaimsByUri, - (myPurchases: Array, claimsByUri: { [string]: Claim }) => { - if (!myPurchases) { - return undefined; - } - - if (!query) { - // ensure no duplicates from double purchase bugs - return [...new Set(myPurchases)]; - } - - const fileInfos = myPurchases.map(uri => claimsByUri[uri]); - const matchingFileInfos = filterClaims(fileInfos, query); - const start = (Number(page) - 1) * Number(PAGE_SIZE); - const end = Number(page) * Number(PAGE_SIZE); - return matchingFileInfos && matchingFileInfos.length - ? matchingFileInfos - .slice(start, end) - .map(fileInfo => fileInfo.canonical_url || fileInfo.permanent_url) - : []; - } - ); - -export const makeSelectClaimWasPurchased = (uri: string) => - createSelector( - makeSelectClaimForUri(uri), - claim => { - return claim && claim.purchase_receipt !== undefined; - } - ); - export const selectAllFetchingChannelClaims = createSelector( selectState, state => state.fetchingChannelClaims || {} @@ -286,26 +148,6 @@ export const makeSelectClaimsInChannelForPage = (uri: string, page?: number) => } ); -export const makeSelectTotalClaimsInChannelSearch = (uri: string) => - createSelector( - selectClaimsById, - selectAllClaimsByChannel, - (byId, allClaims) => { - const byChannel = allClaims[uri] || {}; - return byChannel['itemCount']; - } - ); - -export const makeSelectTotalPagesInChannelSearch = (uri: string) => - createSelector( - selectClaimsById, - selectAllClaimsByChannel, - (byId, allClaims) => { - const byChannel = allClaims[uri] || {}; - return byChannel['pageCount']; - } - ); - export const makeSelectClaimsInChannelForCurrentPageState = (uri: string) => createSelector( selectClaimsById, @@ -330,48 +172,12 @@ export const makeSelectMetadataForUri = (uri: string) => } ); -export const makeSelectMetadataItemForUri = (uri: string, key: string) => - createSelector( - makeSelectMetadataForUri(uri), - (metadata: ChannelMetadata | StreamMetadata) => { - return metadata ? metadata[key] : undefined; - } - ); - export const makeSelectTitleForUri = (uri: string) => createSelector( makeSelectMetadataForUri(uri), metadata => metadata && metadata.title ); -export const makeSelectDateForUri = (uri: string) => - createSelector( - makeSelectClaimForUri(uri), - claim => { - const timestamp = - claim && - claim.value && - (claim.value.release_time - ? claim.value.release_time * 1000 - : claim.meta && claim.meta.creation_timestamp - ? claim.meta.creation_timestamp * 1000 - : null); - if (!timestamp) { - return undefined; - } - const dateObj = new Date(timestamp); - return dateObj; - } - ); - -export const makeSelectAmountForUri = (uri: string) => - createSelector( - makeSelectClaimForUri(uri), - claim => { - return claim && claim.amount; - } - ); - export const makeSelectContentTypeForUri = (uri: string) => createSelector( makeSelectClaimForUri(uri), @@ -386,18 +192,7 @@ export const makeSelectThumbnailForUri = (uri: string) => makeSelectClaimForUri(uri), claim => { const thumbnail = claim && claim.value && claim.value.thumbnail; - return thumbnail && thumbnail.url - ? thumbnail.url.trim().replace(/^http:\/\//i, 'https://') - : undefined; - } - ); - -export const makeSelectCoverForUri = (uri: string) => - createSelector( - makeSelectClaimForUri(uri), - claim => { - const cover = claim && claim.value && claim.value.cover; - return cover && cover.url ? cover.url.trim().replace(/^http:\/\//i, 'https://') : undefined; + return thumbnail ? thumbnail.url : undefined; } ); @@ -406,33 +201,12 @@ export const selectIsFetchingClaimListMine = createSelector( state => state.isFetchingClaimListMine ); -export const selectMyClaimsPage = createSelector( - selectState, - state => state.myClaimsPageResults || [] -); - -export const selectMyClaimsPageNumber = createSelector( - selectState, - state => (state.claimListMinePage && state.claimListMinePage.items) || [], - - state => (state.txoPage && state.txoPage.page) || 1 -); - -export const selectMyClaimsPageItemCount = createSelector( - selectState, - state => state.myClaimsPageTotalResults || 1 -); - -export const selectFetchingMyClaimsPageError = createSelector( - selectState, - state => state.fetchingClaimListMinePageError -); - export const selectMyClaims = createSelector( selectMyActiveClaims, selectClaimsById, selectAbandoningIds, - (myClaimIds, byId, abandoningIds) => { + selectPendingClaims, + (myClaimIds, byId, abandoningIds, pendingClaims) => { const claims = []; myClaimIds.forEach(id => { @@ -441,33 +215,13 @@ export const selectMyClaims = createSelector( if (claim && abandoningIds.indexOf(id) === -1) claims.push(claim); }); - return [...claims]; + return [...claims, ...pendingClaims]; } ); export const selectMyClaimsWithoutChannels = createSelector( selectMyClaims, - myClaims => - myClaims.filter(claim => !claim.name.match(/^@/)).sort((a, b) => a.timestamp - b.timestamp) -); - -export const selectMyClaimUrisWithoutChannels = createSelector( - selectMyClaimsWithoutChannels, - myClaims => { - return myClaims - .sort((a, b) => { - if (a.height < 1) { - return -1; - } else if (b.height < 1) { - return 1; - } else { - return b.timestamp - a.timestamp; - } - }) - .map(claim => { - return claim.canonical_url || claim.permanent_url; - }); - } + myClaims => myClaims.filter(claim => !claim.name.match(/^@/)) ); export const selectAllMyClaimsByOutpoint = createSelector( @@ -496,12 +250,9 @@ export const selectMyChannelClaims = createSelector( selectState, selectClaimsById, (state, byId) => { - const ids = state.myChannelClaims; - if (!ids) { - return ids; - } - + const ids = state.myChannelClaims || []; const claims = []; + ids.forEach(id => { if (byId[id]) { // I'm not sure why this check is necessary, but it ought to be a quick fix for https://github.com/lbryio/lbry-desktop/issues/544 @@ -513,21 +264,11 @@ export const selectMyChannelClaims = createSelector( } ); -export const selectMyChannelUrls = createSelector( - selectMyChannelClaims, - claims => (claims ? claims.map(claim => claim.canonical_url || claim.permanent_url) : undefined) -); - export const selectResolvingUris = createSelector( selectState, state => state.resolvingUris || [] ); -export const selectChannelImportPending = createSelector( - selectState, - state => state.pendingChannelImport -); - export const makeSelectIsUriResolving = (uri: string) => createSelector( selectResolvingUris, @@ -590,17 +331,6 @@ export const makeSelectNsfwCountForChannel = (uri: string) => } ); -export const makeSelectOmittedCountForChannel = (uri: string) => - createSelector( - makeSelectTotalItemsForChannel(uri), - makeSelectTotalClaimsInChannelSearch(uri), - (claimsInChannel, claimsInSearch) => { - if (claimsInChannel && typeof claimsInSearch === 'number' && claimsInSearch >= 0) { - return claimsInChannel - claimsInSearch; - } else return 0; - } - ); - export const makeSelectClaimIsNsfw = (uri: string): boolean => createSelector( makeSelectClaimForUri(uri), @@ -608,7 +338,7 @@ export const makeSelectClaimIsNsfw = (uri: string): boolean => // Or possibly come from users settings of what tags they want to hide // For now, there is just a hard coded list of tags inside `isClaimNsfw` // selectNaughtyTags(), - (claim: Claim) => { + (claim: StreamClaim) => { if (!claim) { return false; } @@ -621,31 +351,19 @@ export const makeSelectRecommendedContentForUri = (uri: string) => createSelector( makeSelectClaimForUri(uri), selectSearchUrisByQuery, - makeSelectClaimIsNsfw(uri), - (claim, searchUrisByQuery, isMature) => { + (claim, searchUrisByQuery) => { const atVanityURI = !uri.includes('#'); let recommendedContent; if (claim) { - // always grab full URL - this can change once search returns canonical - const currentUri = buildURI({ streamClaimId: claim.claim_id, streamName: claim.name }); + // If we are at a vanity uri, build the full uri so we can properly filter + const currentUri = atVanityURI + ? buildURI({ claimId: claim.claim_id, claimName: claim.name }) + : uri; const { title } = claim.value; - if (!title) { - return; - } - - const options: { - related_to?: string, - nsfw?: boolean, - isBackgroundSearch?: boolean, - } = { related_to: claim.claim_id, isBackgroundSearch: true }; - - if (!isMature) { - options['nsfw'] = false; - } - const searchQuery = getSearchQueryString(title.replace(/\//, ' '), options); + const searchQuery = getSearchQueryString(title.replace(/\//, ' ')); let searchUris = searchUrisByQuery[searchQuery]; if (searchUris) { @@ -670,172 +388,13 @@ export const makeSelectFirstRecommendedFileForUri = (uri: string) => export const makeSelectChannelForClaimUri = (uri: string, includePrefix: boolean = false) => createSelector( makeSelectClaimForUri(uri), - (claim: ?Claim) => { - if (!claim || !claim.signing_channel || !claim.is_channel_signature_valid) { + (claim: ?StreamClaim) => { + if (!claim || !claim.signing_channel) { return null; } - const { canonical_url: canonicalUrl, permanent_url: permanentUrl } = claim.signing_channel; - - if (canonicalUrl) { - return includePrefix ? canonicalUrl : canonicalUrl.slice('lbry://'.length); - } else { - return includePrefix ? permanentUrl : permanentUrl.slice('lbry://'.length); - } - } - ); - -export const makeSelectTagsForUri = (uri: string) => - createSelector( - makeSelectMetadataForUri(uri), - (metadata: ?GenericMetadata) => { - return (metadata && metadata.tags) || []; - } - ); - -export const selectFetchingClaimSearchByQuery = createSelector( - selectState, - state => state.fetchingClaimSearchByQuery || {} -); - -export const selectFetchingClaimSearch = createSelector( - selectFetchingClaimSearchByQuery, - fetchingClaimSearchByQuery => Boolean(Object.keys(fetchingClaimSearchByQuery).length) -); - -export const selectClaimSearchByQuery = createSelector( - selectState, - state => state.claimSearchByQuery || {} -); - -export const selectClaimSearchByQueryLastPageReached = createSelector( - selectState, - state => state.claimSearchByQueryLastPageReached || {} -); - -export const makeSelectShortUrlForUri = (uri: string) => - createSelector( - makeSelectClaimForUri(uri), - claim => claim && claim.short_url - ); - -export const makeSelectCanonicalUrlForUri = (uri: string) => - createSelector( - makeSelectClaimForUri(uri), - claim => claim && claim.canonical_url - ); - -export const makeSelectPermanentUrlForUri = (uri: string) => - createSelector( - makeSelectClaimForUri(uri), - claim => claim && claim.permanent_url - ); - -export const makeSelectSupportsForUri = (uri: string) => - createSelector( - selectSupportsByOutpoint, - makeSelectClaimForUri(uri), - (byOutpoint, claim: ?StreamClaim) => { - if (!claim || !claim.is_my_output) { - return null; - } - - const { claim_id: claimId } = claim; - let total = 0; - - Object.values(byOutpoint).forEach(support => { - // $FlowFixMe - const { claim_id, amount } = support; - total = claim_id === claimId && amount ? total + parseFloat(amount) : total; - }); - - return total; - } - ); - -export const selectUpdatingChannel = createSelector( - selectState, - state => state.updatingChannel -); - -export const selectUpdateChannelError = createSelector( - selectState, - state => state.updateChannelError -); - -export const makeSelectReflectingClaimForUri = (uri: string) => - createSelector( - selectClaimIdsByUri, - selectReflectingById, - (claimIdsByUri, reflectingById) => { - const claimId = claimIdsByUri[normalizeURI(uri)]; - return reflectingById[claimId]; - } - ); - -export const makeSelectMyStreamUrlsForPage = (page: number = 1) => - createSelector( - selectMyClaimUrisWithoutChannels, - urls => { - const start = (Number(page) - 1) * Number(PAGE_SIZE); - const end = Number(page) * Number(PAGE_SIZE); - - return urls && urls.length ? urls.slice(start, end) : []; - } - ); - -export const selectMyStreamUrlsCount = createSelector( - selectMyClaimUrisWithoutChannels, - channels => channels.length -); - -export const makeSelectResolvedRecommendedContentForUri = ( - uri: string, - size: number, - claimId: string, - claimName: string, - claimTitle: string -) => - createSelector( - makeSelectClaimForUri(uri), - selectResolvedSearchResultsByQuery, - makeSelectClaimIsNsfw(uri), - (claim, resolvedResultsByQuery, isMature) => { - const atVanityURI = !uri.includes('#'); - - let currentUri; - let recommendedContent; - let title; - if (claim) { - // always grab full URL - this can change once search returns canonical - currentUri = buildURI({ streamClaimId: claim.claim_id, streamName: claim.name }); - title = claim.value ? claim.value.title : null; - } else { - // for cases on mobile where the claim may not have been resolved () - currentUri = buildURI({ streamClaimId: claimId, streamName: claimName }); - title = claimTitle; - } - - if (!title) { - return; - } - - const options: { - related_to?: string, - nsfw?: boolean, - isBackgroundSearch?: boolean, - } = { related_to: claim ? claim.claim_id : claimId, size, isBackgroundSearch: false }; - - const searchQuery = getSearchQueryString(title.replace(/\//, ' '), options); - let results = resolvedResultsByQuery[searchQuery]; - if (results) { - results = results.filter( - result => - buildURI({ streamClaimId: result.claimId, streamName: result.name }) !== currentUri - ); - recommendedContent = results; - } - - return recommendedContent; + const { claim_id: claimId, name } = claim.signing_channel; + let channel = `${name}#${claimId}`; + return includePrefix ? `lbry://${channel}` : channel; } ); diff --git a/src/redux/selectors/comments.js b/src/redux/selectors/comments.js deleted file mode 100644 index d8033ff..0000000 --- a/src/redux/selectors/comments.js +++ /dev/null @@ -1,71 +0,0 @@ -// @flow -import { createSelector } from 'reselect'; - -const selectState = state => state.comments || {}; - -export const selectCommentsById = createSelector( - selectState, - state => state.commentById || {} -); - -export const selectIsFetchingComments = createSelector( - selectState, - state => state.isLoading -); - -export const selectCommentsByClaimId = createSelector( - selectState, - selectCommentsById, - (state, byId) => { - const byClaimId = state.byId || {}; - const comments = {}; - - // replace every comment_id in the list with the actual comment object - Object.keys(byClaimId).forEach(claimId => { - const commentIds = byClaimId[claimId]; - - comments[claimId] = Array(commentIds === null ? 0 : commentIds.length); - for (let i = 0; i < commentIds.length; i++) { - comments[claimId][i] = byId[commentIds[i]]; - } - }); - - return comments; - } -); - -// previously this used a mapping from claimId -> Array -/* export const selectCommentsById = createSelector( - selectState, - state => state.byId || {} -); */ -export const selectCommentsByUri = createSelector( - selectState, - state => { - const byUri = state.commentsByUri || {}; - const comments = {}; - Object.keys(byUri).forEach(uri => { - const claimId = byUri[uri]; - if (claimId === null) { - comments[uri] = null; - } else { - comments[uri] = claimId; - } - }); - - return comments; - } -); - -export const makeSelectCommentsForUri = (uri: string) => - createSelector( - selectCommentsByClaimId, - selectCommentsByUri, - (byClaimId, byUri) => { - const claimId = byUri[uri]; - return byClaimId && byClaimId[claimId]; - } - ); - -// todo: allow SDK to retrieve user comments through comment_list -// todo: implement selectors for selecting comments owned by user diff --git a/src/redux/selectors/content.js b/src/redux/selectors/content.js index 2daac6e..f3d967f 100644 --- a/src/redux/selectors/content.js +++ b/src/redux/selectors/content.js @@ -1,4 +1,3 @@ -// @flow import { createSelector } from 'reselect'; import { makeSelectClaimForUri } from 'redux/selectors/claims'; diff --git a/src/redux/selectors/file_info.js b/src/redux/selectors/file_info.js index d52987f..7ccfe7c 100644 --- a/src/redux/selectors/file_info.js +++ b/src/redux/selectors/file_info.js @@ -3,13 +3,9 @@ import { selectIsFetchingClaimListMine, selectMyClaims, selectClaimsById, - makeSelectContentTypeForUri, - makeSelectClaimForUri, } from 'redux/selectors/claims'; import { createSelector } from 'reselect'; import { buildURI } from 'lbryURI'; -import Lbry from 'lbry'; -import { PAGE_SIZE } from 'constants/claim'; export const selectState = state => state.fileInfo || {}; @@ -57,40 +53,28 @@ export const makeSelectDownloadingForUri = uri => export const selectUrisLoading = createSelector( selectState, - state => state.fetching || {} + state => state.urisLoading || {} ); export const makeSelectLoadingForUri = uri => createSelector( selectUrisLoading, - makeSelectClaimForUri(uri), - (fetchingByOutpoint, claim) => { - if (!claim) { - return false; - } - - const { txid, nout } = claim; - const outpoint = `${txid}:${nout}`; - const isFetching = fetchingByOutpoint[outpoint]; - return isFetching; - } + byUri => byUri && byUri[uri] ); export const selectFileInfosDownloaded = createSelector( selectFileInfosByOutpoint, selectMyClaims, (byOutpoint, myClaims) => - Object.values(byOutpoint) - .reverse() - .filter(fileInfo => { - const myClaimIds = myClaims.map(claim => claim.claim_id); + Object.values(byOutpoint).filter(fileInfo => { + const myClaimIds = myClaims.map(claim => claim.claim_id); - return ( - fileInfo && - myClaimIds.indexOf(fileInfo.claim_id) === -1 && - (fileInfo.completed || fileInfo.written_bytes > 0 || fileInfo.blobs_completed > 0) - ); - }) + return ( + fileInfo && + myClaimIds.indexOf(fileInfo.claim_id) === -1 && + (fileInfo.completed || fileInfo.written_bytes) + ); + }) ); // export const selectFileInfoForUri = (state, props) => { @@ -135,6 +119,104 @@ export const selectTotalDownloadProgress = createSelector( } ); +export const selectSearchDownloadUris = query => + createSelector( + selectFileInfosDownloaded, + selectClaimsById, + (fileInfos, claimsById) => { + if (!query || !fileInfos.length) { + return null; + } + + const queryParts = query.toLowerCase().split(' '); + const searchQueryDictionary = {}; + queryParts.forEach(subQuery => { + searchQueryDictionary[subQuery] = subQuery; + }); + + const arrayContainsQueryPart = array => { + for (let i = 0; i < array.length; i += 1) { + const subQuery = array[i]; + if (searchQueryDictionary[subQuery]) { + return true; + } + } + return false; + }; + + const downloadResultsFromQuery = []; + fileInfos.forEach(fileInfo => { + const { channel_name: channelName, claim_name: claimName, metadata } = fileInfo; + const { author, description, title } = metadata; + + if (channelName) { + const lowerCaseChannel = channelName.toLowerCase(); + const strippedOutChannelName = lowerCaseChannel.slice(1); // trim off the @ + if (searchQueryDictionary[channelName] || searchQueryDictionary[strippedOutChannelName]) { + downloadResultsFromQuery.push(fileInfo); + return; + } + } + + const nameParts = claimName.toLowerCase().split('-'); + if (arrayContainsQueryPart(nameParts)) { + downloadResultsFromQuery.push(fileInfo); + return; + } + + const titleParts = title.toLowerCase().split(' '); + if (arrayContainsQueryPart(titleParts)) { + downloadResultsFromQuery.push(fileInfo); + return; + } + + if (author) { + const authorParts = author.toLowerCase().split(' '); + if (arrayContainsQueryPart(authorParts)) { + downloadResultsFromQuery.push(fileInfo); + return; + } + } + + if (description) { + const descriptionParts = description.toLowerCase().split(' '); + if (arrayContainsQueryPart(descriptionParts)) { + downloadResultsFromQuery.push(fileInfo); + } + } + }); + + return downloadResultsFromQuery.length + ? downloadResultsFromQuery.map(fileInfo => { + const { + channel_name: channelName, + claim_id: claimId, + claim_name: claimName, + } = fileInfo; + + const uriParams = {}; + + if (channelName) { + const claim = claimsById[claimId]; + if (claim) { + uriParams.claimId = claim.channel_id; + } else { + uriParams.claimId = claimId; + } + uriParams.channelName = channelName; + uriParams.contentName = claimName; + } else { + uriParams.claimId = claimId; + uriParams.claimName = claimName; + } + + const uri = buildURI(uriParams); + return uri; + }) + : null; + } + ); + export const selectFileListPublishedSort = createSelector( selectState, state => state.fileListPublishedSort @@ -144,118 +226,3 @@ export const selectFileListDownloadedSort = createSelector( selectState, state => state.fileListDownloadedSort ); - -export const selectDownloadedUris = createSelector( - selectFileInfosDownloaded, - // We should use permament_url but it doesn't exist in file_list - info => info.slice().map(claim => `lbry://${claim.claim_name}#${claim.claim_id}`) -); - -export const makeSelectMediaTypeForUri = uri => - createSelector( - makeSelectFileInfoForUri(uri), - makeSelectContentTypeForUri(uri), - (fileInfo, contentType) => { - if (!fileInfo && !contentType) { - return undefined; - } - - const fileName = fileInfo && fileInfo.file_name; - return Lbry.getMediaType(contentType, fileName); - } - ); - -export const makeSelectUriIsStreamable = uri => - createSelector( - makeSelectMediaTypeForUri(uri), - mediaType => { - const isStreamable = ['audio', 'video', 'image'].indexOf(mediaType) !== -1; - return isStreamable; - } - ); - -export const makeSelectDownloadPathForUri = uri => - createSelector( - makeSelectFileInfoForUri(uri), - fileInfo => { - return fileInfo && fileInfo.download_path; - } - ); - -export const makeSelectFilePartlyDownloaded = uri => - createSelector( - makeSelectFileInfoForUri(uri), - fileInfo => { - if (!fileInfo) { - return false; - } - - return fileInfo.written_bytes > 0 || fileInfo.blobs_completed > 0; - } - ); - -export const makeSelectFileNameForUri = uri => - createSelector( - makeSelectFileInfoForUri(uri), - fileInfo => { - return fileInfo && fileInfo.file_name; - } - ); - -export const selectDownloadUrlsCount = createSelector( - selectDownloadedUris, - uris => uris.length -); - -function filterFileInfos(fileInfos, query) { - if (query) { - const queryMatchRegExp = new RegExp(query, 'i'); - return fileInfos.filter(fileInfo => { - const { metadata } = fileInfo; - - return ( - (metadata.title && metadata.title.match(queryMatchRegExp)) || - (fileInfo.channel_name && fileInfo.channel_name.match(queryMatchRegExp)) || - (fileInfo.claim_name && fileInfo.claim_name.match(queryMatchRegExp)) - ); - }); - } - - return fileInfos; -} - -export const makeSelectSearchDownloadUrlsForPage = (query, page = 1) => - createSelector( - selectFileInfosDownloaded, - fileInfos => { - const matchingFileInfos = filterFileInfos(fileInfos, query); - const start = (Number(page) - 1) * Number(PAGE_SIZE); - const end = Number(page) * Number(PAGE_SIZE); - - return matchingFileInfos && matchingFileInfos.length - ? matchingFileInfos.slice(start, end).map(fileInfo => - buildURI({ - streamName: fileInfo.claim_name, - channelName: fileInfo.channel_name, - channelClaimId: fileInfo.channel_claim_id, - }) - ) - : []; - } - ); - -export const makeSelectSearchDownloadUrlsCount = query => - createSelector( - selectFileInfosDownloaded, - fileInfos => { - return fileInfos && fileInfos.length ? filterFileInfos(fileInfos, query).length : 0; - } - ); - -export const makeSelectStreamingUrlForUri = uri => - createSelector( - makeSelectFileInfoForUri(uri), - fileInfo => { - return fileInfo && fileInfo.streaming_url; - } - ); diff --git a/src/redux/selectors/navigation.js b/src/redux/selectors/navigation.js new file mode 100644 index 0000000..71992c7 --- /dev/null +++ b/src/redux/selectors/navigation.js @@ -0,0 +1,78 @@ +import { createSelector } from 'reselect'; +import { parseQueryParams } from 'util/query_params'; + +export const selectState = state => state.navigation || {}; + +export const selectCurrentPath = createSelector( + selectState, + state => state.currentPath +); + +export const computePageFromPath = path => (path ? path.replace(/^\//, '').split('?')[0] : ''); + +export const selectCurrentPage = createSelector( + selectCurrentPath, + path => computePageFromPath(path) +); + +export const selectCurrentParams = createSelector( + selectCurrentPath, + path => { + if (path === undefined) return {}; + if (!path.match(/\?/)) return {}; + + return parseQueryParams(path.split('?')[1]); + } +); + +export const makeSelectCurrentParam = param => + createSelector( + selectCurrentParams, + params => (params ? params[param] : undefined) + ); + +export const selectPathAfterAuth = createSelector( + selectState, + state => state.pathAfterAuth +); + +export const selectIsBackDisabled = createSelector( + selectState, + state => state.index === 0 +); + +export const selectIsForwardDisabled = createSelector( + selectState, + state => state.index === state.stack.length - 1 +); + +export const selectIsHome = createSelector( + selectCurrentPage, + page => page === 'discover' +); + +export const selectHistoryIndex = createSelector( + selectState, + state => state.index +); + +export const selectHistoryStack = createSelector( + selectState, + state => state.stack +); + +// returns current page attributes (scrollY, path) +export const selectActiveHistoryEntry = createSelector( + selectState, + state => state.stack[state.index] +); + +export const selectPageTitle = createSelector( + selectCurrentPage, + page => { + switch (page) { + default: + return ''; + } + } +); diff --git a/src/redux/selectors/publish.js b/src/redux/selectors/publish.js deleted file mode 100644 index 10ed95b..0000000 --- a/src/redux/selectors/publish.js +++ /dev/null @@ -1,134 +0,0 @@ -import { createSelector } from 'reselect'; -import { buildURI, parseURI } from 'lbryURI'; -import { - selectClaimsById, - selectMyClaimsWithoutChannels, - selectResolvingUris, - selectClaimsByUri, -} from 'redux/selectors/claims'; - -const selectState = state => state.publish || {}; - -// Is the current uri the same as the uri they clicked "edit" on -export const selectIsStillEditing = createSelector( - selectState, - publishState => { - const { editingURI, uri } = publishState; - - if (!editingURI || !uri) { - return false; - } - - const { - isChannel: currentIsChannel, - streamName: currentClaimName, - channelName: currentContentName, - } = parseURI(uri); - const { - isChannel: editIsChannel, - streamName: editClaimName, - channelName: editContentName, - } = parseURI(editingURI); - - // Depending on the previous/current use of a channel, we need to compare different things - // ex: going from a channel to anonymous, the new uri won't return contentName, so we need to use claimName - const currentName = currentIsChannel ? currentContentName : currentClaimName; - const editName = editIsChannel ? editContentName : editClaimName; - return currentName === editName; - } -); - -export const selectPublishFormValues = createSelector( - selectState, - selectIsStillEditing, - (state, isStillEditing) => { - const { pendingPublish, language, languages, ...formValues } = state; - - let actualLanguage; - // Sets default if editing a claim with a set language - if (!language && isStillEditing && languages && languages[0]) { - actualLanguage = languages[0]; - } else { - actualLanguage = language || 'en'; - } - return { ...formValues, language: actualLanguage }; - } -); - -export const makeSelectPublishFormValue = item => - createSelector( - selectState, - state => state[item] - ); - -export const selectMyClaimForUri = createSelector( - selectPublishFormValues, - selectIsStillEditing, - selectClaimsById, - selectMyClaimsWithoutChannels, - ({ editingURI, uri }, isStillEditing, claimsById, myClaims) => { - const { channelName: contentName, streamName: claimName } = parseURI(uri); - const { streamClaimId: editClaimId } = parseURI(editingURI); - - // If isStillEditing - // They clicked "edit" from the file page - // They haven't changed the channel/name after clicking edit - // Get the claim so they can edit without re-uploading a new file - return isStillEditing - ? claimsById[editClaimId] - : myClaims.find(claim => - !contentName - ? claim.name === claimName - : claim.name === contentName || claim.name === claimName - ); - } -); - -export const selectIsResolvingPublishUris = createSelector( - selectState, - selectResolvingUris, - ({ uri, name }, resolvingUris) => { - if (uri) { - const isResolvingUri = resolvingUris.includes(uri); - const { isChannel } = parseURI(uri); - - let isResolvingShortUri; - if (isChannel && name) { - const shortUri = buildURI({ streamName: name }); - isResolvingShortUri = resolvingUris.includes(shortUri); - } - - return isResolvingUri || isResolvingShortUri; - } - - return false; - } -); - -export const selectTakeOverAmount = createSelector( - selectState, - selectMyClaimForUri, - selectClaimsByUri, - ({ name }, myClaimForUri, claimsByUri) => { - if (!name) { - return null; - } - - // We only care about the winning claim for the short uri - const shortUri = buildURI({ streamName: name }); - const claimForShortUri = claimsByUri[shortUri]; - - if (!myClaimForUri && claimForShortUri) { - return claimForShortUri.meta.effective_amount; - } else if (myClaimForUri && claimForShortUri) { - // https://github.com/lbryio/lbry/issues/1476 - // We should check the current effective_amount on my claim to see how much additional lbc - // is needed to win the claim. Currently this is not possible during a takeover. - // With this, we could say something like, "You have x lbc in support, if you bid y additional LBC you will control the claim" - // For now just ignore supports. We will just show the winning claim's bid amount - return claimForShortUri.meta.effective_amount || claimForShortUri.amount; - } - - return null; - } -); diff --git a/src/redux/selectors/search.js b/src/redux/selectors/search.js index b5288fd..b519425 100644 --- a/src/redux/selectors/search.js +++ b/src/redux/selectors/search.js @@ -1,6 +1,6 @@ // @flow import { SEARCH_TYPES, SEARCH_OPTIONS } from 'constants/search'; -import { getSearchQueryString } from 'util/query-params'; +import { getSearchQueryString } from 'util/query_params'; import { normalizeURI, parseURI } from 'lbryURI'; import { createSelector } from 'reselect'; @@ -44,38 +44,6 @@ export const makeSelectSearchUris = (query: string): ((state: State) => Array byQuery[query ? query.replace(/^lbry:\/\//i, '').replace(/\//, ' ') : query] ); -export const selectResolvedSearchResultsByQuery: ( - state: State -) => { [string]: Array } = createSelector( - selectState, - state => state.resolvedResultsByQuery -); - -export const selectResolvedSearchResultsByQueryLastPageReached: ( - state: State -) => { [string]: Array } = createSelector( - selectState, - state => state.resolvedResultsByQueryLastPageReached -); - -export const makeSelectResolvedSearchResults = ( - query: string -): ((state: State) => Array) => - // replace statement below is kind of ugly, and repeated in doSearch action - createSelector( - selectResolvedSearchResultsByQuery, - byQuery => byQuery[query ? query.replace(/^lbry:\/\//i, '').replace(/\//, ' ') : query] - ); - -export const makeSelectResolvedSearchResultsLastPageReached = ( - query: string -): ((state: State) => boolean) => - // replace statement below is kind of ugly, and repeated in doSearch action - createSelector( - selectResolvedSearchResultsByQueryLastPageReached, - byQuery => byQuery[query ? query.replace(/^lbry:\/\//i, '').replace(/\//, ' ') : query] - ); - export const selectSearchBarFocused: boolean = createSelector( selectState, state => state.focused @@ -88,35 +56,35 @@ export const selectSearchSuggestions: Array = createSelector( if (!query) { return []; } - const queryIsPrefix = - query === 'lbry:' || query === 'lbry:/' || query === 'lbry://' || query === 'lbry://@'; - if (queryIsPrefix) { - // If it is a prefix, wait until something else comes to figure out what to do - return []; - } else if (query.startsWith('lbry://')) { + const queryIsPrefix = query === 'lbry:' || query === 'lbry:/' || query === 'lbry://'; + + if (query.startsWith('lbry://') && query !== 'lbry://') { // If it starts with a prefix, don't show any autocomplete results // They are probably typing/pasting in a lbry uri return [ { value: query, - type: query[7] === '@' ? SEARCH_TYPES.CHANNEL : SEARCH_TYPES.FILE, + type: SEARCH_TYPES.FILE, }, ]; + } else if (queryIsPrefix) { + // If it is a prefix, wait until something else comes to figure out what to do + return []; } let searchSuggestions = []; try { const uri = normalizeURI(query); - const { channelName, streamName, isChannel } = parseURI(uri); + const { claimName, isChannel } = parseURI(uri); searchSuggestions.push( { - value: query, + value: claimName, type: SEARCH_TYPES.SEARCH, }, { value: uri, - shorthand: isChannel ? channelName : streamName, + shorthand: isChannel ? claimName.slice(1) : claimName, type: isChannel ? SEARCH_TYPES.CHANNEL : SEARCH_TYPES.FILE, } ); @@ -127,11 +95,6 @@ export const selectSearchSuggestions: Array = createSelector( }); } - searchSuggestions.push({ - value: query, - type: SEARCH_TYPES.TAG, - }); - const apiSuggestions = suggestions[query] || []; if (apiSuggestions.length) { searchSuggestions = searchSuggestions.concat( @@ -141,11 +104,11 @@ export const selectSearchSuggestions: Array = createSelector( // determine if it's a channel try { const uri = normalizeURI(suggestion); - const { channelName, streamName, isChannel } = parseURI(uri); + const { claimName, isChannel } = parseURI(uri); return { value: uri, - shorthand: isChannel ? channelName : streamName, + shorthand: isChannel ? claimName.slice(1) : claimName, type: isChannel ? SEARCH_TYPES.CHANNEL : SEARCH_TYPES.FILE, }; } catch (e) { @@ -165,22 +128,23 @@ export const selectSearchSuggestions: Array = createSelector( // Creates a query string based on the state in the search reducer // Can be overrided by passing in custom sizes/from values for other areas pagination - -type CustomOptions = { - isBackgroundSearch?: boolean, - size?: number, - from?: number, - related_to?: string, - nsfw?: boolean, -}; - -export const makeSelectQueryWithOptions = (customQuery: ?string, options: CustomOptions) => +export const makeSelectQueryWithOptions = ( + customQuery: ?string, + customSize: ?number, + customFrom: ?number, + isBackgroundSearch: boolean = false // If it's a background search, don't use the users settings +) => createSelector( selectSearchValue, selectSearchOptions, - (query, defaultOptions) => { - const searchOptions = { ...defaultOptions, ...options }; - const queryString = getSearchQueryString(customQuery || query, searchOptions); + (query, options) => { + const size = customSize || options[SEARCH_OPTIONS.RESULT_COUNT]; + + const queryString = getSearchQueryString( + customQuery || query, + { ...options, size, from: customFrom }, + !isBackgroundSearch + ); return queryString; } diff --git a/src/redux/selectors/tags.js b/src/redux/selectors/tags.js deleted file mode 100644 index 17f3fd8..0000000 --- a/src/redux/selectors/tags.js +++ /dev/null @@ -1,47 +0,0 @@ -// @flow -import { createSelector } from 'reselect'; - -const selectState = (state: { tags: TagState }) => state.tags || {}; - -export const selectKnownTagsByName = createSelector( - selectState, - (state: TagState): KnownTags => state.knownTags -); - -export const selectFollowedTagsList = createSelector( - selectState, - (state: TagState): Array => state.followedTags.filter(tag => typeof tag === 'string') -); - -export const selectFollowedTags = createSelector( - selectFollowedTagsList, - (followedTags: Array): Array => - followedTags - .map(tag => ({ name: tag.toLowerCase() })) - .sort((a, b) => a.name.localeCompare(b.name)) -); - -export const selectUnfollowedTags = createSelector( - selectKnownTagsByName, - selectFollowedTagsList, - (tagsByName: KnownTags, followedTags: Array): Array => { - const followedTagsSet = new Set(followedTags); - let tagsToReturn = []; - Object.keys(tagsByName).forEach(key => { - if (!followedTagsSet.has(key)) { - const { name } = tagsByName[key]; - tagsToReturn.push({ name: name.toLowerCase() }); - } - }); - - return tagsToReturn; - } -); - -export const makeSelectIsFollowingTag = (tag: string) => - createSelector( - selectFollowedTags, - followedTags => { - return followedTags.some(followedTag => followedTag.name === tag.toLowerCase()); - } - ); diff --git a/src/redux/selectors/wallet.js b/src/redux/selectors/wallet.js index 6765f59..636c406 100644 --- a/src/redux/selectors/wallet.js +++ b/src/redux/selectors/wallet.js @@ -1,7 +1,6 @@ import { createSelector } from 'reselect'; import * as TRANSACTIONS from 'constants/transaction_types'; -import { PAGE_SIZE, LATEST_PAGE_SIZE } from 'constants/transaction_list'; -import { selectClaimIdsByUri } from 'redux/selectors/claims'; + export const selectState = state => state.wallet || {}; export const selectWalletState = selectState; @@ -21,27 +20,6 @@ export const selectWalletEncryptSucceeded = createSelector( state => state.walletEncryptSucceded ); -export const selectPendingSupportTransactions = createSelector( - selectState, - state => state.pendingSupportTransactions -); - -export const selectAbandonClaimSupportError = createSelector( - selectState, - state => state.abandonClaimSupportError -); - -export const makeSelectPendingAmountByUri = (uri) => createSelector( - selectClaimIdsByUri, - selectPendingSupportTransactions, - (claimIdsByUri, pendingSupports) => { - const uriEntry = Object.entries(claimIdsByUri).find(([u, cid]) => u === uri); - const claimId = uriEntry && uriEntry[1]; - const pendingSupport = claimId && pendingSupports[claimId]; - return pendingSupport ? pendingSupport.effective : undefined; - } -); - export const selectWalletEncryptResult = createSelector( selectState, state => state.walletEncryptResult @@ -102,48 +80,9 @@ export const selectTotalBalance = createSelector( state => state.totalBalance ); -export const selectReservedBalance = createSelector( - selectState, - state => state.reservedBalance -); - -export const selectClaimsBalance = createSelector( - selectState, - state => state.claimsBalance -); - -export const selectSupportsBalance = createSelector( - selectState, - state => state.supportsBalance -); - -export const selectTipsBalance = createSelector( - selectState, - state => state.tipsBalance -); - export const selectTransactionsById = createSelector( selectState, - state => state.transactions || {} -); - -export const selectSupportsByOutpoint = createSelector( - selectState, - state => state.supports || {} -); - -export const selectTotalSupports = createSelector( - selectSupportsByOutpoint, - byOutpoint => { - let total = parseFloat('0.0'); - - Object.values(byOutpoint).forEach(support => { - const { amount } = support; - total = amount ? total + parseFloat(amount) : total; - }); - - return total; - } + state => state.transactions ); export const selectTransactionItems = createSelector( @@ -191,9 +130,26 @@ export const selectTransactionItems = createSelector( if (!append.length) { append.push( - Object.assign({}, tx, { - type: tx.value < 0 ? TRANSACTIONS.SPEND : TRANSACTIONS.RECEIVE, - }) + ...tx.claim_info.map(item => + Object.assign({}, tx, item, { + type: item.claim_name[0] === '@' ? TRANSACTIONS.CHANNEL : TRANSACTIONS.PUBLISH, + }) + ) + ); + append.push( + ...tx.support_info.map(item => + Object.assign({}, tx, item, { + type: !item.is_tip ? TRANSACTIONS.SUPPORT : TRANSACTIONS.TIP, + }) + ) + ); + append.push( + ...tx.update_info.map(item => Object.assign({}, tx, item, { type: TRANSACTIONS.UPDATE })) + ); + append.push( + ...tx.abandon_info.map(item => + Object.assign({}, tx, item, { type: TRANSACTIONS.ABANDON }) + ) ); } @@ -306,76 +262,32 @@ export const selectCurrentHeight = createSelector( state => state.latestBlock ); +export const makeSelectBlockDate = block => + createSelector( + selectBlocks, + selectCurrentHeight, + (blocks, latestBlock) => { + // If we have the block data, look at the actual date, + // If not, try to simulate it based on 2.5 minute blocks + // Adding this on 11/7/2018 because caling block_show for every claim is causing + // performance issues. + if (blocks && blocks[block]) { + return new Date(blocks[block].time * 1000); + } + + // Pending claim + if (block < 1) { + return null; + } + + const difference = latestBlock - block; + const msSincePublish = difference * 2.5 * 60 * 1000; // Number of blocks * 2.5 minutes in ms + const publishDate = Date.now() - msSincePublish; + return new Date(publishDate); + } + ); + export const selectTransactionListFilter = createSelector( selectState, state => state.transactionListFilter || '' ); - -export const selectFilteredTransactions = createSelector( - selectTransactionItems, - selectTransactionListFilter, - (transactions, filter) => { - return transactions.filter(transaction => { - return filter === TRANSACTIONS.ALL || filter === transaction.type; - }); - } -); - -export const selectTxoPageParams = createSelector( - selectState, - state => state.txoFetchParams -); - -export const selectTxoPage = createSelector( - selectState, - state => (state.txoPage && state.txoPage.items) || [], -); - -export const selectTxoPageNumber = createSelector( - selectState, - state => (state.txoPage && state.txoPage.page) || 1, -); - -export const selectTxoItemCount = createSelector( - selectState, - state => (state.txoPage && state.txoPage.total_items) || 1, -); - -export const selectFetchingTxosError = createSelector( - selectState, - state => state.fetchingTxosError, -); - -export const selectIsFetchingTxos = createSelector( - selectState, - state => state.fetchingTxos, -); - -export const makeSelectFilteredTransactionsForPage = (page = 1) => - createSelector( - selectFilteredTransactions, - filteredTransactions => { - const start = (Number(page) - 1) * Number(PAGE_SIZE); - const end = Number(page) * Number(PAGE_SIZE); - return filteredTransactions && filteredTransactions.length - ? filteredTransactions.slice(start, end) - : []; - } - ); - -export const makeSelectLatestTransactions = createSelector( - selectTransactionItems, - transactions => { - return transactions && transactions.length ? transactions.slice(0, LATEST_PAGE_SIZE) : []; - } -); - -export const selectFilteredTransactionCount = createSelector( - selectFilteredTransactions, - filteredTransactions => filteredTransactions.length -); - -export const selectIsWalletReconnecting = createSelector( - selectState, - state => state.walletReconnecting -); diff --git a/src/util/batch-actions.js b/src/util/batchActions.js similarity index 100% rename from src/util/batch-actions.js rename to src/util/batchActions.js diff --git a/src/util/claim.js b/src/util/claim.js index aa685f8..0e56ce3 100644 --- a/src/util/claim.js +++ b/src/util/claim.js @@ -1,9 +1,11 @@ // @flow -import { MATURE_TAGS } from 'constants/tags'; -const matureTagMap = MATURE_TAGS.reduce((acc, tag) => ({ ...acc, [tag]: true }), {}); +const naughtyTags = ['porn', 'nsfw', 'mature', 'xxx'].reduce( + (acc, tag) => ({ ...acc, [tag]: true }), + {} +); -export const isClaimNsfw = (claim: Claim): boolean => { +export const isClaimNsfw = (claim: StreamClaim): boolean => { if (!claim) { throw new Error('No claim passed to isClaimNsfw()'); } @@ -15,56 +17,10 @@ export const isClaimNsfw = (claim: Claim): boolean => { const tags = claim.value.tags || []; for (let i = 0; i < tags.length; i += 1) { const tag = tags[i].toLowerCase(); - if (matureTagMap[tag]) { + if (naughtyTags[tag]) { return true; } } return false; }; - -export function createNormalizedClaimSearchKey(options: { page: number, release_time?: string }) { - // Ignore page because we don't care what the last page searched was, we want everything - // Ignore release_time because that will change depending on when you call claim_search ex: release_time: ">12344567" - const { page: optionToIgnoreForQuery, release_time: anotherToIgnore, ...rest } = options; - const query = JSON.stringify(rest); - return query; -} - -export function concatClaims( - claimList: Array = [], - concatClaimList: Array = [] -): Array { - if (!claimList || claimList.length === 0) { - if (!concatClaimList) { - return []; - } - return concatClaimList.slice(); - } - - const claims = claimList.slice(); - concatClaimList.forEach(claim => { - if (!claims.some(item => item.claim_id === claim.claim_id)) { - claims.push(claim); - } - }); - - return claims; -} - -export function filterClaims(claims: Array, query: ?string): Array { - if (query) { - const queryMatchRegExp = new RegExp(query, 'i'); - return claims.filter(claim => { - const { value } = claim; - - return ( - (value.title && value.title.match(queryMatchRegExp)) || - (claim.signing_channel && claim.signing_channel.name.match(queryMatchRegExp)) || - (claim.name && claim.name.match(queryMatchRegExp)) - ); - }); - } - - return claims; -} diff --git a/src/util/deep-equal.js b/src/util/deep-equal.js deleted file mode 100644 index 1925763..0000000 --- a/src/util/deep-equal.js +++ /dev/null @@ -1,117 +0,0 @@ -/* eslint-disable */ -// underscore's deep equal function -// https://github.com/jashkenas/underscore/blob/master/underscore.js#L1189 - -export default function isEqual(a, b, aStack, bStack) { - // Identical objects are equal. `0 === -0`, but they aren't identical. - // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal). - if (a === b) return a !== 0 || 1 / a === 1 / b; - // `null` or `undefined` only equal to itself (strict comparison). - if (a == null || b == null) return false; - // `NaN`s are equivalent, but non-reflexive. - if (a !== a) return b !== b; - // Exhaust primitive checks - var type = typeof a; - if (type !== 'function' && type !== 'object' && typeof b != 'object') return false; - return deepEq(a, b, aStack, bStack); -} - -function deepEq(a, b, aStack, bStack) { - // Compare `[[Class]]` names. - var className = toString.call(a); - if (className !== toString.call(b)) return false; - switch (className) { - // Strings, numbers, regular expressions, dates, and booleans are compared by value. - case '[object RegExp]': - // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i') - case '[object String]': - // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is - // equivalent to `new String("5")`. - return '' + a === '' + b; - case '[object Number]': - // `NaN`s are equivalent, but non-reflexive. - // Object(NaN) is equivalent to NaN. - if (+a !== +a) return +b !== +b; - // An `egal` comparison is performed for other numeric values. - return +a === 0 ? 1 / +a === 1 / b : +a === +b; - case '[object Date]': - case '[object Boolean]': - // Coerce dates and booleans to numeric primitive values. Dates are compared by their - // millisecond representations. Note that invalid dates with millisecond representations - // of `NaN` are not equivalent. - return +a === +b; - case '[object Symbol]': - return SymbolProto.valueOf.call(a) === SymbolProto.valueOf.call(b); - } - - var areArrays = className === '[object Array]'; - if (!areArrays) { - if (typeof a != 'object' || typeof b != 'object') return false; - - // Objects with different constructors are not equivalent, but `Object`s or `Array`s - // from different frames are. - var aCtor = a.constructor, - bCtor = b.constructor; - if ( - aCtor !== bCtor && - !( - typeof aCtor === 'function' && - aCtor instanceof aCtor && - typeof bCtor === 'function' && - bCtor instanceof bCtor - ) && - ('constructor' in a && 'constructor' in b) - ) { - return false; - } - } - // Assume equality for cyclic structures. The algorithm for detecting cyclic - // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. - - // Initializing stack of traversed objects. - // It's done here since we only need them for objects and arrays comparison. - aStack = aStack || []; - bStack = bStack || []; - var length = aStack.length; - while (length--) { - // Linear search. Performance is inversely proportional to the number of - // unique nested structures. - if (aStack[length] === a) return bStack[length] === b; - } - - // Add the first object to the stack of traversed objects. - aStack.push(a); - bStack.push(b); - - // Recursively compare objects and arrays. - if (areArrays) { - // Compare array lengths to determine if a deep comparison is necessary. - length = a.length; - if (length !== b.length) return false; - // Deep compare the contents, ignoring non-numeric properties. - while (length--) { - if (!isEqual(a[length], b[length], aStack, bStack)) return false; - } - } else { - // Deep compare objects. - var keys = Object.keys(a), - key; - length = keys.length; - // Ensure that both objects contain the same number of properties before comparing deep equality. - if (Object.keys(b).length !== length) return false; - while (length--) { - // Deep compare each member - key = keys[length]; - if (!(has(b, key) && isEqual(a[key], b[key], aStack, bStack))) return false; - } - } - // Remove the first object from the stack of traversed objects. - aStack.pop(); - bStack.pop(); - return true; -} - -function has(obj, path) { - return obj != null && hasOwnProperty.call(obj, path); -} -/* eslint-enable */ diff --git a/src/util/format-credits.js b/src/util/format-credits.js deleted file mode 100644 index a090a33..0000000 --- a/src/util/format-credits.js +++ /dev/null @@ -1,62 +0,0 @@ -function numberWithCommas(x) { - var parts = x.toString().split('.'); - parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ','); - return parts.join('.'); -} - -export function formatCredits(amount, precision, shortFormat = false) { - let actualAmount = parseFloat(amount); - let actualPrecision = parseFloat(precision); - let suffix = ''; - - if (Number.isNaN(actualAmount) || actualAmount === 0) return '0'; - - if (actualAmount >= 1000000) { - if (precision <= 7) { - if (shortFormat) { - actualAmount = actualAmount / 1000000; - suffix = 'M'; - } else { - actualPrecision -= 7; - } - } - } else if (actualAmount >= 1000) { - if (precision <= 4) { - if (shortFormat) { - actualAmount = actualAmount / 1000; - suffix = 'K'; - } else { - actualPrecision -= 4; - } - } - } - - return ( - numberWithCommas( - actualAmount.toFixed(actualPrecision >= 0 ? actualPrecision : 1).replace(/\.*0+$/, '') - ) + suffix - ); -} - -export function formatFullPrice(amount, precision = 1) { - let formated = ''; - - const quantity = amount.toString().split('.'); - const fraction = quantity[1]; - - if (fraction) { - const decimals = fraction.split(''); - const first = decimals.filter(number => number !== '0')[0]; - const index = decimals.indexOf(first); - - // Set format fraction - formated = `.${fraction.substring(0, index + precision)}`; - } - - return parseFloat(quantity[0] + formated); -} - -export function creditsToString(amount) { - const creditString = parseFloat(amount).toFixed(8); - return creditString; -} diff --git a/src/util/formatCredits.js b/src/util/formatCredits.js new file mode 100644 index 0000000..d4c4b49 --- /dev/null +++ b/src/util/formatCredits.js @@ -0,0 +1,29 @@ +export function formatCredits(amount, precision) { + if (Number.isNaN(parseFloat(amount))) return '0'; + return parseFloat(amount) + .toFixed(precision || 1) + .replace(/\.?0+$/, ''); +} + +export function formatFullPrice(amount, precision = 1) { + let formated = ''; + + const quantity = amount.toString().split('.'); + const fraction = quantity[1]; + + if (fraction) { + const decimals = fraction.split(''); + const first = decimals.filter(number => number !== '0')[0]; + const index = decimals.indexOf(first); + + // Set format fraction + formated = `.${fraction.substring(0, index + precision)}`; + } + + return parseFloat(quantity[0] + formated); +} + +export function creditsToString(amount) { + const creditString = parseFloat(amount).toFixed(8); + return creditString; +} diff --git a/src/util/merge-claim.js b/src/util/merge-claim.js deleted file mode 100644 index 3ab2976..0000000 --- a/src/util/merge-claim.js +++ /dev/null @@ -1,7 +0,0 @@ -/* -new claim = { ...maybeResolvedClaim, ...pendingClaim, meta: maybeResolvedClaim['meta'] } - */ - -export default function mergeClaims(maybeResolved, pending){ - return { ...maybeResolved, ...pending, meta: maybeResolved.meta }; -} diff --git a/src/util/query-params.js b/src/util/query-params.js deleted file mode 100644 index 0c207ce..0000000 --- a/src/util/query-params.js +++ /dev/null @@ -1,85 +0,0 @@ -// @flow -import { SEARCH_OPTIONS } from 'constants/search'; - -const DEFAULT_SEARCH_RESULT_FROM = 0; -const DEFAULT_SEARCH_SIZE = 20; - -export function parseQueryParams(queryString: string) { - if (queryString === '') return {}; - const parts = queryString - .split('?') - .pop() - .split('&') - .map(p => p.split('=')); - - const params = {}; - parts.forEach(array => { - const [first, second] = array; - params[first] = second; - }); - return params; -} - -export function toQueryString(params: { [string]: string | number }) { - if (!params) return ''; - - const parts = []; - Object.keys(params).forEach(key => { - if (Object.prototype.hasOwnProperty.call(params, key) && params[key]) { - parts.push(`${key}=${params[key]}`); - } - }); - - return parts.join('&'); -} - -export const getSearchQueryString = (query: string, options: any = {}) => { - const encodedQuery = encodeURIComponent(query); - const queryParams = [ - `s=${encodedQuery}`, - `size=${options.size || DEFAULT_SEARCH_SIZE}`, - `from=${options.from || DEFAULT_SEARCH_RESULT_FROM}`, - ]; - const { isBackgroundSearch } = options; - const includeUserOptions = - typeof isBackgroundSearch === 'undefined' ? false : !isBackgroundSearch; - - if (includeUserOptions) { - const claimType = options[SEARCH_OPTIONS.CLAIM_TYPE]; - if (claimType) { - queryParams.push(`claimType=${claimType}`); - - // If they are only searching for channels, strip out the media info - if (!claimType.includes(SEARCH_OPTIONS.INCLUDE_CHANNELS)) { - queryParams.push( - `mediaType=${[ - SEARCH_OPTIONS.MEDIA_FILE, - SEARCH_OPTIONS.MEDIA_AUDIO, - SEARCH_OPTIONS.MEDIA_VIDEO, - SEARCH_OPTIONS.MEDIA_TEXT, - SEARCH_OPTIONS.MEDIA_IMAGE, - SEARCH_OPTIONS.MEDIA_APPLICATION, - ].reduce( - (acc, currentOption) => (options[currentOption] ? `${acc}${currentOption},` : acc), - '' - )}` - ); - } - } - } - - const additionalOptions = {}; - const { related_to } = options; - const { nsfw } = options; - if (related_to) additionalOptions['related_to'] = related_to; - if (typeof nsfw !== 'undefined') additionalOptions['nsfw'] = nsfw; - - if (additionalOptions) { - Object.keys(additionalOptions).forEach(key => { - const option = additionalOptions[key]; - queryParams.push(`${key}=${option}`); - }); - } - - return queryParams.join('&'); -}; diff --git a/src/util/query_params.js b/src/util/query_params.js new file mode 100644 index 0000000..1e99cb2 --- /dev/null +++ b/src/util/query_params.js @@ -0,0 +1,70 @@ +// @flow +import { SEARCH_OPTIONS } from 'constants/search'; + +const DEFAULT_SEARCH_RESULT_FROM = 0; +const DEFAULT_SEARCH_SIZE = 20; + +export function parseQueryParams(queryString: string) { + if (queryString === '') return {}; + const parts = queryString + .split('?') + .pop() + .split('&') + .map(p => p.split('=')); + + const params = {}; + parts.forEach(array => { + const [first, second] = array; + params[first] = second; + }); + return params; +} + +export function toQueryString(params: { [string]: string | number }) { + if (!params) return ''; + + const parts = []; + Object.keys(params).forEach(key => { + if (Object.prototype.hasOwnProperty.call(params, key) && params[key]) { + parts.push(`${key}=${params[key]}`); + } + }); + + return parts.join('&'); +} + +export const getSearchQueryString = ( + query: string, + options: any = {}, + includeUserOptions: boolean = false +) => { + const encodedQuery = encodeURIComponent(query); + const queryParams = [ + `s=${encodedQuery}`, + `size=${options.size || DEFAULT_SEARCH_SIZE}`, + `from=${options.from || DEFAULT_SEARCH_RESULT_FROM}`, + ]; + + if (includeUserOptions) { + queryParams.push(`claimType=${options[SEARCH_OPTIONS.CLAIM_TYPE]}`); + + // If they are only searching for channels, strip out the media info + if (options[SEARCH_OPTIONS.CLAIM_TYPE] !== SEARCH_OPTIONS.INCLUDE_CHANNELS) { + queryParams.push( + `mediaType=${[ + SEARCH_OPTIONS.MEDIA_FILE, + SEARCH_OPTIONS.MEDIA_AUDIO, + SEARCH_OPTIONS.MEDIA_VIDEO, + SEARCH_OPTIONS.MEDIA_TEXT, + SEARCH_OPTIONS.MEDIA_IMAGE, + SEARCH_OPTIONS.MEDIA_APPLICATION, + ].reduce( + (acc, currentOption) => (options[currentOption] ? `${acc}${currentOption},` : acc), + '' + )}` + ); + } + } + + return queryParams.join('&'); +}; diff --git a/yarn.lock b/yarn.lock index d0ab3dc..49dc513 100644 --- a/yarn.lock +++ b/yarn.lock @@ -170,10 +170,10 @@ acorn@^6.0.7, acorn@^6.1.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.1.1.tgz#7d25ae05bb8ad1f9b699108e1094ecd7884adc1f" integrity sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA== -agent-base@4, agent-base@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" - integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg== +agent-base@4, agent-base@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9" + integrity sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg== dependencies: es6-promisify "^5.0.0" @@ -1418,14 +1418,6 @@ cosmiconfig@^4.0.0: parse-json "^4.0.0" require-from-string "^2.0.1" -cross-env@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-5.2.0.tgz#6ecd4c015d5773e614039ee529076669b9d126f2" - integrity sha512-jtdNFfFW1hB7sMhr/H6rW1Z45LFqyI431m3qU6bFXcQ3Eh7LtBuG3h74o7ohHZ3crrRkkqHlo4jYHFPcjroANg== - dependencies: - cross-spawn "^6.0.5" - is-windows "^1.0.0" - cross-spawn@^5.0.1: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" @@ -1491,7 +1483,7 @@ date-fns@^1.27.2: resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.29.0.tgz#12e609cdcb935127311d04d33334e2960a2a54e6" integrity sha512-lbTXWZ6M20cWH8N9S6afb0SBm6tMk+uUg6z3MqHPKE9atmsY3kJkTm8vKe93izJ2B2+q5MV990sM2CHgtAZaOw== -debug@3.1.0: +debug@3.1.0, debug@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== @@ -1505,13 +1497,6 @@ debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: dependencies: ms "2.0.0" -debug@^3.1.0: - version "3.2.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" - integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== - dependencies: - ms "^2.1.1" - debug@^4.0.1: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" @@ -1689,9 +1674,9 @@ es-to-primitive@^1.2.0: is-symbol "^1.0.2" es6-promise@^4.0.3: - version "4.2.8" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" - integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== + version "4.2.4" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29" + integrity sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ== es6-promisify@^5.0.0: version "5.0.0" @@ -1827,16 +1812,14 @@ eslint-scope@~3.7.1: estraverse "^4.1.1" eslint-utils@^1.3.0, eslint-utils@^1.3.1: - version "1.4.3" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" - integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== - dependencies: - eslint-visitor-keys "^1.1.0" + version "1.3.1" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.3.1.tgz#9a851ba89ee7c460346f97cf8939c7298827e512" + integrity sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q== -eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" - integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== +eslint-visitor-keys@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" + integrity sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ== eslint@^5.1.0, eslint@^5.16.0: version "5.16.0" @@ -1895,9 +1878,9 @@ esprima@^3.1.3: integrity sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM= esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + version "4.0.0" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" + integrity sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw== esquery@^1.0.1: version "1.0.1" @@ -1928,11 +1911,6 @@ estree-walker@^0.6.0: resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.6.0.tgz#5d865327c44a618dde5699f763891ae31f257dae" integrity sha512-peq1RfVAVzr3PU/jL31RaOjUKLoZJpObQWJJ+LgfcxDUifyLZ1RjPQZTl0pzj2uJ45b7A7XpyppXvxdEqzo4rw== -estree-walker@^0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.6.1.tgz#53049143f40c6eb918b23671d1fe3219f3a1b362" - integrity sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w== - esutils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" @@ -2011,9 +1989,9 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: is-extendable "^1.0.1" extend@~3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + version "3.0.1" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" + integrity sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ= external-editor@^3.0.3: version "3.0.3" @@ -2265,9 +2243,9 @@ fs.realpath@^1.0.0: integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= fstream@~1.0.10: - version "1.0.12" - resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045" - integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg== + version "1.0.11" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" + integrity sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE= dependencies: graceful-fs "^4.1.2" inherits "~2.0.0" @@ -2326,7 +2304,7 @@ glob-parent@^2.0.0: dependencies: is-glob "^2.0.0" -glob@^7.1.1, glob@^7.1.2: +glob@^7.0.5, glob@^7.1.1, glob@^7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ== @@ -2339,9 +2317,9 @@ glob@^7.1.1, glob@^7.1.2: path-is-absolute "^1.0.0" glob@^7.1.3: - version "7.1.5" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.5.tgz#6714c69bee20f3c3e64c4dd905553e532b40cdc0" - integrity sha512-J9dlskqUXK1OeTOYBEn5s8aMukWMwWfs+rPTn/jn50Ux4MNXVhubL1wu/j2t+H4NVI+cXEcCaYellqaPVGXNqQ== + version "7.1.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" + integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -2386,9 +2364,9 @@ got@^7.1.0: url-to-options "^1.0.1" graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6: - version "4.2.3" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" - integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== + version "4.1.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + integrity sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg= har-schema@^2.0.0: version "2.0.0" @@ -2530,11 +2508,11 @@ http-signature@~1.2.0: sshpk "^1.7.0" https-proxy-agent@^2.2.0: - version "2.2.4" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b" - integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg== + version "2.2.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0" + integrity sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ== dependencies: - agent-base "^4.3.0" + agent-base "^4.1.0" debug "^3.1.0" husky@^0.14.3: @@ -2602,9 +2580,9 @@ inflight@^1.0.4: wrappy "1" inherits@2, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= inquirer@^6.2.2: version "6.3.1" @@ -2903,7 +2881,7 @@ is-utf8@^0.2.0: resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= -is-windows@^1.0.0, is-windows@^1.0.2: +is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== @@ -3093,7 +3071,7 @@ js-tokens@^3.0.0, js-tokens@^3.0.2: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-yaml@^3.13.0, js-yaml@^3.9.0: +js-yaml@^3.13.0: version "3.13.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== @@ -3101,6 +3079,14 @@ js-yaml@^3.13.0, js-yaml@^3.9.0: argparse "^1.0.7" esprima "^4.0.0" +js-yaml@^3.9.0: + version "3.11.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.11.0.tgz#597c1a8bd57152f26d622ce4117851a51f5ebaef" + integrity sha512-saJstZWv7oNeOyBh3+Dx1qWzhW0+e6/8eDzo7p5rDFqxntSztloLtuKu+Ejhtq82jsilwOIZYsCz+lIjthg1Hw== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" @@ -3395,10 +3381,15 @@ lodash.sortby@^4.7.0: resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= -lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0: - version "4.17.15" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" - integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== +lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0: + version "4.17.10" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" + integrity sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg== + +lodash@^4.17.11: + version "4.17.11" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" + integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== log-symbols@^1.0.2: version "1.0.2" @@ -3449,13 +3440,6 @@ lru-cache@^4.0.1: pseudomap "^1.0.2" yallist "^2.1.2" -magic-string@^0.25.2: - version "0.25.3" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.3.tgz#34b8d2a2c7fec9d9bdf9929a3fd81d271ef35be9" - integrity sha512-6QK0OpF/phMz0Q2AxILkX2mFhi7m+WMwTRg0LQKq/WBB0cDP4rYH3Wp4/d3OTXlrPLVJT/RFqj8tFeAR4nk8AA== - dependencies: - sourcemap-codec "^1.4.4" - make-dir@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.2.0.tgz#6d6a49eead4aae296c53bbf3a1a008bd6c89469b" @@ -3562,9 +3546,9 @@ minimist@0.0.8: integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= mixin-deep@^1.2.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" - integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== + version "1.3.1" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" + integrity sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ== dependencies: for-in "^1.0.2" is-extendable "^1.0.1" @@ -3582,9 +3566,9 @@ ms@2.0.0: integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= ms@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== mute-stream@0.0.7: version "0.0.7" @@ -3744,7 +3728,7 @@ once@^1.3.0: onetime@^1.0.0: version "1.1.0" - resolved "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" + resolved "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" integrity sha1-ofeDj4MUxRbwXs78vEzP4EtO14k= onetime@^2.0.0: @@ -4345,11 +4329,11 @@ ret@~0.1.10: integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== rimraf@2, rimraf@^2.6.2: - version "2.7.1" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" - integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + version "2.6.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" + integrity sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w== dependencies: - glob "^7.1.3" + glob "^7.0.5" rimraf@2.6.3: version "2.6.3" @@ -4395,14 +4379,6 @@ rollup-plugin-includepaths@^0.2.3: resolved "https://registry.yarnpkg.com/rollup-plugin-includepaths/-/rollup-plugin-includepaths-0.2.3.tgz#244d21b9669a0debe476d825e4a02ed08c06b258" integrity sha512-4QbSIZPDT+FL4SViEVCRi4cGCA64zQJu7u5qmCkO3ecHy+l9EQBsue15KfCpddfb6Br0q47V/v2+E2YUiqts9g== -rollup-plugin-replace@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/rollup-plugin-replace/-/rollup-plugin-replace-2.2.0.tgz#f41ae5372e11e7a217cde349c8b5d5fd115e70e3" - integrity sha512-/5bxtUPkDHyBJAKketb4NfaeZjL5yLZdeUihSfbF2PQMz+rSTEb8ARKoOl3UBT4m7/X+QOXJo3sLTcq+yMMYTA== - dependencies: - magic-string "^0.25.2" - rollup-pluginutils "^2.6.0" - rollup-pluginutils@^1.5.0, rollup-pluginutils@^1.5.1: version "1.5.2" resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-1.5.2.tgz#1e156e778f94b7255bfa1b3d0178be8f5c552408" @@ -4419,13 +4395,6 @@ rollup-pluginutils@^2.3.0: estree-walker "^0.6.0" micromatch "^3.1.10" -rollup-pluginutils@^2.6.0: - version "2.8.1" - resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.8.1.tgz#8fa6dd0697344938ef26c2c09d2488ce9e33ce97" - integrity sha512-J5oAoysWar6GuZo0s+3bZ6sVZAC0pfqKz68De7ZgDi5z63jOVZn1uJL/+z1jeKHNbGII8kAyHF5q8LnxSX5lQg== - dependencies: - estree-walker "^0.6.1" - rollup@^1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.8.0.tgz#e3ce8b708ad4325166717f74f244f691595d35e2" @@ -4644,11 +4613,6 @@ source-map@^0.6.0, source-map@~0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -sourcemap-codec@^1.4.4: - version "1.4.6" - resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.6.tgz#e30a74f0402bad09807640d39e971090a08ce1e9" - integrity sha512-1ZooVLYFxC448piVLBbtOxFcXwnymH9oUF8nRd3CuYDVvkRBxRl6pB4Mtas5a4drtL+E8LDgFkQNcgIw6tc8Hg== - spdx-correct@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.0.0.tgz#05a5b4d7153a195bc92c3c425b69f3b2a9524c82" @@ -4785,9 +4749,9 @@ stringify-object@^3.2.2: is-regexp "^1.0.0" stringstream@~0.0.5: - version "0.0.6" - resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.6.tgz#7880225b0d4ad10e30927d167a1d6f2fd3b33a72" - integrity sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA== + version "0.0.5" + resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" + integrity sha1-TkhM1N5aC7vuGORjB3EKioFiGHg= strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1"