cloud-ytdl 1.0.0-rc

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/load.js ADDED
@@ -0,0 +1,38 @@
1
+ 'use strict'
2
+
3
+ const fs = require('fs')
4
+
5
+ function loadCookieHeader(input) {
6
+ if (!input) return ''
7
+
8
+ if (typeof input === 'string' && input.includes('=')
9
+ && !fs.existsSync(input)) {
10
+ return input.trim()
11
+ }
12
+
13
+ const raw = fs.readFileSync(input, 'utf8').trim()
14
+
15
+ if (raw.startsWith('[')) {
16
+ const list = JSON.parse(raw)
17
+
18
+ return list
19
+ .filter(c =>
20
+ c.name &&
21
+ c.value &&
22
+ (!c.expirationDate ||
23
+ c.expirationDate * 1000 > Date.now())
24
+ )
25
+ .map(c => `${c.name}=${c.value}`)
26
+ .join('; ')
27
+ }
28
+
29
+ return raw
30
+ .split('\n')
31
+ .filter(l => l && !l.startsWith('#'))
32
+ .map(l => l.split('\t'))
33
+ .filter(p => p.length >= 7 && p[6])
34
+ .map(p => `${p[5]}=${p[6]}`)
35
+ .join('; ')
36
+ }
37
+
38
+ module.exports = { loadCookieHeader }
@@ -0,0 +1,57 @@
1
+ 'use strict'
2
+
3
+ const { request } = require('undici')
4
+ const utils = require('./utils')
5
+
6
+ async function getPlaylistInfo(url, opts = {}) {
7
+ const res = await request(url, {
8
+ headers: {
9
+ 'user-agent':
10
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',
11
+ ...(opts.agent?.jar && {
12
+ cookie: opts.agent.jar.getCookieStringSync(url)
13
+ })
14
+ },
15
+ dispatcher: opts.agent?.dispatcher
16
+ })
17
+
18
+ const html = await res.body.text()
19
+
20
+ const ytInitialData =
21
+ html.match(/var ytInitialData = (.*?);<\/script>/)?.[1]
22
+
23
+ if (!ytInitialData)
24
+ throw new Error('ytInitialData not found')
25
+
26
+ const data = JSON.parse(ytInitialData)
27
+
28
+ const sidebar =
29
+ data?.contents?.twoColumnWatchNextResults
30
+ ?.playlist?.playlist
31
+
32
+ if (!sidebar)
33
+ throw new Error('playlist data not found')
34
+
35
+ const items =
36
+ sidebar.contents
37
+ .filter(x => x.playlistPanelVideoRenderer)
38
+ .map(x => {
39
+ const v = x.playlistPanelVideoRenderer
40
+ return {
41
+ videoId: v.videoId,
42
+ title: v.title?.simpleText,
43
+ author: v.shortBylineText?.runs?.[0]?.text,
44
+ lengthSeconds:
45
+ utils.parseTime(v.lengthText?.simpleText)
46
+ }
47
+ })
48
+
49
+ return {
50
+ id: sidebar.playlistId,
51
+ title: sidebar.title,
52
+ type: sidebar.isInfinite ? 'radio' : 'playlist',
53
+ items
54
+ }
55
+ }
56
+
57
+ module.exports = { getPlaylistInfo }
package/lib/post.js ADDED
@@ -0,0 +1,88 @@
1
+ const { request } = require('undici')
2
+
3
+ const yt = {}
4
+
5
+ yt.getPostInfo = async url => {
6
+ const res = await request(url, {
7
+ headers: {
8
+ 'user-agent':
9
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/140 Safari/537.36'
10
+ }
11
+ })
12
+
13
+ const html = await res.body.text()
14
+
15
+ const match = html.match(/var ytInitialData = (.*?);<\/script>/s)
16
+ if (!match) throw new Error('ytInitialData not found')
17
+
18
+ const data = JSON.parse(match[1])
19
+
20
+ const post =
21
+ data.contents.twoColumnBrowseResultsRenderer.tabs[0]
22
+ .tabRenderer.content.sectionListRenderer.contents[0]
23
+ .itemSectionRenderer.contents[0]
24
+ .backstagePostThreadRenderer.post.backstagePostRenderer
25
+
26
+ const author = post.authorText?.runs?.[0]?.text || ''
27
+ const authorUrl =
28
+ 'https://youtube.com' +
29
+ (post.authorEndpoint?.commandMetadata?.webCommandMetadata?.url || '')
30
+
31
+ const content =
32
+ post.contentText?.runs?.map(r => r.text).join('') || ''
33
+
34
+ const published = post.publishedTimeText?.runs?.[0]?.text || ''
35
+ const likes = post.voteCount?.simpleText || '0'
36
+
37
+ let images = []
38
+ let poll = null
39
+
40
+ const a = post.backstageAttachment
41
+
42
+ if (a?.postMultiImageRenderer?.images?.length) {
43
+ images = a.postMultiImageRenderer.images.map(
44
+ i => i.backstageImageRenderer.image.thumbnails.at(-1).url
45
+ )
46
+ } else if (a?.backstageImageRenderer?.images?.length) {
47
+ images = a.backstageImageRenderer.images.map(
48
+ i => i.image.thumbnails.at(-1).url
49
+ )
50
+ } else if (a?.backstageImageRenderer?.image?.thumbnails?.length) {
51
+ images = [a.backstageImageRenderer.image.thumbnails.at(-1).url]
52
+ }
53
+
54
+ if (a?.pollRenderer) {
55
+ const pr = a.pollRenderer
56
+
57
+ const options = (pr.choices || []).map(c => {
58
+ const voteText = c.voteCount?.simpleText || '0'
59
+ const voteCount = Number(voteText.replace(/[^\d]/g, ''))
60
+
61
+ return {
62
+ text: c.text?.runs?.map(r => r.text).join('') || '',
63
+ voteCount,
64
+ isCorrect: Boolean(c.isCorrect)
65
+ }
66
+ })
67
+
68
+ poll = {
69
+ question: pr.question?.runs?.map(r => r.text).join('') || '',
70
+ options,
71
+ totalVotes: options.reduce((a, b) => a + b.voteCount, 0),
72
+ correctAnswer:
73
+ options.find(o => o.isCorrect)?.text || null
74
+ }
75
+ }
76
+
77
+ return {
78
+ author,
79
+ authorUrl,
80
+ published,
81
+ content,
82
+ images,
83
+ likes,
84
+ poll
85
+ }
86
+ }
87
+
88
+ module.exports = yt