Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release/0.3.3 #29

Merged
merged 3 commits into from
Jun 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions API/youtubeAPI.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,44 @@ async function youtubeAPI(tokens, resolveName, id, args) {

return allItems;

case 'videosByHandle':
try {
// Get youtuber's handle and find corresponding channel id
var handle = args["handle"];

// Fetch channel data using the handle
var channelData = await youtube.search.list({ part: 'snippet', q: handle, type: 'channel', order: 'relevance' });

if (channelData.data.items && channelData.data.items.length > 0) {
var channelId = channelData.data.items[0].snippet.channelId;
args["channelId"] = channelId;
delete args["handle"];

// Get videos belonging to that channel ID
var data = await youtube.search.list(args);
allItems = data.data.items; // Initialize with initial items

var currentPage = 0;
var nextPageToken = data.data.nextPageToken;

while (currentPage < pages && nextPageToken) {
const newArgs = { ...args, pageToken: nextPageToken };
const newData = await youtube.search.list(newArgs);
allItems = allItems.concat(newData.data.items); // Safely concatenate new items

nextPageToken = newData.data.nextPageToken; // Update the nextPageToken
currentPage++;
}

return allItems;
} else {
throw new Error(`No channel found for handle: ${handle}`);
}
} catch (error) {
console.error(`Error fetching videos for handle ${args["handle"]}:`, error.message);
throw error;
}

case 'playlist':
return (await youtube.playlists.list({
part: 'contentDetails,id,player,snippet,status',
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.3.3] - 2024-06-13
### Added
- Gather YouTube video from a given creator handle [#125](https://github.com/ncsa/standalone-smm-smile/issues/125)

## [0.3.2] - 2024-06-03
### Added
- Youtube list videos API [#23](https://github.com/ncsa/standalone-smm-smile-graphql/issues/23)
Expand Down
148 changes: 148 additions & 0 deletions data/schema/youtubeSchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,154 @@ const youtubeQueryType = module.exports = new GraphQLObjectType({
}
},
resolve: (_, args, context) => youtubeAPI(context, resolveName = 'videos', id = '', args = args)
},
videosByHandle: {
type: new GraphQLList(youtubeListType),
args: {
handle: {
type: GraphQLString,
description: `The handle of youtube creator. e.g.MrBeast`
},
forContentOwner: {
type: GraphQLBoolean,
description: 'boolean for content owner'
},
forDeveloper: {
type: GraphQLBoolean,
description: 'boolean for developer'
},
forMine: {
type: GraphQLBoolean,
description: 'boolean for mine'
},
part: {
type: GraphQLString,
description: 'The part parameter specifies a comma-separated list of one or more search resource properties that the API response will include. The part names that you can include in the parameter value are id and snippet.',
defaultValue: 'id,snippet'
},
channelType:{
type: GraphQLString,
description: 'any, show',
defaultValue: 'any'
},
eventType: {
type: GraphQLString,
description: 'completed, live, upcoming',
},
order: {
type: GraphQLString,
description: 'date, rating, relevance, title, videoCount, viewCount',
defaultValue: 'date'
},
location: {
type: GraphQLString,
description: 'e.g.(37.42307,-122.08427)'
},
locationRadius: {
type: GraphQLString,
description: `Valid measurement units are m, km, ft,
and mi. For example, valid parameter values include
1500m, 5km, 10000ft, and 0.75mi. The API does not support
locationRadius parameter values larger than 1000 kilometers.`
},
maxResults: {
type: GraphQLInt,
defaultValue: 50,
description: 'Acceptable values are 0 to 50, inclusive. The default value is 5.'
},
pages: {
type: GraphQLInt,
defaultValue: 1,
description: 'The maximum number of pages to iterate over' // a made up page to control pagination
},
onBehalfOfContentOwner: {
type: GraphQLString,
description:"This parameter can only be used in a properly authorized request. Note: This parameter is intended exclusively for YouTube content partners."
},
pageToken:{
type: GraphQLString,
description: 'The pageToken parameter identifies a specific page in the result set that should be returned.'
},
publishedAfter: {
type: GraphQLString,
description: 'e.g. 1970-01-01T00:00:00Z'
},
publishedBefore: {
type: GraphQLString,
description: 'e.g. 1970-01-01T00:00:00Z'
},
regionCode:{
type: GraphQLString,
description: 'ISO 3166-1 alpha-2'
},
relevanceLanguage: {
type: GraphQLString,
description: 'ISO 639-1'
},
safeSearch: {
type: GraphQLString,
description: 'moderate, none, strict'
},
topicId: {
type: GraphQLString,
description: 'e.g. /m/04rlf'
},
type: {
type: GraphQLString,
defaultValue: 'video',
description: 'channel,playlist,video'
},
videoCaption: {
type: GraphQLString,
description: 'any, closedCaption, none',
defaultValue: 'any'
},
videoCategoryId: {
type: GraphQLString,
description: 'e.g. 10'
},
videoDefinition: {
type: GraphQLString,
description: 'any, high, standard',
defaultValue: 'any'
},
videoDimension: {
type: GraphQLString,
description: '2d, 3d, any',
defaultValue: 'any'
},
videoDuration: {
type: GraphQLString,
description: 'any, long, medium, short',
defaultValue: 'any'
},
videoEmbeddable: {
type: GraphQLString,
description: 'any, true',
defaultValue: 'any'
},
videoLicense:{
type: GraphQLString,
description: 'any, creativeCommon, youtube',
defaultValue: 'any'
},
videoSyndicated: {
type: GraphQLString,
description: 'any, true',
defaultValue: 'any'
},
videoSyndicationType:{
type: GraphQLString,
description: 'any, broadcast, none',
defaultValue: 'any'
},
videoType: {
type: GraphQLString,
description: 'any, episode, movie',
defaultValue: 'any'
}
},
resolve: (_, args, context) => youtubeAPI(context, resolveName = 'videosByHandle', id = '', args = args)
}
})
});
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "smile_graphql",
"version": "0.3.2",
"version": "0.3.3",
"private": true,
"scripts": {
"start": "forever ./bin/www",
Expand Down
Loading