├── .gitattributes ├── .gitignore ├── .jshintrc ├── gulpfile.js ├── package.json ├── licence.md ├── tools └── accessTokenGenerator.js ├── readme.md └── lib └── index.js /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "curly": true, 3 | "strict": true, 4 | "indent": 2, 5 | "white": true, 6 | "node": true, 7 | "undef": true, 8 | "unused": true, 9 | "-W058": true, 10 | "-W014": true, 11 | "expr": true 12 | } -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var jshint = require('gulp-jshint'); 3 | 4 | gulp.task('lint', function() { 5 | return gulp.src('./lib/*.js') 6 | .pipe(jshint()) 7 | .pipe(jshint.reporter('jshint-stylish')); 8 | }); 9 | 10 | gulp.task("default", ["lint"], function() { 11 | gulp.watch("./lib/*.js", ["lint"]); 12 | }); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-genius", 3 | "version": "1.1.0", 4 | "description": "Node client for the Genius API", 5 | "main": "lib/index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/alexbooker/node-genius" 9 | }, 10 | "bugs": { 11 | "url": "https://github.com/alexbooker/node-genius/issues" 12 | }, 13 | "keywords": [ 14 | "Genius" 15 | ], 16 | "author": "Alex Booker ", 17 | "license": "MIT", 18 | "bugs": { 19 | "url": "https://github.com/alexbooker/node-genius/issues" 20 | }, 21 | "devDependencies": { 22 | "gulp": "^3.9.0", 23 | "gulp-jshint": "^1.11.0", 24 | "jshint-stylish": "^2.0.0", 25 | "express": "^4.12.4" 26 | }, 27 | "dependencies": { 28 | "request": "^2.57.0" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /licence.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Alex Booker 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /tools/accessTokenGenerator.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | var request = require("request"); 3 | 4 | var app = express(); 5 | 6 | var config = { 7 | clientId: "M91xLW_uPOqkP3Mkkf4gQ7QbPV5DjQ_U0w61xaAIPo5JChlNXxIRQHjRKPYhERtD", 8 | redirectUri: "http://localhost:3000/callback", 9 | scope: "vote create_annotation manage_annotation me", 10 | clientSecret: process.env.GENIUS_CLIENT_SECRET 11 | }; 12 | 13 | app.get("/", function(request, response) { 14 | var authUrl = "https://api.genius.com/oauth/authorize?client_id=" + config.clientId + 15 | "&redirect_uri=" + config.redirectUri + 16 | "&scope=" + config.scope + 17 | "&state=&response_type=code"; 18 | response.redirect(authUrl); 19 | }); 20 | 21 | 22 | app.get("/callback", function (req, res) { 23 | 24 | var options = { 25 | url: "https://api.genius.com/oauth/token", 26 | form: { 27 | code: req.query.code, 28 | client_secret: process.env.GENIUS_CLIENT_SECRET, 29 | grant_type: "authorization_code", 30 | client_id: config.clientId, 31 | redirect_uri: config.redirectUri, 32 | response_type: "code" 33 | } 34 | }; 35 | 36 | request.post(options, function (error, response) { 37 | console.log("Status code:", response.statusCode); 38 | if (response.statusCode > 399) { 39 | console.log("Whops. Something weng wrong. What does the status code indiciate? If it is a 401, your client secret is probably invalid"); 40 | } else { 41 | console.log(response.statusCode); 42 | var body = JSON.parse(response.body); 43 | console.log(body.access_token); 44 | } 45 | }) 46 | }); 47 | 48 | app.listen(3000, function() { 49 | console.log("This is a tool used to attain a Genius access token for testing purposes.") 50 | console.log("All you need to do is, go to http://localhost:3000/ and authenticate. Your access token will then appear in this console."); 51 | }); 52 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ![](http://images.rapgenius.com/bdba3ee0c5a1e954cdc3668f4c6a72a7.1000x238x1.png) 2 | 3 | *Node client for the [**Genius API**](https://docs.genius.com/).* 4 | 5 | ##Installation 6 | 7 | ``` 8 | $ npm install --save node-genius 9 | ``` 10 | 11 | ##Usage 12 | 13 | ```JavaScript 14 | // Instantiate a Genius instance: 15 | var Genius = require("node-genius"); 16 | var geniusClient = new Genius(process.env.GENIUS_ACCESS_TOKEN); 17 | 18 | // Call functions on that instance: 19 | geniusClient.getSong("378195", function (error, song) { 20 | if (error) 21 | console.error("Whops. Something went wrong:", error); 22 | else 23 | console.log("Hoorah. Here is the song: ", song); 24 | }); 25 | ``` 26 | 27 | ##Examples 28 | ```JavaScript 29 | var Genius = require("node-genius"); 30 | var geniusClient = new Genius(process.env.GENIUS_ACCESS_TOKEN); 31 | 32 | // Look up an annotation. 33 | geniusClient.getAnnotation("6737668", function (error, annotation) { 34 | }); 35 | 36 | // Create an annotation. 37 | geniusClient.createAnnotation({ 38 | "annotation": { 39 | "body": { 40 | "markdown": "Genius is **awesome!**" 41 | } 42 | }, 43 | "referent": { 44 | "raw_annotatable_url": 45 | "http://genius.com/Marianne-moore-marriage-annotated", 46 | "fragment": "out of respect for which" 47 | } 48 | }, function(error, annotation) { 49 | 50 | }); 51 | 52 | // Update an annotation. 53 | geniusClient.updateAnnotation("123", { 54 | "annotation": { 55 | "body": { 56 | "markdown": "This is an updated annotation" 57 | } 58 | } 59 | }, function(error, annotation) { 60 | 61 | }); 62 | 63 | // Permanently delete an annotation. 64 | geniusClient.deleteAnnotation("123", function (error, response) { 65 | }); 66 | 67 | // Upvote an annotation. 68 | geniusClient.upvoteAnnotation("6737668", function (error, response) { 69 | }); 70 | 71 | // Removes vote (up or down) for the annotation. 72 | geniusClient.unvoteAnnotation("6737668", function (error, response) { 73 | }); 74 | 75 | // Downvote an annotation. 76 | geniusClient.downvoteAnnotation("6737668", function (error, response) { 77 | }); 78 | 79 | // Look up a song. 80 | geniusClient.getSong("378195", function (error, song) { 81 | }); 82 | 83 | // Look up an artist. 84 | geniusClient.getArtist("16775", {"text_format": "plain"}, function (error, artist) { 85 | }); 86 | 87 | // Look up songs by the given artist. 88 | geniusClient.getArtistSongs("16775", {"page": "1", "per_page": "10"}, 89 | function (error, songs) { 90 | }); 91 | 92 | // Look up an album. 93 | geniusClient.getAlbum("104614", function (error, album) { 94 | }); 95 | 96 | // Look up all referents/annotations for a song. 97 | geniusClient.getReferents({"song_id": "378195", "text_format": "plain"}, function (error, results) { 98 | }); 99 | 100 | // Search Genius. 101 | geniusClient.search("Kendrick Lamar", function (error, results) { 102 | }); 103 | 104 | // Look up a web page to which annotations may be attached. 105 | geniusClient.getWebPage({"raw_annotatable_url": "https://docs.genius.com"}, 106 | function(error, page) { 107 | }); 108 | 109 | // Look up information about the currently authenticated user. 110 | geniusClient.getMe(function (error, account) { 111 | }); 112 | 113 | ``` 114 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var request = require("request"); 4 | 5 | function Genius(accessToken) { 6 | 7 | if (!accessToken) { 8 | throw new Error("You need to supply an access token."); 9 | } 10 | 11 | function _makeRequest(options, callback) { 12 | var baseRequest = request.defaults({ 13 | baseUrl: "https://api.genius.com", 14 | headers: { "Authorization": "Bearer " + accessToken } 15 | }); 16 | 17 | baseRequest(options, function(error, response) { 18 | if (response.statusCode > 399) { 19 | callback(response.body); 20 | return; 21 | } 22 | callback(null, response.body); 23 | }); 24 | } 25 | 26 | /** 27 | * Search genius.com. 28 | * @param {String} query The term to search for. 29 | * @param {Function} callback The function to call once the search results 30 | * are available. 31 | * @see https://docs.genius.com/#search-h2 32 | * @example 33 | * search("Kendrick Lamar", function (error, searchResults) { }); 34 | */ 35 | this.search = function(query, callback) { 36 | var request = { 37 | url: "/search", 38 | qs: { "q": query } 39 | }; 40 | _makeRequest(request, callback); 41 | }; 42 | 43 | /** 44 | * Look up an artist. 45 | * @param {String} artistId The artist's id. 46 | * @param {Object} options The possible options e.g. text_format. 47 | * @param {Function} callback The function to call once the artist data is 48 | * available. 49 | * @see https://docs.genius.com/#artists-h2 50 | * @example 51 | * getArtist("16775", function (error, artist) { }); 52 | */ 53 | this.getArtist = function(artistId, options, callback) { 54 | if (typeof options === "function") { 55 | callback = options; 56 | } 57 | 58 | var request = { 59 | url: "artists/" + artistId, 60 | qs: options 61 | }; 62 | _makeRequest(request, callback); 63 | }; 64 | 65 | /** 66 | * Look up songs by the given artist. 67 | * @param {String} artistId The artist's id. 68 | * @param {Object} options The possible options e.g text_format, page, 69 | * per_page 70 | * @param {Function} callback The function to call once the collection of 71 | * songs is available. 72 | * @see https://docs.genius.com/#artists-h2 73 | * @example 74 | * getArtistSongs( 75 | * "16775", 76 | * {"page": "1", "per_page": 10}, 77 | * function (error, songs) { }); 78 | */ 79 | this.getArtistSongs = function(artistId, options, callback) { 80 | if (typeof options === "function") { 81 | callback = options; 82 | } 83 | 84 | var request = { 85 | url: "artists/" + artistId + "/songs", 86 | qs: options 87 | }; 88 | _makeRequest(request, callback); 89 | }; 90 | 91 | /** 92 | * Look up an album on Genius. 93 | * @param {String} albumId The album's id. 94 | * @param {Object} options The possible options e.g. text_format 95 | * @param {Function} callback The function to call once the album data is 96 | * available. 97 | * @example 98 | * getAlbum("104614", function (error, album) { }); 99 | */ 100 | this.getAlbum = function(albumId, options, callback) { 101 | if (typeof options === "function") { 102 | callback = options; 103 | } 104 | 105 | var request = { 106 | url: "albums/" + albumId, 107 | qs: options 108 | }; 109 | _makeRequest(request, callback); 110 | }; 111 | 112 | /** 113 | * Look up a song on Genius. 114 | * @param {String} songId The song's id. 115 | * @param {Object} options The possible options e.g. text_format 116 | * @param {Function} callback The function to call once the song data is 117 | * available. 118 | * @see https://docs.genius.com/#songs-h2 119 | * @example 120 | * getSong("378195", function (error, song) { }); 121 | */ 122 | this.getSong = function(songId, options, callback) { 123 | if (typeof options === "function") { 124 | callback = options; 125 | } 126 | 127 | var request = { 128 | url: "songs/" + songId, 129 | qs: options 130 | }; 131 | _makeRequest(request, callback); 132 | }; 133 | 134 | /** 135 | * Look up all referents/annotations associated with a song on Genius. 136 | * You can pass in song_id, created_by_id, or web_page_id, as well as text_format 137 | * @param {Object} options The possible options e.g. text_format 138 | * @param {Function} callback The function to call once the song data is 139 | * available. 140 | * @see https://docs.genius.com/#referents-h2 141 | * @example 142 | * getReferents({song_id: 378195, text_format: 'plain'}, function (error, song) { }); 143 | */ 144 | this.getReferents = function(options, callback) { 145 | 146 | var request = { 147 | url: "/referents", 148 | qs: options 149 | }; 150 | _makeRequest(request, callback); 151 | } 152 | 153 | /** 154 | * Look up an annotation. 155 | * @param {String} annotationId The annotation's id. 156 | * @param {Object} options The possible options e.g. text_format 157 | * @param {Function} callback The function to call once the annotation is 158 | * available. 159 | * @see https://docs.genius.com/#annotations-h2 160 | * @example 161 | * getAnnotation("6737668", function (error, annotation) { }); 162 | */ 163 | this.getAnnotation = function(annotationId, options, callback) { 164 | if (typeof options === "function") { 165 | callback = options; 166 | } 167 | 168 | var request = { 169 | url: "annotations/" + annotationId, 170 | qs: options 171 | }; 172 | _makeRequest(request, callback); 173 | }; 174 | 175 | /** 176 | * Create an annotation. 177 | * @param {Object} annotation The annotation to create. 178 | * @param {Function} callback The function to call once the annotation has 179 | * been created. 180 | * @see https://docs.genius.com/#annotations-h2 181 | * @example 182 | * createAnnotation({ 183 | * "annotation": { 184 | * "body": { 185 | * "markdown": "Genius is **awesome!**" 186 | * } 187 | * }, 188 | * "referent": { 189 | * "raw_annotatable_url": 190 | * "http://genius.com/Marianne-moore-marriage-annotated", 191 | * "fragment": "out of respect for which" 192 | * } 193 | * }, function (error, createdAnnotation) { }); 194 | */ 195 | this.createAnnotation = function(annotation, callback) { 196 | var request = { 197 | url: "annotations", 198 | json: true, 199 | method: "POST", 200 | body: annotation 201 | }; 202 | _makeRequest(request, callback); 203 | }; 204 | 205 | /** 206 | * Update an annotation. 207 | * @param {Object} annotation The annotation to update. 208 | * @param {Function} callback The function to call once the annotation has 209 | * been updated. 210 | * @see https://docs.genius.com/#annotations-h2 211 | * @example 212 | * createAnnotation({ 213 | * "annotation": { 214 | * "body": { 215 | * "markdown": "This is an updated annotation." 216 | * } 217 | * } 218 | * }, function (error, updatedAnnotation) { }); 219 | */ 220 | this.updateAnnotation = function(annotationId, annotation, callback) { 221 | var request = { 222 | url: "annotations/" + annotationId, 223 | json: true, 224 | method: "PUT", 225 | body: annotation 226 | }; 227 | _makeRequest(request, callback); 228 | }; 229 | 230 | /** 231 | * Permanently delete annotation. 232 | * @param {String} annotationId The annotation's id. 233 | * @param {Function} callback The function to call once the annotation 234 | * has been deleted. 235 | * @see https://docs.genius.com/#annotations-h2 236 | * @example 237 | * deleteAnnotation("123", function (error, response) { }); 238 | */ 239 | this.deleteAnnotation = function (annotationId, callback) { 240 | var request = { 241 | url: "annotations/" + annotationId, 242 | method: "DELETE", 243 | }; 244 | _makeRequest(request, callback); 245 | }; 246 | 247 | /** 248 | * Upvote an annotation. 249 | * @param {String} annotationId The annotation's id. 250 | * @param {Function} callback The function to call once the annotation 251 | * has been upvoted. 252 | * @see https://docs.genius.com/#annotations-h2 253 | * @example 254 | * upvoteAnnotation("6737668", function (error, response) { }); 255 | */ 256 | this.upvoteAnnotation = function (annotationId, callback) { 257 | var request = { 258 | url: "annotations/" + annotationId + "/upvote", 259 | method: "PUT", 260 | }; 261 | _makeRequest(request, callback); 262 | }; 263 | 264 | /** 265 | * Removes vote (up or down) for the annotation. 266 | * @param {String} annotationId The annotation's id. 267 | * @param {Function} callback The function to call once the annotation 268 | * has been unvoted. 269 | * @see https://docs.genius.com/#annotations-h2 270 | * @example 271 | * unvoteAnnotation("6737668", function (error, response) { }); 272 | */ 273 | this.unvoteAnnotation = function (annotationId, callback) { 274 | var request = { 275 | url: "annotations/" + annotationId + "/unvote", 276 | method: "PUT", 277 | }; 278 | _makeRequest(request, callback); 279 | }; 280 | 281 | /** 282 | * Downvote an annotation. 283 | * @param {String} annotationId The annotation's id. 284 | * @param {Function} callback The function to call once the annotation 285 | * has been downvoted. 286 | * @see https://docs.genius.com/#annotations-h2 287 | * @example 288 | * downvoteAnnotation("6737668", function (error, response) { }); 289 | */ 290 | this.downvoteAnnotation = function (annotationId, callback) { 291 | var request = { 292 | url: "annotations/" + annotationId + "/downvote", 293 | method: "PUT", 294 | }; 295 | _makeRequest(request, callback); 296 | }; 297 | 298 | /** 299 | * Look up a web page to which annotations may be attached. 300 | * @param {Object} options The possible options e.g. raw_annotatable_url 301 | * @param {Function} callback The function to call once information about 302 | * the web page is available. 303 | * @see https://docs.genius.com/#web_pages-h2 304 | * @example 305 | * getWebPage({"raw_annotatable_url": "https://docs.genius.com"}, 306 | * function(error, page) {}); 307 | */ 308 | this.getWebPage = function (options, callback) { 309 | var request = { 310 | url: "web_pages/lookup", 311 | qs: options 312 | }; 313 | _makeRequest(request, callback); 314 | }; 315 | 316 | /** 317 | * Look up information about the currently authenticated user. 318 | * @param {Object} options The possible options e.g. text_format 319 | * @param {Function} callback The function to call once information about 320 | * the user is available. 321 | * @see https://docs.genius.com/#account-h2 322 | * @example 323 | * getMe(function(error, accountData) { }); 324 | */ 325 | this.getMe = function (options, callback) { 326 | if (typeof options === "function") { 327 | callback = options; 328 | } 329 | 330 | var request = { 331 | url: "account", 332 | qs: options 333 | }; 334 | _makeRequest(request, callback); 335 | }; 336 | } 337 | 338 | module.exports = Genius; 339 | --------------------------------------------------------------------------------