Skip to content

Commit baf5dd3

Browse files
authored
Merge pull request #311 from B0pol/fixSearchSuggestion
Search: add isCorrectedSearch() and fix YoutubeSearchExtractor#getSea…
2 parents b40ccb5 + 6cff5de commit baf5dd3

11 files changed

Lines changed: 177 additions & 19 deletions

File tree

extractor/src/main/java/org/schabi/newpipe/extractor/search/SearchExtractor.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,16 @@ public String getSearchString() {
2525
return getLinkHandler().getSearchString();
2626
}
2727

28+
/**
29+
* The search suggestion provided by the service.
30+
* <p>
31+
* This method also returns the corrected query if
32+
* {@link SearchExtractor#isCorrectedSearch()} is true.
33+
*
34+
* @return a suggestion to another query, the corrected query, or an empty String.
35+
* @throws ParsingException
36+
*/
37+
@Nonnull
2838
public abstract String getSearchSuggestion() throws ParsingException;
2939

3040
@Override
@@ -37,4 +47,14 @@ public SearchQueryHandler getLinkHandler() {
3747
public String getName() {
3848
return getLinkHandler().getSearchString();
3949
}
50+
51+
/**
52+
* Tell if the search was corrected by the service (if it's not exactly the search you typed).
53+
* <p>
54+
* Example: on YouTube, if you search for "pewdeipie",
55+
* it will give you results for "pewdiepie", then isCorrectedSearch should return true.
56+
*
57+
* @return whether the results comes from a corrected query or not.
58+
*/
59+
public abstract boolean isCorrectedSearch() throws ParsingException;
4060
}

extractor/src/main/java/org/schabi/newpipe/extractor/search/SearchInfo.java

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ public class SearchInfo extends ListInfo<InfoItem> {
1515

1616
private String searchString;
1717
private String searchSuggestion;
18+
private boolean isCorrectedSearch;
1819

1920
public SearchInfo(int serviceId,
2021
SearchQueryHandler qIHandler,
@@ -42,7 +43,12 @@ public static SearchInfo getInfo(SearchExtractor extractor) throws ExtractionExc
4243
info.addError(e);
4344
}
4445
try {
45-
info.searchSuggestion = extractor.getSearchSuggestion();
46+
info.setSearchSuggestion(extractor.getSearchSuggestion());
47+
} catch (Exception e) {
48+
info.addError(e);
49+
}
50+
try {
51+
info.setIsCorrectedSearch(extractor.isCorrectedSearch());
4652
} catch (Exception e) {
4753
info.addError(e);
4854
}
@@ -64,10 +70,22 @@ public static ListExtractor.InfoItemsPage<InfoItem> getMoreItems(StreamingServic
6470

6571
// Getter
6672
public String getSearchString() {
67-
return searchString;
73+
return this.searchString;
6874
}
6975

7076
public String getSearchSuggestion() {
71-
return searchSuggestion;
77+
return this.searchSuggestion;
78+
}
79+
80+
public boolean isCorrectedSearch() {
81+
return this.isCorrectedSearch;
82+
}
83+
84+
public void setIsCorrectedSearch(boolean isCorrectedSearch) {
85+
this.isCorrectedSearch = isCorrectedSearch;
86+
}
87+
88+
public void setSearchSuggestion(String searchSuggestion) {
89+
this.searchSuggestion = searchSuggestion;
7290
}
7391
}

extractor/src/main/java/org/schabi/newpipe/extractor/services/media_ccc/extractors/MediaCCCSearchExtractor.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import org.schabi.newpipe.extractor.channel.ChannelInfoItemExtractor;
1212
import org.schabi.newpipe.extractor.downloader.Downloader;
1313
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
14+
import org.schabi.newpipe.extractor.exceptions.ParsingException;
1415
import org.schabi.newpipe.extractor.linkhandler.SearchQueryHandler;
1516
import org.schabi.newpipe.extractor.search.InfoItemsSearchCollector;
1617
import org.schabi.newpipe.extractor.search.SearchExtractor;
@@ -42,9 +43,15 @@ public MediaCCCSearchExtractor(final StreamingService service,
4243
}
4344
}
4445

46+
@Nonnull
4547
@Override
4648
public String getSearchSuggestion() {
47-
return null;
49+
return "";
50+
}
51+
52+
@Override
53+
public boolean isCorrectedSearch() {
54+
return false;
4855
}
4956

5057
@Nonnull

extractor/src/main/java/org/schabi/newpipe/extractor/services/peertube/extractors/PeertubeSearchExtractor.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.schabi.newpipe.extractor.utils.Parser;
2121
import org.schabi.newpipe.extractor.utils.Parser.RegexException;
2222

23+
import javax.annotation.Nonnull;
2324
import java.io.IOException;
2425

2526
import static org.schabi.newpipe.extractor.services.peertube.PeertubeParsingHelper.*;
@@ -33,9 +34,15 @@ public PeertubeSearchExtractor(StreamingService service, SearchQueryHandler link
3334
super(service, linkHandler);
3435
}
3536

37+
@Nonnull
3638
@Override
3739
public String getSearchSuggestion() throws ParsingException {
38-
return null;
40+
return "";
41+
}
42+
43+
@Override
44+
public boolean isCorrectedSearch() {
45+
return false;
3946
}
4047

4148
@Override

extractor/src/main/java/org/schabi/newpipe/extractor/services/soundcloud/extractors/SoundcloudSearchExtractor.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,15 @@ public SoundcloudSearchExtractor(StreamingService service, SearchQueryHandler li
3333
super(service, linkHandler);
3434
}
3535

36+
@Nonnull
3637
@Override
3738
public String getSearchSuggestion() {
38-
return null;
39+
return "";
40+
}
41+
42+
@Override
43+
public boolean isCorrectedSearch() {
44+
return false;
3945
}
4046

4147
@Nonnull

extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeMusicSearchExtractor.java

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.schabi.newpipe.extractor.search.InfoItemsSearchCollector;
1919
import org.schabi.newpipe.extractor.search.SearchExtractor;
2020
import org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper;
21+
import org.schabi.newpipe.extractor.utils.JsonUtils;
2122
import org.schabi.newpipe.extractor.utils.Utils;
2223

2324
import java.io.IOException;
@@ -125,15 +126,40 @@ public String getUrl() throws ParsingException {
125126
return super.getUrl();
126127
}
127128

129+
@Nonnull
128130
@Override
129131
public String getSearchSuggestion() throws ParsingException {
130-
final JsonObject didYouMeanRenderer = initialData.getObject("contents").getObject("sectionListRenderer")
131-
.getArray("contents").getObject(0).getObject("itemSectionRenderer")
132-
.getArray("contents").getObject(0).getObject("didYouMeanRenderer");
133-
if (!didYouMeanRenderer.has("correctedQuery")) {
132+
final JsonObject itemSectionRenderer = initialData.getObject("contents").getObject("sectionListRenderer")
133+
.getArray("contents").getObject(0).getObject("itemSectionRenderer");
134+
if (itemSectionRenderer.isEmpty()) {
135+
return "";
136+
}
137+
138+
final JsonObject didYouMeanRenderer = itemSectionRenderer.getArray("contents")
139+
.getObject(0).getObject("didYouMeanRenderer");
140+
final JsonObject showingResultsForRenderer = itemSectionRenderer.getArray("contents").getObject(0)
141+
.getObject("showingResultsForRenderer");
142+
143+
if (!didYouMeanRenderer.isEmpty()) {
144+
return getTextFromObject(didYouMeanRenderer.getObject("correctedQuery"));
145+
} else if (!showingResultsForRenderer.isEmpty()) {
146+
return JsonUtils.getString(showingResultsForRenderer, "correctedQueryEndpoint.searchEndpoint.query");
147+
} else {
134148
return "";
135149
}
136-
return getTextFromObject(didYouMeanRenderer.getObject("correctedQuery"));
150+
}
151+
152+
@Override
153+
public boolean isCorrectedSearch() {
154+
final JsonObject itemSectionRenderer = initialData.getObject("contents").getObject("sectionListRenderer")
155+
.getArray("contents").getObject(0).getObject("itemSectionRenderer");
156+
if (itemSectionRenderer.isEmpty()) {
157+
return false;
158+
}
159+
160+
final JsonObject showingResultsForRenderer = itemSectionRenderer.getArray("contents").getObject(0)
161+
.getObject("showingResultsForRenderer");
162+
return !showingResultsForRenderer.isEmpty();
137163
}
138164

139165
@Nonnull

extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeSearchExtractor.java

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import com.grack.nanojson.JsonArray;
44
import com.grack.nanojson.JsonObject;
5-
65
import org.schabi.newpipe.extractor.InfoItem;
76
import org.schabi.newpipe.extractor.StreamingService;
87
import org.schabi.newpipe.extractor.downloader.Downloader;
@@ -12,10 +11,10 @@
1211
import org.schabi.newpipe.extractor.localization.TimeAgoParser;
1312
import org.schabi.newpipe.extractor.search.InfoItemsSearchCollector;
1413
import org.schabi.newpipe.extractor.search.SearchExtractor;
15-
16-
import java.io.IOException;
14+
import org.schabi.newpipe.extractor.utils.JsonUtils;
1715

1816
import javax.annotation.Nonnull;
17+
import java.io.IOException;
1918

2019
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getJsonResponse;
2120
import static org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper.getTextFromObject;
@@ -63,17 +62,35 @@ public String getUrl() throws ParsingException {
6362
return super.getUrl() + "&gl=" + getExtractorContentCountry().getCountryCode();
6463
}
6564

65+
@Nonnull
6666
@Override
6767
public String getSearchSuggestion() throws ParsingException {
68-
final JsonObject showingResultsForRenderer = initialData.getObject("contents")
68+
final JsonObject itemSectionRenderer = initialData.getObject("contents")
6969
.getObject("twoColumnSearchResultsRenderer").getObject("primaryContents")
7070
.getObject("sectionListRenderer").getArray("contents").getObject(0)
71-
.getObject("itemSectionRenderer").getArray("contents").getObject(0)
71+
.getObject("itemSectionRenderer");
72+
final JsonObject didYouMeanRenderer = itemSectionRenderer.getArray("contents").getObject(0)
73+
.getObject("didYouMeanRenderer");
74+
final JsonObject showingResultsForRenderer = itemSectionRenderer.getArray("contents").getObject(0)
7275
.getObject("showingResultsForRenderer");
73-
if (!showingResultsForRenderer.has("correctedQuery")) {
76+
77+
if (!didYouMeanRenderer.isEmpty()) {
78+
return JsonUtils.getString(didYouMeanRenderer, "correctedQueryEndpoint.searchEndpoint.query");
79+
} else if (showingResultsForRenderer != null) {
80+
return getTextFromObject(showingResultsForRenderer.getObject("correctedQuery"));
81+
} else {
7482
return "";
7583
}
76-
return getTextFromObject(showingResultsForRenderer.getObject("correctedQuery"));
84+
}
85+
86+
@Override
87+
public boolean isCorrectedSearch() {
88+
final JsonObject showingResultsForRenderer = initialData.getObject("contents")
89+
.getObject("twoColumnSearchResultsRenderer").getObject("primaryContents")
90+
.getObject("sectionListRenderer").getArray("contents").getObject(0)
91+
.getObject("itemSectionRenderer").getArray("contents").getObject(0)
92+
.getObject("showingResultsForRenderer");
93+
return !showingResultsForRenderer.isEmpty();
7794
}
7895

7996
@Nonnull

extractor/src/test/java/org/schabi/newpipe/extractor/services/BaseSearchExtractorTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@
44
public interface BaseSearchExtractorTest extends BaseListExtractorTest {
55
void testSearchString() throws Exception;
66
void testSearchSuggestion() throws Exception;
7+
void testSearchCorrected() throws Exception;
78
}

extractor/src/test/java/org/schabi/newpipe/extractor/services/DefaultSearchExtractorTest.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ public abstract class DefaultSearchExtractorTest extends DefaultListExtractorTes
1616
public abstract String expectedSearchString();
1717
@Nullable public abstract String expectedSearchSuggestion();
1818

19+
public boolean isCorrectedSearch() {
20+
return false;
21+
}
22+
1923
@Test
2024
@Override
2125
public void testSearchString() throws Exception {
@@ -32,4 +36,9 @@ public void testSearchSuggestion() throws Exception {
3236
assertEquals(expectedSearchSuggestion, extractor().getSearchSuggestion());
3337
}
3438
}
39+
40+
@Test
41+
public void testSearchCorrected() throws Exception {
42+
assertEquals(isCorrectedSearch(), extractor().isCorrectedSearch());
43+
}
3544
}

extractor/src/test/java/org/schabi/newpipe/extractor/services/youtube/search/YoutubeMusicSearchExtractorTest.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,4 +150,28 @@ public static void setUp() throws Exception {
150150
@Nullable @Override public String expectedSearchSuggestion() { return "mega man x3"; }
151151
@Override public InfoItem.InfoType expectedInfoItemType() { return InfoItem.InfoType.STREAM; }
152152
}
153+
154+
public static class CorrectedSearch extends DefaultSearchExtractorTest {
155+
private static SearchExtractor extractor;
156+
private static final String QUERY = "duo lipa";
157+
private static final String EXPECTED_SUGGESTION = "dua lipa";
158+
159+
@BeforeClass
160+
public static void setUp() throws Exception {
161+
NewPipe.init(DownloaderTestImpl.getInstance());
162+
extractor = YouTube.getSearchExtractor(QUERY, singletonList(YoutubeSearchQueryHandlerFactory.MUSIC_SONGS), "");
163+
extractor.fetchPage();
164+
}
165+
166+
@Override public SearchExtractor extractor() { return extractor; }
167+
@Override public StreamingService expectedService() { return YouTube; }
168+
@Override public String expectedName() { return QUERY; }
169+
@Override public String expectedId() { return QUERY; }
170+
@Override public String expectedUrlContains() { return "music.youtube.com/search?q=" + URLEncoder.encode(QUERY); }
171+
@Override public String expectedOriginalUrlContains() { return "music.youtube.com/search?q=" + URLEncoder.encode(QUERY); }
172+
@Override public String expectedSearchString() { return QUERY; }
173+
@Nullable @Override public String expectedSearchSuggestion() { return EXPECTED_SUGGESTION; }
174+
@Override public InfoItem.InfoType expectedInfoItemType() { return InfoItem.InfoType.STREAM; }
175+
@Override public boolean isCorrectedSearch() { return true; }
176+
}
153177
}

0 commit comments

Comments
 (0)