Skip to content

Commit

Permalink
Local API: Handle new shorts node (#5679)
Browse files Browse the repository at this point in the history
* Local API: Handle new shorts node

* Update YouTube.js from 10.4.0 to 10.5.0
  • Loading branch information
absidue authored Sep 21, 2024
1 parent 841e301 commit fa4886e
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 18 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
"vue-observe-visibility": "^1.0.0",
"vue-router": "^3.6.5",
"vuex": "^3.6.2",
"youtubei.js": "^10.4.0"
"youtubei.js": "^10.5.0"
},
"devDependencies": {
"@babel/core": "^7.25.2",
Expand Down
77 changes: 66 additions & 11 deletions src/renderer/helpers/api/local.js
Original file line number Diff line number Diff line change
Expand Up @@ -741,20 +741,38 @@ export function parseLocalChannelVideos(videos, channelId, channelName) {
}

/**
* @param {import('youtubei.js').YTNodes.ReelItem[]} shorts
* @param {(import('youtubei.js').YTNodes.ReelItem | import('youtubei.js').YTNodes.ShortsLockupView)[]} shorts
* @param {string} channelId
* @param {string} channelName
*/
export function parseLocalChannelShorts(shorts, channelId, channelName) {
return shorts.map(short => {
return {
type: 'video',
videoId: short.id,
title: short.title.text,
author: channelName,
authorId: channelId,
viewCount: short.views.isEmpty() ? null : parseLocalSubscriberCount(short.views.text),
lengthSeconds: ''
if (short.type === 'ReelItem') {
/** @type {import('youtubei.js').YTNodes.ReelItem} */
const reelItem = short

return {
type: 'video',
videoId: reelItem.id,
title: reelItem.title.text,
author: channelName,
authorId: channelId,
viewCount: reelItem.views.isEmpty() ? null : parseLocalSubscriberCount(reelItem.views.text),
lengthSeconds: ''
}
} else {
/** @type {import('youtubei.js').YTNodes.ShortsLockupView} */
const shortsLockupView = short

return {
type: 'video',
videoId: shortsLockupView.on_tap_endpoint.payload.videoId,
title: shortsLockupView.overlay_metadata.primary_text.text,
author: channelName,
authorId: channelId,
viewCount: shortsLockupView.overlay_metadata.secondary_text ? parseLocalSubscriberCount(shortsLockupView.overlay_metadata.secondary_text.text) : null,
lengthSeconds: ''
}
}
})
}
Expand Down Expand Up @@ -866,7 +884,7 @@ function handleSearchResponse(response) {
}

/**
* @param {import('youtubei.js').YTNodes.PlaylistVideo|import('youtubei.js').YTNodes.ReelItem} video
* @param {import('youtubei.js').YTNodes.PlaylistVideo|import('youtubei.js').YTNodes.ReelItem|import('youtubei.js').YTNodes.ShortsLockupView} video
*/
export function parseLocalPlaylistVideo(video) {
if (video.type === 'ReelItem') {
Expand All @@ -880,6 +898,42 @@ export function parseLocalPlaylistVideo(video) {
viewCount: parseLocalSubscriberCount(short.views.text),
lengthSeconds: ''
}
} else if (video.type === 'ShortsLockupView') {
/** @type {import('youtubei.js').YTNodes.ShortsLockupView} */
const shortsLockupView = video

let viewCount = null

// the accessiblity text is the only place with the view count
if (shortsLockupView.accessibility_text) {
// the `.*\s+` at the start of the regex, ensures we match the last occurence
// just in case the video title also contains that pattern
const match = shortsLockupView.accessibility_text.match(/.*\s+(\d+(?:[,.]\d+)?\s?(?:[BKMbkm]|million)?|no)\s+views?/)

if (match) {
const count = match[1]

// as it's rare that a video has no views,
// checking the length allows us to avoid running toLowerCase unless we have to
if (count.length === 2 && count === 'no') {
viewCount = 0
} else {
const views = parseLocalSubscriberCount(count)

if (!isNaN(views)) {
viewCount = views
}
}
}
}

return {
type: 'video',
videoId: shortsLockupView.on_tap_endpoint.payload.videoId,
title: shortsLockupView.overlay_metadata.primary_text.text,
viewCount,
lengthSeconds: ''
}
} else {
/** @type {import('youtubei.js').YTNodes.PlaylistVideo} */
const video_ = video
Expand Down Expand Up @@ -1362,7 +1416,7 @@ export function filterLocalFormats(formats, allowAv1 = false) {
* @param {string} text
*/
export function parseLocalSubscriberCount(text) {
const match = text.match(/(\d+)(?:[,.](\d+))?\s?([BKMbkm])\b/)
const match = text.match(/(\d+)(?:[,.](\d+))?\s?([BKMbkm]|million)\b/)

if (match) {
let multiplier = 0
Expand All @@ -1374,6 +1428,7 @@ export function parseLocalSubscriberCount(text) {
break
case 'M':
case 'm':
case 'million':
multiplier = 6
break
case 'B':
Expand Down
6 changes: 4 additions & 2 deletions src/renderer/views/Playlist/Playlist.js
Original file line number Diff line number Diff line change
Expand Up @@ -305,9 +305,11 @@ export default defineComponent({
channelName = subtitle.substring(0, index).trim()
}

const playlistItems = result.items.map(parseLocalPlaylistVideo)

this.playlistTitle = result.info.title
this.playlistDescription = result.info.description ?? ''
this.firstVideoId = result.items[0].id
this.firstVideoId = playlistItems[0].videoId
this.playlistThumbnail = result.info.thumbnails[0].url
this.viewCount = result.info.views.toLowerCase() === 'no views' ? 0 : extractNumberFromString(result.info.views)
this.videoCount = extractNumberFromString(result.info.total_items)
Expand All @@ -323,7 +325,7 @@ export default defineComponent({
channelId: this.channelId
})

this.playlistItems = result.items.map(parseLocalPlaylistVideo)
this.playlistItems = playlistItems

let shouldGetNextPage = false
if (result.has_continuation) {
Expand Down
14 changes: 10 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1099,6 +1099,11 @@
"@babel/helper-validator-identifier" "^7.24.7"
to-fast-properties "^2.0.0"

"@bufbuild/protobuf@^2.0.0":
version "2.1.0"
resolved "https://registry.yarnpkg.com/@bufbuild/protobuf/-/protobuf-2.1.0.tgz#6925f30c25789b4f74d7c505e731c96f79fb48a7"
integrity sha512-+2Mx67Y3skJ4NCD/qNSdBJNWtu6x6Qr53jeNg+QcwiL6mt0wK+3jwHH2x1p7xaYH6Ve2JKOVn0OxU35WsmqI9A==

"@csstools/css-parser-algorithms@^3.0.0", "@csstools/css-parser-algorithms@^3.0.1":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.1.tgz#f14ade63bae5f6025ac85c7d03fe47a7ca0e58af"
Expand Down Expand Up @@ -8965,11 +8970,12 @@ yocto-queue@^1.0.0:
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.0.0.tgz#7f816433fb2cbc511ec8bf7d263c3b58a1a3c251"
integrity sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==

youtubei.js@^10.4.0:
version "10.4.0"
resolved "https://registry.yarnpkg.com/youtubei.js/-/youtubei.js-10.4.0.tgz#5c13ecdab7241960cb63533cb2bac274ddc3105a"
integrity sha512-FZahkkg5ROyH/FgJ4czy/xDNkqHbJTCUQzumQlnR+2Q7m6HaWghAFWWJUTcexemGuu7t/5EuyQz98eBgKQRMog==
youtubei.js@^10.5.0:
version "10.5.0"
resolved "https://registry.yarnpkg.com/youtubei.js/-/youtubei.js-10.5.0.tgz#3cf0c79cf73fb26e13d167f37dec7d65419e91b8"
integrity sha512-iyA+VF28c15tCCKH9ExM2RKC3zYiHzA/eixGlJ3vERANkuI+xYKzAZ4vtOhmyqwrAddu88R/DkzEsmpph5NWjg==
dependencies:
"@bufbuild/protobuf" "^2.0.0"
jintr "^2.1.1"
tslib "^2.5.0"
undici "^5.19.1"

0 comments on commit fa4886e

Please sign in to comment.