Publishing #158
27 changed files with 1512 additions and 661 deletions
|
@ -10,6 +10,7 @@
|
|||
"__": true
|
||||
},
|
||||
"rules": {
|
||||
"camelcase": 0,
|
||||
"no-multi-spaces": 0,
|
||||
"new-cap": 0,
|
||||
"prefer-promise-reject-errors": 0,
|
||||
|
|
1341
dist/bundle.es.js
vendored
1341
dist/bundle.es.js
vendored
File diff suppressed because it is too large
Load diff
47
dist/flow-typed/Claim.js
vendored
47
dist/flow-typed/Claim.js
vendored
|
@ -1,49 +1,51 @@
|
|||
// @flow
|
||||
|
||||
declare type ClaimWithPossibleCertificate = {
|
||||
certificate?: ChannelClaim,
|
||||
claim: StreamClaim,
|
||||
};
|
||||
declare type Claim = StreamClaim | ChannelClaim;
|
||||
|
||||
declare type ChannelClaim = GenericClaim & {
|
||||
is_channel_signature_valid?: boolean, // we may have signed channels in the future
|
||||
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: number, // bid amount at time of tx
|
||||
amount: string, // bid amount at time of tx
|
||||
canonical_url: string, // URL with short id, includes channel with short id
|
||||
claim_id: string, // unique claim identifier
|
||||
claim_sequence: number,
|
||||
claim_sequence: number, // not being used currently
|
||||
claim_op: 'create' | 'update',
|
||||
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
|
||||
effective_amount: number, // bid amount + supports
|
||||
timestamp?: number, // date of transaction
|
||||
has_signature: boolean,
|
||||
confirmations: number,
|
||||
decoded_claim: boolean, // Not available currently https://github.com/lbryio/lbry/issues/2044
|
||||
timestamp?: number, // date of last transaction
|
||||
height: number, // block height the tx was confirmed
|
||||
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
|
||||
supports: Array<{}>, // TODO: add support type once we start using it
|
||||
short_url: string, // permanent_url with short id, no channel
|
||||
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,
|
||||
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,
|
||||
trending_global: number,
|
||||
trending_group: number,
|
||||
trending_local: number,
|
||||
trending_mixed: number,
|
||||
},
|
||||
};
|
||||
|
||||
declare type GenericMetadata = {
|
||||
|
@ -59,6 +61,7 @@ declare type GenericMetadata = {
|
|||
|
||||
declare type ChannelMetadata = GenericMetadata & {
|
||||
public_key: string,
|
||||
public_key_id: string,
|
||||
cover_url?: string,
|
||||
email?: string,
|
||||
website_url?: string,
|
||||
|
|
18
dist/flow-typed/Comment.js
vendored
Normal file
18
dist/flow-typed/Comment.js
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
declare type Comment = {
|
||||
author: string,
|
||||
claim_index?: number,
|
||||
comment_id?: number,
|
||||
downvotes?: number,
|
||||
message: string,
|
||||
omitted?: number,
|
||||
reply_count?: number,
|
||||
time_posted?: number,
|
||||
upvotes?: number,
|
||||
parent_id?: number,
|
||||
};
|
||||
|
||||
declare type CommentsState = {
|
||||
byId: {},
|
||||
isLoading: boolean,
|
||||
commentsByUri: { [string]: string },
|
||||
}
|
19
dist/flow-typed/Lbry.js
vendored
19
dist/flow-typed/Lbry.js
vendored
|
@ -66,8 +66,8 @@ declare type VersionResponse = {
|
|||
declare type ResolveResponse = {
|
||||
// Keys are the url(s) passed to resolve
|
||||
[string]:
|
||||
| { error: {}, certificate: ChannelClaim, claims_in_channel: number }
|
||||
| { error?: {}, claim: StreamClaim, certificate?: ChannelClaim },
|
||||
| Claim
|
||||
| { error?: {} },
|
||||
};
|
||||
|
||||
declare type GetResponse = FileListItem;
|
||||
|
@ -86,24 +86,28 @@ 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<StreamClaim>,
|
||||
outputs: Array<Claim>,
|
||||
};
|
||||
|
||||
declare type ClaimSearchResponse = {
|
||||
items: Array<StreamClaim>,
|
||||
items: Array<Claim>,
|
||||
page: number,
|
||||
page_size: number,
|
||||
page_number: number,
|
||||
total_items: number,
|
||||
total_pages: number,
|
||||
};
|
||||
|
||||
declare type ClaimListResponse = {
|
||||
claims: Array<ChannelClaim | StreamClaim>,
|
||||
claims: Array<ChannelClaim | Claim>,
|
||||
};
|
||||
|
||||
declare type ChannelCreateResponse = GenericTxResponse & {
|
||||
outputs: Array<ChannelClaim>,
|
||||
};
|
||||
|
||||
declare type CommentCreateResponse = Comment;
|
||||
declare type CommentListResponse = Array<Comment>;
|
||||
|
||||
declare type ChannelListResponse = Array<ChannelClaim>;
|
||||
|
||||
declare type FileListResponse = Array<FileListItem>;
|
||||
|
@ -183,6 +187,9 @@ declare type LbryTypes = {
|
|||
blob_delete: (params: {}) => Promise<string>,
|
||||
blob_list: (params: {}) => Promise<BlobListResponse>,
|
||||
|
||||
// Commenting
|
||||
comment_list: (params: {}) => Promise<CommentListResponse>,
|
||||
comment_create: (params: {}) => Promise<CommentCreateResponse>,
|
||||
// Wallet utilities
|
||||
account_balance: (params: {}) => Promise<string>,
|
||||
account_decrypt: (prams: {}) => Promise<boolean>,
|
||||
|
|
21
dist/flow-typed/Tags.js
vendored
Normal file
21
dist/flow-typed/Tags.js
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
declare type TagState = {
|
||||
followedTags: FollowedTags,
|
||||
knownTags: KnownTags,
|
||||
};
|
||||
|
||||
declare type Tag = {
|
||||
name: string,
|
||||
};
|
||||
|
||||
declare type KnownTags = {
|
||||
[string]: Tag,
|
||||
};
|
||||
|
||||
declare type FollowedTags = Array<string>;
|
||||
|
||||
declare type TagAction = {
|
||||
type: string,
|
||||
data: {
|
||||
name: string,
|
||||
},
|
||||
};
|
47
flow-typed/Claim.js
vendored
47
flow-typed/Claim.js
vendored
|
@ -1,49 +1,51 @@
|
|||
// @flow
|
||||
|
||||
declare type ClaimWithPossibleCertificate = {
|
||||
certificate?: ChannelClaim,
|
||||
claim: StreamClaim,
|
||||
};
|
||||
declare type Claim = StreamClaim | ChannelClaim;
|
||||
|
||||
declare type ChannelClaim = GenericClaim & {
|
||||
is_channel_signature_valid?: boolean, // we may have signed channels in the future
|
||||
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: number, // bid amount at time of tx
|
||||
amount: string, // bid amount at time of tx
|
||||
canonical_url: string, // URL with short id, includes channel with short id
|
||||
claim_id: string, // unique claim identifier
|
||||
claim_sequence: number,
|
||||
claim_sequence: number, // not being used currently
|
||||
claim_op: 'create' | 'update',
|
||||
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
|
||||
effective_amount: number, // bid amount + supports
|
||||
timestamp?: number, // date of transaction
|
||||
has_signature: boolean,
|
||||
confirmations: number,
|
||||
decoded_claim: boolean, // Not available currently https://github.com/lbryio/lbry/issues/2044
|
||||
timestamp?: number, // date of last transaction
|
||||
height: number, // block height the tx was confirmed
|
||||
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
|
||||
supports: Array<{}>, // TODO: add support type once we start using it
|
||||
short_url: string, // permanent_url with short id, no channel
|
||||
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,
|
||||
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,
|
||||
trending_global: number,
|
||||
trending_group: number,
|
||||
trending_local: number,
|
||||
trending_mixed: number,
|
||||
},
|
||||
};
|
||||
|
||||
declare type GenericMetadata = {
|
||||
|
@ -59,6 +61,7 @@ declare type GenericMetadata = {
|
|||
|
||||
declare type ChannelMetadata = GenericMetadata & {
|
||||
public_key: string,
|
||||
public_key_id: string,
|
||||
cover_url?: string,
|
||||
email?: string,
|
||||
website_url?: string,
|
||||
|
|
18
flow-typed/Comment.js
vendored
Normal file
18
flow-typed/Comment.js
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
declare type Comment = {
|
||||
author: string,
|
||||
claim_index?: number,
|
||||
comment_id?: number,
|
||||
downvotes?: number,
|
||||
message: string,
|
||||
omitted?: number,
|
||||
reply_count?: number,
|
||||
time_posted?: number,
|
||||
upvotes?: number,
|
||||
parent_id?: number,
|
||||
};
|
||||
|
||||
declare type CommentsState = {
|
||||
byId: {},
|
||||
isLoading: boolean,
|
||||
commentsByUri: { [string]: string },
|
||||
}
|
19
flow-typed/Lbry.js
vendored
19
flow-typed/Lbry.js
vendored
|
@ -66,8 +66,8 @@ declare type VersionResponse = {
|
|||
declare type ResolveResponse = {
|
||||
// Keys are the url(s) passed to resolve
|
||||
[string]:
|
||||
| { error: {}, certificate: ChannelClaim, claims_in_channel: number }
|
||||
| { error?: {}, claim: StreamClaim, certificate?: ChannelClaim },
|
||||
| Claim
|
||||
| { error?: {} },
|
||||
};
|
||||
|
||||
declare type GetResponse = FileListItem;
|
||||
|
@ -86,24 +86,28 @@ 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<StreamClaim>,
|
||||
outputs: Array<Claim>,
|
||||
};
|
||||
|
||||
declare type ClaimSearchResponse = {
|
||||
items: Array<StreamClaim>,
|
||||
items: Array<Claim>,
|
||||
page: number,
|
||||
page_size: number,
|
||||
page_number: number,
|
||||
total_items: number,
|
||||
total_pages: number,
|
||||
};
|
||||
|
||||
declare type ClaimListResponse = {
|
||||
claims: Array<ChannelClaim | StreamClaim>,
|
||||
claims: Array<ChannelClaim | Claim>,
|
||||
};
|
||||
|
||||
declare type ChannelCreateResponse = GenericTxResponse & {
|
||||
outputs: Array<ChannelClaim>,
|
||||
};
|
||||
|
||||
declare type CommentCreateResponse = Comment;
|
||||
declare type CommentListResponse = Array<Comment>;
|
||||
|
||||
declare type ChannelListResponse = Array<ChannelClaim>;
|
||||
|
||||
declare type FileListResponse = Array<FileListItem>;
|
||||
|
@ -183,6 +187,9 @@ declare type LbryTypes = {
|
|||
blob_delete: (params: {}) => Promise<string>,
|
||||
blob_list: (params: {}) => Promise<BlobListResponse>,
|
||||
|
||||
// Commenting
|
||||
comment_list: (params: {}) => Promise<CommentListResponse>,
|
||||
comment_create: (params: {}) => Promise<CommentCreateResponse>,
|
||||
// Wallet utilities
|
||||
account_balance: (params: {}) => Promise<string>,
|
||||
account_decrypt: (prams: {}) => Promise<boolean>,
|
||||
|
|
21
flow-typed/Tags.js
vendored
Normal file
21
flow-typed/Tags.js
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
declare type TagState = {
|
||||
followedTags: FollowedTags,
|
||||
knownTags: KnownTags,
|
||||
};
|
||||
|
||||
declare type Tag = {
|
||||
name: string,
|
||||
};
|
||||
|
||||
declare type KnownTags = {
|
||||
[string]: Tag,
|
||||
};
|
||||
|
||||
declare type FollowedTags = Array<string>;
|
||||
|
||||
declare type TagAction = {
|
||||
type: string,
|
||||
data: {
|
||||
name: string,
|
||||
},
|
||||
};
|
|
@ -88,6 +88,17 @@ 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';
|
||||
|
||||
// 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';
|
||||
|
||||
// Files
|
||||
export const FILE_LIST_STARTED = 'FILE_LIST_STARTED';
|
||||
|
@ -177,21 +188,6 @@ 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';
|
||||
|
@ -229,3 +225,7 @@ export const FETCH_DATE = 'FETCH_DATE';
|
|||
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';
|
||||
|
|
20
src/index.js
20
src/index.js
|
@ -49,6 +49,7 @@ export {
|
|||
doResolveUri,
|
||||
doFetchChannelListMine,
|
||||
doCreateChannel,
|
||||
doClaimSearch,
|
||||
} from 'redux/actions/claims';
|
||||
|
||||
export { doDeletePurchasedUri, doPurchaseUri, doFileGet } from 'redux/actions/file';
|
||||
|
@ -101,6 +102,10 @@ export {
|
|||
doUpdateBlockHeight,
|
||||
} from 'redux/actions/wallet';
|
||||
|
||||
export { doToggleTagFollow, doAddTag, doDeleteTag } from 'redux/actions/tags';
|
||||
|
||||
export { doCommentList, doCommentCreate } from 'redux/actions/comments';
|
||||
|
||||
// utils
|
||||
export { batchActions } from 'util/batchActions';
|
||||
export { parseQueryParams, toQueryString } from 'util/query_params';
|
||||
|
@ -109,12 +114,14 @@ export { isClaimNsfw } from 'util/claim';
|
|||
|
||||
// reducers
|
||||
export { claimsReducer } from 'redux/reducers/claims';
|
||||
export { commentReducer } from 'redux/reducers/comments';
|
||||
export { contentReducer } from 'redux/reducers/content';
|
||||
export { fileReducer } from 'redux/reducers/file';
|
||||
export { fileInfoReducer } from 'redux/reducers/file_info';
|
||||
export { fileReducer } from 'redux/reducers/file';
|
||||
export { notificationsReducer } from 'redux/reducers/notifications';
|
||||
export { searchReducer } from 'redux/reducers/search';
|
||||
export { publishReducer } from 'redux/reducers/publish';
|
||||
export { searchReducer } from 'redux/reducers/search';
|
||||
export { tagsReducerBuilder } from 'redux/reducers/tags';
|
||||
export { walletReducer } from 'redux/reducers/wallet';
|
||||
|
||||
// selectors
|
||||
|
@ -142,6 +149,7 @@ export {
|
|||
makeSelectCoverForUri,
|
||||
makeSelectTitleForUri,
|
||||
makeSelectDateForUri,
|
||||
makeSelectTagsForUri,
|
||||
makeSelectContentTypeForUri,
|
||||
makeSelectIsUriResolving,
|
||||
makeSelectTotalItemsForChannel,
|
||||
|
@ -167,6 +175,7 @@ export {
|
|||
selectPendingClaims,
|
||||
selectMyClaims,
|
||||
selectMyClaimsWithoutChannels,
|
||||
selectMyClaimUrisWithoutChannels,
|
||||
selectAllMyClaimsByOutpoint,
|
||||
selectMyClaimsOutpoints,
|
||||
selectFetchingMyChannels,
|
||||
|
@ -175,8 +184,12 @@ export {
|
|||
selectPlayingUri,
|
||||
selectChannelClaimCounts,
|
||||
selectCurrentChannelPage,
|
||||
selectFetchingClaimSearch,
|
||||
selectLastClaimSearchUris,
|
||||
} from 'redux/selectors/claims';
|
||||
|
||||
export { makeSelectCommentsForUri } from 'redux/selectors/comments';
|
||||
|
||||
export {
|
||||
makeSelectFileInfoForUri,
|
||||
makeSelectDownloadingForUri,
|
||||
|
@ -192,6 +205,7 @@ export {
|
|||
selectSearchDownloadUris,
|
||||
selectFileListDownloadedSort,
|
||||
selectFileListPublishedSort,
|
||||
selectDownloadedUris,
|
||||
} from 'redux/selectors/file_info';
|
||||
|
||||
export {
|
||||
|
@ -244,3 +258,5 @@ export {
|
|||
selectWalletUnlockResult,
|
||||
selectTransactionListFilter,
|
||||
} from 'redux/selectors/wallet';
|
||||
|
||||
export { selectFollowedTags, selectUnfollowedTags } from 'redux/selectors/tags';
|
||||
|
|
|
@ -100,6 +100,9 @@ const Lbry: LbryTypes = {
|
|||
sync_hash: (params = {}) => daemonCallWithResult('sync_hash', params),
|
||||
sync_apply: (params = {}) => daemonCallWithResult('sync_apply', params),
|
||||
|
||||
// Comments
|
||||
comment_list: (params = {}) => daemonCallWithResult('comment_list', params),
|
||||
comment_create: (params = {}) => daemonCallWithResult('comment_create', params),
|
||||
// Connect to the sdk
|
||||
connect: () => {
|
||||
if (Lbry.connectPromise === null) {
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
const channelNameMinLength = 1;
|
||||
const claimIdMaxLength = 40;
|
||||
|
||||
export const regexInvalidURI = /[^A-Za-z0-9-]/g;
|
||||
// see https://spec.lbry.com/#urls
|
||||
export const regexInvalidURI = (exports.regexInvalidURI = /[=&#:$@%?\u{0000}-\u{0008}\u{000b}-\u{000c}\u{000e}-\u{001F}\u{D800}-\u{DFFF}\u{FFFE}-\u{FFFF}]/gu);
|
||||
export const regexAddress = /^(b|r)(?=[^0OIl]{32,33})[0-9A-Za-z]{32,33}$/;
|
||||
|
||||
/**
|
||||
|
@ -200,9 +201,8 @@ export function isURIValid(URI) {
|
|||
return parts && parts.claimName;
|
||||
}
|
||||
|
||||
export function isNameValid(claimName, checkCase = true) {
|
||||
const regexp = new RegExp('^[a-z0-9-]+$', checkCase ? '' : 'i');
|
||||
return regexp.test(claimName);
|
||||
export function isNameValid(claimName) {
|
||||
return !regexInvalidURI.test(claimName);
|
||||
}
|
||||
|
||||
export function isURIClaimable(URI) {
|
||||
|
|
|
@ -7,6 +7,7 @@ import { selectMyClaimsRaw, selectResolvingUris, selectClaimsByUri } from 'redux
|
|||
import { doFetchTransactions } from 'redux/actions/wallet';
|
||||
import { selectSupportsByOutpoint } from 'redux/selectors/wallet';
|
||||
import { creditsToString } from 'util/formatCredits';
|
||||
import { batchActions } from 'util/batchActions';
|
||||
|
||||
export function doResolveUris(uris: Array<string>, returnCachedClaims: boolean = false) {
|
||||
return (dispatch: Dispatch, getState: GetState) => {
|
||||
|
@ -34,8 +35,8 @@ export function doResolveUris(uris: Array<string>, returnCachedClaims: boolean =
|
|||
|
||||
const resolveInfo: {
|
||||
[string]: {
|
||||
claim: ?StreamClaim,
|
||||
certificate: ?ChannelClaim,
|
||||
stream: ?StreamClaim,
|
||||
channel: ?ChannelClaim,
|
||||
claimsInChannel: ?number,
|
||||
},
|
||||
} = {};
|
||||
|
@ -43,20 +44,35 @@ export function doResolveUris(uris: Array<string>, returnCachedClaims: boolean =
|
|||
Lbry.resolve({ urls: urisToResolve }).then((result: ResolveResponse) => {
|
||||
Object.entries(result).forEach(([uri, uriResolveInfo]) => {
|
||||
const fallbackResolveInfo = {
|
||||
claim: null,
|
||||
stream: null,
|
||||
claimsInChannel: null,
|
||||
certificate: null,
|
||||
channel: null,
|
||||
};
|
||||
|
||||
// Flow has terrible Object.entries support
|
||||
// https://github.com/facebook/flow/issues/2221
|
||||
// $FlowFixMe
|
||||
if (uriResolveInfo.error) {
|
||||
resolveInfo[uri] = { ...fallbackResolveInfo };
|
||||
} else {
|
||||
// $FlowFixMe
|
||||
const { claim, certificate, claims_in_channel: claimsInChannel } = uriResolveInfo;
|
||||
resolveInfo[uri] = { claim, certificate, claimsInChannel };
|
||||
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;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -94,7 +110,7 @@ export function doAbandonClaim(txid: string, nout: number) {
|
|||
|
||||
return (dispatch: Dispatch, getState: GetState) => {
|
||||
const state = getState();
|
||||
const myClaims: Array<ChannelClaim | StreamClaim> = selectMyClaimsRaw(state);
|
||||
const myClaims: Array<Claim> = selectMyClaimsRaw(state);
|
||||
const mySupports: { [string]: Support } = selectSupportsByOutpoint(state);
|
||||
|
||||
// A user could be trying to abandon a support or one of their claims
|
||||
|
@ -182,20 +198,23 @@ export function doFetchClaimsByChannel(uri: string, page: number = 1) {
|
|||
data: { uri, page },
|
||||
});
|
||||
|
||||
Lbry.claim_search({ channel_name: uri, page: page || 1, winning: true }).then(
|
||||
(result: ClaimSearchResponse) => {
|
||||
const { items: claimsInChannel, page: returnedPage } = result;
|
||||
Lbry.claim_search({
|
||||
channel: uri,
|
||||
valid_channel_signature: true,
|
||||
page: page || 1,
|
||||
order_by: ['release_time'],
|
||||
}).then((result: ClaimSearchResponse) => {
|
||||
const { items: claimsInChannel, page: returnedPage } = result;
|
||||
|
||||
dispatch({
|
||||
type: ACTIONS.FETCH_CHANNEL_CLAIMS_COMPLETED,
|
||||
data: {
|
||||
uri,
|
||||
claims: claimsInChannel || [],
|
||||
page: returnedPage || undefined,
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
dispatch({
|
||||
type: ACTIONS.FETCH_CHANNEL_CLAIMS_COMPLETED,
|
||||
data: {
|
||||
uri,
|
||||
claims: claimsInChannel || [],
|
||||
page: returnedPage || undefined,
|
||||
},
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -245,3 +264,37 @@ export function doFetchChannelListMine() {
|
|||
Lbry.channel_list().then(callback);
|
||||
};
|
||||
}
|
||||
|
||||
export function doClaimSearch(amount: number = 20, options: {} = {}) {
|
||||
return (dispatch: Dispatch) => {
|
||||
dispatch({
|
||||
type: ACTIONS.CLAIM_SEARCH_STARTED,
|
||||
});
|
||||
|
||||
const success = (data: ClaimSearchResponse) => {
|
||||
const resolveInfo = {};
|
||||
const uris = [];
|
||||
data.items.forEach((stream: Claim) => {
|
||||
resolveInfo[stream.permanent_url] = { stream };
|
||||
uris.push(stream.permanent_url);
|
||||
});
|
||||
|
||||
dispatch({
|
||||
type: ACTIONS.CLAIM_SEARCH_COMPLETED,
|
||||
data: { resolveInfo, uris },
|
||||
});
|
||||
};
|
||||
|
||||
const failure = err => {
|
||||
dispatch({
|
||||
type: ACTIONS.CLAIM_SEARCH_FAILED,
|
||||
error: err,
|
||||
});
|
||||
};
|
||||
|
||||
Lbry.claim_search({
|
||||
page_size: amount,
|
||||
...options,
|
||||
}).then(success, failure);
|
||||
};
|
||||
}
|
||||
|
|
80
src/redux/actions/comments.js
Normal file
80
src/redux/actions/comments.js
Normal file
|
@ -0,0 +1,80 @@
|
|||
// @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) {
|
||||
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,
|
||||
})
|
||||
.then((results: CommentListResponse) => {
|
||||
dispatch({
|
||||
type: ACTIONS.COMMENT_LIST_COMPLETED,
|
||||
data: {
|
||||
comments: results,
|
||||
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?: number
|
||||
) {
|
||||
return (dispatch: Dispatch, getState: GetState) => {
|
||||
const state = getState();
|
||||
dispatch({
|
||||
type: ACTIONS.COMMENT_CREATE_STARTED,
|
||||
});
|
||||
const myChannels = selectMyChannelClaims(state);
|
||||
const namedChannelClaim = myChannels.find(myChannel => myChannel.name === channel);
|
||||
const channel_id = namedChannelClaim ? namedChannelClaim.claim_id : null;
|
||||
return Lbry.comment_create({
|
||||
comment,
|
||||
claim_id,
|
||||
channel_id,
|
||||
})
|
||||
.then((result: Comment) => {
|
||||
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: 'Oops, someone broke comments.',
|
||||
isError: true,
|
||||
})
|
||||
);
|
||||
});
|
||||
};
|
||||
}
|
24
src/redux/actions/tags.js
Normal file
24
src/redux/actions/tags.js
Normal file
|
@ -0,0 +1,24 @@
|
|||
// @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,
|
||||
},
|
||||
});
|
|
@ -14,9 +14,9 @@ import { buildURI, parseURI } from 'lbryURI';
|
|||
type State = {
|
||||
channelClaimCounts: { [string]: number },
|
||||
claimsByUri: { [string]: string },
|
||||
byId: { [string]: StreamClaim | ChannelClaim },
|
||||
byId: { [string]: Claim },
|
||||
resolvingUris: Array<string>,
|
||||
pendingById: { [string]: StreamClaim | ChannelClaim },
|
||||
pendingById: { [string]: Claim },
|
||||
myChannelClaims: Set<string>,
|
||||
abandoningById: { [string]: boolean },
|
||||
fetchingChannelClaims: { [string]: number },
|
||||
|
@ -43,40 +43,43 @@ const defaultState = {
|
|||
fetchingMyChannels: false,
|
||||
abandoningById: {},
|
||||
pendingById: {},
|
||||
fetchingClaimSearch: false,
|
||||
lastClaimSearchUris: [],
|
||||
};
|
||||
|
||||
reducers[ACTIONS.RESOLVE_URIS_COMPLETED] = (state: State, action: any): State => {
|
||||
const { resolveInfo }: { [string]: ClaimWithPossibleCertificate } = action.data;
|
||||
function handleClaimAction(state: State, action: any): State {
|
||||
const {
|
||||
resolveInfo,
|
||||
}: {
|
||||
[string]: {
|
||||
stream: ?StreamClaim,
|
||||
channel: ?ChannelClaim,
|
||||
claimsInChannel: ?number,
|
||||
},
|
||||
} = action.data;
|
||||
const byUri = Object.assign({}, state.claimsByUri);
|
||||
const byId = Object.assign({}, state.byId);
|
||||
const channelClaimCounts = Object.assign({}, state.channelClaimCounts);
|
||||
|
||||
Object.entries(resolveInfo).forEach(
|
||||
([uri: string, resolveResponse: ClaimWithPossibleCertificate]) => {
|
||||
Object.entries(resolveInfo).forEach(([uri: string, resolveResponse: Claim]) => {
|
||||
// $FlowFixMe
|
||||
if (resolveResponse.claimsInChannel) {
|
||||
// $FlowFixMe
|
||||
if (resolveResponse.certificate && !Number.isNaN(resolveResponse.claimsInChannel)) {
|
||||
// $FlowFixMe
|
||||
channelClaimCounts[uri] = resolveResponse.claimsInChannel;
|
||||
}
|
||||
channelClaimCounts[uri] = resolveResponse.claimsInChannel;
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// $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;
|
||||
|
||||
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 {
|
||||
Object.entries(resolveInfo).forEach(([uri, { channel, stream }]) => {
|
||||
if (stream) {
|
||||
byId[stream.claim_id] = stream;
|
||||
byUri[uri] = stream.claim_id;
|
||||
}
|
||||
if (channel) {
|
||||
byId[channel.claim_id] = channel;
|
||||
byUri[stream ? channel.permanent_url : uri] = channel.claim_id;
|
||||
}
|
||||
if (!stream && !channel) {
|
||||
byUri[uri] = null;
|
||||
}
|
||||
});
|
||||
|
@ -87,6 +90,12 @@ reducers[ACTIONS.RESOLVE_URIS_COMPLETED] = (state: State, action: any): State =>
|
|||
channelClaimCounts,
|
||||
resolvingUris: (state.resolvingUris || []).filter(uri => !resolveInfo[uri]),
|
||||
});
|
||||
}
|
||||
|
||||
reducers[ACTIONS.RESOLVE_URIS_COMPLETED] = (state: State, action: any): State => {
|
||||
return {
|
||||
...handleClaimAction(state, action),
|
||||
};
|
||||
};
|
||||
|
||||
reducers[ACTIONS.FETCH_CLAIM_LIST_MINE_STARTED] = (state: State): State =>
|
||||
|
@ -95,15 +104,12 @@ reducers[ACTIONS.FETCH_CLAIM_LIST_MINE_STARTED] = (state: State): State =>
|
|||
});
|
||||
|
||||
reducers[ACTIONS.FETCH_CLAIM_LIST_MINE_COMPLETED] = (state: State, action: any): State => {
|
||||
const { claims }: { claims: Array<StreamClaim | ChannelClaim> } = action.data;
|
||||
const { claims }: { claims: Array<Claim> } = action.data;
|
||||
const byId = Object.assign({}, state.byId);
|
||||
const byUri = Object.assign({}, state.claimsByUri);
|
||||
const pendingById: { [string]: StreamClaim | ChannelClaim } = Object.assign(
|
||||
{},
|
||||
state.pendingById
|
||||
);
|
||||
const pendingById: { [string]: Claim } = Object.assign({}, state.pendingById);
|
||||
|
||||
claims.forEach((claim: StreamClaim | ChannelClaim) => {
|
||||
claims.forEach((claim: Claim) => {
|
||||
const uri = buildURI({ claimName: claim.name, claimId: claim.claim_id });
|
||||
|
||||
if (claim.type && claim.type.match(/claim|update/)) {
|
||||
|
@ -267,6 +273,24 @@ reducers[ACTIONS.RESOLVE_URIS_STARTED] = (state: State, action: any): State => {
|
|||
});
|
||||
};
|
||||
|
||||
reducers[ACTIONS.CLAIM_SEARCH_STARTED] = (state: State): State => {
|
||||
return Object.assign({}, state, {
|
||||
fetchingClaimSearch: true,
|
||||
});
|
||||
};
|
||||
reducers[ACTIONS.CLAIM_SEARCH_COMPLETED] = (state: State, action: any): State => {
|
||||
return {
|
||||
...handleClaimAction(state, action),
|
||||
fetchingClaimSearch: false,
|
||||
lastClaimSearchUris: action.data.uris,
|
||||
};
|
||||
};
|
||||
reducers[ACTIONS.CLAIM_SEARCH_FAILED] = (state: State): State => {
|
||||
return Object.assign({}, state, {
|
||||
fetchingClaimSearch: false,
|
||||
});
|
||||
};
|
||||
|
||||
export function claimsReducer(state: State = defaultState, action: any) {
|
||||
const handler = reducers[action.type];
|
||||
if (handler) return handler(state, action);
|
||||
|
|
63
src/redux/reducers/comments.js
Normal file
63
src/redux/reducers/comments.js
Normal file
|
@ -0,0 +1,63 @@
|
|||
// @flow
|
||||
import * as ACTIONS from 'constants/action_types';
|
||||
import { handleActions } from 'util/redux-utils';
|
||||
|
||||
const defaultState: CommentsState = {
|
||||
byId: {},
|
||||
commentsByUri: {},
|
||||
isLoading: false,
|
||||
};
|
||||
|
||||
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 }: any = action.data;
|
||||
const byId = Object.assign({}, state.byId);
|
||||
const comments = byId[claimId];
|
||||
const newComments = comments.slice();
|
||||
|
||||
newComments.unshift(comment);
|
||||
byId[claimId] = newComments;
|
||||
|
||||
return {
|
||||
...state,
|
||||
byId,
|
||||
};
|
||||
},
|
||||
|
||||
[ACTIONS.COMMENT_LIST_STARTED]: state => ({ ...state, isLoading: true }),
|
||||
|
||||
[ACTIONS.COMMENT_LIST_COMPLETED]: (state: CommentsState, action: any) => {
|
||||
const { comments, claimId, uri } = action.data;
|
||||
const byId = Object.assign({}, state.byId);
|
||||
const commentsByUri = Object.assign({}, state.commentsByUri);
|
||||
|
||||
if (comments['items']) {
|
||||
byId[claimId] = comments['items'];
|
||||
commentsByUri[uri] = claimId;
|
||||
}
|
||||
return {
|
||||
...state,
|
||||
byId,
|
||||
commentsByUri,
|
||||
isLoading: false,
|
||||
};
|
||||
},
|
||||
|
||||
[ACTIONS.COMMENT_LIST_FAILED]: (state: CommentsState, action: any) => ({
|
||||
...state,
|
||||
isLoading: false,
|
||||
}),
|
||||
},
|
||||
defaultState
|
||||
);
|
|
@ -161,16 +161,6 @@ reducers[ACTIONS.LOADING_VIDEO_FAILED] = (state, action) => {
|
|||
});
|
||||
};
|
||||
|
||||
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',
|
||||
|
|
55
src/redux/reducers/tags.js
Normal file
55
src/redux/reducers/tags.js
Normal file
|
@ -0,0 +1,55 @@
|
|||
// @flow
|
||||
import * as ACTIONS from 'constants/action_types';
|
||||
import { handleActions } from 'util/redux-utils';
|
||||
|
||||
export const tagsReducerBuilder = (defaultState: TagState) =>
|
||||
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,
|
||||
};
|
||||
},
|
||||
},
|
||||
defaultState
|
||||
);
|
|
@ -190,7 +190,12 @@ export const makeSelectDateForUri = (uri: string) =>
|
|||
createSelector(
|
||||
makeSelectClaimForUri(uri),
|
||||
claim => {
|
||||
const timestamp = claim && claim.timestamp ? claim.timestamp * 1000 : undefined;
|
||||
const timestamp =
|
||||
claim &&
|
||||
claim.value &&
|
||||
(claim.value.release_time
|
||||
? claim.value.release_time * 1000
|
||||
: claim.meta.creation_timestamp * 1000);
|
||||
if (!timestamp) {
|
||||
return undefined;
|
||||
}
|
||||
|
@ -254,6 +259,11 @@ export const selectMyClaimsWithoutChannels = createSelector(
|
|||
myClaims => myClaims.filter(claim => !claim.name.match(/^@/))
|
||||
);
|
||||
|
||||
export const selectMyClaimUrisWithoutChannels = createSelector(
|
||||
selectMyClaimsWithoutChannels,
|
||||
myClaims => myClaims.map(claim => `lbry://${claim.name}#${claim.claim_id}`)
|
||||
);
|
||||
|
||||
export const selectAllMyClaimsByOutpoint = createSelector(
|
||||
selectMyClaimsRaw,
|
||||
claims =>
|
||||
|
@ -368,7 +378,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: StreamClaim) => {
|
||||
(claim: Claim) => {
|
||||
if (!claim) {
|
||||
return false;
|
||||
}
|
||||
|
@ -428,3 +438,21 @@ export const makeSelectChannelForClaimUri = (uri: string, includePrefix: boolean
|
|||
return includePrefix ? `lbry://${channel}` : channel;
|
||||
}
|
||||
);
|
||||
|
||||
export const makeSelectTagsForUri = (uri: string) =>
|
||||
createSelector(
|
||||
makeSelectMetadataForUri(uri),
|
||||
(metadata: ?GenericMetadata) => {
|
||||
return (metadata && metadata.tags) || [];
|
||||
}
|
||||
);
|
||||
|
||||
export const selectFetchingClaimSearch = createSelector(
|
||||
selectState,
|
||||
state => state.fetchingClaimSearch
|
||||
);
|
||||
|
||||
export const selectLastClaimSearchUris = createSelector(
|
||||
selectState,
|
||||
state => state.lastClaimSearchUris
|
||||
);
|
||||
|
|
36
src/redux/selectors/comments.js
Normal file
36
src/redux/selectors/comments.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
// @flow
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
const selectState = state => state.comments || {};
|
||||
|
||||
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(
|
||||
selectCommentsById,
|
||||
selectCommentsByUri,
|
||||
(byId, byUri) => {
|
||||
const claimId = byUri[uri];
|
||||
return byId && byId[claimId];
|
||||
}
|
||||
);
|
|
@ -164,10 +164,12 @@ export const selectSearchDownloadUris = query =>
|
|||
return;
|
||||
}
|
||||
|
||||
const titleParts = title.toLowerCase().split(' ');
|
||||
if (arrayContainsQueryPart(titleParts)) {
|
||||
downloadResultsFromQuery.push(fileInfo);
|
||||
return;
|
||||
if (title) {
|
||||
const titleParts = title.toLowerCase().split(' ');
|
||||
if (arrayContainsQueryPart(titleParts)) {
|
||||
downloadResultsFromQuery.push(fileInfo);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (author) {
|
||||
|
@ -226,3 +228,9 @@ 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.map(claim => `lbry://${claim.claim_name}#${claim.claim_id}`)
|
||||
);
|
||||
|
|
|
@ -57,20 +57,21 @@ export const selectSearchSuggestions: Array<SearchSuggestion> = createSelector(
|
|||
return [];
|
||||
}
|
||||
|
||||
const queryIsPrefix = query === 'lbry:' || query === 'lbry:/' || query === 'lbry://';
|
||||
const queryIsPrefix =
|
||||
query === 'lbry:' || query === 'lbry:/' || query === 'lbry://' || query === 'lbry://@';
|
||||
|
||||
if (query.startsWith('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://')) {
|
||||
// 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: SEARCH_TYPES.FILE,
|
||||
type: query[7] === '@' ? SEARCH_TYPES.CHANNEL : 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 = [];
|
||||
|
|
38
src/redux/selectors/tags.js
Normal file
38
src/redux/selectors/tags.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
// @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<string> => state.followedTags
|
||||
);
|
||||
|
||||
export const selectFollowedTags = createSelector(
|
||||
selectFollowedTagsList,
|
||||
(followedTags: Array<string>): Array<Tag> =>
|
||||
followedTags.map(tag => ({ name: tag })).sort((a, b) => a.name.localeCompare(b.name))
|
||||
);
|
||||
|
||||
export const selectUnfollowedTags = createSelector(
|
||||
selectKnownTagsByName,
|
||||
selectFollowedTagsList,
|
||||
(tagsByName: KnownTags, followedTags: Array<string>): Array<Tag> => {
|
||||
const followedTagsSet = new Set(followedTags);
|
||||
let tagsToReturn = [];
|
||||
|
||||
Object.keys(tagsByName).forEach(key => {
|
||||
if (!followedTagsSet.has(key)) {
|
||||
const { name } = tagsByName[key];
|
||||
tagsToReturn.push({ name });
|
||||
}
|
||||
});
|
||||
|
||||
return tagsToReturn;
|
||||
}
|
||||
);
|
|
@ -5,7 +5,7 @@ const naughtyTags = ['porn', 'nsfw', 'mature', 'xxx'].reduce(
|
|||
{}
|
||||
);
|
||||
|
||||
export const isClaimNsfw = (claim: StreamClaim): boolean => {
|
||||
export const isClaimNsfw = (claim: Claim): boolean => {
|
||||
if (!claim) {
|
||||
throw new Error('No claim passed to isClaimNsfw()');
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue