UNPKG

freesound-client

Version:

![Test](https://github.com/amilajack/freesound-client/workflows/Test/badge.svg) [![NPM version](https://badge.fury.io/js/freesound-client.svg)](http://badge.fury.io/js/freesound-client) [![npm](https://img.shields.io/npm/dm/freesound-client.svg)](https://

504 lines 19.5 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); /** * There are three kinds of tokens: * 1. Auth tokens * 2. Access tokens * 3. Refresh tokens * * Auth tokens expire after 10 minutes. They can be used to get access tokens * Access tokens expire after 24hrs * Access token relates your application with the user that has logged in. */ const node_fetch_1 = __importDefault(require("node-fetch")); const form_data_1 = __importDefault(require("form-data")); const url_1 = require("url"); // A hack that prevents the 'TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation' issue const fetch = node_fetch_1.default; ; ; class FreeSound { constructor() { this.authHeader = ''; this.clientId = ''; this.clientSecret = ''; this.host = 'freesound.org'; this.uris = { base: `https://${this.host}/apiv2`, textSearch: '/search/text/', contentSearch: '/search/content/', combinedSearch: '/search/combined/', sound: '/sounds/<sound_id>/', soundAnalysis: '/sounds/<sound_id>/analysis/', similarSounds: '/sounds/<sound_id>/similar/', comments: '/sounds/<sound_id>/comments/', download: '/sounds/<sound_id>/download/', upload: '/sounds/upload/', describe: '/sounds/<sound_id>/describe/', pending: '/sounds/pending_uploads/', bookmark: '/sounds/<sound_id>/bookmark/', rate: '/sounds/<sound_id>/rate/', comment: '/sounds/<sound_id>/comment/', authorize: '/oauth2/authorize/', logout: '/api-auth/logout/', logoutAuthorize: '/oauth2/logout_and_authorize/', me: '/me/', user: '/users/<username>/', userSounds: '/users/<username>/sounds/', userPacks: '/users/<username>/packs/', userBookmarkCategories: '/users/<username>/bookmark_categories/', userBookmarkCategorySounds: '/users/<username>/bookmark_categories/<category_id>/sounds/', pack: '/packs/<pack_id>/', packSounds: '/packs/<pack_id>/sounds/', packDownload: '/packs/<pack_id>/download/', // @TODO // edit: '' }; } checkOauth() { // @TODO: Support node if (typeof window !== 'object') { throw new Error('OAuth is not supported in Node'); } if (!this.authHeader.includes('Bearer')) { throw new Error('Oauth authentication required'); } } makeFormData(obj, prevFormData) { const formData = prevFormData ? prevFormData : new form_data_1.default(); for (const prop in obj) { formData.append(prop, obj[prop]); } return formData; } search(options, uri) { if (options.analysis_file) { return this.makeRequest(this.makeUri(uri), 'POST', this.makeFormData(options)); } return this.makeRequest(this.makeUri(uri), 'GET', options); } Collection(oldJsonObject) { const nextOrPrev = (which) => this.makeRequest(which).then(this.Collection); const nextPage = () => nextOrPrev(oldJsonObject.next); const previousPage = () => nextOrPrev(oldJsonObject.previous); const getItem = (idx) => oldJsonObject.results[idx]; return { ...oldJsonObject, getItem, nextOrPrev, previousPage, nextPage }; } SoundCollection(jsonObject) { const collection = this.Collection(jsonObject); return { ...collection, getSound: idx => this.SoundObject(collection.results[idx]) }; } PackCollection(jsonObject) { const collection = this.Collection(jsonObject); return { ...collection, getPack: (idx) => this.PackObject(collection.results[idx]) }; } SoundObject(oldJsonObject) { const jsonObject = { ...oldJsonObject }; const getAnalysis = (filter) => this.makeRequest(this.makeUri(this.uris.soundAnalysis, [jsonObject.id, filter || ''])); const getSimilar = (params = {}) => this.makeRequest(this.makeUri(this.uris.similarSounds, [jsonObject.id]), 'GET', params).then(e => this.SoundCollection(e)); // @TODO const getComments = () => this.makeRequest(this.makeUri(this.uris.comments, [jsonObject.id]), 'GET'); const download = () => { // can be window, new, or iframe this.checkOauth(); const uri = this.makeUri(this.uris.download, [jsonObject.id]); return this.fetchWithAuthParams(uri); }; // @TODO // const comment = () => { // this.checkOauth(); // const data = new FormData(); // data.append('comment', this.comment); // const uri = this.makeUri(this.uris.comment, [jsonObject.id]); // return this.makeRequest(uri, 'POST', data); // }; const rate = (rating) => { this.checkOauth(); const data = new form_data_1.default(); data.append('rating', rating); const uri = this.makeUri(this.uris.rate, [jsonObject.id]); return this.makeRequest(uri, 'POST', data); }; const bookmark = (name, category) => { this.checkOauth(); const data = new form_data_1.default(); data.append('name', name); if (category) { data.append('category', category); } const uri = this.makeUri(this.uris.bookmark, [jsonObject.id]); return this.makeRequest(uri, 'POST', data); }; // @TODO // const edit = (description: { description: string }) => { // this.checkOauth(); // const data = this.makeFormData(description); // const uri = this.makeUri(this.uris.edit, [jsonObject.id]); // return this.makeRequest(uri, 'POST', data); // }; return { ...jsonObject, getAnalysis, getSimilar, download, rate, getComments, bookmark, }; } UserObject(oldJsonObject) { const jsonObject = { ...oldJsonObject }; const sounds = (params = {}) => { const uri = this.makeUri(this.uris.userSounds, [jsonObject.username]); return this.makeRequest(uri, 'GET', params).then(e => this.SoundCollection(e)); }; const packs = () => { const uri = this.makeUri(this.uris.userPacks, [jsonObject.username]); return this.makeRequest(uri).then(e => this.PackCollection(e)); }; const bookmarkCategories = () => { const uri = this.makeUri(this.uris.userBookmarkCategories, [ jsonObject.username ]); return this.makeRequest(uri); }; const bookmarkCategorySounds = (params = {}) => { const uri = this.makeUri(this.uris.userBookmarkCategorySounds, [ jsonObject.username ]); return this.makeRequest(uri, 'GET', params); }; return { ...jsonObject, sounds, packs, bookmarkCategories, bookmarkCategorySounds }; } PackObject(oldJsonObject) { const jsonObject = { ...oldJsonObject }; const sounds = (options = {}) => { const uri = this.makeUri(this.uris.packSounds, [jsonObject.id]); return this.makeRequest(uri, 'GET', options).then(e => this.SoundCollection(e)); }; const download = () => { // can be current or new window, or iframe this.checkOauth(); const uri = this.makeUri(this.uris.packDownload, [jsonObject.id]); return this.fetchWithAuthParams(uri); }; return { ...jsonObject, sounds, download }; } /** * * There are two ways of authenticating: OAuth and token method. * The OAuth method is required for more privilidged actions such as * downloading sounds. * * This method can set both kinds of tokens * * ```typescript * await freeSound.setToken('your-api-key', 'oauth'); * ``` */ setToken(token, type) { this.authHeader = `${type === 'oauth' ? 'Bearer' : 'Token'} ${token}`; return this.authHeader; } /** * Set the credentials supplied by https://freesound.org/apiv2/apply for API * call authentication. See * https://freesound.org/docs/api/authentication.html?highlight=secret#token-authentication * for more information. * * @param id your client ID, obtainable at https://freesound.org/apiv2/apply * @param secret your client secret, obtainable at https://freesound.org/apiv2/apply * * ```typescript * await freeSound.setClientSecrets( * "your-client-id", * "your-secret-key" * ); * ``` */ setClientSecrets(id, secret) { this.clientId = id; this.clientSecret = secret; } /** * This method allows you to get a new token using a refresh token or an auth * token * * ```typescript * await freeSound.postAccessCode('your-temporary-code-from-login'); * ``` */ postAccessCode(token, type = 'auth') { const postUrl = `${this.uris.base}/oauth2/access_token/`; const data = new form_data_1.default(); data.append('client_id', this.clientId); data.append('client_secret', this.clientSecret); const tokenType = type === 'auth' ? 'code' : 'refresh_token'; data.append(tokenType, token); const grantType = type === 'auth' ? 'authorization_code' : 'refresh_token'; data.append('grant_type', grantType); return this.makeRequest(postUrl, 'POST', data); } /** * Search sounds in Freesound by matching their tags and other kinds of metadata. See * https://freesound.org/docs/api/resources_apiv2.html#sound-text-search for more * information. * * ```typescript * await freeSound.textSearch('violoncello', { * page: 1, * filter: 'tag:tenuto duration:[1.0 TO 15.0]', * sort: 'rating_desc', * fields: 'id,name,url' * }); * ``` */ textSearch(query, opts = {}) { const options = { ...opts }; options.query = query || ' '; return this.search(options, this.uris.textSearch).then(e => this.SoundCollection(e)); } /** * Search sounds in Freesound based on their content descriptors. See * https://freesound.org/docs/api/resources_apiv2.html#content-search * for more information. * * ```typescript * const result = await freeSound.contentSearch({ * target: 'lowlevel.pitch.mean:220', * }); * ``` */ contentSearch(options) { if (!(options.target || options.analysis_file || options.descriptors_filter)) { throw new Error('Missing target or analysis_file'); } return this.search(options, this.uris.contentSearch).then(e => this.SoundCollection(e)); } /** * Search sounds in Freesound based on their tags, metadata and content-based descriptiors via * a combination of text search and content search. See * https://freesound.org/docs/api/resources_apiv2.html#combined-search for more information. * * ```typescript * const soundCollectionResults = await freeSound.combinedSearch( * filter: 'tag:scale', * target: 'rhythm.bpm:120', * ); * ``` */ combinedSearch(options) { if (!(options.target || options.query || options.descriptors_filter || options.target || options.filter)) { throw new Error('Missing target, query, descriptors_filter, target, filter, or analysis_file'); } return this.search(options, this.uris.combinedSearch); } /** * Upload an audio file into Freesound and optionally describe it. * If there is no file description, only the audio file will upload, and * the user will need to add a description later using * the describe(description: { description: string }) method. If the file description * is present, the uploaded file will be ready for the processing and moderation stage. * A list of uploaded files pending a description, processing or moderation is * obtainable through the getPendingSounds() method. See * https://freesound.org/docs/api/resources_apiv2.html#upload-sound-oauth2-required * for more information. This method requires OAuth2 authentication. * * @param audiofile the audio file to upload * @param filename the name of the audio file to upload * @param description the description of the audio file to upload */ upload(audiofile, filename, description) { this.checkOauth(); let formData = new form_data_1.default(); formData.append('audiofile', audiofile, filename); if (description) { formData = this.makeFormData(description, formData); } return this.makeRequest(this.makeUri(this.uris.upload), 'POST', formData); } /** * Describe a previously uploaded file that does not have a description. * Note: after a sound receives a description, the team of Freesound moderators * still needs to process and moderate it, so it may not yet appear in Freesound. * A list of sounds uploaded and described by the user, but still * pending processing and moderation, is viewable with * the getPendingSounds() method. This method requires OAuth2 authentication. See * https://freesound.org/docs/api/resources_apiv2.html#describe-sound-oauth2-required * for more information. * * @param description a description for an uploaded sound */ describe(description) { this.checkOauth(); const formData = this.makeFormData(description); return this.makeRequest(this.makeUri(this.uris.upload), 'POST', formData); } /** * Retrieve a list of audio files uploaded by he Freesound user logged in using * OAuth2 are not described, processed or moderated. In Freesound, sounds need * descriptions after their upload. Then, sounds are automatically processed, and, * finally, a team of human moderators either accepts or rejects the upload. This method * keeps track of the status of these uploads and requires OAuth2 authentication. See * https://freesound.org/docs/api/resources_apiv2.html#pending-uploads-oauth2-required * for more information. * * ```typescript * const result = await freeSound.getPendingSounds() * ``` */ getPendingSounds() { this.checkOauth(); return this.makeRequest(this.makeUri(this.uris.pending)); } /** * Return basic information about the user that is logged in via OAuth2. * This application can use it to identify which Freesound user has logged in. * * ```typescript * const result = await freeSound.me(); * ``` */ me() { this.checkOauth(); return this.makeRequest(this.makeUri(this.uris.me)); } /** * Navigate to Freesound for user login. * * @returns a url where the user can login * * ```typescript * const navigateToLogin = () => { * window.location.replace(freeSound.getLoginURL()); * }; * ``` */ getLoginURL() { if (!this.clientId) throw new Error('client_id was not set'); let loginUrl = this.makeUri(this.uris.authorize); loginUrl += `?client_id=${this.clientId}&response_type=code`; return loginUrl; } getLogoutURL() { let logoutUrl = this.makeUri(this.uris.logoutAuthorize); logoutUrl += `?client_id=${this.clientId}&response_type=code`; return logoutUrl; } /** * Retrieve information about a particular Freesound user. See * https://freesound.org/docs/api/resources_apiv2.html#user-instance * for more information. * * @param username the username of the Freesound user * @returns information about a particular Freesound user * * ```typescript * // Get information about the user https://freesound.org/people/MTG/. * const user = await freeSound.getUser('MTG'); * ``` */ getUser(username) { return this.makeRequest(this.makeUri(this.uris.user, [username])).then(e => this.UserObject(e)); } /** * Retrieve the list of sounds included in a pack. See * https://freesound.org/docs/api/resources_apiv2.html#pack-sounds for more information. * * @param packId the identification number of the pack to fetch * @returns a list of sounds included in the pack that has packId as its identification number * * ```typescript * // Fetch the pack * // https://freesound.org/people/vroomvro0om/packs/21143/. * const packObj = await freeSound.getPack(21143); * ``` */ async getPack(packId, options = {}) { const pack = await this.makeRequest(this.makeUri(this.uris.pack, [packId]), 'GET', options); return this.PackObject(pack); } /** * Retrieve detailed information about a sound. See * https://freesound.org/docs/api/resources_apiv2.html#sound-resources * for more information. * * @param soundId the identification number of the sound * @returns detailed information about a sound * * ```typescript * // Fetch the sound * // https://freesound.org/people/vroomvro0om/sounds/376626/. * const fetchedSound = await freeSound.getSound(376626); * ``` */ async getSound(soundId) { const sound = await this.makeRequest(this.makeUri(this.uris.sound, [soundId])); return this.SoundObject(sound); } makeUri(uri, args) { let newUri = String(uri); if (args) { args.forEach(element => { newUri = newUri.replace(/<[\w_]+>/, String(element)); }); } return this.uris.base + newUri; } async fetchWithAuthParams(uri, method = 'GET', params = {}) { const IsoURLSearchParams = typeof window === 'object' ? URLSearchParams : url_1.URLSearchParams; return fetch(params ? `${uri}?${new IsoURLSearchParams(params).toString()}` : uri, { method, headers: { Authorization: this.authHeader } }); } async makeRequest(uri, method = 'GET', params = {}) { return this.fetchWithAuthParams(uri, method, params) .then(res => res.json()) .then(res => { if (res.error) { throw new Error(res.error); } if (res.detail === 'Authentication credentials were not provided') { throw new Error(res.detail); } return res; }); } } exports.default = FreeSound; //# sourceMappingURL=index.js.map