-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathapp.js
168 lines (153 loc) · 5.16 KB
/
app.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
const express = require('express')
const axios = require('axios')
const app = express()
const videoDetailsURL = `https://yt.lemnoslife.com/noKey/videos?part=contentDetails&fields=items/contentDetails/duration`
const playlistItemsURL = `https://yt.lemnoslife.com/noKey/playlistItems?part=contentDetails&maxResults=50&fields=items/contentDetails/videoId,nextPageToken`
app.use(express.urlencoded({ extended: true }))
app.use(express.static('views'))
//Generates URL for required videos.
function generateVideosURL (id) {
return `${videoDetailsURL}&id=${id}`
}
// Requests for videoIDS and nextPageToken(s)
async function getVideoIdsForPageToken (url) {
try {
console.log(url)
const { data } = await axios.get(url)
const nextPageToken = data.nextPageToken
const videoIds = data.items.map(video => {
return video.contentDetails.videoId
})
return { videoIds, nextPageToken }
} catch (e) {
if (e.response) {
const { code, message } = e.response.data.error
console.log('Errow while fetching videos list.')
throw new Error(`StatusCode ${code}. Reason: ${message}`)
} else {
throw new Error(e.message)
}
}
}
// Returns details for videos in the playlist.
async function getDetailsForVideoIds (id) {
try {
const { data } = await axios.get(generateVideosURL(id))
return data.items
} catch (e) {
console.log('Error while fetching video details. ')
throw new Error(e.message)
}
}
// Formats all the returned duration info into seconds.
function returnedToSeconds (input) {
try {
const daysHrsMinsSecs = /^P(?:(\d+)D)?T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?$/
let days = 0
let hours = 0
let minutes = 0
let seconds = 0
let totalSeconds = 0
if (daysHrsMinsSecs.test(input)) {
let toMatch = daysHrsMinsSecs.exec(input)
if (toMatch[1]) days = Number(toMatch[1])
if (toMatch[2]) hours = Number(toMatch[2])
if (toMatch[3]) minutes = Number(toMatch[3])
if (toMatch[4]) seconds = Number(toMatch[4])
totalSeconds = days * 86400 + hours * 3600 + minutes * 60 + seconds
} else {
console.log(returnedToSeconds)
}
return totalSeconds
} catch (e) {
console.error(e)
if (e.message.includes('Invalid date')) {
return 'Invalid date in returned data.'
}
}
}
async function getPlaylistTotalDuration (extractedPlaylistIDId, newPageToken) {
try {
// Step 1: Create the required query URL based on the newPageToken parameter
let url = newPageToken
? `${playlistItemsURL}&playlistId=${extractedPlaylistIDId}&pageToken=${newPageToken}`
: `${playlistItemsURL}&playlistId=${extractedPlaylistIDId}`
// Step 2: Start a local duration counter
let totalDuration = 0
let numberOfVideos = 0
let firstVideoIds
// Step 3: Get the video details based on the URL created in Step 1
const { videoIds, nextPageToken } = await getVideoIdsForPageToken(url)
const returnedVideoIds = []
returnedVideoIds.push(getDetailsForVideoIds(videoIds))
const videoGroups = await Promise.all(returnedVideoIds)
for (const group of videoGroups) {
for (const video of group) {
// Step 4: Get the durations in seconds and add it to the local duration counter created in Step 2
totalDuration += returnedToSeconds(video.contentDetails.duration)
}
}
numberOfVideos = videoGroups[0].length
firstVideoIds = videoIds[0]
// Step 5: Check if the return of Step 3 has a nextPageToken, if so do a recursive call to self with the new token
if (nextPageToken) {
firstVideoIds
let returnedTotalDuration = await getPlaylistTotalDuration(
extractedPlaylistIDId,
nextPageToken
)
totalDuration += returnedTotalDuration.totalDuration
let returnedNoOfVideos = returnedTotalDuration.numberOfVideos
numberOfVideos += returnedNoOfVideos
firstVideoIds = videoIds[0]
}
return { totalDuration, numberOfVideos, firstVideoIds }
} catch (e) {
console.log('Error while navigating between video pages.')
throw new Error(e)
}
}
app.post('/search', async (req, res) => {
async function checkID (playlistID) {
let checkRes
await axios
.get(
`https://yt.lemnoslife.com/noKey/playlistItems?part=status&maxResults=1&playlistId=${playlistID}`
)
.then(res => {
checkRes = true
})
.catch(error => {
if (error.response) {
console.log(error.response.status)
checkRes = false
}
})
return checkRes
}
;(async () => {
extractedPlaylistIDId = null
const playlisturl = req.body.playlistID
if (await checkID(playlisturl)) {
let resp = await getPlaylistTotalDuration(playlisturl)
console.log(
'Someone just fetched a playlist of ' +
resp.totalDuration +
' seconds with ' +
resp.numberOfVideos +
' videos with the first video id ' +
resp.firstVideoIds
)
res.send(resp)
} else {
res.send('API_Error')
}
})()
})
app.get('/', function (req, res) {
res.render('index')
})
// Port Route.
app.listen(process.env.PORT || 3000, () => {
console.log(`Playlist data is now running baby!)`)
})