1 | const miniget = require('miniget')
|
2 |
|
3 | module.exports = async (query, options = {}) => {
|
4 | const response = await miniget(
|
5 | 'https://www.youtube.com/results?search_query=' + encodeURIComponent(query), options
|
6 | ).text()
|
7 | const line = response.match(/window\["ytInitialData"]\s*=\s*(.*);+\n/)[0]
|
8 | const json = JSON.parse(line.substring(line.indexOf('{'), line.length - 2))
|
9 | const result = json
|
10 | ['contents']['twoColumnSearchResultsRenderer']['primaryContents']['sectionListRenderer']
|
11 | ['contents'][0]['itemSectionRenderer']['contents']
|
12 | return result.filter(video => {
|
13 | const type = Object.keys(video)[0].replace('Renderer', '')
|
14 | return ['video', 'playlist'].includes(type)
|
15 | }).map(video => {
|
16 | const type = Object.keys(video)[0].replace('Renderer', '')
|
17 | const data = video[type + 'Renderer']
|
18 | const identifier = data[type + 'Id']
|
19 | if (type === 'video') {
|
20 | const isStream = !Object.keys(data).includes('lengthText')
|
21 | let length = Number.MAX_VALUE
|
22 | if (!isStream) {
|
23 | length = 0
|
24 | data['lengthText']['simpleText'].split(':').reverse().forEach((value, index) => {
|
25 | const i = Number(value)
|
26 | length += (index === 0 ? i : i * (60 ** index))
|
27 | })
|
28 | }
|
29 | return {
|
30 | type: type,
|
31 | identifier: identifier,
|
32 | uri: 'https://www.youtube.com/watch?v=' + identifier,
|
33 | title: data['title']['runs'][0]['text'],
|
34 | author: {
|
35 | name: data['ownerText']['runs'][0]['text'],
|
36 | profile: data['channelThumbnailSupportedRenderers']['channelThumbnailWithLinkRenderer']
|
37 | ['thumbnail']['thumbnails'][0]['url'],
|
38 | uri: 'https://www.youtube.com' + data['ownerText']['runs'][0]['navigationEndpoint']
|
39 | ['commandMetadata']['webCommandMetadata']['url']
|
40 | },
|
41 | length: {
|
42 | ms: isStream ? length : length * 1000,
|
43 | sec: length
|
44 | },
|
45 | isStream: isStream,
|
46 | thumbnails: data['thumbnail']['thumbnails']
|
47 | }
|
48 | } else return {
|
49 | type: type,
|
50 | identifier: identifier,
|
51 | uri: 'https://www.youtube.com/playlist?list=' + identifier,
|
52 | title: data['title']['simpleText'],
|
53 | author: {
|
54 | name: data['longBylineText']['runs'][0]['text'],
|
55 | uri: 'https://www.youtube.com' + data['longBylineText']['runs'][0]['navigationEndpoint']
|
56 | ['commandMetadata']['webCommandMetadata']['url']
|
57 | },
|
58 | count: Number(data['videoCount']),
|
59 | thumbnails: data['thumbnails']
|
60 | }
|
61 | }).filter(it => {
|
62 | if (options.filter === 'video') return it.type === 'video'
|
63 | else if (options.filter === 'playlist') return it.type === 'playlist'
|
64 | else return true
|
65 | })
|
66 | }
|