@@ -55,7 +55,6 @@ export function useCrossSeedSearch(instanceId: number) {
5555 const [ crossSeedIndexerSelection , setCrossSeedIndexerSelection ] = useState < number [ ] > ( [ ] )
5656 const [ crossSeedHasSearched , setCrossSeedHasSearched ] = useState ( false )
5757 const [ crossSeedRefreshCooldownUntil , setCrossSeedRefreshCooldownUntil ] = useState ( 0 )
58- const [ lastSourceTorrent , setLastSourceTorrent ] = useState < CrossSeedTorrentSearchResponse [ "sourceTorrent" ] | null > ( null )
5958
6059 const crossSeedPollingRef = useRef < ReturnType < typeof setInterval > | null > ( null )
6160 const crossSeedPollingInFlightRef = useRef ( false )
@@ -66,53 +65,35 @@ export function useCrossSeedSearch(instanceId: number) {
6665 staleTime : 5 * 60 * 1000 ,
6766 } )
6867
69- useEffect ( ( ) => {
70- if ( crossSeedSearchResponse ?. sourceTorrent ) {
71- setLastSourceTorrent ( crossSeedSearchResponse . sourceTorrent )
72- }
73- } , [ crossSeedSearchResponse ?. sourceTorrent ] )
74-
7568 const crossSeedIndexerOptions = useMemo ( ( ) => {
76- const sourceTorrent = crossSeedSearchResponse ?. sourceTorrent ?? lastSourceTorrent
77- if ( ! sourceTorrent ) {
78- return sortedEnabledIndexers . map ( indexer => ( { id : indexer . id , name : indexer . name } ) )
69+ const allowedIds = crossSeedSearchResponse ?. sourceTorrent ?. availableIndexers
70+ const filteredIds = crossSeedSearchResponse ?. sourceTorrent ?. filteredIndexers
71+ const excludedIds = crossSeedSearchResponse ?. sourceTorrent ?. excludedIndexers
72+
73+ let candidateIds : Set < number > | null = null
74+ if ( allowedIds && allowedIds . length > 0 ) {
75+ candidateIds = new Set ( allowedIds )
76+ } else if ( filteredIds && filteredIds . length > 0 ) {
77+ candidateIds = new Set ( filteredIds )
7978 }
8079
81- if ( sourceTorrent . availableIndexers && sourceTorrent . filteredIndexers ) {
82- const targetIndexerIds = crossSeedHasSearched ? sourceTorrent . filteredIndexers : sourceTorrent . availableIndexers
83- const filteredIds = new Set ( targetIndexerIds )
84- return sortedEnabledIndexers
85- . filter ( indexer => filteredIds . has ( indexer . id ) )
86- . map ( indexer => ( { id : indexer . id , name : indexer . name } ) )
87- }
88-
89- if ( sourceTorrent . filteredIndexers && sourceTorrent . filteredIndexers . length > 0 ) {
90- const filteredIds = new Set ( sourceTorrent . filteredIndexers )
91- return sortedEnabledIndexers
92- . filter ( indexer => filteredIds . has ( indexer . id ) )
93- . map ( indexer => ( { id : indexer . id , name : indexer . name } ) )
94- }
95-
96- const requiredCaps = sourceTorrent . requiredCaps ?? [ ]
97- const requiredCategories = sourceTorrent . searchCategories ?? [ ]
98-
99- const filteredIndexers = sortedEnabledIndexers . filter ( indexer => {
100- if ( requiredCaps . length === 0 && requiredCategories . length === 0 ) {
101- return true
102- }
103-
104- const indexerCaps = indexer . capabilities ?? [ ]
105- const hasRequiredCaps = requiredCaps . length === 0 || requiredCaps . every ( cap => indexerCaps . includes ( cap ) )
106-
107- const indexerCategoryIds = ( indexer . categories ?? [ ] ) . map ( cat => cat . category_id )
108- const hasRequiredCategories = requiredCategories . length === 0 ||
109- requiredCategories . some ( catId => indexerCategoryIds . includes ( catId ) )
110-
111- return hasRequiredCaps && hasRequiredCategories
112- } )
113-
114- return filteredIndexers . map ( indexer => ( { id : indexer . id , name : indexer . name } ) )
115- } , [ sortedEnabledIndexers , crossSeedSearchResponse , lastSourceTorrent , crossSeedHasSearched ] )
80+ const excludedIdSet = excludedIds
81+ ? new Set (
82+ Object . keys ( excludedIds )
83+ . map ( id => Number ( id ) )
84+ . filter ( id => ! Number . isNaN ( id ) )
85+ )
86+ : null
87+
88+ return sortedEnabledIndexers
89+ . filter ( indexer => ( ! candidateIds || candidateIds . has ( indexer . id ) ) && ( ! excludedIdSet || ! excludedIdSet . has ( indexer . id ) ) )
90+ . map ( indexer => ( { id : indexer . id , name : indexer . name } ) )
91+ } , [
92+ crossSeedSearchResponse ?. sourceTorrent ?. availableIndexers ,
93+ crossSeedSearchResponse ?. sourceTorrent ?. filteredIndexers ,
94+ crossSeedSearchResponse ?. sourceTorrent ?. excludedIndexers ,
95+ sortedEnabledIndexers ,
96+ ] )
11697
11798 const crossSeedIndexerNameMap = useMemo ( ( ) => {
11899 const map : Record < number , string > = { }
@@ -122,6 +103,14 @@ export function useCrossSeedSearch(instanceId: number) {
122103 return map
123104 } , [ sortedEnabledIndexers ] )
124105
106+ const excludedIndexerIds = useMemo (
107+ ( ) =>
108+ Object . keys ( crossSeedSearchResponse ?. sourceTorrent ?. excludedIndexers ?? { } )
109+ . map ( id => Number ( id ) )
110+ . filter ( id => ! Number . isNaN ( id ) ) ,
111+ [ crossSeedSearchResponse ?. sourceTorrent ?. excludedIndexers ]
112+ )
113+
125114 const getCrossSeedResultKey = useCallback (
126115 ( result : CrossSeedTorrentSearchResponse [ "results" ] [ number ] , index : number ) =>
127116 result . guid || result . downloadUrl || `${ result . indexer } -${ index } ` ,
@@ -142,7 +131,6 @@ export function useCrossSeedSearch(instanceId: number) {
142131 setCrossSeedApplyResult ( null )
143132 setCrossSeedIndexerMode ( "all" )
144133 setCrossSeedIndexerSelection ( [ ] )
145- setLastSourceTorrent ( null )
146134 setCrossSeedHasSearched ( false )
147135 } , [ ] )
148136
@@ -176,11 +164,17 @@ export function useCrossSeedSearch(instanceId: number) {
176164 return
177165 }
178166
179- let resolvedIndexerIds : number [ ] | undefined
167+ let resolvedIndexerIds : number [ ] | null | undefined
180168 if ( indexerOverride !== undefined ) {
181- resolvedIndexerIds = indexerOverride ?? undefined
182- } else if ( crossSeedIndexerMode === "custom" && crossSeedIndexerSelection . length > 0 ) {
169+ resolvedIndexerIds = indexerOverride
170+ } else if ( crossSeedIndexerMode === "custom" ) {
183171 resolvedIndexerIds = crossSeedIndexerSelection
172+ } else {
173+ resolvedIndexerIds = sortedEnabledIndexers . map ( indexer => indexer . id )
174+ }
175+
176+ if ( Array . isArray ( resolvedIndexerIds ) && excludedIndexerIds . length > 0 ) {
177+ resolvedIndexerIds = resolvedIndexerIds . filter ( id => ! excludedIndexerIds . includes ( id ) )
184178 }
185179
186180 setCrossSeedSearchLoading ( true )
@@ -192,7 +186,7 @@ export function useCrossSeedSearch(instanceId: number) {
192186 void api
193187 . searchCrossSeedTorrent ( instanceId , torrent . hash , {
194188 findIndividualEpisodes : crossSeedSettings ?. findIndividualEpisodes ?? false ,
195- indexerIds : resolvedIndexerIds && resolvedIndexerIds . length > 0 ? resolvedIndexerIds : undefined ,
189+ indexerIds : Array . isArray ( resolvedIndexerIds ) && resolvedIndexerIds . length > 0 ? resolvedIndexerIds : undefined ,
196190 cacheMode : options ?. bypassCache ? "bypass" : undefined ,
197191 } )
198192 . then ( response => {
@@ -235,6 +229,8 @@ export function useCrossSeedSearch(instanceId: number) {
235229 crossSeedIndexerSelection ,
236230 crossSeedSettings ?. findIndividualEpisodes ,
237231 getCrossSeedResultKey ,
232+ excludedIndexerIds ,
233+ sortedEnabledIndexers ,
238234 instanceId ,
239235 ]
240236 )
0 commit comments