diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..ebe51d3b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = false +insert_final_newline = false \ No newline at end of file diff --git a/README.md b/README.md index 1a20749b..c1d301fd 100644 --- a/README.md +++ b/README.md @@ -1153,7 +1153,7 @@ import Innertube from 'youtubei.js'; const youtube = await new Innertube(); const creds_path = './yt_oauth_creds.json'; -const creds = fs.existsSync(creds_path) && JSON.parse(fs.readFileSync(creds_path).toString()) || {}; +const creds = fs.existsSync(creds_path) ? JSON.parse(fs.readFileSync(creds_path).toString()) : {}; youtube.ev.on('auth', (data) => { switch (data.status) { diff --git a/lib/Innertube.js b/lib/Innertube.js index 06d8bd5f..dc4581c4 100644 --- a/lib/Innertube.js +++ b/lib/Innertube.js @@ -132,7 +132,9 @@ class Innertube { async signOut() { if (!this.logged_in) throw new Utils.InnertubeError('You are not signed in'); const response = await this.oauth.revokeAccessToken(); - response.success && (this.logged_in = false); + if (response.success) { + this.logged_in = false; + } return response; } diff --git a/lib/core/AccountManager.js b/lib/core/AccountManager.js index 37f46135..93450f4f 100644 --- a/lib/core/AccountManager.js +++ b/lib/core/AccountManager.js @@ -137,10 +137,17 @@ class AccountManager { const response = await this.#actions.browse(type); - const contents = ({ - SPaccount_notifications: () => Utils.findNode(response.data, 'contents', 'Your preferences', 13, false).options, - SPaccount_privacy: () => Utils.findNode(response.data, 'contents', 'settingsSwitchRenderer', 13, false).options - })[type.trim()](); + const contents = (() => { + switch (type.trim()) { + case 'SPaccount_notifications': + return Utils.findNode(response.data, 'contents', 'Your preferences', 13, false).options; + case 'SPaccount_privacy': + return Utils.findNode(response.data, 'contents', 'settingsSwitchRenderer', 13, false).options; + default: + // this is just for maximum compatibility, this is most definitely a bad way to handle this + throw new TypeError('undefined is not a function'); + } + })() const option = contents.find((option) => option.settingsSwitchRenderer.enableServiceEndpoint.setSettingEndpoint.settingItemIdForClient == setting_id); diff --git a/lib/core/Actions.js b/lib/core/Actions.js index dad3295d..c3a0838a 100644 --- a/lib/core/Actions.js +++ b/lib/core/Actions.js @@ -43,15 +43,17 @@ class Actions { const data = {}; - args.params && - (data.params = args.params); + if (args.params) data.params = args.params; - args.is_ctoken && - (data.continuation = id) || - (data.browseId = id); + if (args.is_ctoken) { + data.continuation = id + } else { + data.browseId = id; + } - args.client && - (data.client = args.client); + if (args.client) { + data.client = args.client; + } const response = await this.#request.post('/browse', data); @@ -83,7 +85,9 @@ class Actions { data.target = {}; data.videoId = args.video_id; - args.params && (data.params = args.params); + if (args.params) { + data.params = args.params; + } break; case 'subscription/subscribe': case 'subscription/unsubscribe': @@ -99,11 +103,19 @@ class Actions { data.commentText = args.text; break; case 'comment/perform_comment_action': - const target_action = ({ - like: () => Proto.encodeCommentActionParams(5, args), - dislike: () => Proto.encodeCommentActionParams(4, args), - translate: () => Proto.encodeCommentActionParams(22, args) - })[args.comment_action](); + const target_action = (() => { + switch (args.comment_action) { + case 'like': + return Proto.encodeCommentActionParams(5, args); + case 'dislike': + return Proto.encodeCommentActionParams(4, args); + case 'translate': + return Proto.encodeCommentActionParams(22, args); + default: + // this is just for maximum compatibility, this is most definitely a bad way to handle this + throw new TypeError('undefined is not a function'); + } + })() data.actions = [ target_action ]; break; @@ -161,23 +173,29 @@ class Actions { async search(args = {}) { const data = {}; - args.query && - (data.query = args.query); + if (args.query) { + data.query = args.query; + } - args.ctoken && - (data.continuation = args.ctoken); + if (args.ctoken) { + data.continuation = args.ctoken; + } - args.params && - (data.params = args.params); + if (args.params) { + data.params + } if (args.filters) { - args.client == 'YTMUSIC' && - (data.params = Proto.encodeMusicSearchFilters(args.filters)) || - (data.params = Proto.encodeSearchFilters(args.filters)); + if (args.client == 'YTMUSIC') { + data.filters = Proto.encodeMusicSearchFilters(args.filters); + } else { + data.filters = Proto.encodeSearchFilters(args.filters); + } } - args.client && - (data.client = args.client); + if (args.client) { + data.client + } const response = await this.#request.post('/search', data); @@ -262,16 +280,23 @@ class Actions { break; case 'browse/edit_playlist': data.playlistId = args.playlist_id; - data.actions = args.ids.map((id) => ({ - 'ACTION_ADD_VIDEO': { - action: args.action, - addedVideoId: id - }, - 'ACTION_REMOVE_VIDEO': { - action: args.action, - setVideoId: id - } - })[args.action]); + data.actions = args.ids.map((id) => { + switch (args.action) { + case 'ACTION_ADD_VIDEO': + return { + action: args.action, + addedVideoId: id + } + case 'ACTION_REMOVE_VIDEO': + return { + action: args.action, + setVideoId: id + } + default: + // this is just for maximum compatibility, this is most definitely a bad way to handle this + throw new TypeError('undefined is not a function'); + } + }); break; default: throw new Utils.InnertubeError('Action not implemented', action); @@ -305,7 +330,7 @@ class Actions { break; case 'get_notification_menu': data.notificationsMenuRequestType = 'NOTIFICATIONS_MENU_REQUEST_TYPE_INBOX'; - args.ctoken && (data.ctoken = args.ctoken); + if (args.ctoken) data.ctoken = args.ctoken; break; case 'record_interactions': data.serializedRecordNotificationInteractionsRequest = args.params; @@ -356,7 +381,7 @@ class Actions { break; case 'updated_metadata': data.videoId = args.video_id; - args.ctoken && (data.continuation = args.ctoken); + if (args.ctoken) data.continuation = args.ctoken; break; default: throw new Utils.InnertubeError('Action not implemented', action); @@ -476,14 +501,17 @@ class Actions { async next(args = {}) { const data = {}; - args.ctoken && - (data.continuation = args.ctoken); + if (args.ctoken) { + data.continuation + } - args.video_id && - (data.videoId = args.video_id); + if (args.video_id) { + data.videoId + } - args.client && - (data.client = args.client); + if (args.client) { + data.client + } const response = await this.#request.post('/next', data); @@ -519,9 +547,13 @@ class Actions { videoId: id }; - client && (data.client = client); + if (client) { + data.client = client + } - cpn && (data.cpn = cpn); + if (cpn) { + data.cpn = cpn + } const response = await this.#request.post('/player', data); diff --git a/lib/deciphers/NToken.js b/lib/deciphers/NToken.js index 5a0d5317..4a7634f4 100644 --- a/lib/deciphers/NToken.js +++ b/lib/deciphers/NToken.js @@ -48,7 +48,7 @@ class NTokenTransforms { * @returns {void} */ static translate1(arr, token, is_reverse_base64) { - const characters = is_reverse_base64 && BASE64_DIALECT.REVERSE || BASE64_DIALECT.NORMAL; + const characters = is_reverse_base64 ? BASE64_DIALECT.REVERSE : BASE64_DIALECT.NORMAL; const token_chars = token.split(''); arr.forEach((char, index, loc) => { token_chars.push(loc[index] = characters[(characters.indexOf(char) - characters.indexOf(token_chars[index]) + 64) % characters.length]); @@ -70,7 +70,7 @@ class NTokenTransforms { * @returns {string[]} */ static getBase64Dia(is_reverse_base64) { - const characters = is_reverse_base64 && BASE64_DIALECT.REVERSE || BASE64_DIALECT.NORMAL; + const characters = is_reverse_base64 ? BASE64_DIALECT.REVERSE : BASE64_DIALECT.NORMAL; return characters; } diff --git a/lib/parser/contents/classes/Author.js b/lib/parser/contents/classes/Author.js index 7f9879ed..e61307c9 100644 --- a/lib/parser/contents/classes/Author.js +++ b/lib/parser/contents/classes/Author.js @@ -16,7 +16,7 @@ class Author { this.#nav_text.endpoint?.browse?.id || 'N/A'; this.name = this.#nav_text.text || 'N/A'; - this.thumbnails = thumbs && Thumbnail.fromResponse(thumbs) || []; + this.thumbnails = thumbs ? Thumbnail.fromResponse(thumbs) : []; this.endpoint = this.#nav_text.runs?.[0].endpoint || this.#nav_text.endpoint; this.badges = Array.isArray(badges) ? Parser.parse(badges) : []; this.is_verified = this.badges?.some((badge) => badge.style == 'BADGE_STYLE_TYPE_VERIFIED') || null; diff --git a/lib/parser/contents/classes/Button.js b/lib/parser/contents/classes/Button.js index ed914bd2..6ab3feba 100644 --- a/lib/parser/contents/classes/Button.js +++ b/lib/parser/contents/classes/Button.js @@ -9,14 +9,17 @@ class Button { constructor(data) { this.text = new Text(data.text).toString(); - data.accessibility?.label && - (this.label = data.accessibility?.label); + if (data.accessibility?.label) { + this.label = data.accessibility?.label + } - data.tooltip && - (this.tooltip = data.tooltip); - - data.icon?.iconType && - (this.icon_type = data.icon?.iconType); + if (data.tooltip) { + this.tooltip = data.tooltip + } + + if (data.icon?.iconType) { + this.iconType = data.icon?.iconType + } this.endpoint = new NavigationEndpoint(data.navigationEndpoint || data.serviceEndpoint); } diff --git a/lib/parser/contents/classes/C4TabbedHeader.js b/lib/parser/contents/classes/C4TabbedHeader.js index fff05e9c..ffa780ca 100644 --- a/lib/parser/contents/classes/C4TabbedHeader.js +++ b/lib/parser/contents/classes/C4TabbedHeader.js @@ -13,9 +13,9 @@ class C4TabbedHeader { simpleText: data.title, navigationEndpoint: data.navigationEndpoint }, data.badges, data.avatar); - this.banner = data.banner && Thumbnail.fromResponse(data.banner) || []; - this.tv_banner = data.tvBanner && Thumbnail.fromResponse(data.tvBanner) || []; - this.mobile_banner = data.mobileBanner && Thumbnail.fromResponse(data.mobileBanner) || []; + this.banner = data.banner ? Thumbnail.fromResponse(data.banner) : []; + this.tv_banner = data.tvBanner ? Thumbnail.fromResponse(data.tvBanner) : []; + this.mobile_banner = data.mobileBanner ? Thumbnail.fromResponse(data.mobileBanner) : []; this.subscribers = new Text(data.subscriberCountText); this.sponsor_button = data.sponsorButton && Parser.parse(data.sponsorButton); this.subscribe_button = data.subscribeButton && Parser.parse(data.subscribeButton); diff --git a/lib/parser/contents/classes/EndscreenElement.js b/lib/parser/contents/classes/EndscreenElement.js index ef26fb7e..2f41ce83 100644 --- a/lib/parser/contents/classes/EndscreenElement.js +++ b/lib/parser/contents/classes/EndscreenElement.js @@ -10,24 +10,30 @@ class EndscreenElement { constructor(data) { this.style = data.style; - - data.image && - (this.image = Thumbnail.fromResponse(data.image)); + + if (data.image) { + this.image = Thumbnail.fromResponse(data.image) + } - data.icon && - (this.icon = Thumbnail.fromResponse(data.icon)); + if (data.icon) { + this.icon = Thumbnail.fromResponse(data.icon) + } - data.metadata && - (this.metadata = new Text(data.metadata)); + if (data.metadata) { + this.metadata = new Text(data.metadata) + } - data.callToAction && - (this.call_to_action = new Text(data.callToAction)); + if (data.callToAction) { + this.call_to_action = new Text(data.callToAction) + } - data.hovercardButton && - (this.hovercard_button = Parser.parse(data.hovercardButton)); + if (data.hovercardButton) { + this.hovercard_button = Parser.parse(data.hovercardButton) + } - data.isSubscribe && - (this.is_subscribe = data.isSubscribe); + if (data.isSubscribe) { + this.is_subscribe = data.isSubscribe + } this.title = new Text(data.title); this.endpoint = new NavigationEndpoint(data.endpoint); diff --git a/lib/parser/contents/classes/GridPlaylist.js b/lib/parser/contents/classes/GridPlaylist.js index 888efd07..bdf472c6 100644 --- a/lib/parser/contents/classes/GridPlaylist.js +++ b/lib/parser/contents/classes/GridPlaylist.js @@ -14,8 +14,9 @@ class GridPlaylist { this.id = data.playlistId; this.title = new Text(data.title); - data.shortBylineText && - (this.author = new PlaylistAuthor(data.shortBylineText, data.ownerBadges)); + if (data.shortBylineText) { + this.author = new PlaylistAuthor(data.shortBylineText, data.ownerBadges) + } this.badges = Parser.parse(data.ownerBadges); this.endpoint = new NavigationEndpoint(data.navigationEndpoint); diff --git a/lib/parser/contents/classes/ItemSection.js b/lib/parser/contents/classes/ItemSection.js index 70550ba4..541d0a0e 100644 --- a/lib/parser/contents/classes/ItemSection.js +++ b/lib/parser/contents/classes/ItemSection.js @@ -9,8 +9,9 @@ class ItemSection { this.header = Parser.parse(data.header); this.contents = Parser.parse(data.contents); - (data.targetId || data.sectionIdentifier) && - (this.target_id = data?.target_id || data?.sectionIdentifier); + if (data.targetId || data.sectionIdentifier) { + this.target_id = data?.target_id || data?.sectionIdentifier; + } } } diff --git a/lib/parser/contents/classes/LikeButton.js b/lib/parser/contents/classes/LikeButton.js index 5f8ca05e..be6979af 100644 --- a/lib/parser/contents/classes/LikeButton.js +++ b/lib/parser/contents/classes/LikeButton.js @@ -13,8 +13,9 @@ class LikeButton { this.like_status = data.likeStatus; this.likes_allowed = data.likesAllowed; - data.serviceEndpoints && - (this.endpoints = data.serviceEndpoints?.map((endpoint) => new NavigationEndpoint(endpoint))); + if (data.serviceEndpoints) { + this.endpoints = data.serviceEndpoints?.map((endpoint) => new NavigationEndpoint(endpoint)) + } } } diff --git a/lib/parser/contents/classes/LiveChatAuthorBadge.js b/lib/parser/contents/classes/LiveChatAuthorBadge.js index cdadbba9..952a8b22 100644 --- a/lib/parser/contents/classes/LiveChatAuthorBadge.js +++ b/lib/parser/contents/classes/LiveChatAuthorBadge.js @@ -7,7 +7,7 @@ class LiveChatAuthorBadge extends MetadataBadge { constructor(data) { super(data); - this.custom_thumbnail = data.customThumbnail && Thumbnail.fromResponse(data.customThumbnail) || null; + this.custom_thumbnail = data.customThumbnail ? Thumbnail.fromResponse(data.customThumbnail) : null; } } diff --git a/lib/parser/contents/classes/MusicCarouselShelf.js b/lib/parser/contents/classes/MusicCarouselShelf.js index e87aed05..89e05376 100644 --- a/lib/parser/contents/classes/MusicCarouselShelf.js +++ b/lib/parser/contents/classes/MusicCarouselShelf.js @@ -9,8 +9,9 @@ class MusicCarouselShelf { this.header = Parser.parse(data.header); this.contents = Parser.parse(data.contents); - data.numItemsPerColumn && - (this.num_items_per_column = data.numItemsPerColumn); + if (data.numItemsPerColumn) { + this.num_items_per_column = data.numItemsPerColumn + } } } diff --git a/lib/parser/contents/classes/MusicCarouselShelfBasicHeader.js b/lib/parser/contents/classes/MusicCarouselShelfBasicHeader.js index 83105558..9a06fb68 100644 --- a/lib/parser/contents/classes/MusicCarouselShelfBasicHeader.js +++ b/lib/parser/contents/classes/MusicCarouselShelfBasicHeader.js @@ -7,16 +7,18 @@ class MusicCarouselShelfBasicHeader { type = 'MusicCarouselShelfBasicHeader'; constructor(data) { - data.strapline && - (this.strapline = new Text(data.strapline).toString()); + if (data.strapline) { + this.strapline = new Text(data.strapline).toString() + } this.title = new Text(data.title).toString(); // this.label = data.accessibilityData.accessibilityData.label; // ^^ redundant? - data.thumbnail && - (this.thumbnail = Thumbnail.fromResponse(data.thumbnail.musicThumbnailRenderer.thumbnail)); + if (data.thumbnail) { + this.thumbnail = Thumbnail.fromResponse(data.thumbnail.musicThumbnailRenderer.thumbnail) + } } } diff --git a/lib/parser/contents/classes/MusicDescriptionShelf.js b/lib/parser/contents/classes/MusicDescriptionShelf.js index 5c17f7de..be6958bb 100644 --- a/lib/parser/contents/classes/MusicDescriptionShelf.js +++ b/lib/parser/contents/classes/MusicDescriptionShelf.js @@ -8,11 +8,13 @@ class MusicDescriptionShelf { constructor(data) { this.description = new Text(data.description); - this.max_collapsed_lines && - (this.max_collapsed_lines = data.maxCollapsedLines); + if (this.max_collapsed_lines) { + this.max_collapsed_lines = data.maxCollapsedLines + } - this.max_expanded_lines && - (this.max_expanded_lines = data.maxExpandedLines); + if (this.max_expanded_lines) { + this.max_expanded_lines = data.maxExpandedLines + } this.footer = new Text(data.footer); } diff --git a/lib/parser/contents/classes/MusicPlayButton.js b/lib/parser/contents/classes/MusicPlayButton.js index be637f9c..62c8eb82 100644 --- a/lib/parser/contents/classes/MusicPlayButton.js +++ b/lib/parser/contents/classes/MusicPlayButton.js @@ -10,11 +10,13 @@ class MusicPlayButton { this.play_icon_type = data.playIcon.iconType; this.pause_icon_type = data.pauseIcon.iconType; - data.accessibilityPlayData && - (this.play_label = data.accessibilityPlayData.accessibilityData.label); + if (data.accessibilityPlayData) { + this.play_label = data.accessibilityPlayData.accessibilityData.label + } - data.accessibilityPlayData && - (this.pause_label = data.accessibilityPauseData?.accessibilityData.label); + if (data.accessibilityPlayData) { + this.pause_label = data.accessibilityPauseData?.accessibilityData.label + } this.icon_color = data.iconColor; } diff --git a/lib/parser/contents/classes/MusicResponsiveListItem.js b/lib/parser/contents/classes/MusicResponsiveListItem.js index 50d974b5..2d2b9248 100644 --- a/lib/parser/contents/classes/MusicResponsiveListItem.js +++ b/lib/parser/contents/classes/MusicResponsiveListItem.js @@ -44,10 +44,11 @@ class MusicResponsiveListItem { break; } - data.index && - (this.index = new Text(data.index)); + if (data.index) { + this.index = new Text(data.index) + } - this.thumbnails = data.thumbnail && Thumbnail.fromResponse(data.thumbnail.musicThumbnailRenderer.thumbnail) || []; + this.thumbnails = data.thumbnail ? Thumbnail.fromResponse(data.thumbnail.musicThumbnailRenderer.thumbnail) : []; this.badges = Parser.parse(data.badges) || []; this.menu = Parser.parse(data.menu); @@ -83,19 +84,23 @@ class MusicResponsiveListItem { const album = this.#flex_columns[1].title.runs?.find((run) => run.endpoint.browse?.id.startsWith('MPR')); - album && (this.album = { - id: album.endpoint.browse.id, - name: album.text, - endpoint: album.endpoint - }); + if (album) { + this.album = { + id: album.endpoint.browse.id, + name: album.text, + endpoint: album.endpoint + } + } const artists = this.#flex_columns[1].title.runs?.filter((run) => run.endpoint.browse?.id.startsWith('UC')); - artists && (this.artists = artists.map((artist) => ({ - name: artist.text, - channel_id: artist.endpoint.browse.id, - endpoint: artist.endpoint - }))); + if (artists) { + this.artists = artists.map((artist) => ({ + name: artist.text, + channel_id: artist.endpoint.browse.id, + endpoint: artist.endpoint + })) + } } #parseVideo() { @@ -106,11 +111,13 @@ class MusicResponsiveListItem { const authors = this.#flex_columns[1].title.runs?.filter((run) => run.endpoint.browse?.id.startsWith('UC')); - authors && (this.authors = authors.map((author) => ({ + if (authors) { + this.authors = authors.map((author) => ({ name: author.text, channel_id: author.endpoint.browse.id, endpoint: author.endpoint - }))) && (this.author = this.authors[0]); + })) + } const duration_text = this.#flex_columns[1].title.runs .find((run) => /^\d+$/.test(run.text.replace(/:/g, '')))?.text; diff --git a/lib/parser/contents/classes/MusicShelf.js b/lib/parser/contents/classes/MusicShelf.js index d547803b..12f9c4ba 100644 --- a/lib/parser/contents/classes/MusicShelf.js +++ b/lib/parser/contents/classes/MusicShelf.js @@ -12,14 +12,17 @@ class MusicShelf { this.contents = Parser.parse(data.contents); - data.bottomEndpoint && - (this.endpoint = new NavigationEndpoint(data.bottomEndpoint)); + if (data.bottomEndpoint) { + this.endpoint = new NavigationEndpoint(data.bottomEndpoint) + } - this.continuation && - (this.continuation = data.continuations?.[0].nextContinuationData.continuation); + if (this.continuation) { + this.continuation = data.continuations?.[0].nextContinuationData.continuation + } - data.bottomText && - (this.bottom_text = new Text(data.bottomText)); + if (data.bottomText) { + this.bottom_text = new Text(data.bottomText) + } } } diff --git a/lib/parser/contents/classes/MusicTwoRowItem.js b/lib/parser/contents/classes/MusicTwoRowItem.js index 9c87dedd..2e540970 100644 --- a/lib/parser/contents/classes/MusicTwoRowItem.js +++ b/lib/parser/contents/classes/MusicTwoRowItem.js @@ -36,19 +36,25 @@ class MusicTwoRowItem { const artists = this.subtitle.runs.filter((run) => run.endpoint.browse?.id.startsWith('UC')); - artists && (this.artists = artists.map((artist) => ({ - name: artist.text, - channel_id: artist.endpoint.browse.id, - endpoint: artist.endpoint - }))) + if (artists) { + this.artists = artists.map((artist) => ({ + name: artist.text, + channel_id: artist.endpoint.browse.id, + endpoint: artist.endpoint + })) + } this.year = this.subtitle.runs.slice(-1)[0].text; - isNaN(this.year) && (delete this.year); + if (isNaN(this.year)) { + delete this.year; + } break; default: - this.subtitle.runs[0].text !== 'Song' && - (this.type = 'video') || - (this.type = 'song'); + if (this.subtitle.runs[0].text !== 'Song') { + this.type = 'video'; + } else { + this.type = 'song'; + } if (this.type == 'video') { this.views = this.subtitle.runs @@ -64,11 +70,13 @@ class MusicTwoRowItem { } else { const artists = this.subtitle.runs.filter((run) => run.endpoint.browse?.id.startsWith('UC')); - artists && (this.artists = artists.map((artist) => ({ - name: artist.text, - channel_id: artist.endpoint.browse.id, - endpoint: artist.endpoint - }))); + if (artists) { + this.artists = artists.map((artist) => ({ + name: artist.text, + channel_id: artist.endpoint.browse.id, + endpoint: artist.endpoint + })) + } } break; } diff --git a/lib/parser/contents/classes/NavigationEndpoint.js b/lib/parser/contents/classes/NavigationEndpoint.js index ff36e381..64031e43 100644 --- a/lib/parser/contents/classes/NavigationEndpoint.js +++ b/lib/parser/contents/classes/NavigationEndpoint.js @@ -8,22 +8,27 @@ class NavigationEndpoint { type = 'NavigationEndpoint'; constructor(data) { - data?.serviceEndpoint && - (data = data.serviceEndpoint); + if (data?.serviceEndpoint) { + data = data.serviceEndpoint + } this.metadata = {}; - data?.commandMetadata?.webCommandMetadata?.url && - (this.metadata.url = data.commandMetadata.webCommandMetadata.url); + if (data?.commandMetadata?.webCommandMetadata?.url) { + this.metadata.url = data.commandMetadata.webCommandMetadata.url + } - data?.commandMetadata?.webCommandMetadata?.webPageType && - (this.metadata.page_type = data.commandMetadata.webCommandMetadata.webPageType); + if (data?.commandMetadata?.webCommandMetadata?.webPageType) { + this.metadata.page_type = data.commandMetadata.webCommandMetadata.webPageType + } - data?.commandMetadata?.webCommandMetadata?.apiUrl && - (this.metadata.api_url = data.commandMetadata.webCommandMetadata.apiUrl.replace('/youtubei/v1/', '')); + if (data?.commandMetadata?.webCommandMetadata?.apiUrl) { + this.metadata.api_url = data.commandMetadata.webCommandMetadata.apiUrl.replace('/youtubei/v1/', '') + } - data?.commandMetadata?.webCommandMetadata?.sendPost && - (this.metadata.send_post = data.commandMetadata.webCommandMetadata.sendPost); + if (data?.commandMetadata?.webCommandMetadata?.sendPost) { + this.metadata.send_post = data.commandMetadata.webCommandMetadata.sendPost + } if (data?.browseEndpoint) { const configs = data?.browseEndpoint?.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig; @@ -199,8 +204,9 @@ class NavigationEndpoint { if (this.browse) { const args = { client }; - this.browse.params && - (args.params = this.browse.params); + if (this.browse.params) { + args.params = this.browse.params + } const response = await actions.browse(this.browse.id, args); return Parser.parseResponse(response.data); diff --git a/lib/parser/contents/classes/SectionList.js b/lib/parser/contents/classes/SectionList.js index bee232d5..dbfbbd44 100644 --- a/lib/parser/contents/classes/SectionList.js +++ b/lib/parser/contents/classes/SectionList.js @@ -6,8 +6,9 @@ class SectionList { type = 'SectionList'; constructor(data) { - data.targetId - && (this.target_id = data.targetId); + if (data.targetId) { + this.target_id = data.targetId; + } this.contents = Parser.parse(data.contents); @@ -19,8 +20,9 @@ class SectionList { } } - data.header && - (data.header = Parser.parse(data.header)); + if (data.header) { + this.header = Parser.parse(data.header); + } } } diff --git a/lib/parser/contents/classes/Shelf.js b/lib/parser/contents/classes/Shelf.js index 0613a186..176bf35a 100644 --- a/lib/parser/contents/classes/Shelf.js +++ b/lib/parser/contents/classes/Shelf.js @@ -10,16 +10,19 @@ class Shelf { constructor(data) { this.title = new Text(data.title); - data.endpoint && - (this.endpoint = new NavigationEndpoint(data.endpoint)); + if (data.endpoint) { + this.endpoint = new NavigationEndpoint(data.endpoint) + } this.content = Parser.parse(data.content) || []; - data.icon?.iconType && - (this.icon_type = data.icon?.iconType); + if (data.icon?.iconType) { + this.icon_type = data.icon?.iconType + } - data.menu && - (this.menu = Parser.parse(data.menu)); + if (data.menu) { + this.menu = Parser.parse(data.menu) + } } } diff --git a/lib/parser/contents/classes/TextRun.js b/lib/parser/contents/classes/TextRun.js index a87568f2..1fdcfe33 100644 --- a/lib/parser/contents/classes/TextRun.js +++ b/lib/parser/contents/classes/TextRun.js @@ -5,7 +5,7 @@ const NavigationEndpoint = require('./NavigationEndpoint'); class TextRun { constructor(data) { this.text = data.text; - this.endpoint = data.navigationEndpoint && new NavigationEndpoint(data.navigationEndpoint) || {}; + this.endpoint = data.navigationEndpoint ? new NavigationEndpoint(data.navigationEndpoint) : {}; } } diff --git a/lib/parser/contents/classes/ToggleButton.js b/lib/parser/contents/classes/ToggleButton.js index 496f9a8a..c0a71e37 100644 --- a/lib/parser/contents/classes/ToggleButton.js +++ b/lib/parser/contents/classes/ToggleButton.js @@ -19,9 +19,12 @@ class ToggleButton { data.defaultText?.accessibility?.accessibilityData.label || data?.accessibility?.label; - this.icon_type == 'LIKE' && - (this.like_count = parseInt(acc_label.replace(/\D/g, ''))) && - (this.short_like_count = new Text(data.defaultText).toString()); + if (this.icon_type == 'LIKE') { + this.like_count = parseInt(acc_label.replace(/\D/g, '')) + if (this.like_count) { + this.short_like_count = new Text(data.defaultText).toString() + } + } this.endpoint = data.defaultServiceEndpoint?.commandExecutorCommand?.commands && diff --git a/lib/parser/contents/index.js b/lib/parser/contents/index.js index bf3db6f3..5a279fae 100644 --- a/lib/parser/contents/index.js +++ b/lib/parser/contents/index.js @@ -107,17 +107,17 @@ class Parser { this.#clearMemo(); this.#createMemo(); - const on_response_received_actions = data.onResponseReceivedActions && Parser.parseRR(data.onResponseReceivedActions) || null; + const on_response_received_actions = data.onResponseReceivedActions ? Parser.parseRR(data.onResponseReceivedActions) : null; const on_response_received_actions_memo = Parser.#memo; this.#clearMemo(); this.#createMemo(); - const on_response_received_endpoints = data.onResponseReceivedEndpoints && Parser.parseRR(data.onResponseReceivedEndpoints) || null; + const on_response_received_endpoints = data.onResponseReceivedEndpoints ? Parser.parseRR(data.onResponseReceivedEndpoints) : null; const on_response_received_endpoints_memo = Parser.#memo; this.#clearMemo(); this.#createMemo(); - const on_response_received_commands = data.onResponseReceivedCommands && Parser.parseRR(data.onResponseReceivedCommands) || null; + const on_response_received_commands = data.onResponseReceivedCommands ? Parser.parseRR(data.onResponseReceivedCommands) : null; const on_response_received_commands_memo = Parser.#memo; this.#clearMemo(); @@ -131,9 +131,9 @@ class Parser { on_response_received_commands, on_response_received_commands_memo, /** @type {*} */ - continuation: data.continuation && Parser.parseC(data.continuation) || null, + continuation: data.continuation ? Parser.parseC(data.continuation) : null, /** @type {*} */ - continuation_contents: data.continuationContents && Parser.parseLC(data.continuationContents) || null, + continuation_contents: data.continuationContents ? Parser.parseLC(data.continuationContents) : null, actions: data.actions && Parser.parseLA(data.actions), metadata: Parser.parse(data.metadata), header: Parser.parse(data.header), @@ -232,7 +232,7 @@ class Parser { if (!this.shouldIgnore(classname)) { try { - const path = module && module + '/' || ''; + const path = module ? module + '/' : ''; const TargetClass = require('./classes/' + path + classname); const result = new TargetClass(item[keys[0]]); @@ -252,7 +252,7 @@ class Parser { if (!this.shouldIgnore(classname)) { try { - const path = module && module + '/' || ''; + const path = module ? module + '/' : ''; const TargetClass = require('./classes/' + path + classname); const result = new TargetClass(data[keys[0]]); diff --git a/lib/parser/index.js b/lib/parser/index.js index 53e0cdef..8b785836 100644 --- a/lib/parser/index.js +++ b/lib/parser/index.js @@ -26,27 +26,52 @@ class Parser { switch (client) { case 'YOUTUBE': - processed_data = ({ - SEARCH: () => this.#processSearch(), - CHANNEL: () => this.#processChannel(), - PLAYLIST: () => this.#processPlaylist(), - SUBSFEED: () => this.#processSubscriptionFeed(), - HOMEFEED: () => this.#processHomeFeed(), - LIBRARY: () => this.#processLibrary(), //WIP - TRENDING: () => this.#processTrending(), - HISTORY: () => this.#processHistory(), - COMMENTS: () => this.#processComments(), - VIDEO_INFO: () => this.#processVideoInfo(), - NOTIFICATIONS: () => this.#processNotifications(), - SEARCH_SUGGESTIONS: () => this.#processSearchSuggestions(), - })[data_type]() + processed_data = (() => { + switch (data_type) { + case 'SEARCH': + return this.#processSearch(); + case 'CHANNEL': + return this.#processChannel(); + case 'PLAYLIST': + return this.#processPlaylist(); + case 'SUBSFEED': + return this.#processSubscriptionFeed(); + case 'HOMEFEED': + return this.#processHomeFeed(); + case 'LIBRARY': + return this.#processLibrary(); // WIP + case 'TRENDING': + return this.#processTrending(); + case 'HISTORY': + return this.#processHistory(); + case 'COMMENTS': + return this.#processComments(); + case 'VIDEO_INFO': + return this.#processVideoInfo(); + case 'NOTIFICATIONS': + return this.#processNotifications(); + case 'SEARCH_SUGGESTIONS': + return this.#processSearchSuggestions(); + default: + // this is just for maximum compatibility, this is most definitely a bad way to handle this + throw new TypeError('undefined is not a function'); + } + })() break; case 'YTMUSIC': - processed_data = ({ - SEARCH: () => this.#processMusicSearch(), - PLAYLIST: () => this.#processMusicPlaylist(), - SEARCH_SUGGESTIONS: () => this.#processMusicSearchSuggestions(), - })[data_type](); + processed_data = (() => { + switch (data_type) { + case 'SEARCH': + return this.#processMusicSearch(); + case 'PLAYLIST': + return this.#processMusicPlaylist(); + case 'SEARCH_SUGGESTIONS': + return this.#processMusicSearchSuggestions(); + default: + // this is just for maximum compatibility, this is most definitely a bad way to handle this + throw new TypeError('undefined is not a function'); + } + })() break; default: throw new Utils.InnertubeError('Invalid client'); @@ -202,10 +227,15 @@ class Parser { mf_raw_data.forEach((entry) => { const key = Utils.camelToSnake(entry[0]); if (Constants.METADATA_KEYS.includes(key)) { - key == 'view_count' && (processed_data.metadata[key] = parseInt(entry[1])) || - key == 'owner_profile_url' && (processed_data.metadata.channel_url = entry[1]) || - key == 'owner_channel_name' && (processed_data.metadata.channel_name = entry[1]) || - (processed_data.metadata[key] = entry[1]); + if (key == 'view_count') { + processed_data.metadata[key] = parseInt(entry[1]); + } else if (key == 'owner_profile_url') { + processed_data.metadata.channel_url = entry[1] + } else if (key == 'owner_channel_name') { + processed_data.metadata.channel_name = entry[1] + } else { + processed_data.metadata[key] = entry[1]; + } } else { processed_data[key] = entry[1]; } @@ -216,13 +246,21 @@ class Parser { const key = Utils.camelToSnake(entry[0]); if (Constants.BLACKLISTED_KEYS.includes(key)) return; if (Constants.METADATA_KEYS.includes(key)) { - key == 'view_count' && (processed_data.metadata[key] = parseInt(entry[1])) || - (processed_data.metadata[key] = entry[1]); + if (key == 'view_count') { + processed_data.metadata[key] = parseInt(entry[1]); + } else { + processed_data.metadata[key] = entry[1]; + } } else { - key == 'short_description' && (processed_data.description = entry[1]) || - key == 'thumbnail' && (processed_data.thumbnail = entry[1].thumbnails.slice(-1)[0]) || - key == 'video_id' && (processed_data.id = entry[1]) || - (processed_data[key] = entry[1]); + if (key == 'short_description') { + processed_data.description = entry[1]; + } else if (key == 'thumbnail') { + processed_data.thumbnail = entry[1].thumbnails.slice(-1)[0]; + } else if (key == 'video_id') { + processed_data.id = entry[1]; + } else { + processed_data[key] = entry[1]; + } } }); @@ -266,10 +304,11 @@ class Parser { processed_data.metadata.owner_badges = secondary_info_renderer.owner.videoOwnerRenderer?.badges?.map((badge) => badge.metadataBadgeRenderer.tooltip) || []; } - streaming_data && streaming_data.adaptiveFormats && - (processed_data.metadata.available_qualities = [...new Set(streaming_data.adaptiveFormats.filter(v => v.qualityLabel) - .map(v => v.qualityLabel).sort((a, b) => +a.replace(/\D/gi, '') - +b.replace(/\D/gi, '')))]) || - (processed_data.metadata.available_qualities = []); + if (streaming_data && streaming_data.adaptiveFormats) { + processed_data.metadata.available_qualities = [...new Set(streaming_data.adaptiveFormats.filter(v => v.qualityLabel).map(v => v.qualityLabel).sort((a, b) => +a.replace(/\D/gi, '') - +b.replace(/\D/gi, '')))] + } else { + processed_data.metadata.available_qualities = []; + } return processed_data; } @@ -344,7 +383,7 @@ class Parser { if (!continuation_item) throw new Utils.InnertubeError('You\'ve reached the end'); const is_reply = !!continuation_item.continuationItemRenderer.button; - const payload = Utils.findNode(continuation_item, 'continuationItemRenderer', 'token', is_reply && 5 || 3); + const payload = Utils.findNode(continuation_item, 'continuationItemRenderer', 'token', is_reply ? 5 : 3); const next = await this.session.actions.next({ ctoken: payload.token }); return parseComments(next.data); diff --git a/lib/parser/youtube/LiveChat.js b/lib/parser/youtube/LiveChat.js index b266003b..de193e6e 100644 --- a/lib/parser/youtube/LiveChat.js +++ b/lib/parser/youtube/LiveChat.js @@ -112,8 +112,9 @@ class LiveChat { (async () => { const payload = { video_id: this.#video_info.basic_info.id }; - this.#mcontinuation && - (payload.ctoken = this.#mcontinuation); + if (this.#mcontinuation) { + payload.ctoken = this.#mcontinuation + } const response = await this.#actions.livechat('updated_metadata', payload); const data = Parser.parseResponse(response.data); diff --git a/lib/parser/youtube/VideoInfo.js b/lib/parser/youtube/VideoInfo.js index 4e46ca0a..6b487b24 100644 --- a/lib/parser/youtube/VideoInfo.js +++ b/lib/parser/youtube/VideoInfo.js @@ -425,16 +425,20 @@ class VideoInfo { } else { const chunk_size = 1048576 * 10; // 10MB - let chunk_start = (options.range && options.range.start || 0); - let chunk_end = (options.range && options.range.end || chunk_size); + let chunk_start = (options.range ? options.range.start : 0); + let chunk_end = (options.range ? options.range.end : chunk_size); let downloaded_size = 0; let must_end = false; stream.emit('start'); const downloadChunk = async () => { - (chunk_end >= format.content_length || options.range) && (must_end = true); - options.range && (format.content_length = options.range.end); + if (chunk_end >= format.content_length || options.range) { + must_end = true; + } + if (options.range) { + format.content_length = options.range.end + } const response = await Axios.get(`${format_url}&cpn=${this.#cpn}&range=${chunk_start}-${chunk_end || ''}`, { responseType: 'stream', diff --git a/lib/parser/youtube/others/CommentThread.js b/lib/parser/youtube/others/CommentThread.js index 175b2f09..0523fa03 100644 --- a/lib/parser/youtube/others/CommentThread.js +++ b/lib/parser/youtube/others/CommentThread.js @@ -23,7 +23,7 @@ class CommentThread { is_reply: !!item.commentRenderer, is_liked: like_btn.toggleButtonRenderer.isToggled, is_disliked: dislike_btn.toggleButtonRenderer.isToggled, - is_pinned: comment.commentRenderer.pinnedCommentBadge && true || false, + is_pinned: comment.commentRenderer.pinnedCommentBadge ? true : false, is_channel_owner: comment.commentRenderer.authorIsChannelOwner, like_count: parseInt(like_btn?.toggleButtonRenderer?.accessibilityData?.accessibilityData.label.replace(/\D/g, '')), reply_count: comment.commentRenderer.replyCount || 0, diff --git a/lib/parser/youtube/others/NotificationItem.js b/lib/parser/youtube/others/NotificationItem.js index c88d865e..9a21ed21 100644 --- a/lib/parser/youtube/others/NotificationItem.js +++ b/lib/parser/youtube/others/NotificationItem.js @@ -16,7 +16,7 @@ class NotificationItem { channel_name: notification?.contextualMenu?.menuRenderer?.items[1]?.menuServiceItemRenderer?.text?.runs[1]?.text || 'N/A', channel_thumbnail: notification?.thumbnail?.thumbnails[0], video_thumbnail: notification?.videoThumbnail?.thumbnails[0], - video_url: notification.navigationEndpoint.watchEndpoint && `https://youtu.be/${notification.navigationEndpoint.watchEndpoint.videoId}` || 'N/A', + video_url: notification.navigationEndpoint.watchEndpoint ? `https://youtu.be/${notification.navigationEndpoint.watchEndpoint.videoId}` : 'N/A', read: notification.read }; } diff --git a/lib/parser/youtube/search/VideoResultItem.js b/lib/parser/youtube/search/VideoResultItem.js index b0b13405..6462f732 100644 --- a/lib/parser/youtube/search/VideoResultItem.js +++ b/lib/parser/youtube/search/VideoResultItem.js @@ -14,7 +14,7 @@ class VideoResultItem { id: renderer.videoId, url: `https://youtu.be/${renderer.videoId}`, title: renderer.title.runs[0].text, - description: renderer?.detailedMetadataSnippets && renderer?.detailedMetadataSnippets[0].snippetText.runs.map((item) => item.text).join('') || 'N/A', + description: renderer?.detailedMetadataSnippets ? renderer?.detailedMetadataSnippets[0].snippetText.runs.map((item) => item.text).join('') : 'N/A', channel: { id: renderer?.ownerText?.runs[0]?.navigationEndpoint?.browseEndpoint?.browseId, name: renderer?.ownerText?.runs[0]?.text, diff --git a/lib/parser/ytmusic/search/MusicSearchSuggestionItem.js b/lib/parser/ytmusic/search/MusicSearchSuggestionItem.js index d7029f6a..ffef018f 100644 --- a/lib/parser/ytmusic/search/MusicSearchSuggestionItem.js +++ b/lib/parser/ytmusic/search/MusicSearchSuggestionItem.js @@ -11,9 +11,11 @@ class MusicSearchSuggestionItem { static parseItem(item) { let suggestion; - item.historySuggestionRenderer && - (suggestion = item.historySuggestionRenderer.suggestion) || - (suggestion = item.searchSuggestionRenderer.suggestion); + if (item.historySuggestionRenderer) { + suggestion = item.historySuggestionRenderer.suggestion + } else { + suggestion = item.searchSuggestionRenderer.suggestion + } return suggestion; } diff --git a/lib/parser/ytmusic/search/TopResultItem.js b/lib/parser/ytmusic/search/TopResultItem.js index 7673d98a..70ab8cc6 100644 --- a/lib/parser/ytmusic/search/TopResultItem.js +++ b/lib/parser/ytmusic/search/TopResultItem.js @@ -14,16 +14,28 @@ class TopResultItem { const runs = list_item.flexColumns[1]?.musicResponsiveListItemFlexColumnRenderer.text.runs; const type = runs[0].text.toLowerCase(); - const parsed_item = ({ - playlist: () => PlaylistResultItem.parseItem(item), - song: () => SongResultItem.parseItem(item), - video: () => VideoResultItem.parseItem(item), - artist: () => ArtistResultItem.parseItem(item), - album: () => AlbumResultItem.parseItem(item), - single: () => AlbumResultItem.parseItem(item) - }[type] || (() => {}))(); + const parsed_item = (() => { + switch (type) { + case 'playlist': + return PlaylistResultItem.parseItem(item); + case 'song': + return SongResultItem.parseItem(item); + case 'video': + return VideoResultItem.parseItem(item); + case 'artist': + return ArtistResultItem.parseItem(item); + case 'album': + return AlbumResultItem.parseItem(item); + case 'single': + return AlbumResultItem.parseItem(item); + default: + return undefined; + } + })() - parsed_item && (parsed_item.type = type); + if (parsed_item) { + parsed_item.type = type + } return parsed_item; }).filter((item) => item); diff --git a/lib/proto/index.js b/lib/proto/index.js index 60ea7460..66b3d974 100644 --- a/lib/proto/index.js +++ b/lib/proto/index.js @@ -70,28 +70,33 @@ class Proto { const data = {}; - filters && - (data.filters = {}) || - (data.no_filter = 0); + if (filters) { + data.filters = {}; + } else { + data.no_filter = 0; + } if (filters) { - if (filters.upload_date && filters.type !== 'video') - throw new Error('Upload date filter cannot be used with type ' + filters.type); + if (filters.upload_date && filters.type !== 'video') + throw new Error('Upload date filter cannot be used with type ' + filters.type); - filters.upload_date && - (data.filters.upload_date = upload_date[filters.upload_date]); + if (filters.upload_date) { + data.filters.upload_date = upload_date[filters.upload_date] + } - filters.type && - (data.filters.type = type[filters.type]); + if (filters.type) { + data.filters.type = type[filters.type] + } - filters.duration && - (data.filters.duration = duration[filters.duration]); + if (filters.duration) { + data.filters.duration = duration[filters.duration] + } - filters.sort_by && - (filters.sort_by !== 'relevance') && - (data.sort_by = order[filters.sort_by]); - } - + if (filters.sort_by && filters.sort_by !== 'relevance') { + data.sort_by = order[filters.sort_by] + } + } + const buf = messages.SearchFilter.encode(data); return encodeURIComponent(Buffer.from(buf).toString('base64')); } diff --git a/lib/utils/Request.js b/lib/utils/Request.js index 7cd4bf6f..3eb92e99 100644 --- a/lib/utils/Request.js +++ b/lib/utils/Request.js @@ -58,7 +58,7 @@ class Request { this.session.access_token; config.headers.cookie = cookie || ''; - config.headers.authorization = cookie && token || `Bearer ${token}`; + config.headers.authorization = cookie ? token : `Bearer ${token}`; !cookie && (delete config.params.key); } diff --git a/lib/utils/Utils.js b/lib/utils/Utils.js index b48d64d2..a62b698b 100644 --- a/lib/utils/Utils.js +++ b/lib/utils/Utils.js @@ -8,7 +8,9 @@ class InnertubeError extends Error { constructor (message, info) { super(message); - info && (this.info = info); + if (info) { + this.info = info; + } this.date = new Date(); this.version = require('../../package.json').version; @@ -211,11 +213,17 @@ function generateRandomString(length) { function timeToSeconds(time) { let params = time.split(':'); - return parseInt(({ - 3: +params[0] * 3600 + +params[1] * 60 + +params[2], - 2: +params[0] * 60 + +params[1], - 1: +params[0] - })[params.length]); + switch (params.length) { + case 1: + return parseInt(+params[0]); + case 2: + return parseInt(+params[0] * 60 + +params[1]); + case 3: + return parseInt(+params[0] * 3600 + +params[1] * 60 + +params[2]); + default: + // this is just for maximum compatibility, this is most definitely a bad way to handle this + throw new TypeError('undefined is not a function'); + } } /**