-
Notifications
You must be signed in to change notification settings - Fork 936
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #32 from hiteshchoudhary/feat/youtube-api
Quick YouTube public apis without any credentials - Public YouTube API filled with Hitesh sir's youtube channel data. - Equivalent to the YouTube's public api, but FREE, requiring no cumbersome API Key or credentials! - Offering a wide array of endpoints that provide access to video lists, video details (complete with statistics), video comments, related videos, channel playlists, playlist items and channel details (accompanied by comprehensive channel statistics) - With this wealth of information at fingertips, one can confidently develop their very own YouTube clone without the hassle of dealing with a complex API setup.
- Loading branch information
Showing
12 changed files
with
48,349 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -144,3 +144,4 @@ logs | |
!/public/temp/.gitkeep | ||
|
||
NOTES.md | ||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,242 @@ | ||
import { YouTubeFilterEnum, AvailableYouTubeFilters } from "../../constants.js"; | ||
import channelJson from "../../json/youtube/channel.json" assert { type: "json" }; | ||
import commentsJson from "../../json/youtube/comments.json" assert { type: "json" }; | ||
import playlistItemsJson from "../../json/youtube/playlistitems.json" assert { type: "json" }; | ||
import playlistsJson from "../../json/youtube/playlists.json" assert { type: "json" }; | ||
import videosJson from "../../json/youtube/videos.json" assert { type: "json" }; | ||
import { ApiError } from "../../utils/ApiError.js"; | ||
import { ApiResponse } from "../../utils/ApiResponse.js"; | ||
import { asyncHandler } from "../../utils/asyncHandler.js"; | ||
import { filterObjectKeys, getPaginatedPayload } from "../../utils/helpers.js"; | ||
|
||
const getChannelDetails = asyncHandler(async (req, res) => { | ||
const channelDetails = channelJson.channel; | ||
return res | ||
.status(200) | ||
.json( | ||
new ApiResponse( | ||
200, | ||
channelDetails, | ||
"Channel details fetched successfully!" | ||
) | ||
); | ||
}); | ||
|
||
const getPlaylists = asyncHandler(async (req, res) => { | ||
const page = +(req.query.page || 1); | ||
const limit = +(req.query.limit || 10); | ||
|
||
const playlists = playlistsJson; | ||
|
||
return res | ||
.status(200) | ||
.json( | ||
new ApiResponse( | ||
200, | ||
getPaginatedPayload(playlists, page, limit), | ||
"Playlists fetched successfully" | ||
) | ||
); | ||
}); | ||
|
||
const getPlaylistById = asyncHandler(async (req, res) => { | ||
const { playlistId } = req.params; | ||
|
||
// filter out the playlist by id from json array | ||
const playlist = playlistsJson.find((playlist) => playlist.id === playlistId); | ||
|
||
if (!playlist) { | ||
throw new ApiError( | ||
404, | ||
"Playlist with ID " + playlistId + " Does not exist" | ||
); | ||
} | ||
|
||
// get the channel info | ||
const channel = { | ||
info: channelJson.channel.info.snippet, | ||
statistics: channelJson.channel.info.statistics, | ||
}; | ||
|
||
// Get the playlist items in the playlist | ||
const playlistItems = playlistItemsJson.filter( | ||
(item) => item.snippet.playlistId === playlistId | ||
); | ||
|
||
return res.status(200).json( | ||
new ApiResponse( | ||
200, | ||
{ | ||
channel, | ||
playlist, | ||
playlistItems, | ||
}, | ||
"Playlist fetched successfully" | ||
) | ||
); | ||
}); | ||
|
||
const getVideos = asyncHandler(async (req, res) => { | ||
const page = +(req.query.page || 1); | ||
const limit = +(req.query.limit || 10); | ||
|
||
/** | ||
* @type {AvailableYouTubeFilters[0]} | ||
*/ | ||
const sortBy = req.query.sortBy; | ||
|
||
const query = req.query.query?.toLowerCase(); // search query | ||
const inc = req.query.inc?.split(","); // only include fields mentioned in this query | ||
|
||
const videos = videosJson.channelVideos; | ||
|
||
let videosArray = query | ||
? structuredClone(videos).filter((video) => { | ||
return ( | ||
// Search videos based on title, description and tags | ||
video.items.snippet.title.toLowerCase().includes(query) || | ||
video.items.snippet.tags?.includes(query) || | ||
video.items.snippet.description?.includes(query) | ||
); | ||
}) | ||
: structuredClone(videos); | ||
|
||
if (inc && inc[0]?.trim()) { | ||
videosArray = filterObjectKeys(inc, videosArray); | ||
} | ||
|
||
switch (sortBy) { | ||
case YouTubeFilterEnum.LATEST: | ||
// sort by publishedAt key in descending order | ||
videosArray.sort( | ||
(a, b) => | ||
new Date(b.items.snippet.publishedAt) - | ||
new Date(a.items.snippet.publishedAt) | ||
); | ||
break; | ||
case YouTubeFilterEnum.OLDEST: | ||
// sort by publishedAt key in ascending order | ||
videosArray.sort( | ||
(a, b) => | ||
new Date(a.items.snippet.publishedAt) - | ||
new Date(b.items.snippet.publishedAt) | ||
); | ||
break; | ||
case YouTubeFilterEnum.MOST_LIKED: | ||
videosArray.sort( | ||
(a, b) => +b.items.statistics.likeCount - +a.items.statistics.likeCount | ||
); | ||
break; | ||
case YouTubeFilterEnum.MOST_VIEWED: | ||
videosArray.sort( | ||
(a, b) => +b.items.statistics.viewCount - +a.items.statistics.viewCount | ||
); | ||
break; | ||
default: | ||
// Return latest videos by default | ||
videosArray.sort( | ||
(a, b) => | ||
new Date(b.items.snippet.publishedAt) - | ||
new Date(a.items.snippet.publishedAt) | ||
); | ||
break; | ||
} | ||
|
||
return res | ||
.status(200) | ||
.json( | ||
new ApiResponse( | ||
200, | ||
getPaginatedPayload(videosArray, page, limit), | ||
"Videos fetched successfully" | ||
) | ||
); | ||
}); | ||
|
||
const getVideoById = asyncHandler(async (req, res) => { | ||
const { videoId } = req.params; | ||
|
||
// get filter based on id | ||
const video = videosJson.channelVideos.find( | ||
(video) => video.items.id === videoId | ||
); | ||
|
||
if (!video) { | ||
throw new ApiError(404, "Video with ID " + videoId + " Does not exist"); | ||
} | ||
|
||
const channel = { | ||
info: channelJson.channel.info.snippet, | ||
statistics: channelJson.channel.info.statistics, | ||
}; | ||
|
||
return res.status(200).json( | ||
new ApiResponse( | ||
200, | ||
{ | ||
channel, | ||
video, | ||
}, | ||
"Video fetched successfully" | ||
) | ||
); | ||
}); | ||
|
||
const getVideoComments = asyncHandler(async (req, res) => { | ||
const { videoId } = req.params; | ||
|
||
const video = videosJson.channelVideos.find( | ||
(video) => video.items.id === videoId | ||
); | ||
|
||
if (!video) { | ||
throw new ApiError(404, "Video with ID " + videoId + " Does not exist"); | ||
} | ||
|
||
const comments = commentsJson[videoId]?.items || []; | ||
|
||
return res | ||
.status(200) | ||
.json( | ||
new ApiResponse(200, comments, "Video comments fetched successfully") | ||
); | ||
}); | ||
|
||
const getRelatedVideos = asyncHandler(async (req, res) => { | ||
const { videoId } = req.params; | ||
const page = +(req.query.page || 1); | ||
const limit = +(req.query.limit || 10); | ||
|
||
const video = videosJson.channelVideos.find( | ||
(video) => video.items.id === videoId | ||
); | ||
|
||
if (!video) { | ||
throw new ApiError(404, "Video with ID " + videoId + " Does not exist"); | ||
} | ||
|
||
// related videos are all except the selected one | ||
const relatedVideos = videosJson.channelVideos.filter( | ||
(video) => video.items.id !== videoId | ||
); | ||
|
||
return res | ||
.status(200) | ||
.json( | ||
new ApiResponse( | ||
200, | ||
getPaginatedPayload(relatedVideos, page, limit), | ||
"Related videos fetched successfully" | ||
) | ||
); | ||
}); | ||
|
||
export { | ||
getChannelDetails, | ||
getPlaylistById, | ||
getPlaylists, | ||
getRelatedVideos, | ||
getVideoById, | ||
getVideoComments, | ||
getVideos, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
{ | ||
"channel": { | ||
"kind": "youtube#channelListResponse", | ||
"info": { | ||
"kind": "youtube#channel", | ||
"id": "UCXgGY0wkgOzynnHvSEVmE3A", | ||
"snippet": { | ||
"title": "Hitesh Choudhary", | ||
"description": "Website: https://hiteshchoudhary.com\nHey there everyone, Hitesh here back again with another video!\nThis means I create a lot of videos, every single week. I cover a wide range of subjects like programming, what's latest in tech, new frameworks, open-source products etc. I keep my interest in a wide area of tech like Javascript, Python, PHP, Machine Learning, etc.\n\nFor the Business purpose, Sponsorships and invitation, reach out at [email protected]\n\nNOTE: Personal questions and code-related questions are not answered at this email. Post them in the course discussion section or react me out at social platforms.\n\n#iWriteCode\n\nInstagram: https://instagram.com/hiteshchoudharyofficial\nFacebook: www.fb.com/HiteshChoudharyPage", | ||
"customUrl": "@hiteshchoudharydotcom", | ||
"publishedAt": "2011-10-24T10:25:16Z", | ||
"thumbnails": { | ||
"default": { | ||
"url": "https://yt3.ggpht.com/ytc/AOPolaTLK52bUQ_YHxgb7RK8GMt_bksIMavy-aEZ9fUOvg=s88-c-k-c0x00ffffff-no-rj", | ||
"width": 88, | ||
"height": 88 | ||
}, | ||
"medium": { | ||
"url": "https://yt3.ggpht.com/ytc/AOPolaTLK52bUQ_YHxgb7RK8GMt_bksIMavy-aEZ9fUOvg=s240-c-k-c0x00ffffff-no-rj", | ||
"width": 240, | ||
"height": 240 | ||
}, | ||
"high": { | ||
"url": "https://yt3.ggpht.com/ytc/AOPolaTLK52bUQ_YHxgb7RK8GMt_bksIMavy-aEZ9fUOvg=s800-c-k-c0x00ffffff-no-rj", | ||
"width": 800, | ||
"height": 800 | ||
} | ||
}, | ||
"localized": { | ||
"title": "Hitesh Choudhary", | ||
"description": "Website: https://hiteshchoudhary.com\nHey there everyone, Hitesh here back again with another video!\nThis means I create a lot of videos, every single week. I cover a wide range of subjects like programming, what's latest in tech, new frameworks, open-source products etc. I keep my interest in a wide area of tech like Javascript, Python, PHP, Machine Learning, etc.\n\nFor the Business purpose, Sponsorships and invitation, reach out at [email protected]\n\nNOTE: Personal questions and code-related questions are not answered at this email. Post them in the course discussion section or react me out at social platforms.\n\n#iWriteCode\n\nInstagram: https://instagram.com/hiteshchoudharyofficial\nFacebook: www.fb.com/HiteshChoudharyPage" | ||
}, | ||
"country": "IN" | ||
}, | ||
"statistics": { | ||
"viewCount": "54384618", | ||
"subscriberCount": "801000", | ||
"hiddenSubscriberCount": false, | ||
"videoCount": "1442" | ||
}, | ||
"brandingSettings": { | ||
"channel": { | ||
"title": "Hitesh Choudhary", | ||
"description": "Website: https://hiteshchoudhary.com\nHey there everyone, Hitesh here back again with another video!\nThis means I create a lot of videos, every single week. I cover a wide range of subjects like programming, what's latest in tech, new frameworks, open-source products etc. I keep my interest in a wide area of tech like Javascript, Python, PHP, Machine Learning, etc.\n\nFor the Business purpose, Sponsorships and invitation, reach out at [email protected]\n\nNOTE: Personal questions and code-related questions are not answered at this email. Post them in the course discussion section or react me out at social platforms.\n\n#iWriteCode\n\nInstagram: https://instagram.com/hiteshchoudharyofficial\nFacebook: www.fb.com/HiteshChoudharyPage", | ||
"keywords": "Programming computers code hitesh udemy Udacity Edx \"machine learning\" python javascript devops cloud", | ||
"unsubscribedTrailer": "xJq0EQMFGyg", | ||
"country": "IN" | ||
}, | ||
"image": { | ||
"bannerExternalUrl": "https://yt3.googleusercontent.com/xGlR3Vz-RYHgwRj50-VEdBksVyjyJhvzQUEVttMCd5iRVdw-OXdFkPBPswF2nG_13QR2UfXnCQ" | ||
} | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.