diff --git a/extras/lbryinc/redux/selectors/ban.js b/extras/lbryinc/redux/selectors/ban.js index d6a686c07..a34d65fd1 100644 --- a/extras/lbryinc/redux/selectors/ban.js +++ b/extras/lbryinc/redux/selectors/ban.js @@ -6,15 +6,17 @@ import { createCachedSelector } from 're-reselect'; import { selectClaimForUri, makeSelectIsBlacklisted } from 'redux/selectors/claims'; +import { selectMutedChannels } from 'redux/selectors/blocked'; import { selectModerationBlockList } from 'redux/selectors/comments'; import { getChannelFromClaim } from 'util/claim'; import { isURIEqual } from 'util/lbryURI'; export const selectBanStateForUri = createCachedSelector( selectClaimForUri, + selectMutedChannels, selectModerationBlockList, (state, uri) => makeSelectIsBlacklisted(uri)(state), - (claim, personalBlocklist, isBlacklisted) => { + (claim, mutedChannelUris, personalBlocklist, isBlacklisted) => { const banState = {}; if (!claim) { @@ -27,6 +29,14 @@ export const selectBanStateForUri = createCachedSelector( banState['blacklisted'] = true; } + // block stream claims + // block channel claims if we can't control for them in claim search + if (mutedChannelUris.length && channelClaim) { + if (mutedChannelUris.some((blockedUri) => isURIEqual(blockedUri, channelClaim.permanent_url))) { + banState['muted'] = true; + } + } + // Commentron blocklist if (personalBlocklist.length && channelClaim) { if (personalBlocklist.some((blockedUri) => isURIEqual(blockedUri, channelClaim.permanent_url))) { diff --git a/ui/component/channelContent/index.js b/ui/component/channelContent/index.js index e74dfd6aa..46e9b29eb 100644 --- a/ui/component/channelContent/index.js +++ b/ui/component/channelContent/index.js @@ -9,6 +9,7 @@ import { } from 'redux/selectors/claims'; import { doResolveUris } from 'redux/actions/claims'; import * as SETTINGS from 'constants/settings'; +import { makeSelectChannelIsMuted } from 'redux/selectors/blocked'; import { withRouter } from 'react-router'; import { selectUserVerifiedEmail } from 'redux/selectors/user'; import { makeSelectClientSetting, selectShowMatureContent } from 'redux/selectors/settings'; @@ -26,7 +27,7 @@ const select = (state, props) => { fetching: makeSelectFetchingChannelClaims(props.uri)(state), totalPages: makeSelectTotalPagesInChannelSearch(props.uri, PAGE_SIZE)(state), channelIsMine: selectClaimIsMine(state, claim), - channelIsBlocked: false, + channelIsBlocked: makeSelectChannelIsMuted(props.uri)(state), claim, isAuthenticated: selectUserVerifiedEmail(state), showMature: selectShowMatureContent(state), diff --git a/ui/component/channelMuteButton/index.js b/ui/component/channelMuteButton/index.js index da02392dc..781ae1880 100644 --- a/ui/component/channelMuteButton/index.js +++ b/ui/component/channelMuteButton/index.js @@ -1,9 +1,10 @@ import { connect } from 'react-redux'; import { doChannelMute, doChannelUnmute } from 'redux/actions/blocked'; +import { makeSelectChannelIsMuted } from 'redux/selectors/blocked'; import ChannelMuteButton from './view'; -const select = () => ({ - isMuted: false, +const select = (state, props) => ({ + isMuted: makeSelectChannelIsMuted(props.uri)(state), }); export default connect(select, { diff --git a/ui/component/claimListDiscover/index.js b/ui/component/claimListDiscover/index.js index a33d94b65..eac963d15 100644 --- a/ui/component/claimListDiscover/index.js +++ b/ui/component/claimListDiscover/index.js @@ -8,6 +8,7 @@ import { import { doClaimSearch } from 'redux/actions/claims'; import * as SETTINGS from 'constants/settings'; import { selectFollowedTags } from 'redux/selectors/tags'; +import { selectMutedChannels } from 'redux/selectors/blocked'; import { doToggleTagFollowDesktop } from 'redux/actions/tags'; import { makeSelectClientSetting, selectShowMatureContent, selectLanguage } from 'redux/selectors/settings'; import { selectModerationBlockList } from 'redux/selectors/comments'; @@ -23,7 +24,7 @@ const select = (state) => ({ showNsfw: selectShowMatureContent(state), hideReposts: makeSelectClientSetting(SETTINGS.HIDE_REPOSTS)(state), languageSetting: selectLanguage(state), - mutedUris: [], + mutedUris: selectMutedChannels(state), blockedUris: selectModerationBlockList(state), searchInLanguage: makeSelectClientSetting(SETTINGS.SEARCH_IN_LANGUAGE)(state), }); diff --git a/ui/component/claimMenuList/index.js b/ui/component/claimMenuList/index.js index cd121274b..8439ffae6 100644 --- a/ui/component/claimMenuList/index.js +++ b/ui/component/claimMenuList/index.js @@ -12,6 +12,7 @@ import { } from 'redux/selectors/collections'; import { makeSelectFileInfoForUri } from 'redux/selectors/file_info'; import * as COLLECTIONS_CONSTS from 'constants/collections'; +import { makeSelectChannelIsMuted } from 'redux/selectors/blocked'; import { doChannelMute, doChannelUnmute } from 'redux/actions/blocked'; import { doSetActiveChannel, doSetIncognito, doOpenModal } from 'redux/actions/app'; import { @@ -62,7 +63,7 @@ const select = (state, props) => { COLLECTIONS_CONSTS.FAVORITES_ID, contentPermanentUri )(state), - channelIsMuted: false, + channelIsMuted: makeSelectChannelIsMuted(contentChannelUri)(state), channelIsBlocked: makeSelectChannelIsBlocked(contentChannelUri)(state), fileInfo: makeSelectFileInfoForUri(contentPermanentUri)(state), isSubscribed: selectIsSubscribedForUri(state, contentChannelUri), diff --git a/ui/component/claimTilesDiscover/index.js b/ui/component/claimTilesDiscover/index.js index d5977fff5..5aed218be 100644 --- a/ui/component/claimTilesDiscover/index.js +++ b/ui/component/claimTilesDiscover/index.js @@ -7,6 +7,7 @@ import { MATURE_TAGS } from 'constants/tags'; import { doFetchViewCount } from 'lbryinc'; import { doToggleTagFollowDesktop } from 'redux/actions/tags'; import { makeSelectClientSetting, selectShowMatureContent } from 'redux/selectors/settings'; +import { selectMutedAndBlockedChannelIds } from 'redux/selectors/blocked'; import { ENABLE_NO_SOURCE_CLAIMS } from 'config'; import { createNormalizedClaimSearchKey } from 'util/claim'; @@ -15,7 +16,7 @@ import ClaimListDiscover from './view'; const select = (state, props) => { const showNsfw = selectShowMatureContent(state); const hideReposts = makeSelectClientSetting(SETTINGS.HIDE_REPOSTS)(state); - const mutedAndBlockedChannelIds = []; + const mutedAndBlockedChannelIds = selectMutedAndBlockedChannelIds(state); const options = resolveSearchOptions({ showNsfw, diff --git a/ui/component/collectionPreviewTile/index.js b/ui/component/collectionPreviewTile/index.js index c83f2d27d..f6ce4126a 100644 --- a/ui/component/collectionPreviewTile/index.js +++ b/ui/component/collectionPreviewTile/index.js @@ -18,6 +18,7 @@ import { } from 'redux/selectors/collections'; import { doFetchItemsInCollection, doCollectionDelete } from 'redux/actions/collections'; import { doResolveUri } from 'redux/actions/claims'; +import { selectMutedChannels } from 'redux/selectors/blocked'; import { selectShowMatureContent } from 'redux/selectors/settings'; import CollectionPreviewTile from './view'; @@ -42,7 +43,7 @@ const select = (state, props) => { title: collectionUri && selectTitleForUri(state, collectionUri), blackListedOutpoints: [], filteredOutpoints: [], - blockedChannelUris: [], + blockedChannelUris: selectMutedChannels(state), showMature: selectShowMatureContent(state), isMature: makeSelectClaimIsNsfw(collectionUri)(state), }; diff --git a/ui/component/comment/index.js b/ui/component/comment/index.js index eab8eeeb3..4b04bac5a 100644 --- a/ui/component/comment/index.js +++ b/ui/component/comment/index.js @@ -7,6 +7,7 @@ import { selectMyClaimIdsRaw, } from 'redux/selectors/claims'; import { doCommentUpdate, doCommentList } from 'redux/actions/comments'; +import { makeSelectChannelIsMuted } from 'redux/selectors/blocked'; import { doToast } from 'redux/actions/notifications'; import { doClearPlayingUri } from 'redux/actions/content'; import { selectUserVerifiedEmail } from 'redux/selectors/user'; @@ -31,7 +32,7 @@ const select = (state, props) => { myChannelIds: selectMyClaimIdsRaw(state), claim: makeSelectClaimForUri(uri)(state), thumbnail: author_uri && selectThumbnailForUri(state, author_uri), - channelIsBlocked: Boolean(author_uri), + channelIsBlocked: author_uri && makeSelectChannelIsMuted(author_uri)(state), commentingEnabled: IS_WEB ? Boolean(selectUserVerifiedEmail(state)) : true, othersReacts: selectOthersReactsForComment(state, reactionKey), activeChannelClaim, diff --git a/ui/page/channel/index.js b/ui/page/channel/index.js index 88ee18b16..bbf4cdb85 100644 --- a/ui/page/channel/index.js +++ b/ui/page/channel/index.js @@ -13,6 +13,7 @@ import { doFetchSubCount, selectSubCountForUri } from 'lbryinc'; // ban state import { selectYoutubeChannels } from 'redux/selectors/user'; import { selectIsSubscribedForUri } from 'redux/selectors/subscriptions'; import { selectModerationBlockList } from 'redux/selectors/comments'; +import { selectMutedChannels } from 'redux/selectors/blocked'; import { doOpenModal } from 'redux/actions/app'; import ChannelPage from './view'; @@ -32,7 +33,7 @@ const select = (state, props) => { pending: makeSelectClaimIsPending(props.uri)(state), youtubeChannels: selectYoutubeChannels(state), blockedChannels: selectModerationBlockList(state), // banlist - mutedChannels: [], + mutedChannels: selectMutedChannels(state), unpublishedCollections: selectMyUnpublishedCollections(state), }; }; diff --git a/ui/page/channelsFollowingDiscover/index.js b/ui/page/channelsFollowingDiscover/index.js index 4eb18bc42..72ae9b316 100644 --- a/ui/page/channelsFollowingDiscover/index.js +++ b/ui/page/channelsFollowingDiscover/index.js @@ -1,5 +1,6 @@ import { connect } from 'react-redux'; import { selectFollowedTags } from 'redux/selectors/tags'; +import { selectMutedChannels } from 'redux/selectors/blocked'; import { selectSubscriptions } from 'redux/selectors/subscriptions'; import { selectHomepageData } from 'redux/selectors/settings'; import ChannelsFollowingManagePage from './view'; @@ -7,7 +8,7 @@ import ChannelsFollowingManagePage from './view'; const select = (state) => ({ followedTags: selectFollowedTags(state), subscribedChannels: selectSubscriptions(state), - blockedChannels: [], + blockedChannels: selectMutedChannels(state), homepageData: selectHomepageData(state), }); diff --git a/ui/page/listBlocked/index.js b/ui/page/listBlocked/index.js index 131d71d10..41f0e9f11 100644 --- a/ui/page/listBlocked/index.js +++ b/ui/page/listBlocked/index.js @@ -1,5 +1,6 @@ import { connect } from 'react-redux'; import { doFetchModBlockedList, doFetchCommentModAmIList } from 'redux/actions/comments'; +import { selectMutedChannels } from 'redux/selectors/blocked'; import { selectModerationBlockList, selectAdminBlockList, @@ -15,7 +16,7 @@ import { selectMyChannelClaimIds } from 'redux/selectors/claims'; import ListBlocked from './view'; const select = (state) => ({ - mutedUris: [], + mutedUris: selectMutedChannels(state), personalBlockList: selectModerationBlockList(state), adminBlockList: selectAdminBlockList(state), moderatorBlockList: selectModeratorBlockList(state), diff --git a/ui/redux/selectors/blocked.js b/ui/redux/selectors/blocked.js new file mode 100644 index 000000000..9977c6d8f --- /dev/null +++ b/ui/redux/selectors/blocked.js @@ -0,0 +1,26 @@ +// @flow +import { createSelector } from 'reselect'; +import { splitBySeparator } from 'util/lbryURI'; + +const selectState = (state: { blocked: BlocklistState }) => state.blocked || {}; + +export const selectMutedChannels = createSelector(selectState, (state: BlocklistState) => { + return state.blockedChannels.filter((e) => typeof e === 'string'); +}); + +export const makeSelectChannelIsMuted = (uri: string) => + createSelector(selectMutedChannels, (state: Array) => { + return state.includes(uri); + }); + +export const selectMutedAndBlockedChannelIds = createSelector( + selectState, + (state) => state.comments, + (state, commentsState) => { + const mutedUris = state.blockedChannels; + const blockedUris = commentsState.moderationBlockList; + return Array.from( + new Set((mutedUris || []).concat(blockedUris || []).map((uri) => splitBySeparator(uri)[1])) + ).sort(); + } +); diff --git a/ui/redux/selectors/comments.js b/ui/redux/selectors/comments.js index 1ad77e946..3bbaa2c68 100644 --- a/ui/redux/selectors/comments.js +++ b/ui/redux/selectors/comments.js @@ -1,6 +1,7 @@ // @flow import { createSelector } from 'reselect'; import { createCachedSelector } from 're-reselect'; +import { selectMutedChannels } from 'redux/selectors/blocked'; import { selectShowMatureContent } from 'redux/selectors/settings'; import { selectMentionSearchResults, selectMentionQuery } from 'redux/selectors/search'; import { @@ -197,6 +198,7 @@ const filterCommentsDepOnList = { myClaimIds: selectMyClaimIdsRaw, myChannelClaimIds: selectMyChannelClaimIds, personalBlockList: selectModerationBlockList, + mutedChannels: selectMutedChannels, showMatureContent: selectShowMatureContent, }; @@ -279,7 +281,8 @@ const filterComments = (comments: Array, claimId?: string, filterInputs return acc; }, {}); - const { claimsById, myClaimIds, myChannelClaimIds, personalBlockList, showMatureContent } = filterProps; + const { claimsById, myClaimIds, myChannelClaimIds, personalBlockList, mutedChannels, showMatureContent } = + filterProps; return comments ? comments.filter((comment) => { @@ -320,7 +323,7 @@ const filterComments = (comments: Array, claimId?: string, filterInputs } } - return true; + return !mutedChannels.includes(comment.channel_url); }) : []; }; diff --git a/ui/redux/selectors/search.js b/ui/redux/selectors/search.js index e7d4bb055..dea8e5254 100644 --- a/ui/redux/selectors/search.js +++ b/ui/redux/selectors/search.js @@ -15,6 +15,7 @@ import { isClaimNsfw } from 'util/claim'; import { createSelector } from 'reselect'; import { createCachedSelector } from 're-reselect'; import { createNormalizedSearchKey, getRecommendationSearchOptions } from 'util/search'; +import { selectMutedChannels } from 'redux/selectors/blocked'; import { selectHistory } from 'redux/selectors/content'; import { selectAllCostInfoByUri } from 'lbryinc'; @@ -57,10 +58,11 @@ export const selectRecommendedContentForUri = createCachedSelector( selectHistory, selectClaimsByUri, selectShowMatureContent, + selectMutedChannels, selectAllCostInfoByUri, selectSearchResultByQuery, selectClaimIsNsfwForUri, // (state, uri) - (uri, history, claimsByUri, matureEnabled, costInfoByUri, searchUrisByQuery, isMature) => { + (uri, history, claimsByUri, matureEnabled, blockedChannels, costInfoByUri, searchUrisByQuery, isMature) => { const claim = claimsByUri[uri]; if (!claim) return; @@ -95,13 +97,17 @@ export const selectRecommendedContentForUri = createCachedSelector( if (!searchClaim) return; + const signingChannel = searchClaim && searchClaim.signing_channel; + const channelUri = signingChannel && signingChannel.canonical_url; + const blockedMatch = blockedChannels.some((blockedUri) => blockedUri.includes(channelUri)); + let isEqualUri; try { const { claimId: searchId } = parseURI(searchUri); isEqualUri = searchId === currentClaimId; } catch (e) {} - return !isEqualUri; + return !isEqualUri && !blockedMatch; }); // Claim to play next: playable and free claims not played before in history