From ede83f358d3465e20c852b69c083c6e6fbec84ff Mon Sep 17 00:00:00 2001 From: infinite-persistence Date: Fri, 19 Mar 2021 11:16:05 +0800 Subject: [PATCH] Fix autoplay infinite loop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Issue Closes 3661: Autoplay + Related go into loops ( infinite ) sometimes ## GUI Push the actual "next" item into the top of the list. ## History search 1. Skip if the next item is itself. 2. The URL stored in the history comes in various forms, so a direct comparison won't work. - There's also a weird case where the URL differs by just a little (p.09 vs p-09), but with the same claim ID: lbry://vacuum-tube-computer-p.09-–-building#5212bc8bc63c373e2bf1ebc5b765595ed7b6514d lbry://vacuum-tube-computer-p-09-–-building#5212bc8bc63c373e2bf1ebc5b765595ed7b6514d Check the claim_id as well to cover cases like these. --- ui/component/recommendedContent/index.js | 4 +++- ui/component/recommendedContent/view.jsx | 21 +++++++++++++++++++-- ui/redux/selectors/content.js | 18 +++++++++++++++++- 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/ui/component/recommendedContent/index.js b/ui/component/recommendedContent/index.js index 1509e617f..c6cedd6b5 100644 --- a/ui/component/recommendedContent/index.js +++ b/ui/component/recommendedContent/index.js @@ -3,17 +3,19 @@ import { makeSelectClaimForUri, makeSelectClaimIsNsfw } from 'lbry-redux'; import { doSearch } from 'redux/actions/search'; import { makeSelectRecommendedContentForUri, selectIsSearching } from 'redux/selectors/search'; import { selectUserVerifiedEmail } from 'redux/selectors/user'; +import { makeSelectNextUnplayedRecommended } from 'redux/selectors/content'; import RecommendedVideos from './view'; const select = (state, props) => ({ claim: makeSelectClaimForUri(props.uri)(state), mature: makeSelectClaimIsNsfw(props.uri)(state), recommendedContent: makeSelectRecommendedContentForUri(props.uri)(state), + nextRecommendedUri: makeSelectNextUnplayedRecommended(props.uri)(state), isSearching: selectIsSearching(state), isAuthenticated: selectUserVerifiedEmail(state), }); -const perform = dispatch => ({ +const perform = (dispatch) => ({ search: (query, options) => dispatch(doSearch(query, options)), }); diff --git a/ui/component/recommendedContent/view.jsx b/ui/component/recommendedContent/view.jsx index d556b4e51..54e089a6c 100644 --- a/ui/component/recommendedContent/view.jsx +++ b/ui/component/recommendedContent/view.jsx @@ -15,6 +15,7 @@ type Props = { uri: string, claim: ?StreamClaim, recommendedContent: Array, + nextRecommendedUri: string, isSearching: boolean, search: (string, Options) => void, mature: boolean, @@ -22,7 +23,7 @@ type Props = { }; export default function RecommendedContent(props: Props) { - const { uri, claim, search, mature, recommendedContent, isSearching, isAuthenticated } = props; + const { uri, claim, search, mature, recommendedContent, nextRecommendedUri, isSearching, isAuthenticated } = props; const isMobile = useIsMobile(); const isMedium = useIsMediumScreen(); @@ -43,6 +44,22 @@ export default function RecommendedContent(props: Props) { } }, [stringifiedClaim, mature, search]); + function reorderList(recommendedContent) { + let newList = recommendedContent; + if (newList) { + const index = newList.indexOf(nextRecommendedUri); + if (index === -1) { + // This would be weird. Shouldn't happen since it is derived from the same list. + } else if (index !== 0) { + // Swap the "next" item to the top of the list + const a = newList[0]; + newList[0] = nextRecommendedUri; + newList[index] = a; + } + } + return newList; + } + React.useEffect(() => { getRecommendedContent(); }, [uri, getRecommendedContent]); @@ -57,7 +74,7 @@ export default function RecommendedContent(props: Props) { continue; } - if (!history.some((item) => item.uri === recommendedForUri[i])) { + const recommendedUriInfo = parseURI(recommendedUri); + const recommendedUriShort = recommendedUriInfo.claimName + '#' + recommendedUriInfo.claimId.substring(0, 1); + + if (claimsByUri[uri] && claimsByUri[uri].claim_id === recommendedUriInfo.claimId) { + // Skip myself (same claim ID) + continue; + } + + if ( + !history.some((h) => { + const directMatch = h.uri === recommendedForUri[i]; + const shortUriMatch = h.uri.includes(recommendedUriShort); + const idMatch = claimsByUri[h.uri] && claimsByUri[h.uri].claim_id === recommendedUriInfo.claimId; + + return directMatch || shortUriMatch || idMatch; + }) + ) { return recommendedForUri[i]; } }