brandonbothell / popyt Goto Github PK
View Code? Open in Web Editor NEWA very easy to use Youtube Data v3 API library.
Home Page: https://brandonbothell.github.io/popyt/
License: The Unlicense
A very easy to use Youtube Data v3 API library.
Home Page: https://brandonbothell.github.io/popyt/
License: The Unlicense
Hello,
Thanks for your hard work : this library is by far the cleanest I have seen for this domain ;)
Like the title said, I would like to get all the playlists for a channel ( for exemple mine :
UCG0N7IV-C43AM9psxslejCQ ). Your searchPlaylists function doesn't include a parameter for that.
From what I read on the docs , you only have to include the optional parameter channelId in your requests. ( demo url )
Thank you in advance
Structure:
{
"kind": "youtube#playlistItem",
"etag": etag,
"id": string,
"snippet": {
"publishedAt": datetime,
"channelId": string,
"title": string,
"description": string,
"thumbnails": {
(key): {
"url": string,
"width": unsigned integer,
"height": unsigned integer
}
},
"channelTitle": string,
"playlistId": string,
"position": unsigned integer,
"resourceId": {
"kind": string,
"videoId": string,
}
},
"contentDetails": {
"videoId": string,
"startAt": string,
"endAt": string,
"note": string,
"videoPublishedAt": datetime
},
"status": {
"privacyStatus": string
}
}
Methods:
Insert:
POST https://www.googleapis.com/youtube/v3/playlistItems
part: string
- The parts to both insert and return.
contentDetails
id
snippet
status
snippet.playlistId
- requiredsnippet.position
snippet.resourceId
- requiredcontentDetails.note
contentDetails.startAt
contentDetails.endAt
PlaylistItem
resource.Update:
PUT https://www.googleapis.com/youtube/v3/playlistItems
Insert
method]id
- requiredInsert
method]PlaylistItem
resource.Delete:
DELETE https://www.googleapis.com/youtube/v3/playlistItems
id: string
- YouTube playlist item ID for the playlist item that is being deleted.204 No Content
This may be a YouTube limitation but reporting here in case it's otherwise. If you try getChannel()
with this URL it will fail with "Item not found" error:
https://www.youtube.com/c/ChilledCow
but the same URL with a trailing slash will work just fine:
https://www.youtube.com/c/ChilledCow/
Using just "ChilledCow" also works. However, other channels do not work even with trailing slash or with only the end path.
const { YouTube } = require('popyt');
const youtube = new YouTube(YOUTUBE_KEY);
/*
Working:
'https://www.youtube.com/c/ChilledCow/'
'ChilledCow'
"Item not found":
'https://www.youtube.com/c/ChilledCow'
'https://www.youtube.com/c/fosterkittensofficial/'
'https://www.youtube.com/c/fosterkittensofficial'
'fosterkittensofficial'
*/
const query = 'https://www.youtube.com/c/ChilledCow/';
youtube
.getChannel(query)
.then(res => console.log(res.data.snippet))
.catch(err => console.error(err));
When I load those failing URLs in the browser, they load fine and I can't discern any particular difference between the working and non-working URLs. Thank you for the library! ๐๐ผโโ๏ธ
// todo
Structure:
{
"kind": "youtube#playlist",
"etag": etag,
"id": string,
"snippet": {
"publishedAt": datetime,
"channelId": string,
"title": string,
"description": string,
"thumbnails": {
(key): {
"url": string,
"width": unsigned integer,
"height": unsigned integer
}
},
"channelTitle": string,
"tags": [
string
],
"defaultLanguage": string,
"localized": {
"title": string,
"description": string
}
},
"status": {
"privacyStatus": string
},
"contentDetails": {
"itemCount": unsigned integer
},
"player": {
"embedHtml": string
},
"localizations": {
(key): {
"title": string,
"description": string
}
}
}
Methods:
Insert:
POST https://www.googleapis.com/youtube/v3/playlists
part: string
- The parts to insert and to return.
contentDetails
id
localizations
player
snippet
status
snippet.title
- requiredsnippet.description
status.privacyStatus
snippet.tags[]
snippet.defaultLanguage
localizations.(key)
localizations.(key).title
localizations.(key).description
Playlist
resource.Update:
PUT https://www.googleapis.com/youtube/v3/playlists
Insert
method]id
- requiredInsert
method]Playlist
resource.Delete:
DELETE https://www.googleapis.com/youtube/v3/playlists
id: string
- YouTube playlist ID for the playlist that is being deleted.204 No Content
// todo
// todo
Escalating this because the API key and access token are secure values and could really benefit from this change
Overall, the file looks well-structured and organized. Here are a few suggestions for optimizations:
1. Use type aliases for resolvable types: In the current implementation, the GenericService.getId
method takes a resolvable
parameter which can be either a string, a Video
, or a Channel
. It would be more type-safe to use type aliases for these resolvable types instead of string | Video | Channel
. For example:
type VideoResolvable = string | Video;
type ChannelResolvable = string | Channel;
Remove deprecated methods: The getChannelComments
method is marked as deprecated and has a note pointing to a Google support thread. It might be better to remove this method altogether from the file.
/
Use async/await instead of Promises: The file uses both Promises and async/await syntax for asynchronous operations. It would be more consistent to use async/await throughout the file.
Use destructuring for function parameters: Some functions take multiple parameters, and it might be more readable to use destructuring to extract the required parameters. For example:
~~public async getPlaylistItems (playlistResolvable: string | Playlist, { maxResults = 10, pageToken, parts }: { maxResults?: number, pageToken?: string, parts?: PlaylistItemParts } = {}): Promise<Video[]> {
const playlistId = await GenericService.getId(this, playlistResolvable, Playlist);
return (await GenericService.getPaginatedItems(
{ youtube: this, type: PaginatedItemType.PlaylistItems, id: playlistId, maxResults, pageToken, parts })).results as Video[];
}~~
public async getVideoComments (videoResolvable: string | Video, { maxResults = 20, pageToken, sortOrder = 'time', parts }: { maxResults?: number, pageToken?: string, sortOrder?: 'relevance' | 'time' | 'likes', parts?: CommentThreadParts } = {}): Promise<YTComment[]> {
const videoId = await GenericService.getId(this, videoResolvable, Video);
return (await GenericService.getPaginatedItems(
{ youtube: this, type: PaginatedItemType.VideoComments, id: videoId, maxResults, pageToken, parts, order: sortOrder })).results as YTComment[];
}
Split the code into smaller modules: The index.ts file currently contains a lot of code and imports. Consider splitting the code into smaller modules based on functionality. This will improve maintainability and make the codebase easier to navigate.
Group Imports: Instead of importing each entity individually from the ./entities module, you can use a wildcard import to import all entities at once. For example, replace that long devilish thing with:
import * as Entities from './entities';
Add Activities endpoints
#43
Add ChannelBanners endpoints
#42
Add Channels endpoints
#41
Add ChannelSections endpoints
#40
Add Comment endpoints
#39
Add GuideCategories endpoints
#38
Add i18nLanguages endpoints
#37
Add i18nRegions endpoints
#36
Add Members endpoint (awaiting special permission by YouTube)
#94
Add MembersipsLevels endpoint (awaiting special permission by YouTube)
#95
Add Captions endpoints
#103
Add PlaylistItems endpoints
#35
Add Playlists endpoints
#34
Add Watermarks endpoints
#31
Structure:
{
"kind": "youtube#videoCategory",
"etag": etag,
"id": string,
"snippet": {
"channelId": "UCBR8-60-B28hp2BmDPdntcQ",
"title": string,
"assignable": boolean
}
}
Methods:
GET https://www.googleapis.com/youtube/v3/videoCategories
part: string
- Set the part to snippet
.id: string
- Comma-separated list of video category IDs for the resources that you are retrieving.regionCode: string
- instructs the API to return the list of video categories available in the specified country. The parameter value is an ISO 3166-1 alpha-2 country code.{
"kind": "youtube#videoCategoryListResponse",
"etag": etag,
"nextPageToken": string,
"prevPageToken": string,
"pageInfo": {
"totalResults": integer,
"resultsPerPage": integer
},
"items": [
videoCategory resource
]
}
Hello
When I tried to call fetchVideos with a number greater than 50, the library throws an error. This seems a bit harsh given that 100 still seems like a reasonable size for playlists.
Why does this limitation exist? Is there a workaround to indeed do fetch all the videos of the playlist, at least up to a greater limit? This is really a serious limitation for me at the moment, as I'm using the library for developing a musicbot on Discord. I hope there can be a solution.
Thank you for a response.
// todo
// todo
Implementing this will save lots of quota
A value of "live", "upcoming" or "false" according to the docs
A value of undefined is returned
let search = await youtube.searchChannels('PewDiePie', 1); console.log(search);
Outputs:
{ results: [ Channel { youtube: [YouTube], data: [Object], full: false, id: 'UC-lHJZR3Gqxm24_Vd_AJ5Yw', liveStatus: undefined, profilePictures: [Object], dateCreated: 2010-04-29T10:54:00.000Z, name: 'PewDiePie', about: 'I make videos.', url: 'https://youtube.com/channel/UC-lHJZR3Gqxm24_Vd_AJ5Yw' } ],
I'm trying to make my Discord bot check whether a youtube channel is live or not, please tell me if I'm missing something as I'm a very new to programming myself.
There is an error with this repository's Renovate configuration that needs to be fixed. As a precaution, Renovate will stop PRs until it is resolved.
Error type: undefined. Note: this is a nested preset so please contact the preset author if you are unable to fix it yourself.
Originally posted by @eric2788 in #49 (comment)
This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.
These updates are currently rate-limited. Click on a checkbox below to force their creation now.
mocha
, @types/mocha
)node
, @types/node
)@types/react
, @types/react-dom
, react
, react-dom
)@typescript-eslint/eslint-plugin
, @typescript-eslint/parser
)@typescript-eslint/eslint-plugin
, @typescript-eslint/parser
)@docusaurus/core
, @docusaurus/module-type-aliases
, @docusaurus/preset-classic
, @docusaurus/theme-classic
, @docusaurus/theme-common
, @docusaurus/tsconfig
, @docusaurus/types
)These updates have all been created already. Click a checkbox below to force a retry/rebase of any.
chai
, @types/chai
)These are blocked by an existing closed PR and will not be recreated unless you click a checkbox below.
.github/workflows/coverage.yml
actions/checkout v3
actions/setup-node v3.8.2
borales/actions-yarn v4
codecov/codecov-action v3
.github/workflows/main.yml
actions/checkout v3
actions/setup-node v3.8.2
borales/actions-yarn v4
borales/actions-yarn v4
borales/actions-yarn v4
actions/checkout v3
actions/setup-node v3.8.2
borales/actions-yarn v4
codecov/codecov-action v3
.github/workflows/release.yml
actions/checkout v3
actions/setup-node v3.8.2
borales/actions-yarn v4
borales/actions-yarn v4
actions/checkout v3
actions/setup-node v3.8.2
borales/actions-yarn v4
borales/actions-yarn v4
.github/workflows/renovate.yml
actions/checkout v3
actions/setup-node v3.8.2
borales/actions-yarn v4
borales/actions-yarn v4
borales/actions-yarn v4
borales/actions-yarn v4
.yarn/sdks/eslint/package.json
.yarn/sdks/typescript/package.json
docusaurus/package.json
@docusaurus/core 2.4.3
@docusaurus/preset-classic 2.4.3
@mdx-js/react 1.6.22
@types/react 18.2.35
clsx 2.0.0
prism-react-renderer 1.3.5
react 18.2.0
react-dom 18.2.0
@docusaurus/module-type-aliases 2.4.3
@docusaurus/theme-classic 2.4.3
@docusaurus/theme-common 2.4.3
@docusaurus/tsconfig 0.0.0-5601
@docusaurus/types 2.4.3
@types/node 20.9.0
docusaurus-plugin-typedoc 0.19.2
typedoc 0.24.8
typedoc-plugin-markdown 3.17.0
typescript 5.1.6
node >=16.14
@types/react 18.2.35
@types/react-dom 18.2.14
yarn 3.6.2
package.json
@googleapis/youtube 11.0.1
@istanbuljs/nyc-config-typescript 1.0.2
@types/chai 4.3.10
@types/gulp 4.0.16
@types/gulp-sourcemaps 0.0.37
@types/merge2 1.4.3
@types/mocha 10.0.3
@types/node 20.9.0
@typescript-eslint/eslint-plugin 6.13.0
@typescript-eslint/parser 6.13.0
chai 4.3.10
cross-env 7.0.3
dotenv 16.3.1
eslint 8.53.0
eslint-plugin-import 2.29.0
eslint-plugin-jsdoc 46.8.2
eslint-plugin-unused-imports 3.0.0
mocha 10.2.0
nyc 15.1.0
source-map-support 0.5.21
ts-node 10.9.1
typescript 5.1.6
node 20.9.0
node-preload 0.2.0
yarn 3.6.2
This will likely involve a complete refactor of the Cache
class, specifically one that takes in some prespecified data keys/values for each type of data that will be cached.
// todo
When I try to use popyt with my discord bot, this error shows up:
(node:14684) UnhandledPromiseRejectionWarning: Items must either specify an ID or the 'mine' parameter. (node:14684) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag
--unhandled-rejections=strict (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 2) (node:14684) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
I don't know why is this happening, everything should be working.
The code is:
const Discord = require("discord.js"); const { YouTube } = require('popyt'); const prefix = "~" const youtube = new YouTube('<token here>'); module.exports.run = async (bot, msg, args) => { const argums = msg.content.slice(prefix.length).split(' '); if (!argums.length) { return msg.channel.send(
You didn't provide any arguments, ${msg.author}!); } else { const video = await youtube.getVideo(argums) msg.channel.send(video); } }
Would it be possible to add the length of the videos when we request a playlist? When I use playlist.fetchVideos()
, it returns a lot of information, but the length of the videos doesn't come.
Sure, here are some suggestions and optimizations for the Video.ts
file:
Use type aliases for complex types: The Video
class has several complex types such as VideoUpdateResource
, CommentThreadParts
, etc. It would be more readable to use type aliases for these types instead of defining them inline.
Use object destructuring to extract properties: Some functions in the Video
class take an object as a parameter, and it might be more readable to use object destructuring to extract only the required properties. For example:
public async update ({ title, description, tags, categoryId, privacyStatus }: { title?: string, description?: string, tags?: string[], categoryId?: string, privacyStatus?: 'public' | 'private' | 'unlisted' } = {}): Promise<void> {
const request: VideoUpdateResource = {
id: this.id,
snippet: {
title: title || this.title,
description: description || this.description,
tags: tags || this.tags,
categoryId: categoryId || this.data.snippet.categoryId
},
status: {
privacyStatus: privacyStatus || this.data.status.privacyStatus
}
}
await this.youtube._updateVideo(request)
if (title) this.title = title
if (description) this.description = description
if (tags) this.tags = tags
if (categoryId) this.data.snippet.categoryId = categoryId
if (privacyStatus) this.data.status.privacyStatus = privacyStatus
}
const
instead of let
: Some variables in the Video
class are not reassigned and can be declared as const
instead of let
. For example:const { items } = await this.youtube._makeRequest({
method: 'GET',
params: {
part: ['snippet', 'contentDetails', 'statistics', 'status'].join(','),
id: this.id
}
})
Use arrow functions for class methods: Some class methods in the Video
class use function
syntax instead of arrow functions. It might be more consistent to use arrow functions throughout the class.
Use optional chaining for nested properties: Some properties in the Video
class are nested and might be undefined. It would be more readable to use optional chaining to avoid errors when accessing nested properties. For example:
this._length = Parser.parseIsoDuration(video.contentDetails?.duration)
Add JSDoc comments to public methods: Some public methods in the Video
class lack JSDoc comments, which makes it harder to understand their usage and parameters.
Remove unused code: The postComment
method is not used in the class, and can be removed.
Remove unreachable code: The this.liveStatus
property is always assigned one of two values, so the else
block in the corresponding if
statement is unreachable and can be removed.
Overall, the Video.ts
file looks well-structured and easy to understand, with only minor improvements needed for readability and maintainability.
// todo
Would it be possible to add Live endpoints? https://developers.google.com/youtube/v3/live
Rename to cache.ts
Consider Using a Map Instead of Object: Instead of using a plain object { [key: string]: CacheItem } to store cache items, consider using a Map data structure. Maps provide built-in methods for managing key-value pairs and can improve performance and code readability.
Improve Naming: Consider using more descriptive names for variables and functions. For example, instead of using name as a parameter in the set and get methods, consider using a more meaningful name, such as key or cacheKey.
Search currently supports these parameters: types, searchTerm, maxResult and pageToken
https://github.com/jasonhaxstuff/popyt/blob/master/src/index.ts#L90
Would be nice if it also supported these: eventType, fields, type, videoCategoryId and videoEmbeddable.
https://developers.google.com/youtube/v3/docs/search/list supports a number of other p
it
I had to figure out why Hungarian searches failed in our Discord bot... it's easy to fix (I did fix it for myself) but it can be confusing, so why not call an encodeURI on the searchTerm at some point.
Looks like a tag that wasn't escaped. It breaks the rest of the page and makes it not visible.
Hi,
I am getting the following error when I tried to call function
const youtube = new YouTube(process.env.YOUTUBE_API_KEY, { cache: false })
const YTCategories = await youtube.getCategories()
console.log(process.env.YTCategories);
Error: Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.
at IncomingMessage. (D:\xampp\htdocs\nextjs-prisma-devcomm\node_modules\popyt\out\util\request.js:148:39)
Can you please help me to resolve this asap?
Thanks,
Structure:
{
"kind": "youtube#videoAbuseReportReason",
"etag": etag,
"id": string,
"snippet": {
"label": string,
"secondaryReasons": [
{
"id": string,
"label": string
}
]
}
}
Methods:
GET https://www.googleapis.com/youtube/v3/videoAbuseReportReasons
part: string
- Supported values are id
and snippet
(should use both).hl?: string
- Language to use for the response. Defaults to en_US
.{
"kind": "youtube#videoAbuseReportReasonListResponse",
"etag": etag,
"items": [
videoAbuseReportReason resource
]
}
// todo
Structure:
{
"timing": {
"type": string,
"offsetMs": unsigned long,
"durationMs": unsigned long
},
"position": {
"type": string,
"cornerPosition": string
},
"imageUrl": string,
"imageBytes": bytes,
"targetChannelId": string
}
Methods:
POST https://www.googleapis.com/upload/youtube/v3/watermarks/set
channelId: string
- YouTube channel ID for which the watermark is being provided.Watermark
resource in the request body204 No Content
POST https://www.googleapis.com/youtube/v3/watermarks/unset
channelId: string
- YouTube channel ID for which the watermark is being unset.204 No Content
Make sure all entities contain the following properties/methods:
fetch
method for fetching the entity againid
propertydata
propertyyoutube
propertyfull
propertyurl
propertyRunning the following code snippet should return a list of comments for the given video:
const comments = await youtube.getVideoComments(Video, 0)
I get the error commentThreads not found
Full snippet:
const channel = await youtube.getChannel(process.env.YOUTUBE_CHANNEL_ID)
const uploadsPlaylistId = channel.data.contentDetails.relatedPlaylists.uploads
const playlist = await youtube.getPlaylistItems(uploadsPlaylistId, 0)
for(let video of playlist) {
const comments = await youtube.getVideoComments(video, 0)
console.log(comments)
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.