New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

youtube-feeds

Package Overview
Dependencies
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

youtube-feeds - npm Package Compare versions

Comparing version 2.3.0 to 2.4.0

.travis.yml

7

package.json

@@ -9,3 +9,3 @@ {

"description": "Access public YouTube Data API v2 feeds, mostly with the clean JSON-C results",
"version": "2.3.0",
"version": "2.4.0",
"repository": {

@@ -25,4 +25,7 @@ "type": "git",

"engines": {
"node": "<=0.8.3 >=0.10.0"
"node": ">=0.8.28"
},
"scripts": {
"test": "node test.js"
},
"keywords": ["youtube", "youtubev2", "video", "feeds", "api"],

@@ -29,0 +32,0 @@ "license": {

@@ -1,3 +0,3 @@

nodejs-youtube
==============
youtube-feeds
=============

@@ -7,3 +7,5 @@

[![Build Status](https://travis-ci.org/fvdm/nodejs-youtube.svg?branch=master)](https://travis-ci.org/fvdm/nodejs-youtube)
End of life notice

@@ -18,35 +20,14 @@ ------------------

Suggestion: [youtube-api](https://www.npmjs.org/package/youtube-api) on npm ([Github](https://github.com/IonicaBizau/youtube-api))
> See the Wiki for a working example: <https://github.com/fvdm/nodejs-youtube/wiki>
Installation
------------
### From npm registry
Stable: `npm install youtube-feeds`
The npm release is always the recent *stable* version.
Develop: `npm install fvdm/youtube-feeds#develop`
```
npm install youtube-feeds
```
```js
var youtube = require('youtube-feeds')
```
### From Github
The code on Github is the most recent version, but may be untested.
```
git clone https://github.com/fvdm/nodejs-youtube
cd nodejs-youtube
npm install
```
```js
var youtube = require('/path/to/nodejs-youtube')
```
Usage

@@ -67,23 +48,19 @@ -----

* `httpProtocol` (string)
param | type | default | description
-------------|---------|---------|------------
httpProtocol | string | http | Which HTTP protocol to use
timeout | integer | 30000 | Request wait timeout in ms
developerKey | string | | Your YouTube [developer key](http://code.google.com/apis/youtube/dashboard/)
Which HTTP protocol to use: `http` (default) or `https`
* `timeout` (integer)
> `developerKey` is required for some methods, ie. [user.activity](#useractivity).
> You can also temporarily override the global setting with the `key` property in a method's vars.
Destroy the request after this number of *milliseconds*. Default: 30000 (30 sec).
* `developerKey` (string)
Set your YouTube developer key ([manage](http://code.google.com/apis/youtube/dashboard/)).
This is required for some methods, ie. [user.activity](#useractivity).
You can also temporarily override the global setting with the `key` property in a method's vars.
### Example:
```js
var youtube = require('youtube-feeds')
youtube.httpProtocol = 'https'
youtube.feeds.videos( {q:'keywords'}, callback )
var youtube = require ('youtube-feeds');
youtube.httpProtocol = 'https';
youtube.feeds.videos ({q: 'keywords'}, callback);
```

@@ -98,7 +75,7 @@

```js
function( err, data ) {
if( err instanceof Error ) {
console.log( err )
function (err, data) {
if (err) {
console.log (err);
} else {
console.log( data )
console.log (data);
}

@@ -108,26 +85,31 @@ }

Properties:
#### Error Properties
err.message : the error message
err.stack : stack trace
err.origin : what it relates to (api, method, request)
err.details : api response or other information when available, or `null`
property | type | description
------------|--------|----------------------------------
err.message | string | the error message
err.stack | string | stack trace
err.origin | string | Context; api, method, request
err.details | mixed | API response or other information
Messages:
Error: invalid response api API response can't be parsed
Error: not json api Expected JSON, received something else
Error: not found method Requested data was not found
Error: not allowed method No permission to requested data
Error: invalid id method Requested video ID is invalid
Error: connection closed api Connection dropped early
Error: connection error request Can't connect to API
Error: request timeout request The request took too long to connect or process
Error: error api API returned an error, see err.details
Error: developer key missing api developerKey is not set, see Configuration.
#### Error Messages
message | origin | description
----------------------|---------|------------------------------------------------
invalid response | api | API response can't be parsed
not json | api | Expected JSON, received something else
not found | method | Requested data was not found
not allowed | method | No permission to requested data
invalid id | method | Requested video ID is invalid
connection closed | api | Connection dropped early
connection error | request | Can't connect to API
request timeout | request | The request took too long to connect or process
error | api | API returned an error, see err.details
developer key missing | api | developerKey is not set, see Configuration.
===========================================================================================
=================================================================================
Feeds

@@ -148,3 +130,3 @@ -----

```js
youtube.feeds.videos(
youtube.feeds.videos (
{

@@ -156,3 +138,3 @@ q: 'parkour',

console.log
)
);
```

@@ -242,3 +224,3 @@

```js
youtube.feeds.standard( 'most_recent', console.log )
youtube.feeds.standard ('most_recent', console.log);
```

@@ -250,3 +232,3 @@

```js
youtube.feeds.standard( 'NL/top_rated_News', {time: 'today'}, console.log )
youtube.feeds.standard ('NL/top_rated_News', {time: 'today'}, console.log);
```

@@ -262,3 +244,3 @@

===========================================================================================
=======================================================================

@@ -269,3 +251,2 @@

The **video** function provides shorthand methods for one specific video.

@@ -281,3 +262,3 @@

```js
youtube.video( 'ern37eWDnT0', console.log )
youtube.video ('ern37eWDnT0', console.log);
```

@@ -293,3 +274,3 @@

```js
youtube.video( 'ern37eWDnT0' ).details( console.log )
youtube.video ('ern37eWDnT0').details (console.log);
```

@@ -305,3 +286,3 @@

```js
youtube.video( 'ern37eWDnT0' ).related( {'max-results': 2}, console.log )
youtube.video ('ern37eWDnT0').related ({'max-results': 2}, console.log);
```

@@ -317,3 +298,3 @@

```js
youtube.video( 'ern37eWDnT0' ).responses( {'max-results': 2}, console.log )
youtube.video ('ern37eWDnT0').responses ({'max-results': 2}, console.log);
```

@@ -329,7 +310,7 @@

```js
youtube.video( 'ern37eWDnT0' ).comments( {'max-results': 2}, console.log )
youtube.video ('ern37eWDnT0').comments ({'max-results': 2}, console.log);
```
===========================================================================================
=======================================================================

@@ -350,3 +331,3 @@

```js
youtube.user( 'user', console.log )
youtube.user ('user', console.log);
```

@@ -362,3 +343,3 @@

```js
youtube.user( 'user' ).profile( console.log )
youtube.user ('user').profile (console.log);
```

@@ -374,5 +355,6 @@

```js
youtube.user( 'user' ).favorites( console.log )
youtube.user ('user').favorites (console.log);
```
user.playlists

@@ -392,8 +374,9 @@ --------------

```js
youtube.user( 'user' ).uploads( console.log )
youtube.user ('user').uploads (console.log);
```
===========================================================================================
=======================================================================
talk

@@ -406,16 +389,13 @@ ----

Param Type Description
---------- -------- ----------------------------------------------------
path string full method path without leading slash
fields object GET parameters
callback function callback function to receive results
oldJsonKey boolean force old XML-to-JSON format instead of clean JSON-C
its value is the key containing the expected results
Param | Type | Description
-----------|----------|------------------------------------------------
path | string | full method path without leading slash
fields | object | GET parameters
callback | function | callback function to receive results
oldJsonKey | boolean | force old XML-to-JSON format instead of clean JSON-C its value is the key containing the expected results
Unlicense / Public Domain
-------------------------
This is free and unencumbered software released into the public domain.

@@ -445,1 +425,9 @@

For more information, please refer to <http://unlicense.org>
Author
------
Franklin van de Meent
| [Website](https://frankl.in)
| [Github](https://github.com/fvdm)

@@ -10,10 +10,10 @@ /*

var xml2json = require('node-xml2json')
var querystring = require('querystring')
var xml2json = require ('node-xml2json');
var querystring = require ('querystring');
var app = {
httpProtocol: 'http', // http, https
timeout: 5000, // max execution time in milliseconds
developerKey: null // YouTube developer key
}
httpProtocol: 'http', // http, https
timeout: 5000, // max execution time in milliseconds
developerKey: null // YouTube developer key
};

@@ -26,39 +26,37 @@

app.feeds = {
// Videos
videos: function( vars, cb ) {
app.talk( 'feeds/api/videos', vars, cb )
},
// Related videos
related: function( videoid, vars, cb ) {
app.talk( 'feeds/api/videos/'+ videoid +'/related', vars, cb )
},
// Responses
responses: function( videoid, vars, cb ) {
app.talk( 'feeds/api/videos/'+ videoid +'/responses', vars, cb )
},
// Comments
comments: function( videoid, vars, cb ) {
app.talk( 'feeds/api/videos/'+ videoid +'/comments', vars, cb, 'feed' )
},
// Standard feed
// https://developers.google.com/youtube/2.0/reference#Standard_feeds
// feeds.standard( 'most_recent', console.log )
// feeds.standard( 'NL/top_rated_News', {time: 'today'}, console.log )
standard: function( feed, vars, cb ) {
app.talk( 'feeds/api/standardfeeds/'+ feed, vars, cb )
},
// Playlist
playlist: function( playlistid, vars, cb ) {
app.talk( 'feeds/api/playlists/'+ playlistid, vars, cb )
}
}
// Videos
videos: function (vars, cb) {
app.talk ('feeds/api/videos', vars, cb);
},
// Related videos
related: function (videoid, vars, cb) {
app.talk ('feeds/api/videos/'+ videoid +'/related', vars, cb);
},
// Responses
responses: function (videoid, vars, cb) {
app.talk ('feeds/api/videos/'+ videoid +'/responses', vars, cb);
},
// Comments
comments: function (videoid, vars, cb) {
app.talk ('feeds/api/videos/'+ videoid +'/comments', vars, cb, 'feed');
},
// Standard feed
// https://developers.google.com/youtube/2.0/reference#Standard_feeds
// feeds.standard ('most_recent', console.log)
// feeds.standard ('NL/top_rated_News', {time: 'today'}, console.log)
standard: function (feed, vars, cb) {
app.talk ('feeds/api/standardfeeds/'+ feed, vars, cb);
},
// Playlist
playlist: function (playlistid, vars, cb) {
app.talk ('feeds/api/playlists/'+ playlistid, vars, cb);
}
};
///////////

@@ -68,74 +66,67 @@ // VIDEO //

app.video = function( videoid, cb ) {
if( typeof cb === 'function' ) {
app.talk( 'feeds/api/videos/'+ videoid, cb )
}
// video shortcuts
return {
details: function( cb ) {
app.video( videoid, cb )
},
related: function( vars, cb ) {
app.feeds.related( videoid, vars, cb )
},
responses: function( vars, cb ) {
app.feeds.responses( videoid, vars, cb )
},
comments: function( vars, cb ) {
app.feeds.comments( videoid, vars, cb )
}
}
}
app.video = function (videoid, cb) {
if (typeof cb === 'function') {
app.talk ('feeds/api/videos/'+ videoid, cb);
}
// video shortcuts
return {
details: function (cb) {
app.video (videoid, cb);
},
related: function (vars, cb) {
app.feeds.related (videoid, vars, cb);
},
responses: function (vars, cb) {
app.feeds.responses (videoid, vars, cb);
},
comments: function (vars, cb) {
app.feeds.comments (videoid, vars, cb);
}
};
};
//////////
// USER //
//////////
// User
app.user = function( userid, cb ) {
if( cb && typeof cb === 'function' ) {
app.user( userid ).profile( cb )
}
return {
// Favorites
favorites: function( vars, cb ) {
app.talk( 'feeds/api/users/'+ userid +'/favorites', vars, cb )
},
// Playlists
playlists: function( vars, cb ) {
app.talk( 'feeds/api/users/'+ userid +'/playlists', vars, cb )
},
// Profile
profile: function( cb ) {
app.talk( 'feeds/api/users/'+ userid, {}, cb, 'entry' )
},
// Uploads
uploads: function( vars, cb ) {
app.talk( 'feeds/api/users/'+ userid +'/uploads', vars, cb )
},
// New subscription videos
newsubscriptionvideos: function( vars, cb ) {
app.talk( 'feeds/api/users/'+ userid +'/newsubscriptionvideos', vars, cb )
}
}
}
app.user = function (userid, cb) {
if (cb && typeof cb === 'function') {
app.user (userid).profile (cb);
}
return {
// Favorites
favorites: function (vars, cb) {
app.talk ('feeds/api/users/'+ userid +'/favorites', vars, cb);
},
// Playlists
playlists: function (vars, cb) {
app.talk ('feeds/api/users/'+ userid +'/playlists', vars, cb);
},
// Profile
profile: function (cb) {
app.talk ('feeds/api/users/'+ userid, {}, cb, 'entry');
},
// Uploads
uploads: function (vars, cb) {
app.talk ('feeds/api/users/'+ userid +'/uploads', vars, cb);
},
// New subscription videos
newsubscriptionvideos: function (vars, cb) {
app.talk ('feeds/api/users/'+ userid +'/newsubscriptionvideos', vars, cb);
}
};
};
/////////////////

@@ -145,231 +136,201 @@ // COMMUNICATE //

app.talk = function( path, fields, cb, oldJsonKey ) {
var complete = false
// fix callback
if( !cb && typeof fields === 'function' ) {
var cb = fields
var fields = {}
}
// fix fields
if( !fields || typeof fields !== 'object' ) {
var fields = {}
}
// force JSON-C and version
fields.alt = oldJsonKey !== undefined ? 'json' : 'jsonc'
fields.v = 2
// prepare
var options = {
hostname: 'gdata.youtube.com',
path: '/'+ path +'?'+ querystring.stringify( fields ),
headers: {
'User-Agent': 'youtube-feeds.js (https://github.com/fvdm/nodejs-youtube)',
'Accept': 'application/json',
'GData-Version': '2'
},
method: 'GET'
}
// use X-GData-Key instead of adding it to the url, as per http://goo.gl/HEiCj
// basically more secure in headers than in query string
if ( fields.key || app.developerKey ) {
options.headers['X-GData-Key'] = 'key=' + fields.key || app.developerKey
delete fields.key
}
if( app.httpProtocol === 'https' ) {
var request = require('https').request( options )
} else {
var request = require('http').request( options )
}
// response
request.on( 'response', function( response ) {
var data = []
var size = 0
response.on( 'data', function( chunk ) {
data.push( chunk )
size += chunk.length
})
response.on( 'end', function() {
if( complete ) {
return
} else {
complete = true
}
// process buffer and clear mem
var buf = new Buffer( size )
var pos = 0
for( var i = 0; i < data.length; ++i ) {
data[i].copy( buf, pos )
pos += data[i].length
}
data = buf.toString('utf8').trim()
var error = null
// validate
if( data.match( /^(\{.*\}|\[.*\])$/ ) ) {
// ok
data = JSON.parse( data )
if( data.data !== undefined ) {
data = data.data
} else if( data.error !== undefined ) {
complete = true
error = new Error('error')
error.origin = 'api'
error.details = data.error
} else if( oldJsonKey !== undefined ) {
if( data[ oldJsonKey ] === undefined ) {
complete = true
error = new Error('invalid response')
error.origin = 'api'
} else {
data = data[ oldJsonKey ]
}
}
} else if( data.match( /^<errors .+<\/errors>$/ ) || data.match( /^<\?xml version.+<\/errors>$/ ) ) {
// xml error response
data = xml2json.parser( data )
// fix for JSONC compatibility
complete = true
error = new Error('error')
error.origin = 'api'
error.details = data.errors.error !== undefined ? [data.errors.error] : data.errors
error.details.forEach( function( err, errk ) {
if( err.internalreason !== undefined ) {
error.details[ errk ].internalReason = err.internalreason
delete error.details[ errk ].internalreason
}
})
} else if( ~data.indexOf('<H2>Error ') ) {
// html error response
complete = true
var error = new Error('error')
data.replace( /<H1>([^<]+)<\/H1>\n<H2>Error (\d+)<\/H2>/, function( s, reason, code ) {
error.origin = 'api'
error.details = {
internalReason: reason,
code: code
}
})
} else {
// not json
complete = true
error = new Error('not json')
error.origin = 'api'
}
// parse error
if( error && error.origin === 'api' && error.message === 'error' ) {
var errorDetails = error.details
if(
error.details[0] !== undefined
&& error.details[0].code !== undefined
&& error.details[0].code === 'ResourceNotFoundException'
) {
complete = true
error = new Error('not found')
error.origin = 'method'
error.details = errorDetails
} else if( error.details.code == 403 ) {
complete = true
error = new Error('not allowed')
error.origin = 'method'
error.details = errorDetails
} else if( error.details.message === 'Invalid id' ) {
complete = true
error = new Error('invalid id')
error.origin = 'method'
error.details = errorDetails
} else if( error.details[0] && error.details[0].internalReason === 'Developer key required for this operation' ) {
complete = true
error = new Error('developer key missing')
error.origin = 'api'
error.details = errorDetails
}
}
// parse response
if( data.totalItems !== undefined && data.totalItems == 0 ) {
complete = true
error = new Error('not found')
error.origin = 'method'
} else if(
data.feed !== undefined
&& data.feed['openSearch$totalResults'] !== undefined
&& data.feed['openSearch$totalResults']['$t'] !== undefined
&& data.feed['openSearch$totalResults']['$t'] == 0
) {
complete = true
error = new Error('not found')
error.origin = 'method'
}
// do callback
cb( error, data )
})
// early disconnect
response.on( 'close', function() {
if( ! complete ) {
complete = true
var err = new Error( 'connection closed' )
err.origin = 'api'
cb( err )
}
})
})
// no endless waiting
request.setTimeout( app.timeout, function() {
if( ! complete ) {
complete = true
var err = new Error('request timeout')
err.origin = 'request'
cb( err )
request.destroy()
}
})
// connection error
request.on( 'error', function( error ) {
if( ! complete ) {
complete = true
var err = new Error( 'connection error' )
err.origin = 'request'
err.details = error
cb( err )
}
})
// perform and finish request
request.end()
}
app.talk = function (path, fields, cb, oldJsonKey) {
var complete = false;
// fix callback
if (!cb && typeof fields === 'function') {
cb = fields;
fields = {};
}
// fix fields
if (!fields || typeof fields !== 'object') {
fields = {};
}
// force JSON-C and version
fields.alt = oldJsonKey ? 'json' : 'jsonc';
fields.v = 2;
// prepare
var options = {
hostname: 'gdata.youtube.com',
path: '/'+ path +'?'+ querystring.stringify (fields),
headers: {
'User-Agent': 'youtube-feeds.js (https://github.com/fvdm/nodejs-youtube)',
'Accept': 'application/json',
'GData-Version': '2'
},
method: 'GET'
};
// use X-GData-Key instead of adding it to the url, as per http://goo.gl/HEiCj
// basically more secure in headers than in query string
if (fields.key || app.developerKey) {
options.headers['X-GData-Key'] = 'key=' + (fields.key || app.developerKey);
delete fields.key;
}
var http = require ('http');
if (app.httpProtocol === 'https') {
http = require ('https');
}
var request = http.request (options);
// response
request.on ('response', function (response) {
var data = [];
var size = 0;
response.on ('data', function (chunk) {
data.push (chunk);
size += chunk.length;
});
response.on ('end', function () {
if (complete) {
return;
} else {
complete = true;
}
// process buffer and clear mem
data = new Buffer.concat (data, size).toString ('utf8').trim ();
var error = null;
// validate
if (data.match (/^(\{.*\}|\[.*\])$/)) {
// ok
data = JSON.parse (data);
if (data.data) {
data = data.data;
} else if (data.error) {
complete = true;
error = new Error ('error');
error.origin = 'api';
error.details = data.error;
} else if (oldJsonKey) {
if (!data[oldJsonKey]) {
complete = true;
error = new Error ('invalid response');
error.origin = 'api';
} else {
data = data[oldJsonKey];
}
}
} else if (data.match (/^<errors .+<\/errors>$/) || data.match (/^<\?xml version.+<\/errors>$/)) {
data = xml2json.parser (data);
// fix for JSONC compatibility
complete = true;
error = new Error ('error');
error.origin = 'api';
error.details = data.errors.error ? [data.errors.error] : data.errors;
error.details.forEach (function (err, errk) {
if (err.internalreason) {
error.details[errk].internalReason = err.internalreason;
delete error.details[errk].internalreason;
}
});
} else if (data.match (/<H2>Error /)) {
// html error response
complete = true;
error = new Error ('error');
data.replace (/<H1>([^<]+)<\/H1>\n<H2>Error (\d+)<\/H2>/, function (s, reason, code) {
error.origin = 'api';
error.details = {
internalReason: reason,
code: code
};
});
} else {
// not json
complete = true;
error = new Error ('not json');
error.origin = 'api';
}
// parse error
if (error && error.origin === 'api' && error.message === 'error') {
var errorDetails = error.details;
if (error.details[0] && error.details[0].code && error.details[0].code === 'ResourceNotFoundException') {
complete = true;
error = new Error ('not found');
error.origin = 'method';
error.details = errorDetails;
} else if (error.details.code === 403) {
complete = true;
error = new Error ('not allowed');
error.origin = 'method';
error.details = errorDetails;
} else if (error.details.message === 'Invalid id') {
complete = true;
error = new Error ('invalid id');
error.origin = 'method';
error.details = errorDetails;
} else if (error.details[0] && error.details[0].internalReason === 'Developer key required for this operation') {
complete = true;
error = new Error ('developer key missing');
error.origin = 'api';
error.details = errorDetails;
}
}
// parse response
if (typeof data.totalItems !== 'undefined' && data.totalItems === 0) {
complete = true;
error = new Error ('not found');
error.origin = 'method';
} else if (data.feed && data.feed.openSearch$totalResults && data.feed.openSearch$totalResults.$t && data.feed.openSearch$totalResults.$t === 0) {
complete = true;
error = new Error ('not found');
error.origin = 'method';
}
// do callback
cb (error, data);
});
// early disconnect
response.on ('close', function () {
if (!complete) {
complete = true;
var err = new Error ('connection closed');
err.origin = 'api';
cb (err);
}
});
});
// no endless waiting
request.setTimeout (parseInt (app.timeout), function () {
if (!complete) {
complete = true;
var err = new Error ('request timeout');
err.origin = 'request';
cb (err);
request.destroy ();
}
});
// connection error
request.on ('error', function (error) {
if (!complete) {
complete = true;
var err = new Error ('connection error');
err.origin = 'request';
err.details = error;
cb (err);
}
});
// perform and finish request
request.end();
};
// ready
module.exports = app
module.exports = app;
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc