better-youtube-api
Advanced tools
Comparing version 2.1.5 to 2.1.6
244
out/index.js
@@ -17,4 +17,4 @@ "use strict"; | ||
const util_1 = require("./util"); | ||
const caching_1 = require("./util/caching"); | ||
const oauth_1 = require("./oauth"); | ||
const services_1 = require("./services"); | ||
__export(require("./entities")); | ||
@@ -38,3 +38,3 @@ /** | ||
if (options.cacheCheckInterval > 0) { | ||
setInterval(caching_1.Cache.checkTTLs, options.cacheCheckInterval * 1000); | ||
setInterval(util_1.Cache.checkTTLs, options.cacheCheckInterval * 1000); | ||
} | ||
@@ -47,3 +47,3 @@ } | ||
this._token = val; | ||
this.tokenType = val.startsWith('ya29') ? 'oauth' : 'key'; | ||
this._tokenType = val.startsWith('ya29') ? 'oauth' : 'key'; | ||
} | ||
@@ -54,3 +54,3 @@ _cache(id, value) { | ||
} | ||
caching_1.Cache.set(id, value, this._cacheTTL > 0 ? this._cacheTTL * 1000 + new Date().getTime() : 0); | ||
util_1.Cache.set(id, value, this._cacheTTL > 0 ? this._cacheTTL * 1000 + new Date().getTime() : 0); | ||
} | ||
@@ -65,3 +65,3 @@ /** | ||
search(types, searchTerm, maxResults = 10, pageToken) { | ||
return this._search(types, searchTerm, maxResults, pageToken); | ||
return services_1.SearchService.search(this, types, searchTerm, maxResults, pageToken); | ||
} | ||
@@ -101,4 +101,4 @@ /** | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const id = yield this.getId(videoResolvable, 'video'); | ||
return this.getItemById(entities_1.Video, id); | ||
const id = yield services_1.GenericService.getId(this, videoResolvable, 'video'); | ||
return services_1.GenericService.getItemById(this, entities_1.Video, id); | ||
}); | ||
@@ -112,4 +112,4 @@ } | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const id = yield this.getId(channelResolvable, 'channel'); | ||
return this.getItemById(entities_1.Channel, id); | ||
const id = yield services_1.GenericService.getId(this, channelResolvable, 'channel'); | ||
return services_1.GenericService.getItemById(this, entities_1.Channel, id); | ||
}); | ||
@@ -123,4 +123,4 @@ } | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const id = yield this.getId(playlistResolvable, 'playlist'); | ||
return this.getItemById(entities_1.Playlist, id); | ||
const id = yield services_1.GenericService.getId(this, playlistResolvable, 'playlist'); | ||
return services_1.GenericService.getItemById(this, entities_1.Playlist, id); | ||
}); | ||
@@ -133,3 +133,3 @@ } | ||
getComment(commentId) { | ||
return this.getItemById(entities_1.YTComment, commentId); | ||
return services_1.GenericService.getItemById(this, entities_1.YTComment, commentId); | ||
} | ||
@@ -147,3 +147,3 @@ /** | ||
} | ||
return this.getItemById(entities_1.Video, id.video); | ||
return services_1.GenericService.getItemById(this, entities_1.Video, id.video); | ||
} | ||
@@ -161,3 +161,3 @@ /** | ||
} | ||
return this.getItemById(entities_1.Channel, id.channel); | ||
return services_1.GenericService.getItemById(this, entities_1.Channel, id.channel); | ||
} | ||
@@ -175,3 +175,3 @@ /** | ||
} | ||
return this.getItemById(entities_1.Playlist, id.playlist); | ||
return services_1.GenericService.getItemById(this, entities_1.Playlist, id.playlist); | ||
} | ||
@@ -185,4 +185,4 @@ /** | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const playlistId = yield this.getId(playlistResolvable, 'playlist'); | ||
return this.getPaginatedItems('playlistItems', playlistId, maxResults); | ||
const playlistId = yield services_1.GenericService.getId(this, playlistResolvable, 'playlist'); | ||
return services_1.GenericService.getPaginatedItems(this, 'playlistItems', playlistId, maxResults); | ||
}); | ||
@@ -197,4 +197,4 @@ } | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const videoId = yield this.getId(videoResolvable, 'video'); | ||
return this.getPaginatedItems('commentThreads:video', videoId, maxResults); | ||
const videoId = yield services_1.GenericService.getId(this, videoResolvable, 'video'); | ||
return services_1.GenericService.getPaginatedItems(this, 'commentThreads:video', videoId, maxResults); | ||
}); | ||
@@ -209,4 +209,4 @@ } | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const channelId = yield this.getId(channelResolvable, 'channel'); | ||
return this.getPaginatedItems('commentThreads:channel', channelId, maxResults); | ||
const channelId = yield services_1.GenericService.getId(this, channelResolvable, 'channel'); | ||
return services_1.GenericService.getPaginatedItems(this, 'commentThreads:channel', channelId, maxResults); | ||
}); | ||
@@ -221,4 +221,4 @@ } | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const channelId = yield this.getId(channelResolvable, 'channel'); | ||
return this.getPaginatedItems('playlists:channel', channelId, maxResults); | ||
const channelId = yield services_1.GenericService.getId(this, channelResolvable, 'channel'); | ||
return services_1.GenericService.getPaginatedItems(this, 'playlists:channel', channelId, maxResults); | ||
}); | ||
@@ -232,200 +232,4 @@ } | ||
getCommentReplies(commentId, maxResults = -1) { | ||
return this.getPaginatedItems('comments', commentId, maxResults); | ||
return services_1.GenericService.getPaginatedItems(this, 'comments', commentId, maxResults); | ||
} | ||
/* istanbul ignore next */ | ||
_search(types, searchTerm, maxResults = 10, pageToken) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const type = types.map(t => t.endpoint.substring(0, t.endpoint.length - 1)).join(','); | ||
const cached = caching_1.Cache.get(`search://${type}/"${searchTerm}"/${maxResults}/"${pageToken}"`); | ||
if (this._shouldCache && cached) { | ||
return cached; | ||
} | ||
if (maxResults < 1 || maxResults > 50) { | ||
return Promise.reject('Max results must be greater than 0 and less than or equal to 50'); | ||
} | ||
const fields = 'prevPageToken,nextPageToken,items(kind,id,snippet(title,description,thumbnails,publishedAt,channelId))'; | ||
const data = { | ||
q: encodeURIComponent(searchTerm), | ||
fields: encodeURIComponent(fields), | ||
maxResults, | ||
part: 'snippet', | ||
type | ||
}; | ||
if (pageToken) { | ||
data.pageToken = pageToken; | ||
} | ||
const results = yield util_1.request.api('search', data, this.token, this.tokenType); | ||
const items = []; | ||
results.items.forEach(item => { | ||
if (item.id.videoId) { | ||
items.push(new entities_1.Video(this, item)); | ||
} | ||
else if (item.id.channelId) { | ||
items.push(new entities_1.Channel(this, item)); | ||
} | ||
else if (item.id.playlistId) { | ||
items.push(new entities_1.Playlist(this, item)); | ||
} | ||
}); | ||
const toReturn = { results: items, prevPageToken: results.prevPageToken, nextPageToken: results.nextPageToken }; | ||
if (this._shouldCache && this._cacheSearches) { | ||
this._cache(`search://${type}/"${searchTerm}"/${maxResults}/"${pageToken}"`, toReturn); | ||
} | ||
return toReturn; | ||
}); | ||
} | ||
/* istanbul ignore next */ | ||
getItemById(type, id) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (!([entities_1.Video, entities_1.Channel, entities_1.Playlist, entities_1.YTComment].includes(type))) { | ||
return Promise.reject('Type must be a video, channel, playlist, or comment.'); | ||
} | ||
const cached = caching_1.Cache.get(`get://${type.endpoint}/${id}`); | ||
if (this._shouldCache && cached) { | ||
return cached; | ||
} | ||
const result = yield util_1.request.api(type.endpoint, { | ||
id, | ||
fields: encodeURIComponent(type.fields), | ||
part: type.part | ||
}, this.token, this.tokenType); | ||
if (result.items.length === 0) { | ||
return Promise.reject('Item not found'); | ||
} | ||
let endResult = new type(this, result.items[0], result.items[0].snippet.channelId ? 'channel' : 'video'); | ||
if (this._shouldCache) { | ||
this._cache(`get://${type.endpoint}/${id}`, endResult); | ||
} | ||
return endResult; | ||
}); | ||
} | ||
/* istanbul ignore next */ | ||
getPaginatedItems(endpoint, id, maxResults = -1) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const cached = caching_1.Cache.get(`get://${endpoint}/${id}/${maxResults}`); | ||
if (this._shouldCache && cached) { | ||
return cached; | ||
} | ||
let items = []; | ||
const full = maxResults <= 0; | ||
const options = { | ||
part: 'snippet', | ||
maxResults: 0 | ||
}; | ||
let max; | ||
let clazz; | ||
let commentType; | ||
if (endpoint === 'playlistItems') { | ||
max = 50; | ||
clazz = entities_1.Video; | ||
options.playlistId = id; | ||
} | ||
else if (endpoint.startsWith('commentThreads')) { | ||
max = 100; | ||
clazz = entities_1.YTComment; | ||
const [, type] = endpoint.split(':'); | ||
commentType = type ? type : 'video'; | ||
endpoint = 'commentThreads'; | ||
options[`${type}Id`] = id; | ||
options.part += ',replies'; | ||
options.textFormat = 'plainText'; | ||
} | ||
else if (endpoint === 'comments') { | ||
max = 100; | ||
clazz = entities_1.YTComment; | ||
options.parentId = id; | ||
} | ||
else if (endpoint === 'playlists:channel') { | ||
max = 50; | ||
clazz = entities_1.Playlist; | ||
endpoint = 'playlists'; | ||
options.part += ',contentDetails,player'; | ||
options.channelId = id; | ||
} | ||
else { | ||
return Promise.reject('Unknown item type ' + endpoint); | ||
} | ||
if (maxResults > max) { | ||
return Promise.reject(`Max results must be ${max} or below for ${endpoint}`); | ||
} | ||
options.maxResults = full ? max : maxResults; | ||
let results; | ||
let pages = null; | ||
let shouldReturn = !full; | ||
for (let i = 1; i < pages ? pages : 3; i++) { | ||
results = yield util_1.request.api(endpoint, options, this.token, this.tokenType).catch(() => { | ||
return Promise.reject('Items not found'); | ||
}); | ||
if (results.items.length === 0) { | ||
return Promise.reject('Items not found'); | ||
} | ||
if (!pages) { | ||
pages = results.pageInfo.totalResults / results.pageInfo.resultsPerPage; | ||
if (pages <= 1) { | ||
shouldReturn = true; | ||
} | ||
pages = Math.floor(pages); | ||
} | ||
results.items.forEach(item => { | ||
let comment; | ||
if (item.snippet.topLevelComment) { | ||
comment = new entities_1.YTComment(this, item.snippet.topLevelComment, commentType); | ||
items.push(comment); | ||
} | ||
else { | ||
items.push(new clazz(this, item, commentType)); | ||
} | ||
if (item.replies) { | ||
item.replies.comments.forEach(reply => { | ||
const created = new entities_1.YTComment(this, reply, commentType); | ||
comment.replies.push(created); | ||
}); | ||
} | ||
}); | ||
if (results.nextPageToken && !shouldReturn) { | ||
options.pageToken = results.nextPageToken; | ||
} | ||
else { | ||
return items; | ||
} | ||
} | ||
if (this._shouldCache) { | ||
this._cache(`get://${endpoint}/${id}/${maxResults}`, items); | ||
} | ||
return items; | ||
}); | ||
} | ||
/* istanbul ignore next */ | ||
getId(input, type) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
let id = null; | ||
if (input.includes('youtube.com') || input.includes('youtu.be')) { | ||
const idFromUrl = util_1.parseUrl(input)[type]; | ||
// Custom channel URLs don't work that well | ||
if (type === 'channel' && idFromUrl && !idFromUrl.startsWith('UC')) { | ||
id = yield util_1.request.api('search', { q: idFromUrl, type, part: 'id' }, this.token, this.tokenType).then(r => r.items[0] ? r.items[0].id.channelId : undefined); | ||
} | ||
id = idFromUrl; | ||
} | ||
if (id !== null && id !== undefined && id !== '') { | ||
return id; | ||
} | ||
if (type === 'channel' && (!input.startsWith('UC') || input.includes(' '))) { | ||
id = yield util_1.request.api('search', { q: input, type, part: 'id', maxResults: 1 }, this.token, this.tokenType).then(r => r.items[0] ? r.items[0].id.channelId : undefined); | ||
} | ||
else if (type === 'playlist' && input.includes(' ')) { | ||
id = yield util_1.request.api('search', { q: input, type, part: 'id', maxResults: 1 }, this.token, this.tokenType).then(r => r.items[0] ? r.items[0].id.playlistId : undefined); | ||
} | ||
else if (type === 'video' && (input.length < 11 || input.includes(' '))) { | ||
id = yield util_1.request.api('search', { q: input, type, part: 'id', maxResults: 1 }, this.token, this.tokenType).then(r => r.items[0] ? r.items[0].id.videoId : undefined); | ||
} | ||
else { | ||
id = input; | ||
} | ||
if (id === null || id === undefined || id === '') { | ||
return Promise.reject('Item not found'); | ||
} | ||
return id; | ||
}); | ||
} | ||
} | ||
@@ -432,0 +236,0 @@ exports.YouTube = YouTube; |
@@ -26,3 +26,3 @@ "use strict"; | ||
checkTokenAndThrow() { | ||
if (this.youtube.tokenType !== 'oauth') { | ||
if (this.youtube._tokenType !== 'oauth') { | ||
throw new Error('Token is not an oauth token'); | ||
@@ -29,0 +29,0 @@ } |
@@ -8,3 +8,4 @@ "use strict"; | ||
__export(require("./request")); | ||
__export(require("./caching")); | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "better-youtube-api", | ||
"version": "2.1.5", | ||
"version": "2.1.6", | ||
"description": "A very easy to use promise-based Youtube Data v3 API.", | ||
@@ -5,0 +5,0 @@ "main": "out/index.js", |
@@ -62,1 +62,8 @@ # Better YouTube API | ||
Note: This wrapper does not implement every feature of the YouTube API. With a single developer working on it, there just isn't time for everything to be implemented. Some of the objectively most-important features have been added. The limits imposed by the wrapper are not imposed by YouTube. | ||
# Development | ||
## Before committing: | ||
* Run TSLint. | ||
* Run `npm run coverage` to check if you've added enough tests. It should display 100% statement, line, and branch coverage. | ||
* Run `yarn test` or `npm run test` and make sure that every test passes. |
@@ -9,8 +9,8 @@ import { Video, Channel, Playlist, YTComment } from './entities'; | ||
export declare class YouTube { | ||
private _shouldCache; | ||
private _cacheSearches; | ||
private _cacheTTL; | ||
_shouldCache: boolean; | ||
_cacheSearches: boolean; | ||
_cacheTTL: number; | ||
_tokenType: 'key' | 'oauth'; | ||
private _token; | ||
token: string; | ||
tokenType: 'key' | 'oauth'; | ||
/** | ||
@@ -141,6 +141,2 @@ * Methods requiring an OAuth token | ||
getCommentReplies(commentId: string, maxResults?: number): Promise<YTComment[]>; | ||
private _search; | ||
private getItemById; | ||
private getPaginatedItems; | ||
private getId; | ||
} | ||
@@ -147,0 +143,0 @@ declare type YouTubeOptions = { |
export * from './util'; | ||
export * from './request'; | ||
export * from './caching'; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
174700
63
2072
69