diff --git a/src/parser/classes/SearchFilter.ts b/src/parser/classes/SearchFilter.ts new file mode 100644 index 000000000..cea552ac3 --- /dev/null +++ b/src/parser/classes/SearchFilter.ts @@ -0,0 +1,22 @@ +import { YTNode } from '../helpers.js'; +import type { RawNode } from '../index.js'; +import Text from './misc/Text.js'; +import NavigationEndpoint from './NavigationEndpoint.js'; + +class SearchFilter extends YTNode { + static type = 'SearchFilter'; + + label: Text; + endpoint: NavigationEndpoint; + tooltip: string; + + constructor(data: RawNode) { + super(); + + this.label = new Text(data.label); + this.endpoint = new NavigationEndpoint(data.endpoint); + this.tooltip = data.tooltip; + } +} + +export default SearchFilter; \ No newline at end of file diff --git a/src/parser/classes/SearchFilterGroup.ts b/src/parser/classes/SearchFilterGroup.ts new file mode 100644 index 000000000..9084a60a8 --- /dev/null +++ b/src/parser/classes/SearchFilterGroup.ts @@ -0,0 +1,20 @@ +import { ObservedArray, YTNode } from '../helpers.js'; +import type { RawNode } from '../index.js'; +import { Parser, YTNodes } from '../index.js'; +import Text from './misc/Text.js'; + +class SearchFilterGroup extends YTNode { + static type = 'SearchFilterGroup'; + + title: Text; + filters: ObservedArray | null; + + constructor(data: RawNode) { + super(); + + this.title = new Text(data.title); + this.filters = Parser.parseArray(data.filters, YTNodes.SearchFilter); + } +} + +export default SearchFilterGroup; \ No newline at end of file diff --git a/src/parser/classes/SearchSubMenu.ts b/src/parser/classes/SearchSubMenu.ts new file mode 100644 index 000000000..e97fddc84 --- /dev/null +++ b/src/parser/classes/SearchSubMenu.ts @@ -0,0 +1,21 @@ +import { ObservedArray, YTNode } from '../helpers.js'; +import type { RawNode } from '../index.js'; +import Parser, { YTNodes } from '../index.js'; +import Text from './misc/Text.js'; + +class SearchSubMenu extends YTNode { + static type = 'SearchSubMenu'; + + title: Text; + groups: ObservedArray | null; + button: YTNodes.ToggleButton | null; + + constructor(data: RawNode) { + super(); + this.title = new Text(data.title); + this.groups = Parser.parseArray(data.groups, YTNodes.SearchFilterGroup); + this.button = Parser.parseItem(data.button, YTNodes.ToggleButton); + } +} + +export default SearchSubMenu; \ No newline at end of file diff --git a/src/parser/map.ts b/src/parser/map.ts index d20ab7351..72822f3bf 100644 --- a/src/parser/map.ts +++ b/src/parser/map.ts @@ -524,8 +524,14 @@ import { default as RichShelf } from './classes/RichShelf.js'; export { RichShelf }; import { default as SearchBox } from './classes/SearchBox.js'; export { SearchBox }; +import { default as SearchFilter } from './classes/SearchFilter.js'; +export { SearchFilter }; +import { default as SearchFilterGroup } from './classes/SearchFilterGroup.js'; +export { SearchFilterGroup }; import { default as SearchRefinementCard } from './classes/SearchRefinementCard.js'; export { SearchRefinementCard }; +import { default as SearchSubMenu } from './classes/SearchSubMenu.js'; +export { SearchSubMenu }; import { default as SearchSuggestion } from './classes/SearchSuggestion.js'; export { SearchSuggestion }; import { default as SearchSuggestionsSection } from './classes/SearchSuggestionsSection.js'; @@ -930,7 +936,10 @@ const map: Record = { RichSection, RichShelf, SearchBox, + SearchFilter, + SearchFilterGroup, SearchRefinementCard, + SearchSubMenu, SearchSuggestion, SearchSuggestionsSection, SecondarySearchContainer, diff --git a/src/parser/parser.ts b/src/parser/parser.ts index 0344eb343..2ded528ef 100644 --- a/src/parser/parser.ts +++ b/src/parser/parser.ts @@ -489,7 +489,6 @@ export default class Parser { 'RunAttestationCommand', 'CompactPromotedVideo', 'StatementBanner', - 'SearchSubMenu', 'GuideSigninPromo' ]); diff --git a/src/parser/youtube/Search.ts b/src/parser/youtube/Search.ts index e63c8e62d..a2e65f19b 100644 --- a/src/parser/youtube/Search.ts +++ b/src/parser/youtube/Search.ts @@ -1,20 +1,22 @@ import Feed from '../../core/Feed.js'; +import { InnertubeError } from '../../utils/Utils.js'; import HorizontalCardList from '../classes/HorizontalCardList.js'; import ItemSection from '../classes/ItemSection.js'; import SearchRefinementCard from '../classes/SearchRefinementCard.js'; +import SearchSubMenu from '../classes/SearchSubMenu.js'; import SectionList from '../classes/SectionList.js'; import UniversalWatchCard from '../classes/UniversalWatchCard.js'; -import { InnertubeError } from '../../utils/Utils.js'; import type Actions from '../../core/Actions.js'; +import type { ApiResponse } from '../../core/Actions.js'; import type { ObservedArray, YTNode } from '../helpers.js'; import type { ISearchResponse } from '../types/ParsedResponse.js'; -import type { ApiResponse } from '../../core/Actions.js'; class Search extends Feed { results?: ObservedArray | null; refinements: string[]; estimated_results: number; + sub_menu?: SearchSubMenu; watch_card?: UniversalWatchCard; refinement_cards?: HorizontalCardList | null; @@ -33,8 +35,9 @@ class Search extends Feed { this.refinements = this.page.refinements || []; this.estimated_results = this.page.estimated_results; + this.sub_menu = this.page.contents_memo?.getType(SearchSubMenu).first(); this.watch_card = this.page.contents_memo?.getType(UniversalWatchCard).first(); - this.refinement_cards = this.results?.get({ type: 'HorizontalCardList' }, true)?.as(HorizontalCardList); + this.refinement_cards = this.results?.firstOfType(HorizontalCardList); } /**