-
-
Notifications
You must be signed in to change notification settings - Fork 543
Youtube search filters #124
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
635d147
d18c68a
7bab982
93239eb
e788a0c
78bb968
e906c37
f71b62f
75ad8f9
98b67a4
b02ca4a
6e8515d
5464d73
cd38c1b
56366eb
7c80354
8152ccf
55b126a
2b771cb
4cfd07b
68f9547
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,19 +2,83 @@ | |
|
|
||
| import org.schabi.newpipe.extractor.exceptions.ParsingException; | ||
| import org.schabi.newpipe.extractor.linkhandler.SearchQueryHandlerFactory; | ||
| import org.schabi.newpipe.extractor.utils.Base64; | ||
|
|
||
| import javax.annotation.Nonnull; | ||
| import javax.annotation.Nullable; | ||
| import java.io.UnsupportedEncodingException; | ||
| import java.net.URLEncoder; | ||
| import java.util.ArrayList; | ||
| import java.util.Arrays; | ||
| import java.util.Collections; | ||
| import java.util.List; | ||
|
|
||
| public class YoutubeSearchQueryHandlerFactory extends SearchQueryHandlerFactory { | ||
|
|
||
| public static final String CHARSET_UTF_8 = "UTF-8"; | ||
|
|
||
| public static final String VIDEOS = "videos"; | ||
| public static final String CHANNELS = "channels"; | ||
| public static final String PLAYLISTS = "playlists"; | ||
| public static final String ALL = "all"; | ||
| public enum FilterType { | ||
| Content((byte)0x10), | ||
| Time((byte)0x08), | ||
| Duration((byte)0x18); | ||
|
|
||
| private final byte value; | ||
|
|
||
| FilterType(byte value) { | ||
| this.value = value; | ||
| } | ||
| } | ||
|
|
||
| public enum Filter { | ||
| All(FilterType.Content,(byte)0), | ||
| Video(FilterType.Content,(byte)0x01), | ||
| Channel(FilterType.Content,(byte)0x02), | ||
| Playlist(FilterType.Content,(byte)0x03), | ||
| Movie(FilterType.Content,(byte)0x04), | ||
| Show(FilterType.Content,(byte)0x05), | ||
|
|
||
| Hour(FilterType.Time,(byte)0x01), | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NewPipe can not handle key value pair filter yet :/
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes this is the issue i ment, it is not possible to add or remove filters like key values. This messes up the UI as you see. The UI should be made ready to handle these filters.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we could implement the filters at 2 levels? We would initially ask the user to select a So, clicking on the menu icon the first time, will load a list containing
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's finish this PR. 🎉 Thanks for being patient! I am working on a proper design for the filters. This might take until next Sunday, because the new semesters is about to start and thus there are a bunch of other things to do. But I would not recommend to have endless lists. They come with bad UI/UX, because it is hard to get all the (important) information. FYI:
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @TobiGr Of course, take your time. I was just surprised and happy that it worked functionally out of the box.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I put my UI ideas into this issue in the app repo. I guess a UI discussion fits better into the other repo. |
||
| Today(FilterType.Time,(byte)0x02), | ||
| Week(FilterType.Time,(byte)0x03), | ||
| Month(FilterType.Time,(byte)0x04), | ||
| Year(FilterType.Time,(byte)0x05), | ||
|
|
||
| Short(FilterType.Duration, (byte)0x01), | ||
| Long(FilterType.Duration, (byte)0x02); | ||
|
|
||
| private final FilterType type; | ||
| private final byte value; | ||
|
|
||
| Filter(FilterType type, byte value) { | ||
| this.type = type; | ||
| this.value = value; | ||
| } | ||
| } | ||
|
|
||
| public enum SorterType { | ||
| Default((byte)0x08); | ||
|
|
||
| private final byte value; | ||
|
|
||
| SorterType(byte value) { | ||
| this.value = value; | ||
| } | ||
| } | ||
|
|
||
| public enum Sorter { | ||
| Relevance(SorterType.Default, (byte)0x00), | ||
| Rating(SorterType.Default, (byte)0x01), | ||
| Upload_Date(SorterType.Default, (byte)0x02), | ||
| View_Count(SorterType.Default, (byte)0x03); | ||
|
|
||
| private final SorterType type; | ||
| private final byte value; | ||
|
|
||
| Sorter(SorterType type, byte value) { | ||
| this.type = type; | ||
| this.value = value; | ||
| } | ||
| } | ||
|
|
||
| public static YoutubeSearchQueryHandlerFactory getInstance() { | ||
| return new YoutubeSearchQueryHandlerFactory(); | ||
|
|
@@ -23,31 +87,118 @@ public static YoutubeSearchQueryHandlerFactory getInstance() { | |
| @Override | ||
| public String getUrl(String searchString, List<String> contentFilters, String sortFilter) throws ParsingException { | ||
| try { | ||
| final String url = "https://www.youtube.com/results" | ||
| + "?q=" + URLEncoder.encode(searchString, CHARSET_UTF_8); | ||
|
|
||
| if(contentFilters.size() > 0) { | ||
| switch (contentFilters.get(0)) { | ||
| case VIDEOS: return url + "&sp=EgIQAVAU"; | ||
| case CHANNELS: return url + "&sp=EgIQAlAU"; | ||
| case PLAYLISTS: return url + "&sp=EgIQA1AU"; | ||
| case ALL: | ||
| default: | ||
| } | ||
| String returnURL = getSearchBaseUrl(searchString); | ||
| String filterQueryParams = getFilterQueryParams(contentFilters, sortFilter); | ||
| if(filterQueryParams != null) { | ||
| returnURL = returnURL + "&sp=" + filterQueryParams; | ||
| } | ||
|
|
||
| return url; | ||
| return returnURL; | ||
| } catch (UnsupportedEncodingException e) { | ||
| throw new ParsingException("Could not encode query", e); | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public String[] getAvailableContentFilter() { | ||
| return new String[] { | ||
| ALL, | ||
| VIDEOS, | ||
| CHANNELS, | ||
| PLAYLISTS}; | ||
| List<String> contentFiltersList = new ArrayList<>(); | ||
| for(Filter contentFilter : Filter.values()) { | ||
| contentFiltersList.add(contentFilter.name()); | ||
| } | ||
| String[] contentFiltersArray = new String[contentFiltersList.size()]; | ||
| contentFiltersArray = contentFiltersList.toArray(contentFiltersArray); | ||
| return contentFiltersArray; | ||
| } | ||
|
|
||
| @Override | ||
| public String[] getAvailableSortFilter() { | ||
| List<String> sortFiltersList = new ArrayList<>(); | ||
| for(Sorter sortFilter : Sorter.values()) { | ||
| sortFiltersList.add(sortFilter.name()); | ||
| } | ||
| String[] sortFiltersArray = new String[sortFiltersList.size()]; | ||
| sortFiltersArray = sortFiltersList.toArray(sortFiltersArray); | ||
| return sortFiltersArray; | ||
| } | ||
|
|
||
| private String getSearchBaseUrl(String searchQuery) | ||
| throws UnsupportedEncodingException { | ||
| return "https://www.youtube.com/results" + | ||
| "?q=" + | ||
| URLEncoder.encode(searchQuery, CHARSET_UTF_8); | ||
| } | ||
|
|
||
| @Nullable | ||
| private String getFilterQueryParams(List<String> contentFilters, String sortFilter) | ||
| throws UnsupportedEncodingException { | ||
| List<Byte> returnList = new ArrayList<>(); | ||
| List<Byte> sortFilterParams = getSortFiltersQueryParam(sortFilter); | ||
| if(!sortFilterParams.isEmpty()) { | ||
| returnList.addAll(sortFilterParams); | ||
| } | ||
| List<Byte> contentFilterParams = getContentFiltersQueryParams(contentFilters); | ||
| if(!contentFilterParams.isEmpty()) { | ||
| returnList.add((byte)0x12); | ||
| returnList.add((byte)contentFilterParams.size()); | ||
| returnList.addAll(contentFilterParams); | ||
| } | ||
|
|
||
| if(returnList.isEmpty()) { | ||
| return null; | ||
| } | ||
| return URLEncoder.encode(Base64.encodeToString(convert(returnList), Base64.URL_SAFE)); | ||
| } | ||
|
|
||
| private List<Byte> getContentFiltersQueryParams(List<String> contentFilter) { | ||
| if(contentFilter == null || contentFilter.isEmpty()) { | ||
| return Collections.emptyList(); | ||
| } | ||
| List<Byte> returnList = new ArrayList<>(); | ||
| for(String filter : contentFilter) { | ||
| List<Byte> byteList = getContentFilterQueryParams(filter); | ||
| if(!byteList.isEmpty()) { | ||
| returnList.addAll(byteList); | ||
| } | ||
| } | ||
| return returnList; | ||
| } | ||
|
|
||
| private List<Byte> getContentFilterQueryParams(String filter) { | ||
| Filter contentFilter; | ||
| try { | ||
| contentFilter = Filter.valueOf(filter); | ||
| } catch (IllegalArgumentException iae) { | ||
| iae.printStackTrace(); | ||
| System.err.println("Unknown content filter type provided = " + filter +", none will be applied"); | ||
| return Collections.emptyList(); | ||
| } | ||
| switch (contentFilter) { | ||
| case All: | ||
| return Collections.emptyList(); | ||
| default: | ||
| return Arrays.asList(contentFilter.type.value, contentFilter.value); | ||
| } | ||
| } | ||
|
|
||
| private List<Byte> getSortFiltersQueryParam(String filter) { | ||
| if(filter == null || filter.isEmpty()) { | ||
| return Collections.emptyList(); | ||
| } | ||
| Sorter sorter; | ||
| try { | ||
| sorter = Sorter.valueOf(filter); | ||
| } catch (IllegalArgumentException e) { | ||
| e.printStackTrace(); | ||
|
theScrabi marked this conversation as resolved.
|
||
| System.err.println("Unknown sort filter = " + filter + " provided, none applied."); | ||
| return Collections.emptyList(); | ||
| } | ||
| return Arrays.asList(sorter.type.value, sorter.value); | ||
| } | ||
|
|
||
| private byte[] convert(@Nonnull List<Byte> bigByteList) { | ||
| byte[] returnArray = new byte[bigByteList.size()]; | ||
| for (int i = 0; i < bigByteList.size(); i++) { | ||
| returnArray[i] = bigByteList.get(i); | ||
| } | ||
| return returnArray; | ||
| } | ||
| } | ||

Uh oh!
There was an error while loading. Please reload this page.