diff --git a/.gitignore b/.gitignore index fbd9508..f51d0b2 100644 --- a/.gitignore +++ b/.gitignore @@ -36,4 +36,5 @@ jspm_packages # Optional REPL history .node_repl_history +.env lib diff --git a/.travis.yml b/.travis.yml index 8db3658..deb0426 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,18 @@ language: node_js node_js: - - "4" - - "5" - "6" - "7" + - "8" # Use container-based Travis infrastructure. sudo: false +env: + global: + - FANART_API_KEY=d9e25d5beda1027a1674c1585882309e + - THEAUDIODB_API_KEY=1 + branches: only: - master diff --git a/README.md b/README.md index 015162b..e027611 100644 --- a/README.md +++ b/README.md @@ -16,9 +16,11 @@ npm install graphbrainz --save **[Try out the live demo!][demo]** :bulb: Use the “Docs” sidebar, the [schema][], or the [types][] docs to help construct your query. +## Contents + -## Contents + - [Usage](#usage) - [As a standalone server](#as-a-standalone-server) @@ -30,6 +32,7 @@ npm install graphbrainz --save - [Pagination](#pagination) - [Questions](#questions) - [Schema](#schema) + - [Extending the schema](#extending-the-schema) @@ -101,14 +104,12 @@ GraphBrainz resolvers expect, like so: ```js import { graphql } from 'graphql'; -import { MusicBrainz, CoverArtArchive } from 'graphbrainz/api'; -import createLoaders from 'graphbrainz/loaders'; -import schema from 'graphbrainz/schema'; +import { MusicBrainz, CoverArtArchive } from 'graphbrainz/lib/api'; +import createContext from 'graphbrainz/lib/context'; +import schema from 'graphbrainz/lib/schema'; const client = new MusicBrainz(); -const coverArtClient = new CoverArtArchive(); -const loaders = createLoaders(client, coverArtClient); -const context = { client, coverArtClient, loaders }; +const context = createContext({ client }) graphql(schema, ` { @@ -142,6 +143,8 @@ graphql(schema, ` day). * **`GRAPHBRAINZ_GRAPHIQL`**: Set this to `true` if you want to force the [GraphiQL][] interface to be available even in production mode. +* **`GRAPHBRAINZ_EXTENSIONS`**: A JSON array of module paths to load as + [extensions](./docs/extensions). * **`PORT`**: Port number to use, if running the standalone server. When running the standalone server, [dotenv][] is used to load these variables @@ -361,7 +364,14 @@ GraphBrainz to use that with no rate limiting. ## Schema -See the [GraphQL schema][schema] or the [types][] documentation. +The [types][] document is the easiest to browse representation of the schema, or +you can read the [schema in GraphQL syntax][schema]. + +### Extending the schema + +The GraphBrainz schema can easily be extended to add integrations with +third-party services. See the [Extensions](./docs/extensions) docs for more +info. [demo]: https://graphbrainz.herokuapp.com/ [Express]: http://expressjs.com/ diff --git a/circle.yml b/circle.yml index 0a691f4..1db357f 100644 --- a/circle.yml +++ b/circle.yml @@ -1,4 +1,3 @@ machine: node: - version: 4.6.0 - + version: 6.0.0 diff --git a/docs/extensions/README.md b/docs/extensions/README.md new file mode 100644 index 0000000..d5a2aab --- /dev/null +++ b/docs/extensions/README.md @@ -0,0 +1,227 @@ +# Extensions + +It is possible to extend the GraphBrainz schema to add integrations with +third-party services that provide more information about MusicBrainz entities. +Extensions can define new GraphQL types and use the `extend type` syntax to add +new fields to any existing GraphBrainz type, including the root query. + +Several extensions are included by default, and you can install any number of +additional extensions from a package manager or [write your own](#extension-api). + +## Contents + + + + + +- [Loading Extensions](#loading-extensions) +- [Built-in Extensions](#built-in-extensions) +- [Extension API](#extension-api) + - [Properties](#properties) + - [name](#name) + - [description](#description) + - [extendContext](#extendcontext) + - [extendSchema](#extendschema) + - [Example](#example) +- [Extension Guidelines](#extension-guidelines) + + + +## Loading Extensions + +The extensions to load are specified using the `extensions` option to the +exported `graphbrainz()` middleware function. Each extension must be an object +conforming to the [Extension API](#extension-api), or the path to a module to +load via `require()` that exports such an object. + +If you are running GraphBrainz as a standalone server, you may specify +extensions via the `GRAPHBRAINZ_EXTENSIONS` environment variable, which will be +parsed as a JSON array. For example: + +```console +$ export GRAPHBRAINZ_EXTENSIONS='["graphbrainz/extensions/fanart-tv"]' +$ graphbrainz +``` + +Note that some extensions may require additional configuration via extra options +or environment variables. Check the documentation for each extension you use. + +The default value of the `extensions` option looks like this: + +```js +[ + 'graphbrainz/extensions/cover-art-archive', + 'graphbrainz/extensions/fanart-tv', + 'graphbrainz/extensions/mediawiki', + 'graphbrainz/extensions/the-audio-db' +] +``` + +## Built-in Extensions + +The following extensions are included with GraphBrainz and loaded by default. +See their respective documentation pages for schema info and config options. + +* [Cover Art Archive](./cover-art-archive.md): Retrieve cover art images for + releases from the Cover Art Archive. +* [fanart.tv](./fanart-tv.md): Retrieve high quality artwork for artists, + releases, and labels from fanart.tv. +* [MediaWiki](./mediawiki.md): Retrieve information from MediaWiki image pages, + like the actual image file URL and EXIF metadata. +* [TheAudioDB](./the-audio-db): Retrieve images and information about artists, + releases, and recordings from TheAudioDB.com. + +## Extension API + +The core idea behind extensions comes from the [schema stitching][] feature +from [graphql-tools][], although GraphBrainz does not currently use the exact +technique documented there. Instead, we call `parse` and `extendSchema` from +[GraphQL.js][], followed by [addResolveFunctionsToSchema][]. + +Extensions must export an object shaped like so: + +```js +type Extension = { + name: string, + description?: string, + extendContext?: (context: Context, options: Options) => Context, + extendSchema?: + { schemas: Array, resolvers: ResolverMap } | + (schema: GraphQLSchema, options: Options) => GraphQLSchema +} +``` + +### Properties + +#### name + +The name of the extension. + +#### description + +A description of the functionality that the extension provides. + +#### extendContext + +An optional function that accepts a base context object (the `context` argument +available to resolver functions) and returns a new context object. Extensions +that access third-party APIs should add any API client instances they need here. +The recommended way is to create a loader with [dataloader][] and add it onto +`context.loaders`. + +#### extendSchema + +An optional object or function to extend the GraphBrainz schema. + +If it is an object, it should have a `schemas` array and a `resolvers` object. +Each schema must be a string (containing type definitions in GraphQL schema +language) or a `DocumentNode` (if the type definitions have already been +parsed). The `resolvers` object should contain a mapping of type fields to new +resolver functions for those fields. See [addResolveFunctionsToSchema][]. + +If it is a function, it should accept `schema` and `options` arguments and +return a new schema. Use this if you’d like to perform custom schema extension +logic. This may be necessary if you already have a `GraphQLSchema` instance and +want to use [mergeSchemas][], for example. In most cases, you should keep it +simple and use the object form. + +### Example + +```js +module.exports = { + name: 'Hello World', + description: 'A simple example extension.', + extendSchema: { + schemas: [` + extend type Query { + helloWorld: String! + } + `], + resolvers: { + Query: { + helloWorld: { + resolve: () => 'It worked!' + } + } + } + } +} +``` + +This will allow the following query to be made: + +```graphql +{ + helloWorld +} +``` + +See the code for the [built-in extensions][] for more examples. + +## Extension Guidelines + +Extensions can load and resolve data in any manner they please, and you can +write them in any way that conforms to the API. But if you want an extra feather +in your cap, there are a few guidelines you should follow in order to maintain +consistency with GraphBrainz and the built-in extensions. Here are some tips +for writing a good extension: + +* If you need to make HTTP requests, using a [Client][] subclass will get you + rate limiting, error handling, and a Promise-based API for free. +* Default to following the rate limiting rules of any APIs you wrap. If there + are no guidelines on rate limiting, consider playing nice anyway and limiting + your client to around 1 to 10 requests per second. +* Use a [DataLoader][dataloader] instance to batch and cache requests. Even if + the data source doesn’t support batching, it will dedupe in-flight requests + for the same key, preventing extra requests before the response has been + cached. +* Use a configurable cache and make sure you aren’t caching everything + indefinitely by accident. The `cacheMap` option to DataLoader is a good place + to put it. +* Get as much configuration from environment variables as possible, so that + people can just run the standalone server instead of writing server code. If + you need more complex configuration, use a single object on the `options` + object as a namespace for your extension’s options. +* Don’t be afraid to rename fields returned by third-party APIs when translating + them to the GraphQL schema. Consistency with GraphQL conventions and the + GraphBrainz schema is more desirable than consistency with the original API + being wrapped. Some general rules: + * Use camel case naming and capitalize acronyms (unless they are the only + word), e.g. `id`, `url`, `artistID`, `pageURL`. + * If it’s ambiguous whether a field refers to an object/list vs. a scalar + summary of an object/list, consider clarifying the field name, e.g. `user` → + `userID`, `members` → `memberCount`. + * Don’t include fields that are already available in MusicBrainz, only include + what’s relevant and useful. +* Add descriptions for everything: types, fields, arguments, enum values, etc. + – with Markdown links wherever they’d be helpful. +* When extending the built-in types, prefer adding a single object field that + serves as a namespace rather than adding many fields. That way it’s more + obvious that the data source isn’t MusicBrainz itself, and you’re less likely + to conflict with new MusicBrainz fields in the future. +* Prefer using a [Relay][]-compliant schema for lists of objects that (1) have + their own IDs and (2) are likely to be paginated. Feel free to add a `nodes` + shortcut field to the Connection type (for users who want to skip over + `edges`). +* If you publish your extension, consider prefixing the package name with + `graphbrainz-extension-` and having the default export of its `main` entry + point be the extension object. That way, using it is as simple as adding the + package name to the list of extensions. +* Consider using [graphql-markdown][] to document the schema created by your + extension; this will match how GraphBrainz itself is documented. You can use + the [diffSchema][] function to document only the schema updates, see + [scripts/build-extension-docs.js][build-extension-docs] for how this is done + with the built-in extensions. + +[graphql-tools]: http://dev.apollodata.com/tools/graphql-tools/index.html +[schema stitching]: http://dev.apollodata.com/tools/graphql-tools/schema-stitching.html +[mergeSchemas]: http://dev.apollodata.com/tools/graphql-tools/schema-stitching.html#mergeSchemas +[dataloader]: https://github.com/facebook/dataloader +[built-in extensions]: ../../src/extensions +[Client]: ../../src/api/client.js +[graphql-markdown]: https://github.com/exogen/graphql-markdown +[diffSchema]: https://github.com/exogen/graphql-markdown#diffschemaoldschema-object-newschema-object-options-object +[build-extension-docs]: ../../scripts/build-extension-docs.js +[Relay]: https://facebook.github.io/relay/ +[GraphQL.js]: http://graphql.org/graphql-js/ +[addResolveFunctionsToSchema]: http://dev.apollodata.com/tools/graphql-tools/resolvers.html#addResolveFunctionsToSchema diff --git a/docs/extensions/cover-art-archive.md b/docs/extensions/cover-art-archive.md new file mode 100644 index 0000000..a7f6846 --- /dev/null +++ b/docs/extensions/cover-art-archive.md @@ -0,0 +1,378 @@ +# Extension: Cover Art Archive + +Retrieve cover art images for releases from the [Cover Art Archive](https://coverartarchive.org/). + +This extension uses its own cache, separate from the MusicBrainz loader cache. + +## Configuration + +This extension can be configured using environment variables: + +* **`COVER_ART_ARCHIVE_BASE_URL`**: The base URL at which to access the Cover + Art Archive API. Defaults to `http://coverartarchive.org/`. +* **`COVER_ART_ARCHIVE_CACHE_SIZE`**: The number of items to keep in the cache. + Defaults to `GRAPHBRAINZ_CACHE_SIZE` if defined, or `8192`. +* **`COVER_ART_ARCHIVE_CACHE_TTL`**: The number of seconds to keep items in the + cache. Defaults to `GRAPHBRAINZ_CACHE_TTL` if defined, or `86400000` (one day). + + +
+ Table of Contents + + * [Objects](#objects) + * [CoverArtArchiveImage](#coverartarchiveimage) + * [CoverArtArchiveImageThumbnails](#coverartarchiveimagethumbnails) + * [CoverArtArchiveRelease](#coverartarchiverelease) + * [Release](#release) + * [ReleaseGroup](#releasegroup) + * [Enums](#enums) + * [CoverArtArchiveImageSize](#coverartarchiveimagesize) + +
+ +## Objects + +### CoverArtArchiveImage + +An individual piece of album artwork from the [Cover Art Archive](https://musicbrainz.org/doc/Cover_Art_Archive). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldArgumentTypeDescription
fileIDString! + +The Internet Archive’s internal file ID for the image. + +
imageURLString! + +The URL at which the image can be found. + +
thumbnailsCoverArtArchiveImageThumbnails! + +A set of thumbnails for the image. + +
frontBoolean! + +Whether this image depicts the “main front” of the release. + +
backBoolean! + +Whether this image depicts the “main back” of the release. + +
types[String]! + +A list of [image types](https://musicbrainz.org/doc/Cover_Art/Types) +describing what part(s) of the release the image includes. + +
editInt + +The MusicBrainz edit ID. + +
approvedBoolean + +Whether the image was approved by the MusicBrainz edit system. + +
commentString + +A free-text comment left for the image. + +
+ +### CoverArtArchiveImageThumbnails + +URLs for thumbnails of different sizes for a particular piece of +cover art. + + + + + + + + + + + + + + + + + + + + + + +
FieldArgumentTypeDescription
smallURLString + +The URL of a small version of the cover art, where the maximum dimension is +250px. + +
largeURLString + +The URL of a large version of the cover art, where the maximum dimension is +500px. + +
+ +### CoverArtArchiveRelease + +An object containing a list of the cover art images for a release obtained +from the [Cover Art Archive](https://musicbrainz.org/doc/Cover_Art_Archive), +as well as a summary of what artwork is available. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldArgumentTypeDescription
frontURLString + + The URL of an image depicting the album cover or “main front” of the release, + i.e. the front of the packaging of the audio recording (or in the case of a + digital release, the image associated with it in a digital media store). + + In the MusicBrainz schema, this field is a Boolean value indicating the + presence of a front image, whereas here the value is the URL for the image + itself if one exists. You can check for null if you just want to determine + the presence of an image. + +
sizeCoverArtArchiveImageSize + +The size of the image to retrieve. By default, the returned image will +have its full original dimensions, but certain thumbnail sizes may be +retrieved as well. + +
backURLString + + The URL of an image depicting the “main back” of the release, i.e. the back + of the packaging of the audio recording. + + In the MusicBrainz schema, this field is a Boolean value indicating the + presence of a back image, whereas here the value is the URL for the image + itself. You can check for null if you just want to determine the presence of + an image. + +
sizeCoverArtArchiveImageSize + +The size of the image to retrieve. By default, the returned image will +have its full original dimensions, but certain thumbnail sizes may be +retrieved as well. + +
images[CoverArtArchiveImage]! + +A list of images depicting the different sides and surfaces of a release’s +media and packaging. + +
artworkBoolean! + +Whether there is artwork present for this release. + +
countInt! + +The number of artwork images present for this release. + +
releaseRelease + +The particular release shown in the returned cover art. + +
+ +### Release + +:small_blue_diamond: *This type has been extended. See the [base schema](../types.md) +for a description and additional fields.* + + + + + + + + + + + + + + + + + +
FieldArgumentTypeDescription
coverArtArchiveCoverArtArchiveRelease + +An object containing a list and summary of the cover art images that are +present for this release from the [Cover Art Archive](https://musicbrainz.org/doc/Cover_Art_Archive). +This field is provided by the Cover Art Archive extension. + +
+ +### ReleaseGroup + +:small_blue_diamond: *This type has been extended. See the [base schema](../types.md) +for a description and additional fields.* + + + + + + + + + + + + + + + + + +
FieldArgumentTypeDescription
coverArtArchiveCoverArtArchiveRelease + +The cover art for a release in the release group, obtained from the +[Cover Art Archive](https://musicbrainz.org/doc/Cover_Art_Archive). A +release in the release group will be chosen as representative of the release +group. +This field is provided by the Cover Art Archive extension. + +
+ +## Enums + +### CoverArtArchiveImageSize + +The image sizes that may be requested at the [Cover Art Archive](https://musicbrainz.org/doc/Cover_Art_Archive). + + + + + + + + + + + + + + + + + + + + +
ValueDescription
SMALL + +A maximum dimension of 250px. + +
LARGE + +A maximum dimension of 500px. + +
FULL + +The image’s original dimensions, with no maximum. + +
diff --git a/docs/extensions/fanart-tv.md b/docs/extensions/fanart-tv.md new file mode 100644 index 0000000..af3c7f7 --- /dev/null +++ b/docs/extensions/fanart-tv.md @@ -0,0 +1,473 @@ +# Extension: fanart.tv + +Retrieve high quality artwork for artists, releases, and labels from [fanart.tv](https://fanart.tv/). + +This extension uses its own cache, separate from the MusicBrainz loader cache. + +## Configuration + +This extension can be configured using environment variables: + +* **`FANART_API_KEY`**: The fanart.tv API key to use. This is required for any + fields added by the extension to successfully resolve. +* **`FANART_BASE_URL`**: The base URL at which to access the + fanart.tv API. Defaults to `http://webservice.fanart.tv/v3/`. +* **`FANART_CACHE_SIZE`**: The number of items to keep in the cache. + Defaults to `GRAPHBRAINZ_CACHE_SIZE` if defined, or `8192`. +* **`FANART_CACHE_TTL`**: The number of seconds to keep items in the + cache. Defaults to `GRAPHBRAINZ_CACHE_TTL` if defined, or `86400000` (one day). + + +
+ Table of Contents + + * [Objects](#objects) + * [Artist](#artist) + * [FanArtAlbum](#fanartalbum) + * [FanArtArtist](#fanartartist) + * [FanArtDiscImage](#fanartdiscimage) + * [FanArtImage](#fanartimage) + * [FanArtLabel](#fanartlabel) + * [FanArtLabelImage](#fanartlabelimage) + * [Label](#label) + * [ReleaseGroup](#releasegroup) + * [Enums](#enums) + * [FanArtImageSize](#fanartimagesize) + +
+ +## Objects + +### Artist + +:small_blue_diamond: *This type has been extended. See the [base schema](../types.md) +for a description and additional fields.* + + + + + + + + + + + + + + + + + +
FieldArgumentTypeDescription
fanArtFanArtArtist + +Images of the artist from [fanart.tv](https://fanart.tv/). +This field is provided by the fanart.tv extension. + +
+ +### FanArtAlbum + +An object containing lists of the different types of release group images from +[fanart.tv](https://fanart.tv/). + + + + + + + + + + + + + + + + + + + + + + +
FieldArgumentTypeDescription
albumCovers[FanArtImage] + +A list of 1000x1000 JPG images of the cover artwork of the release group. + +
discImages[FanArtDiscImage] + +A list of 1000x1000 PNG images of the physical disc media for the release +group, with transparent backgrounds. + +
+ +### FanArtArtist + +An object containing lists of the different types of artist images from +[fanart.tv](https://fanart.tv/). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldArgumentTypeDescription
backgrounds[FanArtImage] + +A list of 1920x1080 JPG images picturing the artist, suitable for use as +backgrounds. + +
banners[FanArtImage] + +A list of 1000x185 JPG images containing the artist and their logo or name. + +
logos[FanArtImage] + +A list of 400x155 PNG images containing the artist’s logo or name, with +transparent backgrounds. + +
logosHD[FanArtImage] + +A list of 800x310 PNG images containing the artist’s logo or name, with +transparent backgrounds. + +
thumbnails[FanArtImage] + +A list of 1000x1000 JPG thumbnail images picturing the artist (usually +containing every member of a band). + +
+ +### FanArtDiscImage + +A disc image from [fanart.tv](https://fanart.tv/). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldArgumentTypeDescription
imageIDID + +The ID of the image on fanart.tv. + +
urlURLString + +The URL of the image. + +
sizeFanArtImageSize + +The size of the image to retrieve. + +
likeCountInt + +The number of likes the image has received by fanart.tv users. + +
discNumberInt + +The disc number. + +
sizeInt + +The width and height of the (square) disc image. + +
+ +### FanArtImage + +A single image from [fanart.tv](https://fanart.tv/). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldArgumentTypeDescription
imageIDID + +The ID of the image on fanart.tv. + +
urlURLString + +The URL of the image. + +
sizeFanArtImageSize + +The size of the image to retrieve. + +
likeCountInt + +The number of likes the image has received by fanart.tv users. + +
+ +### FanArtLabel + +An object containing lists of the different types of label images from +[fanart.tv](https://fanart.tv/). + + + + + + + + + + + + + + + + + +
FieldArgumentTypeDescription
logos[FanArtLabelImage] + +A list of 400x270 PNG images containing the label’s logo. There will +usually be a black version, a color version, and a white version, all with +transparent backgrounds. + +
+ +### FanArtLabelImage + +A music label image from [fanart.tv](https://fanart.tv/). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldArgumentTypeDescription
imageIDID + +The ID of the image on fanart.tv. + +
urlURLString + +The URL of the image. + +
sizeFanArtImageSize + +The size of the image to retrieve. + +
likeCountInt + +The number of likes the image has received by fanart.tv users. + +
colorString + +The type of color content in the image (usually “white” or “colour”). + +
+ +### Label + +:small_blue_diamond: *This type has been extended. See the [base schema](../types.md) +for a description and additional fields.* + + + + + + + + + + + + + + + + + +
FieldArgumentTypeDescription
fanArtFanArtLabel + +Images of the label from [fanart.tv](https://fanart.tv/). +This field is provided by the fanart.tv extension. + +
+ +### ReleaseGroup + +:small_blue_diamond: *This type has been extended. See the [base schema](../types.md) +for a description and additional fields.* + + + + + + + + + + + + + + + + + +
FieldArgumentTypeDescription
fanArtFanArtAlbum + +Images of the release group from [fanart.tv](https://fanart.tv/). +This field is provided by the fanart.tv extension. + +
+ +## Enums + +### FanArtImageSize + +The image sizes that may be requested at [fanart.tv](https://fanart.tv/). + + + + + + + + + + + + + + + + +
ValueDescription
FULL + +The image’s full original dimensions. + +
PREVIEW + +A maximum dimension of 200px. + +
diff --git a/docs/extensions/mediawiki.md b/docs/extensions/mediawiki.md new file mode 100644 index 0000000..bbc7060 --- /dev/null +++ b/docs/extensions/mediawiki.md @@ -0,0 +1,404 @@ +# Extension: MediaWiki + +Retrieve information from MediaWiki image pages, like the actual image file URL and EXIF metadata. + +On entities with [URL relationship types][relationships] that represent images, +this extension will find those URLs that appear to be MediaWiki image pages, and +use the [MediaWiki API][] to fetch information about the image. This information +will include the actual file URL, so you can use it as the `src` in an `` +tag (for example). + +MediaWiki image URLs are assumed to be those with a path that starts with +`/wiki/Image:` or `/wiki/File:`. + +This extension uses its own cache, separate from the MusicBrainz loader cache. + +## Configuration + +This extension can be configured using environment variables: + +* **`COVER_ART_ARCHIVE_BASE_URL`**: The base URL at which to access to Cover Art + Archive API. Defaults to `http://coverartarchive.org/`. +* **`COVER_ART_ARCHIVE_CACHE_SIZE`**: The number of items to keep in the cache. + Defaults to `GRAPHBRAINZ_CACHE_SIZE` if defined, or `8192`. +* **`COVER_ART_ARCHIVE_CACHE_TTL`**: The number of seconds to keep items in the + cache. Defaults to `GRAPHBRAINZ_CACHE_TTL` if defined, or `86400000` (one day). + +[relationships]: https://musicbrainz.org/relationships +[MediaWiki API]: https://www.mediawiki.org/wiki/API:Main_page + + +
+ Table of Contents + + * [Objects](#objects) + * [Artist](#artist) + * [Instrument](#instrument) + * [Label](#label) + * [MediaWikiImage](#mediawikiimage) + * [MediaWikiImageMetadata](#mediawikiimagemetadata) + * [Place](#place) + +
+ +## Objects + +### Artist + +:small_blue_diamond: *This type has been extended. See the [base schema](../types.md) +for a description and additional fields.* + + + + + + + + + + + + + + + + + + + + + + +
FieldArgumentTypeDescription
mediaWikiImages[MediaWikiImage]! + +Artist images found at MediaWiki URLs in the artist’s URL relationships. +Defaults to URL relationships with the type “image”. +This field is provided by the MediaWiki extension. + +
typeString + +The type of URL relationship that will be selected to find images. See +the possible [Artist-URL relationship types](https://musicbrainz.org/relationships/artist-url). + +
+ +### Instrument + +:small_blue_diamond: *This type has been extended. See the [base schema](../types.md) +for a description and additional fields.* + + + + + + + + + + + + + + + + + + + + + + +
FieldArgumentTypeDescription
mediaWikiImages[MediaWikiImage]! + +Instrument images found at MediaWiki URLs in the instrument’s URL +relationships. Defaults to URL relationships with the type “image”. +This field is provided by the MediaWiki extension. + +
typeString + +The type of URL relationship that will be selected to find images. See the +possible [Instrument-URL relationship types](https://musicbrainz.org/relationships/instrument-url). + +
+ +### Label + +:small_blue_diamond: *This type has been extended. See the [base schema](../types.md) +for a description and additional fields.* + + + + + + + + + + + + + + + + + + + + + + +
FieldArgumentTypeDescription
mediaWikiImages[MediaWikiImage]! + +Label images found at MediaWiki URLs in the label’s URL relationships. +Defaults to URL relationships with the type “logo”. +This field is provided by the MediaWiki extension. + +
typeString + +The type of URL relationship that will be selected to find images. See the +possible [Label-URL relationship types](https://musicbrainz.org/relationships/label-url). + +
+ +### MediaWikiImage + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldArgumentTypeDescription
urlURLString! + +The URL of the actual image file. + +
descriptionURLURLString + +The URL of the wiki page describing the image. + +
userString + +The user who uploaded the file. + +
sizeInt + +The size of the file in bytes. + +
widthInt + +The pixel width of the image. + +
heightInt + +The pixel height of the image. + +
canonicalTitleString + +The canonical title of the file. + +
objectNameString + +The image title, brief description, or file name. + +
descriptionHTMLString + +A description of the image, potentially containing HTML. + +
originalDateTimeHTMLString + +The original date of creation of the image. May be a description rather than +a parseable timestamp, and may contain HTML. + +
categories[String]! + +A list of the categories of the image. + +
artistHTMLString + +The name of the image author, potentially containing HTML. + +
creditHTMLString + +The source of the image, potentially containing HTML. + +
licenseShortNameString + +A short human-readable license name. + +
licenseURLURLString + +A web address where the license is described. + +
metadata[MediaWikiImageMetadata]! + +The full list of values in the `extmetadata` field. + +
+ +### MediaWikiImageMetadata + +An entry in the `extmetadata` field of a MediaWiki image file. + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldArgumentTypeDescription
nameString! + +The name of the metadata field. + +
valueString + +The value of the metadata field. All values will be converted to strings. + +
sourceString + +The source of the value. + +
+ +### Place + +:small_blue_diamond: *This type has been extended. See the [base schema](../types.md) +for a description and additional fields.* + + + + + + + + + + + + + + + + + + + + + + +
FieldArgumentTypeDescription
mediaWikiImages[MediaWikiImage]! + +Place images found at MediaWiki URLs in the place’s URL relationships. +Defaults to URL relationships with the type “image”. +This field is provided by the MediaWiki extension. + +
typeString + +The type of URL relationship that will be selected to find images. See the +possible [Place-URL relationship types](https://musicbrainz.org/relationships/place-url). + +
diff --git a/docs/extensions/the-audio-db.md b/docs/extensions/the-audio-db.md new file mode 100644 index 0000000..ab18fb0 --- /dev/null +++ b/docs/extensions/the-audio-db.md @@ -0,0 +1,766 @@ +# Extension: TheAudioDB + +Retrieve images and information about artists, releases, and recordings from [TheAudioDB.com](http://www.theaudiodb.com/). + +This extension uses its own cache, separate from the MusicBrainz loader cache. + +## Configuration + +This extension can be configured using environment variables: + +* **`THEAUDIODB_API_KEY`**: TheAudioDB API key to use. This is required for any + fields added by the extension to successfully resolve. +* **`THEAUDIODB_BASE_URL`**: The base URL at which to access TheAudioDB API. + Defaults to `http://www.theaudiodb.com/api/v1/json/`. +* **`THEAUDIODB_CACHE_SIZE`**: The number of items to keep in the cache. + Defaults to `GRAPHBRAINZ_CACHE_SIZE` if defined, or `8192`. +* **`THEAUDIODB_CACHE_TTL`**: The number of seconds to keep items in the + cache. Defaults to `GRAPHBRAINZ_CACHE_TTL` if defined, or `86400000` (one day). + + +
+ Table of Contents + + * [Objects](#objects) + * [Artist](#artist) + * [Recording](#recording) + * [ReleaseGroup](#releasegroup) + * [TheAudioDBAlbum](#theaudiodbalbum) + * [TheAudioDBArtist](#theaudiodbartist) + * [TheAudioDBMusicVideo](#theaudiodbmusicvideo) + * [TheAudioDBTrack](#theaudiodbtrack) + * [Enums](#enums) + * [TheAudioDBImageSize](#theaudiodbimagesize) + +
+ +## Objects + +### Artist + +:small_blue_diamond: *This type has been extended. See the [base schema](../types.md) +for a description and additional fields.* + + + + + + + + + + + + + + + + + +
FieldArgumentTypeDescription
theAudioDBTheAudioDBArtist + +Data about the artist from [TheAudioDB](http://www.theaudiodb.com/), a good +source of biographical information and images. +This field is provided by TheAudioDB extension. + +
+ +### Recording + +:small_blue_diamond: *This type has been extended. See the [base schema](../types.md) +for a description and additional fields.* + + + + + + + + + + + + + + + + + +
FieldArgumentTypeDescription
theAudioDBTheAudioDBTrack + +Data about the recording from [TheAudioDB](http://www.theaudiodb.com/). +This field is provided by TheAudioDB extension. + +
+ +### ReleaseGroup + +:small_blue_diamond: *This type has been extended. See the [base schema](../types.md) +for a description and additional fields.* + + + + + + + + + + + + + + + + + +
FieldArgumentTypeDescription
theAudioDBTheAudioDBAlbum + +Data about the release group from [TheAudioDB](http://www.theaudiodb.com/), +a good source of descriptive information, reviews, and images. +This field is provided by TheAudioDB extension. + +
+ +### TheAudioDBAlbum + +An album on [TheAudioDB](http://www.theaudiodb.com/) corresponding with a +MusicBrainz Release Group. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldArgumentTypeDescription
albumIDID + +TheAudioDB ID of the album. + +
artistIDID + +TheAudioDB ID of the artist who released the album. + +
descriptionString + +A description of the album, often available in several languages. + +
langString + +The two-letter code for the language in which to retrieve the biography. + +
reviewString + +A review of the album. + +
salesCountInt + +The worldwide sales figure. + +
scoreFloat + +The album’s rating as determined by user votes, out of 10. + +
scoreVotesInt + +The number of users who voted to determine the album’s score. + +
discImageURLString + +An image of the physical disc media for the album. + +
sizeTheAudioDBImageSize + +The size of the image to retrieve. + +
spineImageURLString + +An image of the spine of the album packaging. + +
sizeTheAudioDBImageSize + +The size of the image to retrieve. + +
frontImageURLString + +An image of the front of the album packaging. + +
sizeTheAudioDBImageSize + +The size of the image to retrieve. + +
backImageURLString + +An image of the back of the album packaging. + +
sizeTheAudioDBImageSize + +The size of the image to retrieve. + +
genreString + +The primary musical genre of the album (e.g. “Alternative Rock”). + +
moodString + +The primary musical mood of the album (e.g. “Sad”). + +
styleString + +The primary musical style of the album (e.g. “Rock/Pop”). + +
speedString + +A rough description of the primary musical speed of the album (e.g. “Medium”). + +
themeString + +The primary musical theme of the album (e.g. “In Love”). + +
+ +### TheAudioDBArtist + +An artist on [TheAudioDB](http://www.theaudiodb.com/). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldArgumentTypeDescription
artistIDID + +TheAudioDB ID of the artist. + +
biographyString + +A biography of the artist, often available in several languages. + +
langString + +The two-letter code for the language in which to retrieve the biography. + +
memberCountInt + +The number of members in the musical group, if applicable. + +
bannerURLString + +A 1000x185 JPG banner image containing the artist and their logo or name. + +
sizeTheAudioDBImageSize + +The size of the image to retrieve. + +
fanArt[URLString]! + +A list of 1280x720 or 1920x1080 JPG images depicting the artist. + +
sizeTheAudioDBImageSize + +The size of the images to retrieve. + +
logoURLString + +A 400x155 PNG image containing the artist’s logo or name, with a transparent +background. + +
sizeTheAudioDBImageSize + +The size of the image to retrieve. + +
thumbnailURLString + +A 1000x1000 JPG thumbnail image picturing the artist (usually containing +every member of a band). + +
sizeTheAudioDBImageSize + +The size of the image to retrieve. + +
genreString + +The primary musical genre of the artist (e.g. “Alternative Rock”). + +
moodString + +The primary musical mood of the artist (e.g. “Sad”). + +
styleString + +The primary musical style of the artist (e.g. “Rock/Pop”). + +
+ +### TheAudioDBMusicVideo + +Details of a music video associated with a track on [TheAudioDB](http://www.theaudiodb.com/). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldArgumentTypeDescription
urlURLString + +The URL where the music video can be found. + +
companyNameString + +The video production company of the music video. + +
directorNameString + +The director of the music video. + +
screenshots[URLString]! + +A list of still images from the music video. + +
sizeTheAudioDBImageSize + +The size of the images to retrieve. + +
viewCountInt + +The number of views the video has received at the given URL. This will rarely +be up to date, so use cautiously. + +
likeCountInt + +The number of likes the video has received at the given URL. This will rarely +be up to date, so use cautiously. + +
dislikeCountInt + +The number of dislikes the video has received at the given URL. This will +rarely be up to date, so use cautiously. + +
commentCountInt + +The number of comments the video has received at the given URL. This will +rarely be up to date, so use cautiously. + +
+ +### TheAudioDBTrack + +A track on [TheAudioDB](http://www.theaudiodb.com/) corresponding with a +MusicBrainz Recording. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldArgumentTypeDescription
trackIDID + +TheAudioDB ID of the track. + +
albumIDID + +TheAudioDB ID of the album on which the track appears. + +
artistIDID + +TheAudioDB ID of the artist who released the track. + +
descriptionString + +A description of the track. + +
langString
thumbnailURLString + +A thumbnail image for the track. + +
sizeTheAudioDBImageSize + +The size of the image to retrieve. + +
scoreFloat + +The track’s rating as determined by user votes, out of 10. + +
scoreVotesInt + +The number of users who voted to determine the album’s score. + +
trackNumberInt + +The track number of the song on the album. + +
musicVideoTheAudioDBMusicVideo + +The official music video for the track. + +
genreString + +The primary musical genre of the track (e.g. “Alternative Rock”). + +
moodString + +The primary musical mood of the track (e.g. “Sad”). + +
styleString + +The primary musical style of the track (e.g. “Rock/Pop”). + +
themeString + +The primary musical theme of the track (e.g. “In Love”). + +
+ +## Enums + +### TheAudioDBImageSize + +The image sizes that may be requested at [TheAudioDB](http://www.theaudiodb.com/). + + + + + + + + + + + + + + + + +
ValueDescription
FULL + +The image’s full original dimensions. + +
PREVIEW + +A maximum dimension of 200px. + +
diff --git a/docs/schema.md b/docs/schema.md index c8e897e..895e9a8 100644 --- a/docs/schema.md +++ b/docs/schema.md @@ -596,62 +596,6 @@ type Coordinates { longitude: Degrees } -# An individual piece of album artwork from the [Cover Art Archive](https://musicbrainz.org/doc/Cover_Art_Archive). -type CoverArtImage { - # The Internet Archive’s internal file ID for the image. - fileID: String! - - # The URL at which the image can be found. - image: URLString! - - # A set of thumbnails for the image. - thumbnails: CoverArtImageThumbnails - - # Whether this image depicts the “main front” of the release. - front: Boolean! - - # Whether this image depicts the “main back” of the release. - back: Boolean! - - # A list of [image types](https://musicbrainz.org/doc/Cover_Art/Types) - # describing what part(s) of the release the image includes. - types: [String] - - # The MusicBrainz edit ID. - edit: Int - - # Whether the image was approved by the MusicBrainz edit system. - approved: Boolean - - # A free-text comment left for the image. - comment: String -} - -# The image sizes that may be requested at the [Cover Art -# Archive](https://musicbrainz.org/doc/Cover_Art_Archive). -enum CoverArtImageSize { - # A maximum dimension of 250px. - SMALL - - # A maximum dimension of 500px. - LARGE - - # The image’s original dimensions, with no maximum. - FULL -} - -# URLs for thumbnails of different sizes for a particular piece of -# cover art. -type CoverArtImageThumbnails { - # The URL of a small version of the cover art, where the - # maximum dimension is 250px. - small: URLString - - # The URL of a large version of the cover art, where the - # maximum dimension is 500px. - large: URLString -} - # Year, month (optional), and day (optional) in YYYY-MM-DD format. scalar Date @@ -1703,10 +1647,6 @@ type Release implements Node, Entity { # [EANs](https://en.wikipedia.org/wiki/International_Article_Number). barcode: String - # A list and summary of the cover art images that are present - # for this release from the [Cover Art Archive](https://musicbrainz.org/doc/Cover_Art_Archive). - coverArt: ReleaseCoverArt! - # The status describes how “official” a release is. status: ReleaseStatus @@ -1775,57 +1715,6 @@ type ReleaseConnection { totalCount: Int } -# An object containing a list of the cover art images for a -# release obtained from the [Cover Art Archive](https://musicbrainz.org/doc/Cover_Art_Archive), -# as well as a summary of what artwork is available. -type ReleaseCoverArt { - # The URL of an image depicting the album cover or “main - # front” of the release, i.e. the front of the packaging of the audio recording - # (or in the case of a digital release, the image associated with it in a digital - # media store). - # - # In the MusicBrainz schema, this field is a Boolean value indicating the presence - # of a front image, whereas here the value is the URL for the image itself if one - # exists. You can check for null if you just want to determine the presence of an - # image. - front( - # The size of the image to retrieve. By default, the returned - # image will have its full original dimensions, but certain thumbnail sizes may be - # retrieved as well. - size: CoverArtImageSize = null - ): URLString - - # The URL of an image depicting the “main back” of the - # release, i.e. the back of the packaging of the audio recording. - # - # In the MusicBrainz schema, this field is a Boolean value indicating the presence - # of a back image, whereas here the value is the URL for the image itself. You can - # check for null if you just want to determine the presence of an image. - back( - # The size of the image to retrieve. By default, the returned - # image will have its full original dimensions, but certain thumbnail sizes may be - # retrieved as well. - size: CoverArtImageSize = null - ): URLString - - # A list of images depicting the different sides and surfaces - # of a release’s media and packaging. - images: [CoverArtImage] - - # Whether there is artwork present for this release. - artwork: Boolean! - - # Whether the Cover Art Archive has received a take-down - # request for this release’s artwork, disallowing new uploads. - darkened: Boolean! - - # The number of artwork images present for this release. - count: Int! - - # The particular release shown in the returned cover art. - release: Release! -} - # An edge in a connection. type ReleaseEdge { # The item at the end of the edge @@ -1898,10 +1787,6 @@ type ReleaseGroup implements Node, Entity { # field. secondaryTypeIDs: [MBID] - # The cover art for a release group, obtained from the [Cover - # Art Archive](https://musicbrainz.org/doc/Cover_Art_Archive). - coverArt: ReleaseGroupCoverArt - # A list of artists linked to this entity. artists(after: String, first: Int): ArtistConnection @@ -1946,34 +1831,6 @@ type ReleaseGroupConnection { totalCount: Int } -# An object containing the cover art for a release group obtained -# from the [Cover Art Archive](https://musicbrainz.org/doc/Cover_Art_Archive). For -# release groups, just the front cover of a particular release will be selected. -type ReleaseGroupCoverArt { - # The URL of an image depicting the album cover or “main - # front” of a release in the release group, i.e. the front of the packaging of the - # audio recording (or in the case of a digital release, the image associated with - # it in a digital media store). - front( - # The size of the image to retrieve. By default, the returned - # image will have its full original dimensions, but certain thumbnail sizes may be - # retrieved as well. - size: CoverArtImageSize = null - ): URLString - - # A list of images returned by the [Cover Art - # Archive](https://musicbrainz.org/doc/Cover_Art_Archive) for a release group. A - # particular release’s front image will be included in the list, and likely no - # others, even if other images are available. - images: [CoverArtImage] - - # Whether there is artwork present for this release group. - artwork: Boolean! - - # The particular release shown in the returned cover art. - release: Release! -} - # An edge in a connection. type ReleaseGroupEdge { # The item at the end of the edge diff --git a/docs/types.md b/docs/types.md index b441519..4ee87a7 100644 --- a/docs/types.md +++ b/docs/types.md @@ -20,8 +20,6 @@ You may also be interested in reading the [schema in GraphQL syntax](schema.md). * [CollectionConnection](#collectionconnection) * [CollectionEdge](#collectionedge) * [Coordinates](#coordinates) - * [CoverArtImage](#coverartimage) - * [CoverArtImageThumbnails](#coverartimagethumbnails) * [Disc](#disc) * [Event](#event) * [EventConnection](#eventconnection) @@ -49,12 +47,10 @@ You may also be interested in reading the [schema in GraphQL syntax](schema.md). * [Relationships](#relationships) * [Release](#release) * [ReleaseConnection](#releaseconnection) - * [ReleaseCoverArt](#releasecoverart) * [ReleaseEdge](#releaseedge) * [ReleaseEvent](#releaseevent) * [ReleaseGroup](#releasegroup) * [ReleaseGroupConnection](#releasegroupconnection) - * [ReleaseGroupCoverArt](#releasegroupcoverart) * [ReleaseGroupEdge](#releasegroupedge) * [SearchQuery](#searchquery) * [Series](#series) @@ -68,7 +64,6 @@ You may also be interested in reading the [schema in GraphQL syntax](schema.md). * [WorkConnection](#workconnection) * [WorkEdge](#workedge) * [Enums](#enums) - * [CoverArtImageSize](#coverartimagesize) * [ReleaseGroupType](#releasegrouptype) * [ReleaseStatus](#releasestatus) * [Scalars](#scalars) @@ -2178,143 +2173,6 @@ The east–west position of a point on the Earth’s surface. -### CoverArtImage - -An individual piece of album artwork from the [Cover Art Archive](https://musicbrainz.org/doc/Cover_Art_Archive). - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FieldArgumentTypeDescription
fileIDString! - -The Internet Archive’s internal file ID for the image. - -
imageURLString! - -The URL at which the image can be found. - -
thumbnailsCoverArtImageThumbnails - -A set of thumbnails for the image. - -
frontBoolean! - -Whether this image depicts the “main front” of the release. - -
backBoolean! - -Whether this image depicts the “main back” of the release. - -
types[String] - -A list of [image types](https://musicbrainz.org/doc/Cover_Art/Types) -describing what part(s) of the release the image includes. - -
editInt - -The MusicBrainz edit ID. - -
approvedBoolean - -Whether the image was approved by the MusicBrainz edit system. - -
commentString - -A free-text comment left for the image. - -
- -### CoverArtImageThumbnails - -URLs for thumbnails of different sizes for a particular piece of -cover art. - - - - - - - - - - - - - - - - - - - - - - -
FieldArgumentTypeDescription
smallURLString - -The URL of a small version of the cover art, where the -maximum dimension is 250px. - -
largeURLString - -The URL of a large version of the cover art, where the -maximum dimension is 500px. - -
- ### Disc Information about the physical CD and releases associated with a @@ -5447,16 +5305,6 @@ release has one. The most common types found on releases are 12-digit [UPCs](https://en.wikipedia.org/wiki/Universal_Product_Code) and 13-digit [EANs](https://en.wikipedia.org/wiki/International_Article_Number). - - - -coverArt -ReleaseCoverArt! - - -A list and summary of the cover art images that are present -for this release from the [Cover Art Archive](https://musicbrainz.org/doc/Cover_Art_Archive). - @@ -5709,125 +5557,6 @@ ignoring pagination. -### ReleaseCoverArt - -An object containing a list of the cover art images for a -release obtained from the [Cover Art Archive](https://musicbrainz.org/doc/Cover_Art_Archive), -as well as a summary of what artwork is available. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FieldArgumentTypeDescription
frontURLString - -The URL of an image depicting the album cover or “main -front” of the release, i.e. the front of the packaging of the audio recording -(or in the case of a digital release, the image associated with it in a digital -media store). - -In the MusicBrainz schema, this field is a Boolean value indicating the presence -of a front image, whereas here the value is the URL for the image itself if one -exists. You can check for null if you just want to determine the presence of an -image. - -
sizeCoverArtImageSize - -The size of the image to retrieve. By default, the returned -image will have its full original dimensions, but certain thumbnail sizes may be -retrieved as well. - -
backURLString - -The URL of an image depicting the “main back” of the -release, i.e. the back of the packaging of the audio recording. - -In the MusicBrainz schema, this field is a Boolean value indicating the presence -of a back image, whereas here the value is the URL for the image itself. You can -check for null if you just want to determine the presence of an image. - -
sizeCoverArtImageSize - -The size of the image to retrieve. By default, the returned -image will have its full original dimensions, but certain thumbnail sizes may be -retrieved as well. - -
images[CoverArtImage] - -A list of images depicting the different sides and surfaces -of a release’s media and packaging. - -
artworkBoolean! - -Whether there is artwork present for this release. - -
darkenedBoolean! - -Whether the Cover Art Archive has received a take-down -request for this release’s artwork, disallowing new uploads. - -
countInt! - -The number of artwork images present for this release. - -
releaseRelease! - -The particular release shown in the returned cover art. - -
- ### ReleaseEdge An edge in a connection. @@ -6045,16 +5774,6 @@ that apply to this release group. The MBIDs associated with the values of the `secondaryTypes` field. - - - -coverArt -ReleaseGroupCoverArt - - -The cover art for a release group, obtained from the [Cover -Art Archive](https://musicbrainz.org/doc/Cover_Art_Archive). - @@ -6227,78 +5946,6 @@ ignoring pagination. -### ReleaseGroupCoverArt - -An object containing the cover art for a release group obtained -from the [Cover Art Archive](https://musicbrainz.org/doc/Cover_Art_Archive). For -release groups, just the front cover of a particular release will be selected. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FieldArgumentTypeDescription
frontURLString - -The URL of an image depicting the album cover or “main -front” of a release in the release group, i.e. the front of the packaging of the -audio recording (or in the case of a digital release, the image associated with -it in a digital media store). - -
sizeCoverArtImageSize - -The size of the image to retrieve. By default, the returned -image will have its full original dimensions, but certain thumbnail sizes may be -retrieved as well. - -
images[CoverArtImage] - -A list of images returned by the [Cover Art -Archive](https://musicbrainz.org/doc/Cover_Art_Archive) for a release group. A -particular release’s front image will be included in the list, and likely no -others, even if other images are available. - -
artworkBoolean! - -Whether there is artwork present for this release group. - -
releaseRelease! - -The particular release shown in the returned cover art. - -
- ### ReleaseGroupEdge An edge in a connection. @@ -7374,44 +7021,6 @@ these results were found through a search. ## Enums -### CoverArtImageSize - -The image sizes that may be requested at the [Cover Art -Archive](https://musicbrainz.org/doc/Cover_Art_Archive). - - - - - - - - - - - - - - - - - - - - -
ValueDescription
SMALL - -A maximum dimension of 250px. - -
LARGE - -A maximum dimension of 500px. - -
FULL - -The image’s original dimensions, with no maximum. - -
- ### ReleaseGroupType A type used to describe release groups, e.g. album, single, EP, diff --git a/extensions/cover-art-archive.js b/extensions/cover-art-archive.js new file mode 100644 index 0000000..14af95f --- /dev/null +++ b/extensions/cover-art-archive.js @@ -0,0 +1 @@ +module.exports = require('../lib/extensions/cover-art-archive') diff --git a/extensions/fanart-tv.js b/extensions/fanart-tv.js new file mode 100644 index 0000000..bffd376 --- /dev/null +++ b/extensions/fanart-tv.js @@ -0,0 +1 @@ +module.exports = require('../lib/extensions/fanart-tv') diff --git a/extensions/mediawiki.js b/extensions/mediawiki.js new file mode 100644 index 0000000..8d1d224 --- /dev/null +++ b/extensions/mediawiki.js @@ -0,0 +1 @@ +module.exports = require('../lib/extensions/mediawiki') diff --git a/extensions/the-audio-db.js b/extensions/the-audio-db.js new file mode 100644 index 0000000..d5bf0ac --- /dev/null +++ b/extensions/the-audio-db.js @@ -0,0 +1 @@ +module.exports = require('../lib/extensions/the-audio-db') diff --git a/package.json b/package.json index 90c7c72..413c41e 100644 --- a/package.json +++ b/package.json @@ -15,13 +15,14 @@ "yarn.lock" ], "engines": { - "node": ">=4.6.0", + "node": ">=6.0.0", "npm": ">=3.8.0" }, "scripts": { "build": "npm run build:lib && npm run update-schema && npm run build:docs", - "build:docs": "npm run build:docs:readme && npm run build:docs:schema && npm run build:docs:types", - "build:docs:readme": "doctoc --title \"## Contents\" README.md", + "build:docs": "npm run build:docs:readme && npm run build:docs:schema && npm run build:docs:types && npm run build:docs:extensions", + "build:docs:extensions": "babel-node scripts/build-extension-docs.js", + "build:docs:readme": "doctoc --notitle README.md docs/extensions/README.md", "build:docs:schema": "printf '# GraphQL Schema\\n\\n%s\n' \"$(npm run -s print-schema:md)\" > docs/schema.md", "build:docs:types": "graphql-markdown --require babel-register --prologue 'You may also be interested in reading the [schema in GraphQL syntax](schema.md).' ./src/schema.js > docs/types.md", "build:lib": "babel --out-dir lib src", @@ -71,12 +72,14 @@ "dashify": "^0.2.2", "dataloader": "^1.3.0", "debug": "^3.0.0", + "deep-diff": "^0.3.8", "dotenv": "^4.0.0", "es6-error": "^4.0.2", "express": "^4.15.4", "express-graphql": "^0.6.7", "graphql": "^0.11.7", "graphql-relay": "^0.5.2", + "graphql-tools": "^2.5.1", "lru-cache": "^4.1.1", "pascalcase": "^0.1.1", "postinstall-build": "^5.0.1", @@ -96,7 +99,7 @@ "coveralls": "^3.0.0", "cross-env": "^5.0.5", "doctoc": "^1.3.0", - "graphql-markdown": "^2.2.0", + "graphql-markdown": "^3.1.0", "nodemon": "^1.11.0", "nyc": "^11.1.0", "rimraf": "^2.6.1", @@ -110,6 +113,7 @@ }, "ava": { "require": [ + "dotenv/config", "babel-register" ] }, diff --git a/schema.json b/schema.json index bea27de..e52fc58 100644 --- a/schema.json +++ b/schema.json @@ -2954,22 +2954,6 @@ "isDeprecated": false, "deprecationReason": null }, - { - "name": "coverArt", - "description": "A list and summary of the cover art images that are present\nfor this release from the [Cover Art Archive](https://musicbrainz.org/doc/Cover_Art_Archive).", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "ReleaseCoverArt", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "status", "description": "The status describes how “official” a release is.", @@ -3332,356 +3316,6 @@ "enumValues": null, "possibleTypes": null }, - { - "kind": "OBJECT", - "name": "ReleaseCoverArt", - "description": "An object containing a list of the cover art images for a\nrelease obtained from the [Cover Art Archive](https://musicbrainz.org/doc/Cover_Art_Archive),\nas well as a summary of what artwork is available.", - "fields": [ - { - "name": "front", - "description": "The URL of an image depicting the album cover or “main\nfront” of the release, i.e. the front of the packaging of the audio recording\n(or in the case of a digital release, the image associated with it in a digital\nmedia store).\n\nIn the MusicBrainz schema, this field is a Boolean value indicating the presence\nof a front image, whereas here the value is the URL for the image itself if one\nexists. You can check for null if you just want to determine the presence of an\nimage.", - "args": [ - { - "name": "size", - "description": "The size of the image to retrieve. By default, the returned\nimage will have its full original dimensions, but certain thumbnail sizes may be\nretrieved as well.", - "type": { - "kind": "ENUM", - "name": "CoverArtImageSize", - "ofType": null - }, - "defaultValue": "null" - } - ], - "type": { - "kind": "SCALAR", - "name": "URLString", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "back", - "description": "The URL of an image depicting the “main back” of the\nrelease, i.e. the back of the packaging of the audio recording.\n\nIn the MusicBrainz schema, this field is a Boolean value indicating the presence\nof a back image, whereas here the value is the URL for the image itself. You can\ncheck for null if you just want to determine the presence of an image.", - "args": [ - { - "name": "size", - "description": "The size of the image to retrieve. By default, the returned\nimage will have its full original dimensions, but certain thumbnail sizes may be\nretrieved as well.", - "type": { - "kind": "ENUM", - "name": "CoverArtImageSize", - "ofType": null - }, - "defaultValue": "null" - } - ], - "type": { - "kind": "SCALAR", - "name": "URLString", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "images", - "description": "A list of images depicting the different sides and surfaces\nof a release’s media and packaging.", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "CoverArtImage", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "artwork", - "description": "Whether there is artwork present for this release.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "darkened", - "description": "Whether the Cover Art Archive has received a take-down\nrequest for this release’s artwork, disallowing new uploads.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "count", - "description": "The number of artwork images present for this release.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "release", - "description": "The particular release shown in the returned cover art.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Release", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "CoverArtImageSize", - "description": "The image sizes that may be requested at the [Cover Art\nArchive](https://musicbrainz.org/doc/Cover_Art_Archive).", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "SMALL", - "description": "A maximum dimension of 250px.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "LARGE", - "description": "A maximum dimension of 500px.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FULL", - "description": "The image’s original dimensions, with no maximum.", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "URLString", - "description": "A web address.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "CoverArtImage", - "description": "An individual piece of album artwork from the [Cover Art Archive](https://musicbrainz.org/doc/Cover_Art_Archive).", - "fields": [ - { - "name": "fileID", - "description": "The Internet Archive’s internal file ID for the image.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "image", - "description": "The URL at which the image can be found.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "URLString", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "thumbnails", - "description": "A set of thumbnails for the image.", - "args": [], - "type": { - "kind": "OBJECT", - "name": "CoverArtImageThumbnails", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "front", - "description": "Whether this image depicts the “main front” of the release.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "back", - "description": "Whether this image depicts the “main back” of the release.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "types", - "description": "A list of [image types](https://musicbrainz.org/doc/Cover_Art/Types)\ndescribing what part(s) of the release the image includes.", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "edit", - "description": "The MusicBrainz edit ID.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "approved", - "description": "Whether the image was approved by the MusicBrainz edit system.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "comment", - "description": "A free-text comment left for the image.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "CoverArtImageThumbnails", - "description": "URLs for thumbnails of different sizes for a particular piece of\ncover art.", - "fields": [ - { - "name": "small", - "description": "The URL of a small version of the cover art, where the\nmaximum dimension is 250px.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "URLString", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "large", - "description": "The URL of a large version of the cover art, where the\nmaximum dimension is 500px.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "URLString", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, { "kind": "OBJECT", "name": "Medium", @@ -8106,18 +7740,6 @@ "isDeprecated": false, "deprecationReason": null }, - { - "name": "coverArt", - "description": "The cover art for a release group, obtained from the [Cover\nArt Archive](https://musicbrainz.org/doc/Cover_Art_Archive).", - "args": [], - "type": { - "kind": "OBJECT", - "name": "ReleaseGroupCoverArt", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "artists", "description": "A list of artists linked to this entity.", @@ -8319,88 +7941,6 @@ "enumValues": null, "possibleTypes": null }, - { - "kind": "OBJECT", - "name": "ReleaseGroupCoverArt", - "description": "An object containing the cover art for a release group obtained\nfrom the [Cover Art Archive](https://musicbrainz.org/doc/Cover_Art_Archive). For\nrelease groups, just the front cover of a particular release will be selected.", - "fields": [ - { - "name": "front", - "description": "The URL of an image depicting the album cover or “main\nfront” of a release in the release group, i.e. the front of the packaging of the\naudio recording (or in the case of a digital release, the image associated with\nit in a digital media store).", - "args": [ - { - "name": "size", - "description": "The size of the image to retrieve. By default, the returned\nimage will have its full original dimensions, but certain thumbnail sizes may be\nretrieved as well.", - "type": { - "kind": "ENUM", - "name": "CoverArtImageSize", - "ofType": null - }, - "defaultValue": "null" - } - ], - "type": { - "kind": "SCALAR", - "name": "URLString", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "images", - "description": "A list of images returned by the [Cover Art\nArchive](https://musicbrainz.org/doc/Cover_Art_Archive) for a release group. A\nparticular release’s front image will be included in the list, and likely no\nothers, even if other images are available.", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "CoverArtImage", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "artwork", - "description": "Whether there is artwork present for this release group.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "release", - "description": "The particular release shown in the returned cover art.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Release", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, { "kind": "OBJECT", "name": "SeriesConnection", @@ -9094,6 +8634,16 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "SCALAR", + "name": "URLString", + "description": "A web address.", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, { "kind": "OBJECT", "name": "URL", diff --git a/scripts/build-extension-docs.js b/scripts/build-extension-docs.js new file mode 100644 index 0000000..cf32d68 --- /dev/null +++ b/scripts/build-extension-docs.js @@ -0,0 +1,66 @@ +import fs from 'fs' +import path from 'path' +import { graphql, introspectionQuery } from 'graphql' +import { renderSchema, diffSchema } from 'graphql-markdown' +import baseSchema, { createSchema } from '../src/schema' + +const extensionModules = [ + 'cover-art-archive', + 'fanart-tv', + 'mediawiki', + 'the-audio-db' +] + +function getSchemaJSON (schema) { + return graphql(schema, introspectionQuery).then(result => result.data) +} + +Promise.all(extensionModules.map(extensionModule => { + const extension = require(`../src/extensions/${extensionModule}`).default + console.log(`Generating docs for “${extension.name}” extension...`) + const schema = createSchema(baseSchema, { extensions: [extension] }) + return Promise.all([ + getSchemaJSON(baseSchema), + getSchemaJSON(schema) + ]).then(([baseSchemaJSON, schemaJSON]) => { + const outputSchema = diffSchema(baseSchemaJSON, schemaJSON, { + processTypeDiff (type) { + if (type.description === undefined) { + type.description = + ':small_blue_diamond: *This type has been extended. See the ' + + '[base schema](../types.md)\nfor a description and additional ' + + 'fields.*' + } + return type + } + }) + const outputPath = path.resolve( + __dirname, + `../docs/extensions/${extensionModule}.md` + ) + const stream = fs.createWriteStream(outputPath) + const printer = (line) => stream.write(`${line}\n`) + const prologuePath = path.resolve( + __dirname, + `../src/extensions/${extensionModule}/prologue.md` + ) + const prologue = fs.readFileSync(prologuePath, 'utf8') + renderSchema(outputSchema, { + title: `Extension: ${extension.name}`, + prologue: prologue.trim() + ? `${extension.description}\n\n${prologue}` + : extension.description, + printer, + unknownTypeURL: '../types.md' + }) + stream.end() + return new Promise((resolve, reject) => { + stream.on('error', reject) + stream.on('finish', () => resolve(extension)) + }) + }) +})).then((extensions) => { + console.log(`Built docs for ${extensions.length} extension(s).`) +}).catch(err => { + console.log('Error:', err) +}) diff --git a/src/api/client.js b/src/api/client.js index a6280a1..01d7a9d 100644 --- a/src/api/client.js +++ b/src/api/client.js @@ -29,18 +29,12 @@ export class ClientError extends ExtendableError { export default class Client { constructor ({ - baseURL = process.env.MUSICBRAINZ_BASE_URL || 'http://musicbrainz.org/ws/2/', + baseURL, userAgent = `${pkg.name}/${pkg.version} ` + `( ${pkg.homepage || pkg.author.url || pkg.author.email} )`, extraHeaders = {}, errorClass = ClientError, timeout = 60000, - // MusicBrainz API requests are limited to an *average* of 1 req/sec. - // That means if, for example, we only need to make a few API requests to - // fulfill a query, we might as well make them all at once - as long as - // we then wait a few seconds before making more. In practice this can - // seemingly be set to about 5 requests every 5 seconds before we're - // considered to exceed the rate limit. limit = 1, period = 1000, concurrency = 10, diff --git a/src/api/index.js b/src/api/index.js index fe1b7e9..1b39214 100644 --- a/src/api/index.js +++ b/src/api/index.js @@ -1,10 +1,7 @@ import MusicBrainz, { MusicBrainzError } from './musicbrainz' -import CoverArtArchive, { CoverArtArchiveError } from './cover-art-archive' export { MusicBrainz as default, MusicBrainz, - MusicBrainzError, - CoverArtArchive, - CoverArtArchiveError + MusicBrainzError } diff --git a/src/api/musicbrainz.js b/src/api/musicbrainz.js index ac1bc88..6d42e54 100644 --- a/src/api/musicbrainz.js +++ b/src/api/musicbrainz.js @@ -7,6 +7,12 @@ export default class MusicBrainz extends Client { constructor ({ baseURL = process.env.MUSICBRAINZ_BASE_URL || 'http://musicbrainz.org/ws/2/', errorClass = MusicBrainzError, + // MusicBrainz API requests are limited to an *average* of 1 req/sec. + // That means if, for example, we only need to make a few API requests to + // fulfill a query, we might as well make them all at once - as long as + // we then wait a few seconds before making more. In practice this can + // seemingly be set to about 5 requests every 5 seconds before we're + // considered to exceed the rate limit. limit = 5, period = 5500, ...options diff --git a/src/context.js b/src/context.js new file mode 100644 index 0000000..eb41b5c --- /dev/null +++ b/src/context.js @@ -0,0 +1,27 @@ +import createLoaders from './loaders' + +const debug = require('debug')('graphbrainz:context') + +export function extendContext (extension, context, options) { + if (extension.extendContext) { + if (typeof extension.extendContext === 'function') { + debug(`Extending context via a function from the “${extension.name}” extension.`) + context = extension.extendContext(context, options) + } else { + throw new Error( + `Extension “${extension.name}” contains an invalid \`extendContext\` ` + + `value: ${extension.extendContext}` + ) + } + } + return context +} + +export function createContext (options) { + const { client } = options + const loaders = createLoaders(client) + const context = { client, loaders } + return options.extensions.reduce((context, extension) => { + return extendContext(extension, context, options) + }, context) +} diff --git a/src/api/cover-art-archive.js b/src/extensions/cover-art-archive/client.js similarity index 50% rename from src/api/cover-art-archive.js rename to src/extensions/cover-art-archive/client.js index 3d03cfd..539ebf1 100644 --- a/src/api/cover-art-archive.js +++ b/src/extensions/cover-art-archive/client.js @@ -1,18 +1,18 @@ -import Client, { ClientError } from './client' +import Client from '../../api/client' -export class CoverArtArchiveError extends ClientError {} - -export default class CoverArtArchive extends Client { +export default class CoverArtArchiveClient extends Client { constructor ({ baseURL = process.env.COVER_ART_ARCHIVE_BASE_URL || 'http://coverartarchive.org/', - errorClass = CoverArtArchiveError, limit = 10, period = 1000, ...options } = {}) { - super({ baseURL, errorClass, limit, period, ...options }) + super({ baseURL, limit, period, ...options }) } + /** + * Sinfully attempt to parse HTML responses for the error message. + */ parseErrorMessage (response, body) { if (typeof body === 'string' && body.startsWith('([^<]+)<\/h1>/i.exec(body) @@ -22,25 +22,15 @@ export default class CoverArtArchive extends Client { return super.parseErrorMessage(response, body) } - getImagesURL (entity, mbid) { - return `${entity}/${mbid}` + images (entityType, mbid) { + return this.get(`${entityType}/${mbid}`, { json: true }) } - images (entity, mbid) { - const url = this.getImagesURL(entity, mbid) - return this.get(url, { json: true }) - } - - getImageURL (entity, mbid, typeOrID = 'front', size) { - let url = `${entity}/${mbid}/${typeOrID}` + imageURL (entityType, mbid, typeOrID = 'front', size) { + let url = `${entityType}/${mbid}/${typeOrID}` if (size != null) { url += `-${size}` } - return url - } - - imageURL (entity, mbid, typeOrID = 'front', size) { - const url = this.getImageURL(entity, mbid, typeOrID, size) return this.get(url, { method: 'HEAD', followRedirect: false }) .then(headers => headers.location) } diff --git a/src/extensions/cover-art-archive/index.js b/src/extensions/cover-art-archive/index.js new file mode 100644 index 0000000..228ac4f --- /dev/null +++ b/src/extensions/cover-art-archive/index.js @@ -0,0 +1,36 @@ +import schema from './schema' +import resolvers from './resolvers' +import createLoaders from './loaders' +import CoverArtArchiveClient from './client' +import { ONE_DAY } from '../../util' + +export default { + name: 'Cover Art Archive', + description: + 'Retrieve cover art images for releases from the [Cover Art Archive](https://coverartarchive.org/).', + extendContext (context, { coverArtClient, coverArtArchive = {} } = {}) { + const client = coverArtClient || new CoverArtArchiveClient(coverArtArchive) + const cacheSize = parseInt( + process.env.COVER_ART_ARCHIVE_CACHE_SIZE || process.env.GRAPHBRAINZ_CACHE_SIZE || 8192, + 10 + ) + const cacheTTL = parseInt( + process.env.COVER_ART_ARCHIVE_CACHE_TTL || process.env.GRAPHBRAINZ_CACHE_TTL || ONE_DAY, + 10 + ) + return { + ...context, + // Add the client instance directly onto `context` for backwards + // compatibility. + coverArtClient: client, + loaders: { + ...context.loaders, + ...createLoaders({ client, cacheSize, cacheTTL }) + } + } + }, + extendSchema: { + schemas: [schema], + resolvers + } +} diff --git a/src/extensions/cover-art-archive/loaders.js b/src/extensions/cover-art-archive/loaders.js new file mode 100644 index 0000000..b6dde6d --- /dev/null +++ b/src/extensions/cover-art-archive/loaders.js @@ -0,0 +1,53 @@ +import DataLoader from 'dataloader' +import LRUCache from 'lru-cache' + +const debug = require('debug')('graphbrainz:extensions/cover-art-archive') + +export default function createLoaders (options) { + const { client } = options + const cache = LRUCache({ + max: options.cacheSize, + maxAge: options.cacheTTL, + dispose (key) { + debug(`Removed from cache. key=${key}`) + } + }) + // Make the cache Map-like. + cache.delete = cache.del + cache.clear = cache.reset + + return { + coverArtArchive: new DataLoader(keys => { + return Promise.all(keys.map(key => { + const [ entityType, id ] = key + return client.images(entityType, id) + .catch(err => { + if (err.statusCode === 404) { + return { images: [] } + } + throw err + }).then(coverArt => ({ + ...coverArt, + _entityType: entityType, + _id: id, + _releaseID: coverArt.release && coverArt.release.split('/').pop() + })) + })) + }, { + cacheKeyFn: ([ entityType, id ]) => `${entityType}/${id}`, + cacheMap: cache + }), + coverArtArchiveURL: new DataLoader(keys => { + return Promise.all(keys.map(key => { + const [ entityType, id, type, size ] = key + return client.imageURL(entityType, id, type, size) + })) + }, { + cacheKeyFn: ([ entityType, id, type, size ]) => { + const key = `${entityType}/${id}/${type}` + return size ? `${key}-${size}` : key + }, + cacheMap: cache + }) + } +} diff --git a/src/extensions/cover-art-archive/prologue.md b/src/extensions/cover-art-archive/prologue.md new file mode 100644 index 0000000..255602a --- /dev/null +++ b/src/extensions/cover-art-archive/prologue.md @@ -0,0 +1,12 @@ +This extension uses its own cache, separate from the MusicBrainz loader cache. + +## Configuration + +This extension can be configured using environment variables: + +* **`COVER_ART_ARCHIVE_BASE_URL`**: The base URL at which to access the Cover + Art Archive API. Defaults to `http://coverartarchive.org/`. +* **`COVER_ART_ARCHIVE_CACHE_SIZE`**: The number of items to keep in the cache. + Defaults to `GRAPHBRAINZ_CACHE_SIZE` if defined, or `8192`. +* **`COVER_ART_ARCHIVE_CACHE_TTL`**: The number of seconds to keep items in the + cache. Defaults to `GRAPHBRAINZ_CACHE_TTL` if defined, or `86400000` (one day). diff --git a/src/extensions/cover-art-archive/resolvers.js b/src/extensions/cover-art-archive/resolvers.js new file mode 100644 index 0000000..faa89c5 --- /dev/null +++ b/src/extensions/cover-art-archive/resolvers.js @@ -0,0 +1,75 @@ +import { resolveLookup } from '../../resolvers' + +const SIZES = new Map([ + [null, null], + [250, 250], + [500, 500], + ['FULL', null], + ['SMALL', 250], + ['LARGE', 500] +]) + +function resolveImage (coverArt, args, { loaders }, info) { + // Since migrating the schema to an extension, we lost custom enum values + // for the time being. Translate any incoming `size` arg to the old enum + // values. + const size = SIZES.get(args.size) + // Field should be `front` or `back`. + const field = info.fieldName + if (coverArt.images) { + const matches = coverArt.images.filter(image => image[field]) + if (!matches.length) { + return null + } else if (matches.length === 1) { + const match = matches[0] + if (size === 250) { + return match.thumbnails.small + } else if (size === 500) { + return match.thumbnails.large + } else { + return match.image + } + } + } + const entityType = coverArt._entityType + const id = coverArt._id + const releaseID = coverArt._releaseID + if (entityType === 'release-group' && field === 'front') { + // Release groups only have an endpoint to retrieve the front image. + // If someone requests the back of a release group, return the back of the + // release that the release group's cover art response points to. + return loaders.coverArtArchiveURL.load(['release-group', id, field, size]) + } else { + return loaders.coverArtArchiveURL.load(['release', releaseID, field, size]) + } +} + +export default { + CoverArtArchiveImage: { + fileID: image => image.id + }, + CoverArtArchiveRelease: { + front: resolveImage, + back: resolveImage, + images: coverArt => coverArt.images, + artwork: coverArt => coverArt.images.length > 0, + count: coverArt => coverArt.images.length, + release: (coverArt, args, context, info) => { + const mbid = coverArt._releaseID + if (mbid) { + return resolveLookup(coverArt, { mbid }, context, info) + } + return null + } + }, + Release: { + coverArtArchive: (release, args, { loaders }) => { + return loaders.coverArtArchive.load(['release', release.id]) + } + }, + ReleaseGroup: { + coverArtArchive: (releaseGroup, args, { loaders }) => { + return loaders.coverArtArchive.load(['release-group', releaseGroup.id]) + } + } +} diff --git a/src/extensions/cover-art-archive/schema.js b/src/extensions/cover-art-archive/schema.js new file mode 100644 index 0000000..5d11875 --- /dev/null +++ b/src/extensions/cover-art-archive/schema.js @@ -0,0 +1,121 @@ +export default ` + +# An individual piece of album artwork from the [Cover Art Archive](https://musicbrainz.org/doc/Cover_Art_Archive). +type CoverArtArchiveImage { + # The Internet Archive’s internal file ID for the image. + fileID: String! + + # The URL at which the image can be found. + image: URLString! + + # A set of thumbnails for the image. + thumbnails: CoverArtArchiveImageThumbnails! + + # Whether this image depicts the “main front” of the release. + front: Boolean! + + # Whether this image depicts the “main back” of the release. + back: Boolean! + + # A list of [image types](https://musicbrainz.org/doc/Cover_Art/Types) + # describing what part(s) of the release the image includes. + types: [String]! + + # The MusicBrainz edit ID. + edit: Int + + # Whether the image was approved by the MusicBrainz edit system. + approved: Boolean + + # A free-text comment left for the image. + comment: String +} + +# The image sizes that may be requested at the [Cover Art Archive](https://musicbrainz.org/doc/Cover_Art_Archive). +enum CoverArtArchiveImageSize { + # A maximum dimension of 250px. + SMALL + + # A maximum dimension of 500px. + LARGE + + # The image’s original dimensions, with no maximum. + FULL +} + +# URLs for thumbnails of different sizes for a particular piece of +# cover art. +type CoverArtArchiveImageThumbnails { + # The URL of a small version of the cover art, where the maximum dimension is + # 250px. + small: URLString + + # The URL of a large version of the cover art, where the maximum dimension is + # 500px. + large: URLString +} + +# An object containing a list of the cover art images for a release obtained +# from the [Cover Art Archive](https://musicbrainz.org/doc/Cover_Art_Archive), +# as well as a summary of what artwork is available. +type CoverArtArchiveRelease { + # The URL of an image depicting the album cover or “main front” of the release, + # i.e. the front of the packaging of the audio recording (or in the case of a + # digital release, the image associated with it in a digital media store). + # + # In the MusicBrainz schema, this field is a Boolean value indicating the + # presence of a front image, whereas here the value is the URL for the image + # itself if one exists. You can check for null if you just want to determine + # the presence of an image. + front( + # The size of the image to retrieve. By default, the returned image will + # have its full original dimensions, but certain thumbnail sizes may be + # retrieved as well. + size: CoverArtArchiveImageSize = FULL + ): URLString + + # The URL of an image depicting the “main back” of the release, i.e. the back + # of the packaging of the audio recording. + # + # In the MusicBrainz schema, this field is a Boolean value indicating the + # presence of a back image, whereas here the value is the URL for the image + # itself. You can check for null if you just want to determine the presence of + # an image. + back( + # The size of the image to retrieve. By default, the returned image will + # have its full original dimensions, but certain thumbnail sizes may be + # retrieved as well. + size: CoverArtArchiveImageSize = FULL + ): URLString + + # A list of images depicting the different sides and surfaces of a release’s + # media and packaging. + images: [CoverArtArchiveImage]! + + # Whether there is artwork present for this release. + artwork: Boolean! + + # The number of artwork images present for this release. + count: Int! + + # The particular release shown in the returned cover art. + release: Release +} + +extend type Release { + # An object containing a list and summary of the cover art images that are + # present for this release from the [Cover Art Archive](https://musicbrainz.org/doc/Cover_Art_Archive). + # This field is provided by the Cover Art Archive extension. + coverArtArchive: CoverArtArchiveRelease +} + +extend type ReleaseGroup { + # The cover art for a release in the release group, obtained from the + # [Cover Art Archive](https://musicbrainz.org/doc/Cover_Art_Archive). A + # release in the release group will be chosen as representative of the release + # group. + # This field is provided by the Cover Art Archive extension. + coverArtArchive: CoverArtArchiveRelease +} + +` diff --git a/src/extensions/fanart-tv/client.js b/src/extensions/fanart-tv/client.js new file mode 100644 index 0000000..e27e1c9 --- /dev/null +++ b/src/extensions/fanart-tv/client.js @@ -0,0 +1,60 @@ +import Client from '../../api/client' + +export default class FanArtClient extends Client { + constructor ({ + apiKey = process.env.FANART_API_KEY, + baseURL = process.env.FANART_BASE_URL || 'http://webservice.fanart.tv/v3/', + limit = 10, + period = 1000, + ...options + } = {}) { + super({ baseURL, limit, period, ...options }) + this.apiKey = apiKey + } + + get (path, options = {}) { + const ClientError = this.errorClass + if (!this.apiKey) { + return Promise.reject(new ClientError( + 'No API key was configured for the fanart.tv client.' + )) + } + options = { + json: true, + ...options, + qs: { + ...options.qs, + api_key: this.apiKey + } + } + return super.get(path, options) + } + + musicEntity (entityType, mbid) { + const ClientError = this.errorClass + switch (entityType) { + case 'artist': + return this.musicArtist(mbid) + case 'label': + return this.musicLabel(mbid) + case 'release-group': + return this.musicAlbum(mbid) + default: + return Promise.reject(new ClientError( + `Entity type unsupported: ${entityType}` + )) + } + } + + musicArtist (mbid) { + return this.get(`music/${mbid}`) + } + + musicAlbum (mbid) { + return this.get(`music/albums/${mbid}`) + } + + musicLabel (mbid) { + return this.get(`music/${mbid}`) + } +} diff --git a/src/extensions/fanart-tv/index.js b/src/extensions/fanart-tv/index.js new file mode 100644 index 0000000..bfcbf8f --- /dev/null +++ b/src/extensions/fanart-tv/index.js @@ -0,0 +1,34 @@ +import schema from './schema' +import resolvers from './resolvers' +import createLoader from './loader' +import FanArtClient from './client' +import { ONE_DAY } from '../../util' + +export default { + name: 'fanart.tv', + description: + 'Retrieve high quality artwork for artists, releases, and labels from ' + + '[fanart.tv](https://fanart.tv/).', + extendContext (context, { fanArt = {} } = {}) { + const client = new FanArtClient(fanArt) + const cacheSize = parseInt( + process.env.FANART_CACHE_SIZE || process.env.GRAPHBRAINZ_CACHE_SIZE || 8192, + 10 + ) + const cacheTTL = parseInt( + process.env.FANART_CACHE_TTL || process.env.GRAPHBRAINZ_CACHE_TTL || ONE_DAY, + 10 + ) + return { + ...context, + loaders: { + ...context.loaders, + fanArt: createLoader({ client, cacheSize, cacheTTL }) + } + } + }, + extendSchema: { + schemas: [schema], + resolvers + } +} diff --git a/src/extensions/fanart-tv/loader.js b/src/extensions/fanart-tv/loader.js new file mode 100644 index 0000000..4da6855 --- /dev/null +++ b/src/extensions/fanart-tv/loader.js @@ -0,0 +1,51 @@ +import DataLoader from 'dataloader' +import LRUCache from 'lru-cache' + +const debug = require('debug')('graphbrainz:extensions/fanart-tv') + +export default function createLoader (options) { + const { client } = options + const cache = LRUCache({ + max: options.cacheSize, + maxAge: options.cacheTTL, + dispose (key) { + debug(`Removed from cache. key=${key}`) + } + }) + // Make the cache Map-like. + cache.delete = cache.del + cache.clear = cache.reset + + const loader = new DataLoader(keys => { + return Promise.all(keys.map(key => { + const [ entityType, id ] = key + return client.musicEntity(entityType, id) + .catch(err => { + if (err.statusCode === 404) { + // 404s are OK, just return empty data. + return { + artistbackground: [], + artistthumb: [], + musiclogo: [], + hdmusiclogo: [], + musicbanner: [], + musiclabel: [], + albums: {} + } + } + throw err + }).then(body => { + if (entityType === 'artist') { + const releaseGroupIDs = Object.keys(body.albums) + debug(`Priming album cache with ${releaseGroupIDs.length} album(s).`) + releaseGroupIDs.forEach(key => loader.prime(['release-group', key], body)) + } + return body + }) + })) + }, { + cacheKeyFn: ([ entityType, id ]) => `${entityType}/${id}`, + cacheMap: cache + }) + return loader +} diff --git a/src/extensions/fanart-tv/prologue.md b/src/extensions/fanart-tv/prologue.md new file mode 100644 index 0000000..6533795 --- /dev/null +++ b/src/extensions/fanart-tv/prologue.md @@ -0,0 +1,14 @@ +This extension uses its own cache, separate from the MusicBrainz loader cache. + +## Configuration + +This extension can be configured using environment variables: + +* **`FANART_API_KEY`**: The fanart.tv API key to use. This is required for any + fields added by the extension to successfully resolve. +* **`FANART_BASE_URL`**: The base URL at which to access the + fanart.tv API. Defaults to `http://webservice.fanart.tv/v3/`. +* **`FANART_CACHE_SIZE`**: The number of items to keep in the cache. + Defaults to `GRAPHBRAINZ_CACHE_SIZE` if defined, or `8192`. +* **`FANART_CACHE_TTL`**: The number of seconds to keep items in the + cache. Defaults to `GRAPHBRAINZ_CACHE_TTL` if defined, or `86400000` (one day). diff --git a/src/extensions/fanart-tv/resolvers.js b/src/extensions/fanart-tv/resolvers.js new file mode 100644 index 0000000..37d606c --- /dev/null +++ b/src/extensions/fanart-tv/resolvers.js @@ -0,0 +1,63 @@ +const imageResolvers = { + imageID: image => image.id, + url: (image, args) => { + return args.size === 'PREVIEW' + ? image.url.replace('/fanart/', '/preview/') + : image.url + }, + likeCount: image => image.likes +} + +export default { + FanArtImage: { + ...imageResolvers + }, + FanArtDiscImage: { + ...imageResolvers, + discNumber: image => image.disc + }, + FanArtLabelImage: { + ...imageResolvers, + color: image => image.colour + }, + FanArtArtist: { + backgrounds: artist => { + return artist.artistbackground + }, + thumbnails: artist => { + return artist.artistthumb + }, + logos: artist => { + return artist.musiclogo + }, + logosHD: artist => { + return artist.hdmusiclogo + }, + banners: artist => { + return artist.musicbanner + } + }, + FanArtLabel: { + logos: label => label.musiclabel + }, + FanArtAlbum: { + albumCovers: album => album.albumcover || [], + discImages: album => album.cdart || [] + }, + Artist: { + fanArt: (artist, args, context) => { + return context.loaders.fanArt.load(['artist', artist.id]) + } + }, + Label: { + fanArt: (label, args, context) => { + return context.loaders.fanArt.load(['label', label.id]) + } + }, + ReleaseGroup: { + fanArt: (releaseGroup, args, context) => { + return context.loaders.fanArt.load(['release-group', releaseGroup.id]) + .then(artist => artist.albums[releaseGroup.id]) + } + } +} diff --git a/src/extensions/fanart-tv/schema.js b/src/extensions/fanart-tv/schema.js new file mode 100644 index 0000000..0e7877c --- /dev/null +++ b/src/extensions/fanart-tv/schema.js @@ -0,0 +1,127 @@ +export default ` + +# The image sizes that may be requested at [fanart.tv](https://fanart.tv/). +enum FanArtImageSize { + # The image’s full original dimensions. + FULL + + # A maximum dimension of 200px. + PREVIEW +} + +# A single image from [fanart.tv](https://fanart.tv/). +type FanArtImage { + # The ID of the image on fanart.tv. + imageID: ID + + # The URL of the image. + url( + # The size of the image to retrieve. + size: FanArtImageSize = FULL + ): URLString + + # The number of likes the image has received by fanart.tv users. + likeCount: Int +} + +# A disc image from [fanart.tv](https://fanart.tv/). +type FanArtDiscImage { + # The ID of the image on fanart.tv. + imageID: ID + + # The URL of the image. + url( + # The size of the image to retrieve. + size: FanArtImageSize = FULL + ): URLString + + # The number of likes the image has received by fanart.tv users. + likeCount: Int + + # The disc number. + discNumber: Int + + # The width and height of the (square) disc image. + size: Int +} + +# A music label image from [fanart.tv](https://fanart.tv/). +type FanArtLabelImage { + # The ID of the image on fanart.tv. + imageID: ID + + # The URL of the image. + url( + # The size of the image to retrieve. + size: FanArtImageSize = FULL + ): URLString + + # The number of likes the image has received by fanart.tv users. + likeCount: Int + + # The type of color content in the image (usually “white” or “colour”). + color: String +} + +# An object containing lists of the different types of artist images from +# [fanart.tv](https://fanart.tv/). +type FanArtArtist { + # A list of 1920x1080 JPG images picturing the artist, suitable for use as + # backgrounds. + backgrounds: [FanArtImage] + + # A list of 1000x185 JPG images containing the artist and their logo or name. + banners: [FanArtImage] + + # A list of 400x155 PNG images containing the artist’s logo or name, with + # transparent backgrounds. + logos: [FanArtImage] + + # A list of 800x310 PNG images containing the artist’s logo or name, with + # transparent backgrounds. + logosHD: [FanArtImage] + + # A list of 1000x1000 JPG thumbnail images picturing the artist (usually + # containing every member of a band). + thumbnails: [FanArtImage] +} + +# An object containing lists of the different types of label images from +# [fanart.tv](https://fanart.tv/). +type FanArtLabel { + # A list of 400x270 PNG images containing the label’s logo. There will + # usually be a black version, a color version, and a white version, all with + # transparent backgrounds. + logos: [FanArtLabelImage] +} + +# An object containing lists of the different types of release group images from +# [fanart.tv](https://fanart.tv/). +type FanArtAlbum { + # A list of 1000x1000 JPG images of the cover artwork of the release group. + albumCovers: [FanArtImage] + + # A list of 1000x1000 PNG images of the physical disc media for the release + # group, with transparent backgrounds. + discImages: [FanArtDiscImage] +} + +extend type Artist { + # Images of the artist from [fanart.tv](https://fanart.tv/). + # This field is provided by the fanart.tv extension. + fanArt: FanArtArtist +} + +extend type Label { + # Images of the label from [fanart.tv](https://fanart.tv/). + # This field is provided by the fanart.tv extension. + fanArt: FanArtLabel +} + +extend type ReleaseGroup { + # Images of the release group from [fanart.tv](https://fanart.tv/). + # This field is provided by the fanart.tv extension. + fanArt: FanArtAlbum +} + +` diff --git a/src/extensions/mediawiki/client.js b/src/extensions/mediawiki/client.js new file mode 100644 index 0000000..9249e1a --- /dev/null +++ b/src/extensions/mediawiki/client.js @@ -0,0 +1,54 @@ +import URL from 'url' +import Client from '../../api/client' + +export default class MediaWikiClient extends Client { + constructor ({ + limit = 10, + period = 1000, + ...options + } = {}) { + super({ limit, period, ...options }) + } + + imageInfo (page) { + const pageURL = URL.parse(page, true) + const ClientError = this.errorClass + + if (!pageURL.pathname.startsWith('/wiki/')) { + return Promise.reject(new ClientError( + `MediaWiki page URL does not have the expected /wiki/ prefix: ${page}` + )) + } + + const apiURL = URL.format({ + protocol: pageURL.protocol, + auth: pageURL.auth, + host: pageURL.host, + pathname: '/w/api.php', + query: { + action: 'query', + titles: pageURL.pathname.slice(6), + prop: 'imageinfo', + iiprop: 'url|size|canonicaltitle|user|extmetadata', + format: 'json' + } + }) + + return this.get(apiURL, { json: true }) + .then(body => { + const pageIDs = Object.keys(body.query.pages) + if (pageIDs.length !== 1) { + throw new ClientError( + `Query returned multiple pages: [${pageIDs.join(', ')}]` + ) + } + const imageInfo = body.query.pages[pageIDs[0]].imageinfo + if (imageInfo.length !== 1) { + throw new ClientError( + `Query returned info for ${imageInfo.length} images, expected 1.` + ) + } + return imageInfo[0] + }) + } +} diff --git a/src/extensions/mediawiki/index.js b/src/extensions/mediawiki/index.js new file mode 100644 index 0000000..d7f72f9 --- /dev/null +++ b/src/extensions/mediawiki/index.js @@ -0,0 +1,34 @@ +import schema from './schema' +import resolvers from './resolvers' +import createLoader from './loader' +import MediaWikiClient from './client' +import { ONE_DAY } from '../../util' + +export default { + name: 'MediaWiki', + description: + 'Retrieve information from MediaWiki image pages, like the actual image ' + + 'file URL and EXIF metadata.', + extendContext (context, { mediaWiki = {} } = {}) { + const client = new MediaWikiClient(mediaWiki) + const cacheSize = parseInt( + process.env.MEDIAWIKI_CACHE_SIZE || process.env.GRAPHBRAINZ_CACHE_SIZE || 8192, + 10 + ) + const cacheTTL = parseInt( + process.env.MEDIAWIKI_CACHE_TTL || process.env.GRAPHBRAINZ_CACHE_TTL || ONE_DAY, + 10 + ) + return { + ...context, + loaders: { + ...context.loaders, + mediaWiki: createLoader({ client, cacheSize, cacheTTL }) + } + } + }, + extendSchema: { + schemas: [schema], + resolvers + } +} diff --git a/src/extensions/mediawiki/loader.js b/src/extensions/mediawiki/loader.js new file mode 100644 index 0000000..ca58d98 --- /dev/null +++ b/src/extensions/mediawiki/loader.js @@ -0,0 +1,22 @@ +import DataLoader from 'dataloader' +import LRUCache from 'lru-cache' + +const debug = require('debug')('graphbrainz:extensions/mediawiki') + +export default function createLoader (options) { + const { client } = options + const cache = LRUCache({ + max: options.cacheSize, + maxAge: options.cacheTTL, + dispose (key) { + debug(`Removed from cache. key=${key}`) + } + }) + // Make the cache Map-like. + cache.delete = cache.del + cache.clear = cache.reset + + return new DataLoader(keys => { + return Promise.all(keys.map(key => client.imageInfo(key))) + }, { cacheMap: cache }) +} diff --git a/src/extensions/mediawiki/prologue.md b/src/extensions/mediawiki/prologue.md new file mode 100644 index 0000000..f296d34 --- /dev/null +++ b/src/extensions/mediawiki/prologue.md @@ -0,0 +1,24 @@ +On entities with [URL relationship types][relationships] that represent images, +this extension will find those URLs that appear to be MediaWiki image pages, and +use the [MediaWiki API][] to fetch information about the image. This information +will include the actual file URL, so you can use it as the `src` in an `` +tag (for example). + +MediaWiki image URLs are assumed to be those with a path that starts with +`/wiki/Image:` or `/wiki/File:`. + +This extension uses its own cache, separate from the MusicBrainz loader cache. + +## Configuration + +This extension can be configured using environment variables: + +* **`COVER_ART_ARCHIVE_BASE_URL`**: The base URL at which to access to Cover Art + Archive API. Defaults to `http://coverartarchive.org/`. +* **`COVER_ART_ARCHIVE_CACHE_SIZE`**: The number of items to keep in the cache. + Defaults to `GRAPHBRAINZ_CACHE_SIZE` if defined, or `8192`. +* **`COVER_ART_ARCHIVE_CACHE_TTL`**: The number of seconds to keep items in the + cache. Defaults to `GRAPHBRAINZ_CACHE_TTL` if defined, or `86400000` (one day). + +[relationships]: https://musicbrainz.org/relationships +[MediaWiki API]: https://www.mediawiki.org/wiki/API:Main_page diff --git a/src/extensions/mediawiki/resolvers.js b/src/extensions/mediawiki/resolvers.js new file mode 100644 index 0000000..84c1c6f --- /dev/null +++ b/src/extensions/mediawiki/resolvers.js @@ -0,0 +1,80 @@ +import URL from 'url' + +function resolveMediaWikiImages (source, args, { loaders }) { + const isURL = (relation) => relation['target-type'] === 'url' + let rels = source.relations ? source.relations.filter(isURL) : [] + if (!rels.length) { + rels = loaders.lookup.load([source._type, source.id, { inc: 'url-rels' }]) + .then(source => source.relations.filter(isURL)) + } + return Promise.resolve(rels).then(rels => { + const pages = rels.filter(rel => { + if (rel.type === args.type) { + const url = URL.parse(rel.url.resource) + if (url.pathname.match(/^\/wiki\/(File|Image):/)) { + return true + } + } + return false + }).map(rel => rel.url.resource) + return loaders.mediaWiki.loadMany(pages) + }) +} + +export default { + MediaWikiImage: { + descriptionURL: imageInfo => imageInfo.descriptionurl, + canonicalTitle: imageInfo => imageInfo.canonicaltitle, + objectName: imageInfo => { + const data = imageInfo.extmetadata.ObjectName + return data ? data.value : null + }, + descriptionHTML: imageInfo => { + const data = imageInfo.extmetadata.ImageDescription + return data ? data.value : null + }, + originalDateTimeHTML: imageInfo => { + const data = imageInfo.extmetadata.DateTimeOriginal + return data ? data.value : null + }, + categories: imageInfo => { + const data = imageInfo.extmetadata.Categories + return data ? data.value.split('|') : [] + }, + artistHTML: imageInfo => { + const data = imageInfo.extmetadata.Artist + return data ? data.value : null + }, + creditHTML: imageInfo => { + const data = imageInfo.extmetadata.Credit + return data ? data.value : null + }, + licenseShortName: imageInfo => { + const data = imageInfo.extmetadata.LicenseShortName + return data ? data.value : null + }, + licenseURL: imageInfo => { + const data = imageInfo.extmetadata.LicenseUrl + return data ? data.value : null + }, + metadata: imageInfo => Object.keys(imageInfo.extmetadata).map(key => { + const data = imageInfo.extmetadata[key] + return { ...data, name: key } + }) + }, + MediaWikiImageMetadata: { + value: obj => obj.value == null ? obj.value : `${obj.value}` + }, + Artist: { + mediaWikiImages: resolveMediaWikiImages + }, + Instrument: { + mediaWikiImages: resolveMediaWikiImages + }, + Label: { + mediaWikiImages: resolveMediaWikiImages + }, + Place: { + mediaWikiImages: resolveMediaWikiImages + } +} diff --git a/src/extensions/mediawiki/schema.js b/src/extensions/mediawiki/schema.js new file mode 100644 index 0000000..33ad2e3 --- /dev/null +++ b/src/extensions/mediawiki/schema.js @@ -0,0 +1,108 @@ +export default ` + +type MediaWikiImage { + # The URL of the actual image file. + url: URLString! + + # The URL of the wiki page describing the image. + descriptionURL: URLString + + # The user who uploaded the file. + user: String + + # The size of the file in bytes. + size: Int + + # The pixel width of the image. + width: Int + + # The pixel height of the image. + height: Int + + # The canonical title of the file. + canonicalTitle: String + + # The image title, brief description, or file name. + objectName: String + + # A description of the image, potentially containing HTML. + descriptionHTML: String + + # The original date of creation of the image. May be a description rather than + # a parseable timestamp, and may contain HTML. + originalDateTimeHTML: String + + # A list of the categories of the image. + categories: [String]! + + # The name of the image author, potentially containing HTML. + artistHTML: String + + # The source of the image, potentially containing HTML. + creditHTML: String + + # A short human-readable license name. + licenseShortName: String + + # A web address where the license is described. + licenseURL: URLString + + # The full list of values in the \`extmetadata\` field. + metadata: [MediaWikiImageMetadata]! +} + +# An entry in the \`extmetadata\` field of a MediaWiki image file. +type MediaWikiImageMetadata { + # The name of the metadata field. + name: String! + # The value of the metadata field. All values will be converted to strings. + value: String + # The source of the value. + source: String +} + +extend type Artist { + # Artist images found at MediaWiki URLs in the artist’s URL relationships. + # Defaults to URL relationships with the type “image”. + # This field is provided by the MediaWiki extension. + mediaWikiImages( + # The type of URL relationship that will be selected to find images. See + # the possible [Artist-URL relationship types](https://musicbrainz.org/relationships/artist-url). + type: String = "image" + ): [MediaWikiImage]! +} + +extend type Instrument { + # Instrument images found at MediaWiki URLs in the instrument’s URL + # relationships. Defaults to URL relationships with the type “image”. + # This field is provided by the MediaWiki extension. + mediaWikiImages( + # The type of URL relationship that will be selected to find images. See the + # possible [Instrument-URL relationship types](https://musicbrainz.org/relationships/instrument-url). + type: String = "image" + ): [MediaWikiImage]! +} + +extend type Label { + # Label images found at MediaWiki URLs in the label’s URL relationships. + # Defaults to URL relationships with the type “logo”. + # This field is provided by the MediaWiki extension. + mediaWikiImages( + # The type of URL relationship that will be selected to find images. See the + # possible [Label-URL relationship types](https://musicbrainz.org/relationships/label-url). + type: String = "logo" + ): [MediaWikiImage]! +} + +extend type Place { + # Place images found at MediaWiki URLs in the place’s URL relationships. + # Defaults to URL relationships with the type “image”. + # This field is provided by the MediaWiki extension. + mediaWikiImages( + # The type of URL relationship that will be selected to find images. See the + # possible [Place-URL relationship types](https://musicbrainz.org/relationships/place-url). + type: String = "image" + ): [MediaWikiImage]! +} + +` diff --git a/src/extensions/the-audio-db/client.js b/src/extensions/the-audio-db/client.js new file mode 100644 index 0000000..977038d --- /dev/null +++ b/src/extensions/the-audio-db/client.js @@ -0,0 +1,70 @@ +import Client from '../../api/client' + +export default class TheAudioDBClient extends Client { + constructor ({ + apiKey = process.env.THEAUDIODB_API_KEY, + baseURL = process.env.THEAUDIODB_BASE_URL || 'http://www.theaudiodb.com/api/v1/json/', + limit = 10, + period = 1000, + ...options + } = {}) { + super({ baseURL, limit, period, ...options }) + this.apiKey = apiKey + } + + get (path, options = {}) { + const ClientError = this.errorClass + if (!this.apiKey) { + return Promise.reject(new ClientError( + 'No API key was configured for TheAudioDB client.' + )) + } + return super.get(`${this.apiKey}/${path}`, { json: true, ...options }) + } + + entity (entityType, mbid) { + const ClientError = this.errorClass + switch (entityType) { + case 'artist': + return this.artist(mbid) + case 'release-group': + return this.album(mbid) + case 'recording': + return this.track(mbid) + default: + return Promise.reject(new ClientError( + `Entity type unsupported: ${entityType}` + )) + } + } + + artist (mbid) { + return this.get('artist-mb.php', { qs: { i: mbid } }) + .then(body => { + if (body.artists && body.artists.length === 1) { + return body.artists[0] + } + return null + }) + } + + album (mbid) { + return this.get('album-mb.php', { qs: { i: mbid } }) + .then(body => { + if (body.album && body.album.length === 1) { + return body.album[0] + } + return null + }) + } + + track (mbid) { + return this.get('track-mb.php', { qs: { i: mbid } }) + .then(body => { + if (body.track && body.track.length === 1) { + return body.track[0] + } + return null + }) + } +} diff --git a/src/extensions/the-audio-db/index.js b/src/extensions/the-audio-db/index.js new file mode 100644 index 0000000..ba1c26a --- /dev/null +++ b/src/extensions/the-audio-db/index.js @@ -0,0 +1,34 @@ +import schema from './schema' +import resolvers from './resolvers' +import createLoader from './loader' +import TheAudioDBClient from './client' +import { ONE_DAY } from '../../util' + +export default { + name: 'TheAudioDB', + description: + 'Retrieve images and information about artists, releases, and recordings ' + + 'from [TheAudioDB.com](http://www.theaudiodb.com/).', + extendContext (context, { theAudioDB = {} } = {}) { + const client = new TheAudioDBClient(theAudioDB) + const cacheSize = parseInt( + process.env.THEAUDIODB_CACHE_SIZE || process.env.GRAPHBRAINZ_CACHE_SIZE || 8192, + 10 + ) + const cacheTTL = parseInt( + process.env.THEAUDIODB_CACHE_TTL || process.env.GRAPHBRAINZ_CACHE_TTL || ONE_DAY, + 10 + ) + return { + ...context, + loaders: { + ...context.loaders, + theAudioDB: createLoader({ client, cacheSize, cacheTTL }) + } + } + }, + extendSchema: { + schemas: [schema], + resolvers + } +} diff --git a/src/extensions/the-audio-db/loader.js b/src/extensions/the-audio-db/loader.js new file mode 100644 index 0000000..51e4868 --- /dev/null +++ b/src/extensions/the-audio-db/loader.js @@ -0,0 +1,28 @@ +import DataLoader from 'dataloader' +import LRUCache from 'lru-cache' + +const debug = require('debug')('graphbrainz:extensions/the-audio-db') + +export default function createLoader (options) { + const { client } = options + const cache = LRUCache({ + max: options.cacheSize, + maxAge: options.cacheTTL, + dispose (key) { + debug(`Removed from cache. key=${key}`) + } + }) + // Make the cache Map-like. + cache.delete = cache.del + cache.clear = cache.reset + + return new DataLoader(keys => { + return Promise.all(keys.map(key => { + const [ entityType, id ] = key + return client.entity(entityType, id) + })) + }, { + cacheKeyFn: ([ entityType, id ]) => `${entityType}/${id}`, + cacheMap: cache + }) +} diff --git a/src/extensions/the-audio-db/prologue.md b/src/extensions/the-audio-db/prologue.md new file mode 100644 index 0000000..dd94508 --- /dev/null +++ b/src/extensions/the-audio-db/prologue.md @@ -0,0 +1,14 @@ +This extension uses its own cache, separate from the MusicBrainz loader cache. + +## Configuration + +This extension can be configured using environment variables: + +* **`THEAUDIODB_API_KEY`**: TheAudioDB API key to use. This is required for any + fields added by the extension to successfully resolve. +* **`THEAUDIODB_BASE_URL`**: The base URL at which to access TheAudioDB API. + Defaults to `http://www.theaudiodb.com/api/v1/json/`. +* **`THEAUDIODB_CACHE_SIZE`**: The number of items to keep in the cache. + Defaults to `GRAPHBRAINZ_CACHE_SIZE` if defined, or `8192`. +* **`THEAUDIODB_CACHE_TTL`**: The number of seconds to keep items in the + cache. Defaults to `GRAPHBRAINZ_CACHE_TTL` if defined, or `86400000` (one day). diff --git a/src/extensions/the-audio-db/resolvers.js b/src/extensions/the-audio-db/resolvers.js new file mode 100644 index 0000000..95064cd --- /dev/null +++ b/src/extensions/the-audio-db/resolvers.js @@ -0,0 +1,107 @@ +function handleImageSize (resolver) { + return (source, args, context, info) => { + const getURL = (url) => args.size === 'PREVIEW' ? `${url}/preview` : url + const url = resolver(source, args, context, info) + if (!url) { + return null + } else if (Array.isArray(url)) { + return url.map(getURL) + } else { + return getURL(url) + } + } +} + +export default { + TheAudioDBArtist: { + artistID: artist => artist.idArtist, + biography: (artist, args) => { + const lang = args.lang.toUpperCase() + return artist[`strBiography${lang}`] || null + }, + memberCount: artist => artist.intMembers, + banner: handleImageSize(artist => artist.strArtistBanner), + fanArt: handleImageSize(artist => { + return [ + artist.strArtistFanart, + artist.strArtistFanart2, + artist.strArtistFanart3 + ].filter(Boolean) + }), + logo: handleImageSize(artist => artist.strArtistLogo), + thumbnail: handleImageSize(artist => artist.strArtistThumb), + genre: artist => artist.strGenre || null, + mood: artist => artist.strMood || null, + style: artist => artist.strStyle || null + }, + TheAudioDBAlbum: { + albumID: album => album.idAlbum, + artistID: album => album.idArtist, + description: (album, args) => { + const lang = args.lang.toUpperCase() + return album[`strDescription${lang}`] || null + }, + salesCount: album => album.intSales, + score: album => album.intScore, + scoreVotes: album => album.intScoreVotes, + discImage: handleImageSize(album => album.strAlbumCDart), + spineImage: handleImageSize(album => album.strAlbumSpine), + frontImage: handleImageSize(album => album.strAlbumThumb), + backImage: handleImageSize(album => album.strAlbumThumbBack), + review: album => album.strReview || null, + genre: album => album.strGenre || null, + mood: album => album.strMood || null, + style: album => album.strStyle || null, + speed: album => album.strSpeed || null, + theme: album => album.strTheme || null + }, + TheAudioDBTrack: { + trackID: track => track.idTrack, + albumID: track => track.idAlbum, + artistID: track => track.idArtist, + description: (track, args) => { + const lang = args.lang.toUpperCase() + return track[`strDescription${lang}`] || null + }, + thumbnail: handleImageSize(track => track.strTrackThumb), + score: track => track.intScore, + scoreVotes: track => track.intScoreVotes, + trackNumber: track => track.intTrackNumber, + musicVideo: track => track, + genre: track => track.strGenre || null, + mood: track => track.strMood || null, + style: track => track.strStyle || null, + theme: track => track.strTheme || null + }, + TheAudioDBMusicVideo: { + url: track => track.strMusicVid || null, + companyName: track => track.strMusicVidCompany || null, + directorName: track => track.strMusicVidDirector || null, + screenshots: handleImageSize(track => { + return [ + track.strMusicVidScreen1, + track.strMusicVidScreen2, + track.strMusicVidScreen3 + ].filter(Boolean) + }), + viewCount: track => track.intMusicVidViews, + likeCount: track => track.intMusicVidLikes, + dislikeCount: track => track.intMusicVidDislikes, + commentCount: track => track.intMusicVidComments + }, + Artist: { + theAudioDB: (artist, args, context) => { + return context.loaders.theAudioDB.load(['artist', artist.id]) + } + }, + Recording: { + theAudioDB: (recording, args, context) => { + return context.loaders.theAudioDB.load(['recording', recording.id]) + } + }, + ReleaseGroup: { + theAudioDB: (releaseGroup, args, context) => { + return context.loaders.theAudioDB.load(['release-group', releaseGroup.id]) + } + } +} diff --git a/src/extensions/the-audio-db/schema.js b/src/extensions/the-audio-db/schema.js new file mode 100644 index 0000000..99e06ed --- /dev/null +++ b/src/extensions/the-audio-db/schema.js @@ -0,0 +1,231 @@ +export default ` + +# The image sizes that may be requested at [TheAudioDB](http://www.theaudiodb.com/). +enum TheAudioDBImageSize { + # The image’s full original dimensions. + FULL + + # A maximum dimension of 200px. + PREVIEW +} + +# An artist on [TheAudioDB](http://www.theaudiodb.com/). +type TheAudioDBArtist { + # TheAudioDB ID of the artist. + artistID: ID + + # A biography of the artist, often available in several languages. + biography( + # The two-letter code for the language in which to retrieve the biography. + lang: String = "en" + ): String + + # The number of members in the musical group, if applicable. + memberCount: Int + + # A 1000x185 JPG banner image containing the artist and their logo or name. + banner( + # The size of the image to retrieve. + size: TheAudioDBImageSize = FULL + ): URLString + + # A list of 1280x720 or 1920x1080 JPG images depicting the artist. + fanArt( + # The size of the images to retrieve. + size: TheAudioDBImageSize = FULL + ): [URLString]! + + # A 400x155 PNG image containing the artist’s logo or name, with a transparent + # background. + logo( + # The size of the image to retrieve. + size: TheAudioDBImageSize = FULL + ): URLString + + # A 1000x1000 JPG thumbnail image picturing the artist (usually containing + # every member of a band). + thumbnail( + # The size of the image to retrieve. + size: TheAudioDBImageSize = FULL + ): URLString + + # The primary musical genre of the artist (e.g. “Alternative Rock”). + genre: String + + # The primary musical mood of the artist (e.g. “Sad”). + mood: String + + # The primary musical style of the artist (e.g. “Rock/Pop”). + style: String +} + +# An album on [TheAudioDB](http://www.theaudiodb.com/) corresponding with a +# MusicBrainz Release Group. +type TheAudioDBAlbum { + # TheAudioDB ID of the album. + albumID: ID + + # TheAudioDB ID of the artist who released the album. + artistID: ID + + # A description of the album, often available in several languages. + description( + # The two-letter code for the language in which to retrieve the biography. + lang: String = "en" + ): String + + # A review of the album. + review: String + + # The worldwide sales figure. + salesCount: Int + + # The album’s rating as determined by user votes, out of 10. + score: Float + + # The number of users who voted to determine the album’s score. + scoreVotes: Int + + # An image of the physical disc media for the album. + discImage( + # The size of the image to retrieve. + size: TheAudioDBImageSize = FULL + ): URLString + + # An image of the spine of the album packaging. + spineImage( + # The size of the image to retrieve. + size: TheAudioDBImageSize = FULL + ): URLString + + # An image of the front of the album packaging. + frontImage( + # The size of the image to retrieve. + size: TheAudioDBImageSize = FULL + ): URLString + + # An image of the back of the album packaging. + backImage( + # The size of the image to retrieve. + size: TheAudioDBImageSize = FULL + ): URLString + + # The primary musical genre of the album (e.g. “Alternative Rock”). + genre: String + + # The primary musical mood of the album (e.g. “Sad”). + mood: String + + # The primary musical style of the album (e.g. “Rock/Pop”). + style: String + + # A rough description of the primary musical speed of the album (e.g. “Medium”). + speed: String + + # The primary musical theme of the album (e.g. “In Love”). + theme: String +} + +# A track on [TheAudioDB](http://www.theaudiodb.com/) corresponding with a +# MusicBrainz Recording. +type TheAudioDBTrack { + # TheAudioDB ID of the track. + trackID: ID + + # TheAudioDB ID of the album on which the track appears. + albumID: ID + + # TheAudioDB ID of the artist who released the track. + artistID: ID + + # A description of the track. + description( + lang: String = "en" + ): String + + # A thumbnail image for the track. + thumbnail( + # The size of the image to retrieve. + size: TheAudioDBImageSize = FULL + ): URLString + + # The track’s rating as determined by user votes, out of 10. + score: Float + + # The number of users who voted to determine the album’s score. + scoreVotes: Int + + # The track number of the song on the album. + trackNumber: Int + + # The official music video for the track. + musicVideo: TheAudioDBMusicVideo + + # The primary musical genre of the track (e.g. “Alternative Rock”). + genre: String + + # The primary musical mood of the track (e.g. “Sad”). + mood: String + + # The primary musical style of the track (e.g. “Rock/Pop”). + style: String + + # The primary musical theme of the track (e.g. “In Love”). + theme: String +} + +# Details of a music video associated with a track on [TheAudioDB](http://www.theaudiodb.com/). +type TheAudioDBMusicVideo { + # The URL where the music video can be found. + url: URLString + + # The video production company of the music video. + companyName: String + + # The director of the music video. + directorName: String + + # A list of still images from the music video. + screenshots( + # The size of the images to retrieve. + size: TheAudioDBImageSize = FULL + ): [URLString]! + + # The number of views the video has received at the given URL. This will rarely + # be up to date, so use cautiously. + viewCount: Int + + # The number of likes the video has received at the given URL. This will rarely + # be up to date, so use cautiously. + likeCount: Int + + # The number of dislikes the video has received at the given URL. This will + # rarely be up to date, so use cautiously. + dislikeCount: Int + + # The number of comments the video has received at the given URL. This will + # rarely be up to date, so use cautiously. + commentCount: Int +} + +extend type Artist { + # Data about the artist from [TheAudioDB](http://www.theaudiodb.com/), a good + # source of biographical information and images. + # This field is provided by TheAudioDB extension. + theAudioDB: TheAudioDBArtist +} + +extend type Recording { + # Data about the recording from [TheAudioDB](http://www.theaudiodb.com/). + # This field is provided by TheAudioDB extension. + theAudioDB: TheAudioDBTrack +} + +extend type ReleaseGroup { + # Data about the release group from [TheAudioDB](http://www.theaudiodb.com/), + # a good source of descriptive information, reviews, and images. + # This field is provided by TheAudioDB extension. + theAudioDB: TheAudioDBAlbum +} + +` diff --git a/src/index.js b/src/index.js index 92fb73e..76e2f1d 100644 --- a/src/index.js +++ b/src/index.js @@ -1,9 +1,11 @@ import express from 'express' import graphqlHTTP from 'express-graphql' import compression from 'compression' -import MusicBrainz, { CoverArtArchive } from './api' -import schema from './schema' -import createLoaders from './loaders' +import MusicBrainz from './api' +import schema, { createSchema } from './schema' +import { createContext } from './context' + +const debug = require('debug')('graphbrainz') const formatError = (err) => ({ message: err.message, @@ -13,19 +15,37 @@ const formatError = (err) => ({ const middleware = ({ client = new MusicBrainz(), - coverArtClient = new CoverArtArchive(), - ...options + extensions = process.env.GRAPHBRAINZ_EXTENSIONS + ? JSON.parse(process.env.GRAPHBRAINZ_EXTENSIONS) + : [ + './extensions/cover-art-archive', + './extensions/fanart-tv', + './extensions/mediawiki', + './extensions/the-audio-db' + ], + ...middlewareOptions } = {}) => { + debug(`Loading ${extensions.length} extension(s).`) + const options = { + client, + extensions: extensions.map(extensionModule => { + if (typeof extensionModule === 'object') { + return extensionModule + } + const extension = require(extensionModule) + return extension.default ? extension.default : extension + }), + ...middlewareOptions + } const DEV = process.env.NODE_ENV !== 'production' const graphiql = DEV || process.env.GRAPHBRAINZ_GRAPHIQL === 'true' - const loaders = createLoaders(client, coverArtClient) return graphqlHTTP({ - schema, - context: { client, coverArtClient, loaders }, + schema: createSchema(schema, options), + context: createContext(options), pretty: DEV, graphiql, formatError: DEV ? formatError : undefined, - ...options + ...middlewareOptions }) } diff --git a/src/loaders.js b/src/loaders.js index cce7657..98b4dfe 100644 --- a/src/loaders.js +++ b/src/loaders.js @@ -1,11 +1,11 @@ import DataLoader from 'dataloader' import LRUCache from 'lru-cache' import { toPlural } from './types/helpers' +import { ONE_DAY } from './util' const debug = require('debug')('graphbrainz:loaders') -const ONE_DAY = 24 * 60 * 60 * 1000 -export default function createLoaders (client, coverArtClient) { +export default function createLoaders (client) { // All loaders share a single LRU cache that will remember 8192 responses, // each cached for 1 day. const cache = LRUCache({ @@ -70,36 +70,5 @@ export default function createLoaders (client, coverArtClient) { cacheMap: cache }) - const coverArt = new DataLoader(keys => { - return Promise.all(keys.map(key => { - const [ entityType, id ] = key - return coverArtClient.images(...key).catch(err => { - if (err.statusCode === 404) { - return { images: [] } - } - throw err - }).then(coverArt => { - coverArt._parentType = entityType - coverArt._parentID = id - if (entityType === 'release') { - coverArt._release = id - } else { - coverArt._release = coverArt.release && coverArt.release.split('/').pop() - } - return coverArt - }) - })) - }, { - cacheKeyFn: key => `cover-art/${coverArtClient.getImagesURL(...key)}`, - cacheMap: cache - }) - - const coverArtURL = new DataLoader(keys => { - return Promise.all(keys.map(key => coverArtClient.imageURL(...key))) - }, { - cacheKeyFn: key => `cover-art/url/${coverArtClient.getImageURL(...key)}`, - cacheMap: cache - }) - - return { lookup, browse, search, coverArt, coverArtURL } + return { lookup, browse, search } } diff --git a/src/schema.js b/src/schema.js index 3dd0a7b..d4edcc0 100644 --- a/src/schema.js +++ b/src/schema.js @@ -1,7 +1,50 @@ -import { GraphQLSchema, GraphQLObjectType } from 'graphql' +import { GraphQLSchema, GraphQLObjectType, extendSchema, parse } from 'graphql' +import { addResolveFunctionsToSchema } from 'graphql-tools' import { lookup, browse, search } from './queries' import { nodeField } from './types/node' +const debug = require('debug')('graphbrainz:schema') + +export function applyExtension (extension, schema, options = {}) { + let outputSchema = schema + if (extension.extendSchema) { + if (typeof extension.extendSchema === 'object') { + debug(`Extending schema via an object from the “${extension.name}” extension.`) + const { schemas = [], resolvers } = extension.extendSchema + outputSchema = schemas.reduce((updatedSchema, extensionSchema) => { + if (typeof extensionSchema === 'string') { + extensionSchema = parse(extensionSchema) + } + return extendSchema(updatedSchema, extensionSchema) + }, outputSchema) + if (resolvers) { + addResolveFunctionsToSchema(outputSchema, resolvers) + } + } else if (typeof extension.extendSchema === 'function') { + debug(`Extending schema via a function from the “${extension.name}” extension.`) + outputSchema = extension.extendSchema(schema, options) + } else { + throw new Error( + `The “${extension.name}” extension contains an invalid ` + + `\`extendSchema\` value: ${extension.extendSchema}` + ) + } + } + + // Fix for `graphql-tools` creating a new Query type with no description. + if (outputSchema._queryType.description === undefined) { + outputSchema._queryType.description = schema._queryType.description + } + return outputSchema +} + +export function createSchema (schema, options = {}) { + const extensions = options.extensions || [] + return extensions.reduce((updatedSchema, extension) => { + return applyExtension(extension, updatedSchema, options) + }, schema) +} + export default new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Query', diff --git a/src/types/cover-art-image.js b/src/types/cover-art-image.js deleted file mode 100644 index b71f684..0000000 --- a/src/types/cover-art-image.js +++ /dev/null @@ -1,72 +0,0 @@ -import { - GraphQLObjectType, - GraphQLNonNull, - GraphQLList, - GraphQLBoolean, - GraphQLString, - GraphQLInt -} from 'graphql/type' -import { URLString } from './scalars' - -export const CoverArtImageThumbnails = new GraphQLObjectType({ - name: 'CoverArtImageThumbnails', - description: `URLs for thumbnails of different sizes for a particular piece of -cover art.`, - fields: () => ({ - small: { - type: URLString, - description: `The URL of a small version of the cover art, where the -maximum dimension is 250px.` - }, - large: { - type: URLString, - description: `The URL of a large version of the cover art, where the -maximum dimension is 500px.` - } - }) -}) - -export default new GraphQLObjectType({ - name: 'CoverArtImage', - description: 'An individual piece of album artwork from the [Cover Art Archive](https://musicbrainz.org/doc/Cover_Art_Archive).', - fields: () => ({ - fileID: { - type: new GraphQLNonNull(GraphQLString), - description: 'The Internet Archive’s internal file ID for the image.', - resolve: image => image.id - }, - image: { - type: new GraphQLNonNull(URLString), - description: 'The URL at which the image can be found.' - }, - thumbnails: { - type: CoverArtImageThumbnails, - description: 'A set of thumbnails for the image.' - }, - front: { - type: new GraphQLNonNull(GraphQLBoolean), - description: 'Whether this image depicts the “main front” of the release.' - }, - back: { - type: new GraphQLNonNull(GraphQLBoolean), - description: 'Whether this image depicts the “main back” of the release.' - }, - types: { - type: new GraphQLList(GraphQLString), - description: `A list of [image types](https://musicbrainz.org/doc/Cover_Art/Types) -describing what part(s) of the release the image includes.` - }, - edit: { - type: GraphQLInt, - description: 'The MusicBrainz edit ID.' - }, - approved: { - type: GraphQLBoolean, - description: 'Whether the image was approved by the MusicBrainz edit system.' - }, - comment: { - type: GraphQLString, - description: 'A free-text comment left for the image.' - } - }) -}) diff --git a/src/types/cover-art.js b/src/types/cover-art.js deleted file mode 100644 index 0c84726..0000000 --- a/src/types/cover-art.js +++ /dev/null @@ -1,188 +0,0 @@ -import { - GraphQLObjectType, - GraphQLList, - GraphQLNonNull, - GraphQLBoolean, - GraphQLInt -} from 'graphql/type' -import CoverArtImage from './cover-art-image' -import { CoverArtImageSize } from './enums' -import Release from './release' -import { URLString } from './scalars' -import { resolveLookup } from '../resolvers' -import { getFields } from '../util' - -/** - * Return a resolver that will call `resolveFn` only if the requested field on - * the object is null or not present. - */ -function createFallbackResolver (resolveFn) { - return function resolve (coverArt, args, context, info) { - const value = coverArt[info.fieldName] - if (value == null) { - return resolveFn(coverArt, args, context, info) - } - return value - } -} - -function resolveImage (coverArt, { size }, { loaders }, info) { - if (size === 'FULL') { - size = null - } - const field = info.fieldName - if (coverArt.images) { - const matches = coverArt.images.filter(image => image[field]) - if (!matches.length) { - return null - } else if (matches.length === 1) { - const match = matches[0] - if (size === 250) { - return match.thumbnails.small - } else if (size === 500) { - return match.thumbnails.large - } else { - return match.image - } - } - } - if (coverArt[field] !== false) { - const { - _parentType: entityType = 'release', - _parentID: id = coverArt._release - } = coverArt - return loaders.coverArtURL.load([entityType, id, field, size]) - } -} - -const size = { - type: CoverArtImageSize, - description: `The size of the image to retrieve. By default, the returned -image will have its full original dimensions, but certain thumbnail sizes may be -retrieved as well.`, - defaultValue: null -} - -/** - * Get around both the circular dependency between the release and cover art - * types, and not have to define an identical `release` field twice on - * `ReleaseCoverArt` and `ReleaseGroupCoverArt`. - */ -function createReleaseField () { - return { - type: new GraphQLNonNull(Release), - description: 'The particular release shown in the returned cover art.', - resolve: (coverArt, args, context, info) => { - const id = coverArt._release - const fields = Object.keys(getFields(info)) - if (fields.length > 1 || fields[0] !== 'mbid') { - return resolveLookup(coverArt, { mbid: id }, context, info) - } - return { id } - } - } -} - -// This type combines two sets of data from different places. One is a *summary* -// of the images available at the Cover Art Archive, found in the `cover-art-archive` -// field on releases. The other is the actual list of images with their metadata, -// fetched from the Cover Art Archive itself rather than MusicBrainz. Depending -// on what fields are requested, we may only need to fetch one or the other, or -// both. Much of the summary data can be reconstructed if we already fetched the -// full image list, for example. -export const ReleaseCoverArt = new GraphQLObjectType({ - name: 'ReleaseCoverArt', - description: `An object containing a list of the cover art images for a -release obtained from the [Cover Art Archive](https://musicbrainz.org/doc/Cover_Art_Archive), -as well as a summary of what artwork is available.`, - fields: () => ({ - front: { - type: URLString, - description: `The URL of an image depicting the album cover or “main -front” of the release, i.e. the front of the packaging of the audio recording -(or in the case of a digital release, the image associated with it in a digital -media store). - -In the MusicBrainz schema, this field is a Boolean value indicating the presence -of a front image, whereas here the value is the URL for the image itself if one -exists. You can check for null if you just want to determine the presence of an -image.`, - args: { size }, - resolve: resolveImage - }, - back: { - type: URLString, - description: `The URL of an image depicting the “main back” of the -release, i.e. the back of the packaging of the audio recording. - -In the MusicBrainz schema, this field is a Boolean value indicating the presence -of a back image, whereas here the value is the URL for the image itself. You can -check for null if you just want to determine the presence of an image.`, - args: { size }, - resolve: resolveImage - }, - images: { - type: new GraphQLList(CoverArtImage), - description: `A list of images depicting the different sides and surfaces -of a release’s media and packaging.`, - resolve: createFallbackResolver((coverArt, args, { loaders }) => { - if (coverArt.count === 0) { - return [] - } - return loaders.coverArt.load(['release', coverArt._release]) - .then(coverArt => coverArt.images) - }) - }, - artwork: { - type: new GraphQLNonNull(GraphQLBoolean), - description: 'Whether there is artwork present for this release.', - resolve: createFallbackResolver(coverArt => coverArt.images.length > 0) - }, - darkened: { - type: new GraphQLNonNull(GraphQLBoolean), - description: `Whether the Cover Art Archive has received a take-down -request for this release’s artwork, disallowing new uploads.`, - resolve: createFallbackResolver((coverArt, args, { loaders }) => { - return loaders.lookup.load(['release', coverArt._release]) - .then(release => release['cover-art-archive'].darkened) - }) - }, - count: { - type: new GraphQLNonNull(GraphQLInt), - description: 'The number of artwork images present for this release.', - resolve: createFallbackResolver(coverArt => coverArt.images.length) - }, - release: createReleaseField() - }) -}) - -export const ReleaseGroupCoverArt = new GraphQLObjectType({ - name: 'ReleaseGroupCoverArt', - description: `An object containing the cover art for a release group obtained -from the [Cover Art Archive](https://musicbrainz.org/doc/Cover_Art_Archive). For -release groups, just the front cover of a particular release will be selected.`, - fields: () => ({ - front: { - type: URLString, - description: `The URL of an image depicting the album cover or “main -front” of a release in the release group, i.e. the front of the packaging of the -audio recording (or in the case of a digital release, the image associated with -it in a digital media store).`, - args: { size }, - resolve: resolveImage - }, - images: { - type: new GraphQLList(CoverArtImage), - description: `A list of images returned by the [Cover Art -Archive](https://musicbrainz.org/doc/Cover_Art_Archive) for a release group. A -particular release’s front image will be included in the list, and likely no -others, even if other images are available.` - }, - artwork: { - type: new GraphQLNonNull(GraphQLBoolean), - description: 'Whether there is artwork present for this release group.', - resolve: createFallbackResolver(coverArt => coverArt.images.length > 0) - }, - release: createReleaseField() - }) -}) diff --git a/src/types/release-group.js b/src/types/release-group.js index f7f68b8..6161202 100644 --- a/src/types/release-group.js +++ b/src/types/release-group.js @@ -1,7 +1,6 @@ import { GraphQLObjectType, GraphQLList } from 'graphql/type' import Node from './node' import Entity from './entity' -import { ReleaseGroupCoverArt } from './cover-art' import { DateType } from './scalars' import { ReleaseGroupType } from './enums' import { @@ -59,14 +58,6 @@ e.g. album, single, soundtrack, compilation, etc. A release group can have a description: `Additional [types](https://musicbrainz.org/doc/Release_Group/Type) that apply to this release group.` }), - coverArt: { - type: ReleaseGroupCoverArt, - description: `The cover art for a release group, obtained from the [Cover -Art Archive](https://musicbrainz.org/doc/Cover_Art_Archive).`, - resolve: (releaseGroup, args, { loaders }) => { - return loaders.coverArt.load(['release-group', releaseGroup.id]) - } - }, artists, releases, relationships, diff --git a/src/types/release.js b/src/types/release.js index a8475c7..68b00ab 100644 --- a/src/types/release.js +++ b/src/types/release.js @@ -1,6 +1,5 @@ import { GraphQLObjectType, - GraphQLNonNull, GraphQLString, GraphQLList } from 'graphql/type' @@ -8,7 +7,6 @@ import Node from './node' import Entity from './entity' import { ASIN, DateType } from './scalars' import Media from './media' -import { ReleaseCoverArt } from './cover-art' import { ReleaseStatus } from './enums' import ReleaseEvent from './release-event' import { @@ -74,19 +72,6 @@ release has one. The most common types found on releases are 12-digit [UPCs](https://en.wikipedia.org/wiki/Universal_Product_Code) and 13-digit [EANs](https://en.wikipedia.org/wiki/International_Article_Number).` }, - coverArt: { - type: new GraphQLNonNull(ReleaseCoverArt), - description: `A list and summary of the cover art images that are present -for this release from the [Cover Art Archive](https://musicbrainz.org/doc/Cover_Art_Archive).`, - resolve: (release, args, { loaders }) => { - const coverArt = release['cover-art-archive'] - if (coverArt) { - coverArt._release = release.id - return coverArt - } - return loaders.coverArt.load(['release', release.id]) - } - }, ...fieldWithID('status', { type: ReleaseStatus, description: 'The status describes how “official” a release is.' diff --git a/src/util.js b/src/util.js index 1155a57..808b244 100644 --- a/src/util.js +++ b/src/util.js @@ -1,5 +1,7 @@ import util from 'util' +export const ONE_DAY = 24 * 60 * 60 * 1000 + export function getFields (info, fragments = info.fragments) { if (info.kind !== 'Field') { info = info.fieldNodes[0] @@ -13,6 +15,8 @@ export function getFields (info, fragments = info.fragments) { throw new Error(`Fragment '${name}' was not passed to getFields()`) } fragment.selectionSet.selections.reduce(reducer, fields) + } else if (selection.kind === 'InlineFragment') { + selection.selectionSet.selections.reduce(reducer, fields) } else { fields[selection.name.value] = selection } diff --git a/test/api/cover-art-archive.js b/test/extensions/cover-art-archive/client.js similarity index 90% rename from test/api/cover-art-archive.js rename to test/extensions/cover-art-archive/client.js index 02cf7ab..d9fd005 100644 --- a/test/api/cover-art-archive.js +++ b/test/extensions/cover-art-archive/client.js @@ -1,6 +1,5 @@ import test from 'ava' -import { CoverArtArchiveError } from '../../src/api' -import client from '../helpers/client/cover-art-archive' +import client from '../../helpers/client/cover-art-archive' test('can retrieve a front image URL', t => { return client.imageURL('release', '76df3287-6cda-33eb-8e9a-044b5e15ffdd', 'front') @@ -37,7 +36,7 @@ test('can retrieve a list of release images', t => { }) test('throws an error if given an invalid MBID', t => { - return t.throws(client.images('release', 'xyz'), CoverArtArchiveError) + return t.throws(client.images('release', 'xyz'), client.errorClass) }) test('uses the default error impementation if there is no HTML error', t => { diff --git a/test/extensions/cover-art-archive/schema.js b/test/extensions/cover-art-archive/schema.js new file mode 100644 index 0000000..59ffa0d --- /dev/null +++ b/test/extensions/cover-art-archive/schema.js @@ -0,0 +1,174 @@ +import test from 'ava' +import { graphql } from 'graphql' +import extension from '../../../src/extensions/cover-art-archive' +import baseSchema, { applyExtension } from '../../../src/schema' +import baseContext from '../../helpers/context' + +const schema = applyExtension(extension, baseSchema) +const context = extension.extendContext(baseContext) + +function testData (t, query, handler) { + return graphql(schema, query, null, context).then(result => { + if (result.errors !== undefined) { + console.log(result.errors) + } + t.is(result.errors, undefined) + return handler(t, result.data) + }) +} + +test('releases have a cover art summary', testData, ` + { + lookup { + release(mbid: "b84ee12a-09ef-421b-82de-0441a926375b") { + coverArtArchive { + artwork + count + } + } + } + } +`, (t, data) => { + const { coverArtArchive } = data.lookup.release + t.true(coverArtArchive.artwork) + t.true(coverArtArchive.count >= 10) +}) + +test('releases have a set of cover art images', testData, ` + { + lookup { + release(mbid: "b84ee12a-09ef-421b-82de-0441a926375b") { + coverArtArchive { + front + back + images { + front + back + types + approved + edit + comment + fileID + image + thumbnails { + small + large + } + } + } + } + } + } +`, (t, data) => { + const { coverArtArchive } = data.lookup.release + t.is(coverArtArchive.front, 'http://coverartarchive.org/release/b84ee12a-09ef-421b-82de-0441a926375b/1611507818.jpg') + t.is(coverArtArchive.back, 'http://coverartarchive.org/release/b84ee12a-09ef-421b-82de-0441a926375b/13536418798.jpg') + t.true(coverArtArchive.images.length >= 10) + t.true(coverArtArchive.images.some(image => image.front === true)) + t.true(coverArtArchive.images.some(image => image.back === true)) + t.true(coverArtArchive.images.some(image => image.types.indexOf('Front') >= 0)) + t.true(coverArtArchive.images.some(image => image.types.indexOf('Back') >= 0)) + t.true(coverArtArchive.images.some(image => image.types.indexOf('Liner') >= 0)) + t.true(coverArtArchive.images.some(image => image.types.indexOf('Poster') >= 0)) + t.true(coverArtArchive.images.some(image => image.types.indexOf('Medium') >= 0)) + t.true(coverArtArchive.images.some(image => image.edit === 18544122)) + t.true(coverArtArchive.images.some(image => image.comment === '')) + t.true(coverArtArchive.images.some(image => image.fileID === '1611507818')) + t.true(coverArtArchive.images.some(image => image.image === 'http://coverartarchive.org/release/b84ee12a-09ef-421b-82de-0441a926375b/13536422691.jpg')) + t.true(coverArtArchive.images.every(image => image.approved === true)) + t.true(coverArtArchive.images.every(image => image.thumbnails.small)) + t.true(coverArtArchive.images.every(image => image.thumbnails.large)) +}) + +test('can request a size for front and back cover art', testData, ` + { + lookup { + release(mbid: "b84ee12a-09ef-421b-82de-0441a926375b") { + coverArtArchive { + front(size: LARGE) + back(size: SMALL) + fullFront: front(size: FULL) + } + } + } + } +`, (t, data) => { + const { coverArtArchive } = data.lookup.release + t.is(coverArtArchive.front, 'http://coverartarchive.org/release/b84ee12a-09ef-421b-82de-0441a926375b/1611507818-500.jpg') + t.is(coverArtArchive.back, 'http://coverartarchive.org/release/b84ee12a-09ef-421b-82de-0441a926375b/13536418798-250.jpg') + t.is(coverArtArchive.fullFront, 'http://coverartarchive.org/release/b84ee12a-09ef-421b-82de-0441a926375b/1611507818.jpg') +}) + +test('release groups have a front cover art image', testData, ` + { + lookup { + releaseGroup(mbid: "f5093c06-23e3-404f-aeaa-40f72885ee3a") { + coverArtArchive { + artwork + front + images { + front + image + } + release { + mbid + title + } + } + } + } + } +`, (t, data) => { + const { coverArtArchive } = data.lookup.releaseGroup + t.true(coverArtArchive.artwork) + t.is(coverArtArchive.front, 'http://coverartarchive.org/release/25fbfbb4-b1ee-4448-aadf-ae3bc2e2dd27/1675312275.jpg') + t.is(coverArtArchive.release.mbid, '25fbfbb4-b1ee-4448-aadf-ae3bc2e2dd27') + t.is(coverArtArchive.release.title, 'The Dark Side of the Moon') + t.is(coverArtArchive.images.length, 1) + t.true(coverArtArchive.images[0].front) +}) + +test('release groups have different cover art sizes available', testData, ` + { + lookup { + releaseGroup(mbid: "f5093c06-23e3-404f-aeaa-40f72885ee3a") { + coverArtArchive { + small: front(size: SMALL) + large: front(size: LARGE) + } + } + } + } +`, (t, data) => { + const { coverArtArchive } = data.lookup.releaseGroup + t.is(coverArtArchive.small, 'http://coverartarchive.org/release/25fbfbb4-b1ee-4448-aadf-ae3bc2e2dd27/1675312275-250.jpg') + t.is(coverArtArchive.large, 'http://coverartarchive.org/release/25fbfbb4-b1ee-4448-aadf-ae3bc2e2dd27/1675312275-500.jpg') +}) + +test('can retrieve cover art in searches', testData, ` + { + search { + releases(query: "You Want It Darker") { + edges { + node { + coverArtArchive { + artwork + front + back + images { + image + } + } + } + } + } + } + } +`, (t, data) => { + const releases = data.search.releases.edges.map(edge => edge.node) + t.is(releases.length, 25) + t.true(releases.some(release => release.coverArtArchive.artwork === true)) + t.true(releases.some(release => release.coverArtArchive.images.length > 0)) + t.true(releases.some(release => release.coverArtArchive.front === null)) + t.true(releases.some(release => release.coverArtArchive.back === null)) +}) diff --git a/test/extensions/fanart-tv/schema.js b/test/extensions/fanart-tv/schema.js new file mode 100644 index 0000000..4ddc201 --- /dev/null +++ b/test/extensions/fanart-tv/schema.js @@ -0,0 +1,128 @@ +import test from 'ava' +import { graphql } from 'graphql' +import extension from '../../../src/extensions/fanart-tv' +import baseSchema, { applyExtension } from '../../../src/schema' +import baseContext from '../../helpers/context' + +const schema = applyExtension(extension, baseSchema) +const context = extension.extendContext(baseContext) + +function testData (t, query, handler) { + return graphql(schema, query, null, context).then(result => { + if (result.errors !== undefined) { + console.log(result.errors) + } + t.is(result.errors, undefined) + return handler(t, result.data) + }) +} + +test('artists have a fanArt field and preview images', testData, ` + { + lookup { + artist(mbid: "5b11f4ce-a62d-471e-81fc-a69a8278c7da") { + fanArt { + backgrounds { + imageID + url(size: PREVIEW) + fullSizeURL: url + likeCount + } + banners { + imageID + url(size: PREVIEW) + fullSizeURL: url + likeCount + } + logos { + imageID + url(size: PREVIEW) + fullSizeURL: url + likeCount + } + logosHD { + imageID + url(size: PREVIEW) + fullSizeURL: url + likeCount + } + thumbnails { + imageID + url(size: PREVIEW) + fullSizeURL: url + likeCount + } + } + } + } + } +`, (t, data) => { + t.snapshot(data) + const { fanArt } = data.lookup.artist + const allImages = [] + .concat(fanArt.backgrounds) + .concat(fanArt.banners) + .concat(fanArt.logos) + .concat(fanArt.logosHD) + .concat(fanArt.thumbnails) + allImages.forEach(image => { + t.not(image.url, image.fullSizeURL) + }) +}) + +test('release groups have a fanArt field and preview images', testData, ` + { + lookup { + releaseGroup(mbid: "f5093c06-23e3-404f-aeaa-40f72885ee3a") { + fanArt { + albumCovers { + imageID + url(size: PREVIEW) + fullSizeURL: url + likeCount + } + discImages { + imageID + url(size: PREVIEW) + fullSizeURL: url + discNumber + size + } + } + } + } + } +`, (t, data) => { + t.snapshot(data) + const { fanArt } = data.lookup.releaseGroup + const allImages = [] + .concat(fanArt.albumCovers) + .concat(fanArt.discImages) + allImages.forEach(image => { + t.not(image.url, image.fullSizeURL) + }) +}) + +test('labels have a fanArt field and preview images', testData, ` + { + lookup { + label(mbid: "0cf56645-50ec-4411-aeb6-c9f4ce0f8edb") { + fanArt { + logos { + imageID + url(size: PREVIEW) + fullSizeURL: url + likeCount + color + } + } + } + } + } +`, (t, data) => { + t.snapshot(data) + const { fanArt } = data.lookup.label + fanArt.logos.forEach(image => { + t.not(image.url, image.fullSizeURL) + }) +}) diff --git a/test/extensions/fanart-tv/snapshots/schema.js.md b/test/extensions/fanart-tv/snapshots/schema.js.md new file mode 100644 index 0000000..8b87722 --- /dev/null +++ b/test/extensions/fanart-tv/snapshots/schema.js.md @@ -0,0 +1,424 @@ +# Snapshot report for `test/extensions/fanart-tv/schema.js` + +The actual snapshot is saved in `schema.js.snap`. + +Generated by [AVA](https://ava.li). + +## artists have a fanArt field and preview images + +> Snapshot 1 + + { + lookup: { + artist: { + fanArt: { + backgrounds: [ + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/artistbackground/nirvana-52c91734c39dd.jpg', + imageID: '108996', + likeCount: 7, + url: 'https://assets.fanart.tv/preview/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/artistbackground/nirvana-52c91734c39dd.jpg', + }, + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/artistbackground/nirvana-4ddaf131354a8.jpg', + imageID: '2539', + likeCount: 7, + url: 'https://assets.fanart.tv/preview/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/artistbackground/nirvana-4ddaf131354a8.jpg', + }, + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/artistbackground/nirvana-524daf0607406.jpg', + imageID: '99990', + likeCount: 6, + url: 'https://assets.fanart.tv/preview/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/artistbackground/nirvana-524daf0607406.jpg', + }, + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/artistbackground/nirvana-4de90b913b2a1.jpg', + imageID: '4153', + likeCount: 3, + url: 'https://assets.fanart.tv/preview/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/artistbackground/nirvana-4de90b913b2a1.jpg', + }, + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/artistbackground/nirvana-54dc843050470.jpg', + imageID: '151698', + likeCount: 3, + url: 'https://assets.fanart.tv/preview/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/artistbackground/nirvana-54dc843050470.jpg', + }, + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/artistbackground/nirvana-52c917ac71459.jpg', + imageID: '108997', + likeCount: 3, + url: 'https://assets.fanart.tv/preview/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/artistbackground/nirvana-52c917ac71459.jpg', + }, + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/artistbackground/nirvana-55baa96c8c47f.jpg', + imageID: '172578', + likeCount: 2, + url: 'https://assets.fanart.tv/preview/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/artistbackground/nirvana-55baa96c8c47f.jpg', + }, + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/artistbackground/nirvana-500187e32be79.jpg', + imageID: '42530', + likeCount: 2, + url: 'https://assets.fanart.tv/preview/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/artistbackground/nirvana-500187e32be79.jpg', + }, + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/artistbackground/nirvana-56d0287053099.jpg', + imageID: '190330', + likeCount: 2, + url: 'https://assets.fanart.tv/preview/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/artistbackground/nirvana-56d0287053099.jpg', + }, + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/artistbackground/nirvana-56d02870536ef.jpg', + imageID: '190331', + likeCount: 2, + url: 'https://assets.fanart.tv/preview/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/artistbackground/nirvana-56d02870536ef.jpg', + }, + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/artistbackground/nirvana-54dc845f81d1b.jpg', + imageID: '151699', + likeCount: 2, + url: 'https://assets.fanart.tv/preview/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/artistbackground/nirvana-54dc845f81d1b.jpg', + }, + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/artistbackground/nirvana-524daf0607e44.jpg', + imageID: '99991', + likeCount: 2, + url: 'https://assets.fanart.tv/preview/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/artistbackground/nirvana-524daf0607e44.jpg', + }, + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/artistbackground/nirvana-54ac79e578054.jpg', + imageID: '146472', + likeCount: 1, + url: 'https://assets.fanart.tv/preview/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/artistbackground/nirvana-54ac79e578054.jpg', + }, + ], + banners: [ + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/musicbanner/nirvana-515f7e1a6f50b.jpg', + imageID: '78008', + likeCount: 2, + url: 'https://assets.fanart.tv/preview/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/musicbanner/nirvana-515f7e1a6f50b.jpg', + }, + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/musicbanner/nirvana-591789a12da78.jpg', + imageID: '218845', + likeCount: 2, + url: 'https://assets.fanart.tv/preview/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/musicbanner/nirvana-591789a12da78.jpg', + }, + ], + logos: [ + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/musiclogo/nirvana-4e4b9bc06dcc4.png', + imageID: '8957', + likeCount: 4, + url: 'https://assets.fanart.tv/preview/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/musiclogo/nirvana-4e4b9bc06dcc4.png', + }, + ], + logosHD: [ + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/hdmusiclogo/nirvana-5261733fe6c60.png', + imageID: '101686', + likeCount: 6, + url: 'https://assets.fanart.tv/preview/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/hdmusiclogo/nirvana-5261733fe6c60.png', + }, + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/hdmusiclogo/nirvana-518a696cda12f.png', + imageID: '81480', + likeCount: 4, + url: 'https://assets.fanart.tv/preview/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/hdmusiclogo/nirvana-518a696cda12f.png', + }, + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/hdmusiclogo/nirvana-518ada7d98805.png', + imageID: '81521', + likeCount: 3, + url: 'https://assets.fanart.tv/preview/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/hdmusiclogo/nirvana-518ada7d98805.png', + }, + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/hdmusiclogo/nirvana-518a696c1ab0b.png', + imageID: '81479', + likeCount: 2, + url: 'https://assets.fanart.tv/preview/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/hdmusiclogo/nirvana-518a696c1ab0b.png', + }, + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/hdmusiclogo/nirvana-561900ee87f11.png', + imageID: '181150', + likeCount: 2, + url: 'https://assets.fanart.tv/preview/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/hdmusiclogo/nirvana-561900ee87f11.png', + }, + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/hdmusiclogo/nirvana-59039625adb45.png', + imageID: '217621', + likeCount: 1, + url: 'https://assets.fanart.tv/preview/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/hdmusiclogo/nirvana-59039625adb45.png', + }, + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/hdmusiclogo/nirvana-561900db6b999.png', + imageID: '181149', + likeCount: 1, + url: 'https://assets.fanart.tv/preview/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/hdmusiclogo/nirvana-561900db6b999.png', + }, + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/hdmusiclogo/nirvana-5619010106ffb.png', + imageID: '181151', + likeCount: 1, + url: 'https://assets.fanart.tv/preview/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/hdmusiclogo/nirvana-5619010106ffb.png', + }, + ], + thumbnails: [ + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/artistthumb/nirvana-4fb61ff40a15a.jpg', + imageID: '31455', + likeCount: 4, + url: 'https://assets.fanart.tv/preview/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/artistthumb/nirvana-4fb61ff40a15a.jpg', + }, + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/artistthumb/nirvana-4fb61fd2f3204.jpg', + imageID: '31454', + likeCount: 3, + url: 'https://assets.fanart.tv/preview/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/artistthumb/nirvana-4fb61fd2f3204.jpg', + }, + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/artistthumb/nirvana-4fb6205204d6e.jpg', + imageID: '31456', + likeCount: 3, + url: 'https://assets.fanart.tv/preview/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/artistthumb/nirvana-4fb6205204d6e.jpg', + }, + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/artistthumb/nirvana-515ddb61b444b.jpg', + imageID: '77828', + likeCount: 2, + url: 'https://assets.fanart.tv/preview/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da/artistthumb/nirvana-515ddb61b444b.jpg', + }, + ], + }, + }, + }, + } + +## labels have a fanArt field and preview images + +> Snapshot 1 + + { + lookup: { + label: { + fanArt: { + logos: [], + }, + }, + }, + } + +## release groups have a fanArt field and preview images + +> Snapshot 1 + + { + lookup: { + releaseGroup: { + fanArt: { + albumCovers: [ + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/83d91898-7763-47d7-b03b-b92132375c47/albumcover/the-dark-side-of-the-moon-4decb408b6604.jpg', + imageID: '4417', + likeCount: 11, + url: 'https://assets.fanart.tv/preview/music/83d91898-7763-47d7-b03b-b92132375c47/albumcover/the-dark-side-of-the-moon-4decb408b6604.jpg', + }, + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/83d91898-7763-47d7-b03b-b92132375c47/albumcover/the-dark-side-of-the-moon-53afcfaa65a86.jpg', + imageID: '128223', + likeCount: 6, + url: 'https://assets.fanart.tv/preview/music/83d91898-7763-47d7-b03b-b92132375c47/albumcover/the-dark-side-of-the-moon-53afcfaa65a86.jpg', + }, + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/83d91898-7763-47d7-b03b-b92132375c47/albumcover/the-dark-side-of-the-moon-5647389f76c9a.jpg', + imageID: '183166', + likeCount: 3, + url: 'https://assets.fanart.tv/preview/music/83d91898-7763-47d7-b03b-b92132375c47/albumcover/the-dark-side-of-the-moon-5647389f76c9a.jpg', + }, + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/83d91898-7763-47d7-b03b-b92132375c47/albumcover/the-dark-side-of-the-moon-555319062404d.jpg', + imageID: '163522', + likeCount: 3, + url: 'https://assets.fanart.tv/preview/music/83d91898-7763-47d7-b03b-b92132375c47/albumcover/the-dark-side-of-the-moon-555319062404d.jpg', + }, + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/83d91898-7763-47d7-b03b-b92132375c47/albumcover/the-dark-side-of-the-moon-535054d4e2e32.jpg', + imageID: '118729', + likeCount: 3, + url: 'https://assets.fanart.tv/preview/music/83d91898-7763-47d7-b03b-b92132375c47/albumcover/the-dark-side-of-the-moon-535054d4e2e32.jpg', + }, + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/83d91898-7763-47d7-b03b-b92132375c47/albumcover/the-dark-side-of-the-moon-53cf470795637.jpg', + imageID: '130679', + likeCount: 2, + url: 'https://assets.fanart.tv/preview/music/83d91898-7763-47d7-b03b-b92132375c47/albumcover/the-dark-side-of-the-moon-53cf470795637.jpg', + }, + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/83d91898-7763-47d7-b03b-b92132375c47/albumcover/the-dark-side-of-the-moon-55c4af535f7e9.jpg', + imageID: '173720', + likeCount: 1, + url: 'https://assets.fanart.tv/preview/music/83d91898-7763-47d7-b03b-b92132375c47/albumcover/the-dark-side-of-the-moon-55c4af535f7e9.jpg', + }, + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/83d91898-7763-47d7-b03b-b92132375c47/albumcover/the-dark-side-of-the-moon-55cbdf80ef05c.jpg', + imageID: '174560', + likeCount: 1, + url: 'https://assets.fanart.tv/preview/music/83d91898-7763-47d7-b03b-b92132375c47/albumcover/the-dark-side-of-the-moon-55cbdf80ef05c.jpg', + }, + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/83d91898-7763-47d7-b03b-b92132375c47/albumcover/the-dark-side-of-the-moon-59a82b1a7c6cd.jpg', + imageID: '225420', + likeCount: 0, + url: 'https://assets.fanart.tv/preview/music/83d91898-7763-47d7-b03b-b92132375c47/albumcover/the-dark-side-of-the-moon-59a82b1a7c6cd.jpg', + }, + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/83d91898-7763-47d7-b03b-b92132375c47/albumcover/the-dark-side-of-the-moon-59a82d31adb2f.jpg', + imageID: '225421', + likeCount: 0, + url: 'https://assets.fanart.tv/preview/music/83d91898-7763-47d7-b03b-b92132375c47/albumcover/the-dark-side-of-the-moon-59a82d31adb2f.jpg', + }, + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/83d91898-7763-47d7-b03b-b92132375c47/albumcover/the-dark-side-of-the-moon-59a31c7ad5931.jpg', + imageID: '225172', + likeCount: 0, + url: 'https://assets.fanart.tv/preview/music/83d91898-7763-47d7-b03b-b92132375c47/albumcover/the-dark-side-of-the-moon-59a31c7ad5931.jpg', + }, + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/83d91898-7763-47d7-b03b-b92132375c47/albumcover/the-dark-side-of-the-moon-59a48bfb008e3.jpg', + imageID: '225266', + likeCount: 0, + url: 'https://assets.fanart.tv/preview/music/83d91898-7763-47d7-b03b-b92132375c47/albumcover/the-dark-side-of-the-moon-59a48bfb008e3.jpg', + }, + { + fullSizeURL: 'https://assets.fanart.tv/fanart/music/83d91898-7763-47d7-b03b-b92132375c47/albumcover/the-dark-side-of-the-moon-59a48df6822b4.jpg', + imageID: '225267', + likeCount: 0, + url: 'https://assets.fanart.tv/preview/music/83d91898-7763-47d7-b03b-b92132375c47/albumcover/the-dark-side-of-the-moon-59a48df6822b4.jpg', + }, + ], + discImages: [ + { + discNumber: 1, + fullSizeURL: 'https://assets.fanart.tv/fanart/music/83d91898-7763-47d7-b03b-b92132375c47/cdart/the-dark-side-of-the-moon-56047db2bbb28.png', + imageID: '179437', + size: 1000, + url: 'https://assets.fanart.tv/preview/music/83d91898-7763-47d7-b03b-b92132375c47/cdart/the-dark-side-of-the-moon-56047db2bbb28.png', + }, + { + discNumber: 1, + fullSizeURL: 'https://assets.fanart.tv/fanart/music/83d91898-7763-47d7-b03b-b92132375c47/cdart/the-dark-side-of-the-moon-56047e045d648.png', + imageID: '179438', + size: 1000, + url: 'https://assets.fanart.tv/preview/music/83d91898-7763-47d7-b03b-b92132375c47/cdart/the-dark-side-of-the-moon-56047e045d648.png', + }, + { + discNumber: 3, + fullSizeURL: 'https://assets.fanart.tv/fanart/music/83d91898-7763-47d7-b03b-b92132375c47/cdart/the-dark-side-of-the-moon-50aa6521ef0f3.png', + imageID: '62047', + size: 1000, + url: 'https://assets.fanart.tv/preview/music/83d91898-7763-47d7-b03b-b92132375c47/cdart/the-dark-side-of-the-moon-50aa6521ef0f3.png', + }, + { + discNumber: 1, + fullSizeURL: 'https://assets.fanart.tv/fanart/music/83d91898-7763-47d7-b03b-b92132375c47/cdart/the-dark-side-of-the-moon-56047e56b51f8.png', + imageID: '179439', + size: 1000, + url: 'https://assets.fanart.tv/preview/music/83d91898-7763-47d7-b03b-b92132375c47/cdart/the-dark-side-of-the-moon-56047e56b51f8.png', + }, + { + discNumber: 1, + fullSizeURL: 'https://assets.fanart.tv/fanart/music/83d91898-7763-47d7-b03b-b92132375c47/cdart/the-dark-side-of-the-moon-5957ea48b6728.png', + imageID: '221698', + size: 1000, + url: 'https://assets.fanart.tv/preview/music/83d91898-7763-47d7-b03b-b92132375c47/cdart/the-dark-side-of-the-moon-5957ea48b6728.png', + }, + { + discNumber: 1, + fullSizeURL: 'https://assets.fanart.tv/fanart/music/83d91898-7763-47d7-b03b-b92132375c47/cdart/the-dark-side-of-the-moon-59a0791276643.png', + imageID: '225077', + size: 1000, + url: 'https://assets.fanart.tv/preview/music/83d91898-7763-47d7-b03b-b92132375c47/cdart/the-dark-side-of-the-moon-59a0791276643.png', + }, + { + discNumber: 1, + fullSizeURL: 'https://assets.fanart.tv/fanart/music/83d91898-7763-47d7-b03b-b92132375c47/cdart/the-dark-side-of-the-moon-501c2a49803a0.png', + imageID: '46158', + size: 1000, + url: 'https://assets.fanart.tv/preview/music/83d91898-7763-47d7-b03b-b92132375c47/cdart/the-dark-side-of-the-moon-501c2a49803a0.png', + }, + { + discNumber: 2, + fullSizeURL: 'https://assets.fanart.tv/fanart/music/83d91898-7763-47d7-b03b-b92132375c47/cdart/the-dark-side-of-the-moon-501c3001b1c7c.png', + imageID: '46162', + size: 1000, + url: 'https://assets.fanart.tv/preview/music/83d91898-7763-47d7-b03b-b92132375c47/cdart/the-dark-side-of-the-moon-501c3001b1c7c.png', + }, + { + discNumber: 2, + fullSizeURL: 'https://assets.fanart.tv/fanart/music/83d91898-7763-47d7-b03b-b92132375c47/cdart/the-dark-side-of-the-moon-59a74d8e41558.png', + imageID: '225375', + size: 1000, + url: 'https://assets.fanart.tv/preview/music/83d91898-7763-47d7-b03b-b92132375c47/cdart/the-dark-side-of-the-moon-59a74d8e41558.png', + }, + { + discNumber: 3, + fullSizeURL: 'https://assets.fanart.tv/fanart/music/83d91898-7763-47d7-b03b-b92132375c47/cdart/the-dark-side-of-the-moon-59a74dbb41789.png', + imageID: '225376', + size: 1000, + url: 'https://assets.fanart.tv/preview/music/83d91898-7763-47d7-b03b-b92132375c47/cdart/the-dark-side-of-the-moon-59a74dbb41789.png', + }, + { + discNumber: 4, + fullSizeURL: 'https://assets.fanart.tv/fanart/music/83d91898-7763-47d7-b03b-b92132375c47/cdart/the-dark-side-of-the-moon-59a7719de4451.png', + imageID: '225385', + size: 1000, + url: 'https://assets.fanart.tv/preview/music/83d91898-7763-47d7-b03b-b92132375c47/cdart/the-dark-side-of-the-moon-59a7719de4451.png', + }, + { + discNumber: 5, + fullSizeURL: 'https://assets.fanart.tv/fanart/music/83d91898-7763-47d7-b03b-b92132375c47/cdart/the-dark-side-of-the-moon-59a81404c6562.png', + imageID: '225414', + size: 1000, + url: 'https://assets.fanart.tv/preview/music/83d91898-7763-47d7-b03b-b92132375c47/cdart/the-dark-side-of-the-moon-59a81404c6562.png', + }, + { + discNumber: 6, + fullSizeURL: 'https://assets.fanart.tv/fanart/music/83d91898-7763-47d7-b03b-b92132375c47/cdart/the-dark-side-of-the-moon-59a822507d221.png', + imageID: '225416', + size: 1000, + url: 'https://assets.fanart.tv/preview/music/83d91898-7763-47d7-b03b-b92132375c47/cdart/the-dark-side-of-the-moon-59a822507d221.png', + }, + { + discNumber: 1, + fullSizeURL: 'https://assets.fanart.tv/fanart/music/83d91898-7763-47d7-b03b-b92132375c47/cdart/the-dark-side-of-the-moon-54c55c43410af.png', + imageID: '148887', + size: 1000, + url: 'https://assets.fanart.tv/preview/music/83d91898-7763-47d7-b03b-b92132375c47/cdart/the-dark-side-of-the-moon-54c55c43410af.png', + }, + { + discNumber: 1, + fullSizeURL: 'https://assets.fanart.tv/fanart/music/83d91898-7763-47d7-b03b-b92132375c47/cdart/the-dark-side-of-the-moon-59a3237b3607a.png', + imageID: '225188', + size: 1000, + url: 'https://assets.fanart.tv/preview/music/83d91898-7763-47d7-b03b-b92132375c47/cdart/the-dark-side-of-the-moon-59a3237b3607a.png', + }, + { + discNumber: 1, + fullSizeURL: 'https://assets.fanart.tv/fanart/music/83d91898-7763-47d7-b03b-b92132375c47/cdart/the-dark-side-of-the-moon-532569d57474d.png', + imageID: '115624', + size: 1000, + url: 'https://assets.fanart.tv/preview/music/83d91898-7763-47d7-b03b-b92132375c47/cdart/the-dark-side-of-the-moon-532569d57474d.png', + }, + { + discNumber: 1, + fullSizeURL: 'https://assets.fanart.tv/fanart/music/83d91898-7763-47d7-b03b-b92132375c47/cdart/the-dark-side-of-the-moon-59a375ff8866e.png', + imageID: '225215', + size: 1000, + url: 'https://assets.fanart.tv/preview/music/83d91898-7763-47d7-b03b-b92132375c47/cdart/the-dark-side-of-the-moon-59a375ff8866e.png', + }, + ], + }, + }, + }, + } diff --git a/test/extensions/fanart-tv/snapshots/schema.js.snap b/test/extensions/fanart-tv/snapshots/schema.js.snap new file mode 100644 index 0000000..2ae8799 Binary files /dev/null and b/test/extensions/fanart-tv/snapshots/schema.js.snap differ diff --git a/test/extensions/mediawiki/schema.js b/test/extensions/mediawiki/schema.js new file mode 100644 index 0000000..8633a67 --- /dev/null +++ b/test/extensions/mediawiki/schema.js @@ -0,0 +1,101 @@ +import test from 'ava' +import { graphql } from 'graphql' +import extension from '../../../src/extensions/mediawiki' +import baseSchema, { applyExtension } from '../../../src/schema' +import baseContext from '../../helpers/context' + +const schema = applyExtension(extension, baseSchema) +const context = extension.extendContext(baseContext) + +function testData (t, query, handler) { + return graphql(schema, query, null, context).then(result => { + if (result.errors !== undefined) { + console.log(result.errors) + } + t.is(result.errors, undefined) + return handler(t, result.data) + }) +} + +const fragment = ` + url + descriptionURL + user + size + width + height + canonicalTitle + objectName + descriptionHTML + originalDateTimeHTML + categories + artistHTML + creditHTML + licenseShortName + licenseURL + metadata { + name + value + source + } +` + +test('artists have a mediaWikiImages field', testData, ` + { + lookup { + artist(mbid: "5b11f4ce-a62d-471e-81fc-a69a8278c7da") { + mediaWikiImages { + ${fragment} + } + } + } + } +`, (t, data) => { + t.snapshot(data) +}) + +test('instruments have a mediaWikiImages field', testData, ` + { + search { + instruments(query: "guitar", first: 20) { + nodes { + mediaWikiImages { + ${fragment} + } + } + } + } + } +`, (t, data) => { + t.snapshot(data) +}) + +test('labels have a mediaWikiImages field', testData, ` + { + search { + labels(query: "Sony", first: 50) { + nodes { + mediaWikiImages { + ${fragment} + } + } + } + } + } +`, (t, data) => { + t.snapshot(data) +}) + +test('places have a mediaWikiImages field', testData, ` + { + lookup { + place(mbid: "b5297256-8482-4cba-968a-25db61563faf") { + mediaWikiImages { + ${fragment} + } + } + } + } +`, (t, data) => { + t.snapshot(data) +}) diff --git a/test/extensions/mediawiki/snapshots/schema.js.md b/test/extensions/mediawiki/snapshots/schema.js.md new file mode 100644 index 0000000..a26dcee --- /dev/null +++ b/test/extensions/mediawiki/snapshots/schema.js.md @@ -0,0 +1,580 @@ +# Snapshot report for `test/extensions/mediawiki/schema.js` + +The actual snapshot is saved in `schema.js.snap`. + +Generated by [AVA](https://ava.li). + +## artists have a mediaWikiImages field + +> Snapshot 1 + + { + lookup: { + artist: { + mediaWikiImages: [ + { + artistHTML: 'P.B. Rage from USA', + canonicalTitle: 'File:Nirvana around 1992.jpg', + categories: [ + '1992 in California', + '1992 in television', + 'Fashion in 1992', + 'Flickr images reviewed by trusted users', + 'Krist Novoselic', + 'Kurt Cobain', + 'MTV Video Music Awards', + 'Music events in 1992', + 'Nirvana (band)', + 'Pauley Pavilion', + 'September 1992 in the United States', + ], + creditHTML: 'More Kurt -- too rad', + descriptionHTML: 'Kurt Cobain (front) and Krist Novoselic (left) live at the 1992 MTV Video Music Awards.', + descriptionURL: 'https://commons.wikimedia.org/wiki/File:Nirvana_around_1992.jpg', + height: 346, + licenseShortName: 'CC BY-SA 2.0', + licenseURL: 'https://creativecommons.org/licenses/by-sa/2.0', + metadata: [ + { + name: 'DateTime', + source: 'mediawiki-metadata', + value: '2015-11-21 12:22:55', + }, + { + name: 'ObjectName', + source: 'mediawiki-metadata', + value: 'Nirvana around 1992', + }, + { + name: 'CommonsMetadataExtension', + source: 'extension', + value: '1.2', + }, + { + name: 'Categories', + source: 'commons-categories', + value: '1992 in California|1992 in television|Fashion in 1992|Flickr images reviewed by trusted users|Krist Novoselic|Kurt Cobain|MTV Video Music Awards|Music events in 1992|Nirvana (band)|Pauley Pavilion|September 1992 in the United States', + }, + { + name: 'Assessments', + source: 'commons-categories', + value: '', + }, + { + name: 'ImageDescription', + source: 'commons-desc-page', + value: 'Kurt Cobain (front) and Krist Novoselic (left) live at the 1992 MTV Video Music Awards.', + }, + { + name: 'DateTimeOriginal', + source: 'commons-desc-page', + value: '1992-09-09', + }, + { + name: 'Credit', + source: 'commons-desc-page', + value: 'More Kurt -- too rad', + }, + { + name: 'Artist', + source: 'commons-desc-page', + value: 'P.B. Rage from USA', + }, + { + name: 'LicenseShortName', + source: 'commons-desc-page', + value: 'CC BY-SA 2.0', + }, + { + name: 'UsageTerms', + source: 'commons-desc-page', + value: 'Creative Commons Attribution-Share Alike 2.0', + }, + { + name: 'AttributionRequired', + source: 'commons-desc-page', + value: 'true', + }, + { + name: 'LicenseUrl', + source: 'commons-desc-page', + value: 'https://creativecommons.org/licenses/by-sa/2.0', + }, + { + name: 'Copyrighted', + source: 'commons-desc-page', + value: 'True', + }, + { + name: 'Restrictions', + source: 'commons-desc-page', + value: '', + }, + { + name: 'License', + source: 'commons-templates', + value: 'cc-by-sa-2.0', + }, + ], + objectName: 'Nirvana around 1992', + originalDateTimeHTML: '1992-09-09', + size: 31369, + url: 'https://upload.wikimedia.org/wikipedia/commons/1/19/Nirvana_around_1992.jpg', + user: 'Kigsz', + width: 367, + }, + ], + }, + }, + } + +## instruments have a mediaWikiImages field + +> Snapshot 1 + + { + search: { + instruments: { + nodes: [ + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [ + { + artistHTML: 'TenIslands', + canonicalTitle: 'File:2 Portuguese guitars.jpg', + categories: [ + 'Derivative versions', + 'PD-self', + 'Portuguese guitar', + 'Self-published work', + ], + creditHTML: 'Own work', + descriptionHTML: 'Left: Coimbra Portuguese guitar.
Right: Lisbon Portuguese guitar.', + descriptionURL: 'https://commons.wikimedia.org/wiki/File:2_Portuguese_guitars.jpg', + height: 2304, + licenseShortName: 'Public domain', + licenseURL: null, + metadata: [ + { + name: 'DateTime', + source: 'mediawiki-metadata', + value: '2008-07-20 16:57:38', + }, + { + name: 'ObjectName', + source: 'mediawiki-metadata', + value: '2 Portuguese guitars', + }, + { + name: 'CommonsMetadataExtension', + source: 'extension', + value: '1.2', + }, + { + name: 'Categories', + source: 'commons-categories', + value: 'Derivative versions|PD-self|Portuguese guitar|Self-published work', + }, + { + name: 'Assessments', + source: 'commons-categories', + value: '', + }, + { + name: 'ImageDescription', + source: 'commons-desc-page', + value: 'Left: Coimbra Portuguese guitar.
Right: Lisbon Portuguese guitar.', + }, + { + name: 'DateTimeOriginal', + source: 'commons-desc-page', + value: '2008-07-19', + }, + { + name: 'Credit', + source: 'commons-desc-page', + value: 'Own work', + }, + { + name: 'Artist', + source: 'commons-desc-page', + value: 'TenIslands', + }, + { + name: 'LicenseShortName', + source: 'commons-desc-page', + value: 'Public domain', + }, + { + name: 'UsageTerms', + source: 'commons-desc-page', + value: 'Public domain', + }, + { + name: 'AttributionRequired', + source: 'commons-desc-page', + value: 'false', + }, + { + name: 'Copyrighted', + source: 'commons-desc-page', + value: 'False', + }, + { + name: 'Restrictions', + source: 'commons-desc-page', + value: '', + }, + { + name: 'License', + source: 'commons-templates', + value: 'pd', + }, + ], + objectName: '2 Portuguese guitars', + originalDateTimeHTML: '2008-07-19', + size: 2094702, + url: 'https://upload.wikimedia.org/wikipedia/commons/0/01/2_Portuguese_guitars.jpg', + user: 'TenIslands', + width: 1746, + }, + ], + }, + ], + }, + }, + } + +## labels have a mediaWikiImages field + +> Snapshot 1 + + { + search: { + labels: { + nodes: [ + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + { + mediaWikiImages: [], + }, + ], + }, + }, + } + +## places have a mediaWikiImages field + +> Snapshot 1 + + { + lookup: { + place: { + mediaWikiImages: [ + { + artistHTML: 'Dllu', + canonicalTitle: 'File:Paramount Theater in Seattle showing Wicked.jpg', + categories: [ + 'Paramount Northwest Theater', + 'Self-published work', + ], + creditHTML: 'Own work', + descriptionHTML: 'The Paramount Theatre (Seattle) showing Wicked.', + descriptionURL: 'https://commons.wikimedia.org/wiki/File:Paramount_Theater_in_Seattle_showing_Wicked.jpg', + height: 3840, + licenseShortName: 'CC BY-SA 4.0', + licenseURL: 'https://creativecommons.org/licenses/by-sa/4.0', + metadata: [ + { + name: 'DateTime', + source: 'mediawiki-metadata', + value: '2015-08-01 06:59:27', + }, + { + name: 'ObjectName', + source: 'mediawiki-metadata', + value: 'Paramount Theater in Seattle showing Wicked', + }, + { + name: 'CommonsMetadataExtension', + source: 'extension', + value: '1.2', + }, + { + name: 'Categories', + source: 'commons-categories', + value: 'Paramount Northwest Theater|Self-published work', + }, + { + name: 'Assessments', + source: 'commons-categories', + value: '', + }, + { + name: 'ImageDescription', + source: 'commons-desc-page', + value: 'The Paramount Theatre (Seattle) showing Wicked.', + }, + { + name: 'DateTimeOriginal', + source: 'commons-desc-page', + value: '2015-07-31 20:32:43', + }, + { + name: 'Credit', + source: 'commons-desc-page', + value: 'Own work', + }, + { + name: 'Artist', + source: 'commons-desc-page', + value: 'Dllu', + }, + { + name: 'LicenseShortName', + source: 'commons-desc-page', + value: 'CC BY-SA 4.0', + }, + { + name: 'UsageTerms', + source: 'commons-desc-page', + value: 'Creative Commons Attribution-Share Alike 4.0', + }, + { + name: 'AttributionRequired', + source: 'commons-desc-page', + value: 'true', + }, + { + name: 'LicenseUrl', + source: 'commons-desc-page', + value: 'https://creativecommons.org/licenses/by-sa/4.0', + }, + { + name: 'Copyrighted', + source: 'commons-desc-page', + value: 'True', + }, + { + name: 'Restrictions', + source: 'commons-desc-page', + value: '', + }, + { + name: 'License', + source: 'commons-templates', + value: 'cc-by-sa-4.0', + }, + ], + objectName: 'Paramount Theater in Seattle showing Wicked', + originalDateTimeHTML: '2015-07-31 20:32:43', + size: 12529142, + url: 'https://upload.wikimedia.org/wikipedia/commons/c/ce/Paramount_Theater_in_Seattle_showing_Wicked.jpg', + user: 'Dllu', + width: 2566, + }, + ], + }, + }, + } diff --git a/test/extensions/mediawiki/snapshots/schema.js.snap b/test/extensions/mediawiki/snapshots/schema.js.snap new file mode 100644 index 0000000..94f0e47 Binary files /dev/null and b/test/extensions/mediawiki/snapshots/schema.js.snap differ diff --git a/test/extensions/the-audio-db/schema.js b/test/extensions/the-audio-db/schema.js new file mode 100644 index 0000000..5b4fb04 --- /dev/null +++ b/test/extensions/the-audio-db/schema.js @@ -0,0 +1,118 @@ +import test from 'ava' +import { graphql } from 'graphql' +import extension from '../../../src/extensions/the-audio-db' +import baseSchema, { applyExtension } from '../../../src/schema' +import baseContext from '../../helpers/context' + +const schema = applyExtension(extension, baseSchema) +const context = extension.extendContext(baseContext) + +function testData (t, query, handler) { + return graphql(schema, query, null, context).then(result => { + if (result.errors !== undefined) { + console.log(result.errors) + } + t.is(result.errors, undefined) + return handler(t, result.data) + }) +} + +test('artists have a theAudioDB field', testData, ` + { + lookup { + artist(mbid: "5b11f4ce-a62d-471e-81fc-a69a8278c7da") { + theAudioDB { + artistID + biography + biographyJP: biography(lang: "jp") + memberCount + banner + bannerPreview: banner(size: PREVIEW) + fanArt + fanArtPreview: fanArt(size: PREVIEW) + logo + logoPreview: logo(size: PREVIEW) + thumbnail + thumbnailPreview: thumbnail(size: PREVIEW) + genre + mood + style + } + } + } + } +`, (t, data) => { + t.snapshot(data) +}) + +test('release groups have a theAudioDB field', testData, ` +{ + lookup { + releaseGroup(mbid: "aa997ea0-2936-40bd-884d-3af8a0e064dc") { + theAudioDB { + albumID + artistID + description + descriptionES: description(lang: "es") + review + salesCount + score + scoreVotes + discImage + discImagePreview: discImage(size: PREVIEW) + spineImage + spineImagePreview: spineImage(size: PREVIEW) + frontImage + frontImagePreview: frontImage(size: PREVIEW) + backImage + backImagePreview: backImage(size: PREVIEW) + genre + mood + style + speed + theme + } + } + } +} +`, (t, data) => { + t.snapshot(data) +}) + +test('recordings have a theAudioDB field', testData, ` + { + lookup { + recording(mbid: "1109d8da-ce4a-4739-9414-242dc3e9b81c") { + theAudioDB { + trackID + albumID + artistID + description + descriptionES: description(lang: "es") + thumbnail + thumbnailPreview: thumbnail(size: PREVIEW) + score + scoreVotes + trackNumber + musicVideo { + url + companyName + directorName + screenshots + screenshotsPreview: screenshots(size: PREVIEW) + viewCount + likeCount + dislikeCount + commentCount + } + genre + mood + style + theme + } + } + } + } +`, (t, data) => { + t.snapshot(data) +}) diff --git a/test/extensions/the-audio-db/snapshots/schema.js.md b/test/extensions/the-audio-db/snapshots/schema.js.md new file mode 100644 index 0000000..72ed998 --- /dev/null +++ b/test/extensions/the-audio-db/snapshots/schema.js.md @@ -0,0 +1,125 @@ +# Snapshot report for `test/extensions/the-audio-db/schema.js` + +The actual snapshot is saved in `schema.js.snap`. + +Generated by [AVA](https://ava.li). + +## artists have a theAudioDB field + +> Snapshot 1 + + { + lookup: { + artist: { + theAudioDB: { + artistID: '111319', + banner: 'http://www.theaudiodb.com/images/media/artist/banner/wppvrr1365966313.jpg', + bannerPreview: 'http://www.theaudiodb.com/images/media/artist/banner/wppvrr1365966313.jpg/preview', + biography: `Nirvana was an American rock band that was formed by singer and guitarist Kurt Cobain and bassist Krist Novoselic in Aberdeen, Washington, in 1987. Nirvana went through a succession of drummers, the longest-lasting being Dave Grohl, who joined the band in 1990. Despite releasing only three full-length studio albums in their seven-year career, Nirvana has come to be regarded as one of the most influential and important rock bands of the modern era.␊ + In the late 1980s Nirvana established itself as part of the Seattle grunge scene, releasing its first album Bleach for the independent record label Sub Pop in 1989. The band eventually came to develop a sound that relied on dynamic contrasts, often between quiet verses and loud, heavy choruses. After signing to major label DGC Records, Nirvana found unexpected success with "Smells Like Teen Spirit", the first single from the band's second album Nevermind (1991). Nirvana's sudden success widely popularized alternative rock as a whole, and the band's frontman Cobain found himself referred to in the media as the "spokesman of a generation", with Nirvana being considered the "flagship band" of Generation X. In response, Nirvana's third studio album, In Utero (1993), featured an abrasive, less-mainstream sound and challenged the group's audience. The album did not match the sales figures of Nevermind, but was still a commercial success and critically acclaimed.␊ + Nirvana's brief run ended following the death of Kurt Cobain in 1994, but various posthumous releases have been issued since, overseen by Novoselic, Grohl, and Cobain's widow Courtney Love. Since its debut, the band has sold over 25 million records in the United States alone, and over 75 million records worldwide, making them one of the best-selling bands of all time. Nirvana was inducted into the Rock and Roll Hall of Fame in 2014, in its first year of eligibility.`, + biographyJP: `ニルヴァーナ (Nirvana) は、アメリカのバンド。1980年代終盤にシーンに出現し、1994年のカート自殺による活動停止までの数年に亘って、全世界の若者世代の圧倒的な支持を受けた。彼の死亡後も世界中のミュージシャンに多大な影響を与え続けている。単語「ニルヴァーナ」には、仏教用語の涅槃の境地という意味合いと「生け贄」という意味合いがある。␊ + 「スメルズ・ライク・ティーン・スピリット」の爆発的ヒットによりバンドは一気に有名になり、1990年代以降のロックに絶大な影響を与え、しばしばオルタナティヴ・ロックシーンにおいて『ニルヴァーナ以降』という言い方をされる。␊ + 全世界でのトータルセールスは、約7500万枚[1][2]。␊ + 「ローリング・ストーンの選ぶ歴史上最も偉大な100組のアーティスト」において第30位。`, + fanArt: [ + 'http://media.theaudiodb.com/images/media/artist/fanart/nirvana-4ddaf131354a8.jpg', + 'http://media.theaudiodb.com/images/media/artist/fanart/ussvpr1342344599.jpg', + 'http://media.theaudiodb.com/images/media/artist/fanart/uusxqw1342344614.jpg', + ], + fanArtPreview: [ + 'http://media.theaudiodb.com/images/media/artist/fanart/nirvana-4ddaf131354a8.jpg/preview', + 'http://media.theaudiodb.com/images/media/artist/fanart/ussvpr1342344599.jpg/preview', + 'http://media.theaudiodb.com/images/media/artist/fanart/uusxqw1342344614.jpg/preview', + ], + genre: 'Rock', + logo: 'http://www.theaudiodb.com/images/media/artist/logo/xyryvu1363124407.png', + logoPreview: 'http://www.theaudiodb.com/images/media/artist/logo/xyryvu1363124407.png/preview', + memberCount: 3, + mood: 'Sad', + style: 'Rock/Pop', + thumbnail: 'http://www.theaudiodb.com/images/media/artist/thumb/ryppyp1363124444.jpg', + thumbnailPreview: 'http://www.theaudiodb.com/images/media/artist/thumb/ryppyp1363124444.jpg/preview', + }, + }, + }, + } + +## recordings have a theAudioDB field + +> Snapshot 1 + + { + lookup: { + recording: { + theAudioDB: { + albumID: '2284335', + artistID: '131613', + description: `"Despacito" (American Spanish: ; English: "Slowly") is a single by Puerto Rican singer Luis Fonsi featuring Puerto Rican rapper Daddy Yankee from Fonsi's upcoming studio album. On January 12, 2017, Universal Music Latin released "Despacito" and its music video, which shows both artists performing the song in La Perla neighborhood of Old San Juan, Puerto Rico and the local bar La Factoría. The song's music video is the first video to reach over three billion views on YouTube. The song was written by Luis Fonsi, Erika Ender and Daddy Yankee, and was produced by Andrés Torres and Mauricio Rengifo.␊ + ␊ + It is a reggaeton-pop song composed in common time with lyrics about having a sexual relationship, performed in a smooth and romantic way. Commercially, the song topped the charts of 47 countries and reached the top 10 of ten others, making it both Fonsi and Daddy Yankee's most successful single to date. It became the first song primarily in Spanish to top the Billboard Hot 100 since "Macarena" (Bayside Boys Mix) in 1996. The official video for "Despacito" on YouTube received its 1 billionth view on April 20, 2017 after 97 days, becoming the second-fastest video on the site to reach the milestone -- behind Adele's "Hello". It received its 2 billionth view on June 16 and its 3 billionth view on August 4 after 154 and 204 days, respectively, making it the fastest video on the site to reach both milestones. With its 3.3 million certified sales plus track-equivalent streams, "Despacito" is one of the best-selling Latin singles in the United States.`, + descriptionES: null, + genre: 'Latin', + mood: 'Sensual', + musicVideo: { + commentCount: 1449046, + companyName: null, + directorName: 'Carlos Pérez', + dislikeCount: 2168098, + likeCount: 21015918, + screenshots: [], + screenshotsPreview: [], + url: 'https://www.youtube.com/watch?v=kJQP7kiw5Fk', + viewCount: 2147483647, + }, + score: 10, + scoreVotes: 1, + style: 'Latin', + theme: 'In Love', + thumbnail: 'http://media.theaudiodb.com/images/media/track/thumb/vqqpry1506425784.jpg', + thumbnailPreview: 'http://media.theaudiodb.com/images/media/track/thumb/vqqpry1506425784.jpg/preview', + trackID: '34838814', + trackNumber: 1, + }, + }, + }, + } + +## release groups have a theAudioDB field + +> Snapshot 1 + + { + lookup: { + releaseGroup: { + theAudioDB: { + albumID: '2162908', + artistID: '111492', + backImage: null, + backImagePreview: null, + description: `Random Access Memories is the upcoming fourth studio album by French electronic music duo Daft Punk. It will be released by Daft Life under exclusive license to Columbia Records on May 17, 2013 in Australia, May 20, 2013 in the United Kingdom and on May 21, 2013 in the United States. Work started on the record concurrently with the Tron: Legacy score, without a clear plan as to what its structure would be. Shortly after Daft Punk signed with Columbia, a gradual promotional rollout began for the album including billboards, television advertising and a web series.␊ + Random Access Memories pays tribute to the late 1970s and early 80s era of music in the United States, particularly the sound of Los Angeles recordings of the period. Daft Punk recorded the album largely using live instrumentation with session musicians, and limited the use of electronics to drum machines, a modular synthesizer and vintage vocoders. The album also features collaborations with Panda Bear, Julian Casablancas, Todd Edwards, DJ Falcon, Chilly Gonzales, Giorgio Moroder, Nile Rodgers, Paul Williams and Pharrell Williams. Critical reception to the album has generally been positive.`, + descriptionES: `Random Access Memories es el cuarto álbum de estudio del dúo francés Daft Punk. Fue lanzado oficialmente el 17 de mayo en Australia, lanzado después en el Reino Unido el 20 de mayo y para Estados Unidos el 21 de mayo de 2013, bajo licencia de Daft Life. El inicio de grabación de este disco inició cuando el dúo preparaba el soundtrack de la película Tron: Legacy, sin un plan claro en cuanto a lo que sería su estructura. Después de haber anunciado su nuevo contrato con Columbia Records, Daft Punk empezó a promocionar el nuevo álbum con cartéles, anuncios televisivos y series para internet.␊ + ␊ + Random Access Memories hace un tributo a la música estadounidense de la época de los 1970s y la primera parte de los 1980s, particularmente al sonido de Los Ángeles durante esa época. Daft Punk grabó el álbum en gran parte con orquesta en vivo con sesiónes musicales y con un uso limitado de máquinas de percusión, sintetizador modular, y con una vendimia de vocoders. El álbum contiene un gran número de colaboradores, entre ellos se destácan: Panda Bear, Chilly Gonzales, DJ Falcon, Julian Casablancas, Todd Edwards, Paul Williams, Pharrell Williams, Nile Rodgers y Ghallmarck. El álbum fue recibido con críticas positivas.␊ + ␊ + Durante la primera mitad de 2013, vendió 614 000 copias en los Estados Unidos, donde se convirtió en el décimo álbum más vendido durante dicho periodo.`, + discImage: 'http://www.theaudiodb.com/images/media/album/cdart/random-access-memories-5194a5974107d.png', + discImagePreview: 'http://www.theaudiodb.com/images/media/album/cdart/random-access-memories-5194a5974107d.png/preview', + frontImage: 'http://www.theaudiodb.com/images/media/album/thumb/random-access-memories-51764651042e5.jpg', + frontImagePreview: 'http://www.theaudiodb.com/images/media/album/thumb/random-access-memories-51764651042e5.jpg/preview', + genre: 'House', + mood: 'Happy', + review: null, + salesCount: 0, + score: 8.7, + scoreVotes: 6, + speed: 'Medium', + spineImage: null, + spineImagePreview: null, + style: 'Electronic', + theme: null, + }, + }, + }, + } diff --git a/test/extensions/the-audio-db/snapshots/schema.js.snap b/test/extensions/the-audio-db/snapshots/schema.js.snap new file mode 100644 index 0000000..f78ef6e Binary files /dev/null and b/test/extensions/the-audio-db/snapshots/schema.js.snap differ diff --git a/test/fixtures/09158487d72de391f789b038b8e5d137 b/test/fixtures/09158487d72de391f789b038b8e5d137 new file mode 100644 index 0000000..780cd6f Binary files /dev/null and b/test/fixtures/09158487d72de391f789b038b8e5d137 differ diff --git a/test/fixtures/09158487d72de391f789b038b8e5d137.headers b/test/fixtures/09158487d72de391f789b038b8e5d137.headers new file mode 100644 index 0000000..35c7d67 --- /dev/null +++ b/test/fixtures/09158487d72de391f789b038b8e5d137.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:23:11 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "843", + "x-ratelimit-reset": "1508394191", + "server": "Plack::Handler::Starlet", + "etag": "W/\"bc0fd422eb415020ac9aba896844f774\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/instrument/ba4705aa-ff1d-48d5-ae80-7b2046fb451e?inc=url-rels&fmt=json", + "time": 358, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/0978572ac8e46f70600f576c9e36f019 b/test/fixtures/0978572ac8e46f70600f576c9e36f019 new file mode 100644 index 0000000..29ac8ad Binary files /dev/null and b/test/fixtures/0978572ac8e46f70600f576c9e36f019 differ diff --git a/test/fixtures/0978572ac8e46f70600f576c9e36f019.headers b/test/fixtures/0978572ac8e46f70600f576c9e36f019.headers new file mode 100644 index 0000000..72e23f2 --- /dev/null +++ b/test/fixtures/0978572ac8e46f70600f576c9e36f019.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:12 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "944", + "x-ratelimit-reset": "1508394913", + "server": "Plack::Handler::Starlet", + "etag": "W/\"9fdd463cf441954e7ba61de213c25c21\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/b914f217-8be8-486b-a733-82f03275704a?inc=url-rels&fmt=json", + "time": 375, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/0afc244749f3fddc9a96823dd9b2a898 b/test/fixtures/0afc244749f3fddc9a96823dd9b2a898 new file mode 100644 index 0000000..f449869 Binary files /dev/null and b/test/fixtures/0afc244749f3fddc9a96823dd9b2a898 differ diff --git a/test/fixtures/0afc244749f3fddc9a96823dd9b2a898.headers b/test/fixtures/0afc244749f3fddc9a96823dd9b2a898.headers new file mode 100644 index 0000000..08d85c4 --- /dev/null +++ b/test/fixtures/0afc244749f3fddc9a96823dd9b2a898.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:18 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1060", + "x-ratelimit-reset": "1508394919", + "server": "Plack::Handler::Starlet", + "etag": "W/\"952c89cf2a01358c9a3c8295a61c2d06\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/d49fe768-e91c-404f-9542-3008c4ef9b51?inc=url-rels&fmt=json", + "time": 410, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/0bc1bed2d611a955f254756470f98df4 b/test/fixtures/0bc1bed2d611a955f254756470f98df4 new file mode 100644 index 0000000..09e8d83 Binary files /dev/null and b/test/fixtures/0bc1bed2d611a955f254756470f98df4 differ diff --git a/test/fixtures/0bc1bed2d611a955f254756470f98df4.headers b/test/fixtures/0bc1bed2d611a955f254756470f98df4.headers new file mode 100644 index 0000000..b5c1066 --- /dev/null +++ b/test/fixtures/0bc1bed2d611a955f254756470f98df4.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:34 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "938", + "x-ratelimit-reset": "1508394935", + "server": "Plack::Handler::Starlet", + "etag": "W/\"19db13c6fdb3773a9bae8cd36693257a\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/23e04f48-06e0-4d32-911d-8f6259c62a13?inc=url-rels&fmt=json", + "time": 370, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/0c643a69d0dd86ae242e226c1d85469e b/test/fixtures/0c643a69d0dd86ae242e226c1d85469e new file mode 100644 index 0000000..3c968ae Binary files /dev/null and b/test/fixtures/0c643a69d0dd86ae242e226c1d85469e differ diff --git a/test/fixtures/0c643a69d0dd86ae242e226c1d85469e.headers b/test/fixtures/0c643a69d0dd86ae242e226c1d85469e.headers new file mode 100644 index 0000000..0176e04 --- /dev/null +++ b/test/fixtures/0c643a69d0dd86ae242e226c1d85469e.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:46 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1059", + "x-ratelimit-reset": "1508394947", + "server": "Plack::Handler::Starlet", + "etag": "W/\"2bb8aa78cfd610c5e1a7b121b54efa8f\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/place/b5297256-8482-4cba-968a-25db61563faf?fmt=json", + "time": 327, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/0d366b2eeee8615a4b25b8e601c6020a b/test/fixtures/0d366b2eeee8615a4b25b8e601c6020a new file mode 100644 index 0000000..646f9ec Binary files /dev/null and b/test/fixtures/0d366b2eeee8615a4b25b8e601c6020a differ diff --git a/test/fixtures/0d366b2eeee8615a4b25b8e601c6020a.headers b/test/fixtures/0d366b2eeee8615a4b25b8e601c6020a.headers new file mode 100644 index 0000000..ebb3444 --- /dev/null +++ b/test/fixtures/0d366b2eeee8615a4b25b8e601c6020a.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:34:56 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1040", + "x-ratelimit-reset": "1508394897", + "server": "Plack::Handler::Starlet", + "etag": "W/\"15d3949951847ce0b26e10c0e96e96db\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/08f37a61-1c54-4257-b31d-810fa2ac5cd5?inc=url-rels&fmt=json", + "time": 378, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/0e99fc598c63fd29efff1916c1284bbf b/test/fixtures/0e99fc598c63fd29efff1916c1284bbf new file mode 100644 index 0000000..4b81f6f Binary files /dev/null and b/test/fixtures/0e99fc598c63fd29efff1916c1284bbf differ diff --git a/test/fixtures/0e99fc598c63fd29efff1916c1284bbf.headers b/test/fixtures/0e99fc598c63fd29efff1916c1284bbf.headers new file mode 100644 index 0000000..5cbb105 --- /dev/null +++ b/test/fixtures/0e99fc598c63fd29efff1916c1284bbf.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:40 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1062", + "x-ratelimit-reset": "1508394941", + "server": "Plack::Handler::Starlet", + "etag": "W/\"59e4337aff496a685585c597d32fe368\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/c82b5688-df49-4e21-935b-0b08d13ec98a?inc=url-rels&fmt=json", + "time": 360, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/1bd080df7553608290b4e67175a1a6dc b/test/fixtures/1bd080df7553608290b4e67175a1a6dc new file mode 100644 index 0000000..51ec791 Binary files /dev/null and b/test/fixtures/1bd080df7553608290b4e67175a1a6dc differ diff --git a/test/fixtures/1bd080df7553608290b4e67175a1a6dc.headers b/test/fixtures/1bd080df7553608290b4e67175a1a6dc.headers new file mode 100644 index 0000000..65a3021 --- /dev/null +++ b/test/fixtures/1bd080df7553608290b4e67175a1a6dc.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:29 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "851", + "x-ratelimit-reset": "1508394929", + "server": "Plack::Handler::Starlet", + "etag": "W/\"03f3db33b7222966888909cd6d8d1163\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/decde7d5-dbfe-498d-80ee-dce96ae032e2?inc=url-rels&fmt=json", + "time": 380, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/1bd60b1a1ed81102d4d7271e2237e1bf b/test/fixtures/1bd60b1a1ed81102d4d7271e2237e1bf new file mode 100644 index 0000000..c4f31ef Binary files /dev/null and b/test/fixtures/1bd60b1a1ed81102d4d7271e2237e1bf differ diff --git a/test/fixtures/1bd60b1a1ed81102d4d7271e2237e1bf.headers b/test/fixtures/1bd60b1a1ed81102d4d7271e2237e1bf.headers new file mode 100644 index 0000000..f3202d9 --- /dev/null +++ b/test/fixtures/1bd60b1a1ed81102d4d7271e2237e1bf.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:01 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1127", + "x-ratelimit-reset": "1508394903", + "server": "Plack::Handler::Starlet", + "etag": "W/\"cd510299cdc136110ff7fbcb1332d568\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/151085ba-42d0-477a-83f9-eed3f758c743?inc=url-rels&fmt=json", + "time": 356, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/1ca35d44ecbebc340e09347b6f40c6f7 b/test/fixtures/1ca35d44ecbebc340e09347b6f40c6f7 new file mode 100644 index 0000000..46e5d3a --- /dev/null +++ b/test/fixtures/1ca35d44ecbebc340e09347b6f40c6f7 @@ -0,0 +1 @@ +{"type-id":"cc00f97f-cf3d-3ae2-9163-041cb1a0d726","id":"c0ea0405-ae3f-4851-bf85-277fadff80e2","type":"String instrument","relations":[],"description":"","disambiguation":"","name":"Hawaiian guitar"} \ No newline at end of file diff --git a/test/fixtures/1ca35d44ecbebc340e09347b6f40c6f7.headers b/test/fixtures/1ca35d44ecbebc340e09347b6f40c6f7.headers new file mode 100644 index 0000000..a6678b9 --- /dev/null +++ b/test/fixtures/1ca35d44ecbebc340e09347b6f40c6f7.headers @@ -0,0 +1,27 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:21:19 GMT", + "content-type": "application/json; charset=utf-8", + "content-length": "198", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1101", + "x-ratelimit-reset": "1508394081", + "server": "Plack::Handler::Starlet", + "etag": "\"bada5afab5ba761514e6acb58d47f9ad\"", + "access-control-allow-origin": "*" + }, + "url": "http://musicbrainz.org:80/ws/2/instrument/c0ea0405-ae3f-4851-bf85-277fadff80e2?inc=url-rels&fmt=json", + "time": 341, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/1cd29fc131359a049232fbae39509f53 b/test/fixtures/1cd29fc131359a049232fbae39509f53 new file mode 100644 index 0000000..de26135 Binary files /dev/null and b/test/fixtures/1cd29fc131359a049232fbae39509f53 differ diff --git a/test/fixtures/1cd29fc131359a049232fbae39509f53.headers b/test/fixtures/1cd29fc131359a049232fbae39509f53.headers new file mode 100644 index 0000000..37d76f6 --- /dev/null +++ b/test/fixtures/1cd29fc131359a049232fbae39509f53.headers @@ -0,0 +1,43 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 05:19:02 GMT", + "content-type": "application/json; charset=utf-8", + "content-length": "993", + "connection": "keep-alive", + "server": "mw1203.eqiad.wmnet", + "x-powered-by": "HHVM/3.18.6-dev", + "x-content-type-options": "nosniff", + "cache-control": "private, must-revalidate, max-age=0", + "p3p": "CP=\"This is not a P3P policy! See https://commons.wikimedia.org/wiki/Special:CentralAutoLogin/P3P for more info.\"", + "content-encoding": "gzip", + "x-frame-options": "DENY", + "content-disposition": "inline; filename=\"api-result.json\"", + "vary": "Accept-Encoding,Treat-as-Untrusted,X-Forwarded-Proto,Cookie,Authorization", + "backend-timing": "D=44564 t=1508390342727140", + "x-varnish": "288262213, 11547095, 566162766, 635099657", + "via": "1.1 varnish-v4, 1.1 varnish-v4, 1.1 varnish-v4, 1.1 varnish-v4", + "accept-ranges": "bytes", + "age": "0", + "x-cache": "cp1068 pass, cp2019 pass, cp4018 pass, cp4018 pass", + "x-cache-status": "pass", + "strict-transport-security": "max-age=106384710; includeSubDomains; preload", + "set-cookie": [ + "WMF-Last-Access=19-Oct-2017;Path=/;HttpOnly;secure;Expires=Mon, 20 Nov 2017 00:00:00 GMT", + "GeoIP=US:WA:Seattle:47.61:-122.30:v4; Path=/; secure; Domain=.wikimedia.org" + ], + "x-analytics": "ns=-1;special=Badtitle;https=1;nocookies=1", + "x-client-ip": "66.235.47.149" + }, + "url": "http://commons.wikimedia.org:443/w/api.php?action=query&titles=File%3ANirvana_around_1992.jpg&prop=imageinfo&iiprop=url%7Csize%7Ccanonicaltitle%7Cuser%7Cextmetadata&format=json", + "time": 341, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "commons.wikimedia.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/2025c61957af1edf111c891d3271ffbc b/test/fixtures/2025c61957af1edf111c891d3271ffbc new file mode 100644 index 0000000..0aaae22 Binary files /dev/null and b/test/fixtures/2025c61957af1edf111c891d3271ffbc differ diff --git a/test/fixtures/2025c61957af1edf111c891d3271ffbc.headers b/test/fixtures/2025c61957af1edf111c891d3271ffbc.headers new file mode 100644 index 0000000..2f52c95 --- /dev/null +++ b/test/fixtures/2025c61957af1edf111c891d3271ffbc.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:40 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1065", + "x-ratelimit-reset": "1508394941", + "server": "Plack::Handler::Starlet", + "etag": "W/\"4cc0cf5456c65b053a648dab7d98aed1\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/643330aa-157a-49a2-91f1-973f958e0ddb?inc=url-rels&fmt=json", + "time": 351, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/23aba1f4957dd22a5b21bd71c8dc9be3 b/test/fixtures/23aba1f4957dd22a5b21bd71c8dc9be3 new file mode 100644 index 0000000..7528ad5 Binary files /dev/null and b/test/fixtures/23aba1f4957dd22a5b21bd71c8dc9be3 differ diff --git a/test/fixtures/23aba1f4957dd22a5b21bd71c8dc9be3.headers b/test/fixtures/23aba1f4957dd22a5b21bd71c8dc9be3.headers new file mode 100644 index 0000000..46ebb74 --- /dev/null +++ b/test/fixtures/23aba1f4957dd22a5b21bd71c8dc9be3.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:18 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1063", + "x-ratelimit-reset": "1508394919", + "server": "Plack::Handler::Starlet", + "etag": "W/\"e74c7af5f57a0a9863635ba41bcfc213\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/069ec010-171a-433f-baaf-410d89ae8edc?inc=url-rels&fmt=json", + "time": 469, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/24013351b3e17570d846426ee2b36c7a b/test/fixtures/24013351b3e17570d846426ee2b36c7a new file mode 100644 index 0000000..ade8362 --- /dev/null +++ b/test/fixtures/24013351b3e17570d846426ee2b36c7a @@ -0,0 +1 @@ +{"disambiguation":"","type-id":"cc00f97f-cf3d-3ae2-9163-041cb1a0d726","description":"","type":"String instrument","relations":[],"id":"8ecb065e-fa6a-4009-98bd-bd742307d0e8","name":"table steel guitar"} \ No newline at end of file diff --git a/test/fixtures/24013351b3e17570d846426ee2b36c7a.headers b/test/fixtures/24013351b3e17570d846426ee2b36c7a.headers new file mode 100644 index 0000000..8618e43 --- /dev/null +++ b/test/fixtures/24013351b3e17570d846426ee2b36c7a.headers @@ -0,0 +1,27 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:21:25 GMT", + "content-type": "application/json; charset=utf-8", + "content-length": "201", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "851", + "x-ratelimit-reset": "1508394085", + "server": "Plack::Handler::Starlet", + "etag": "\"2b6ff5fc3682605e4979b3eebccc7add\"", + "access-control-allow-origin": "*" + }, + "url": "http://musicbrainz.org:80/ws/2/instrument/8ecb065e-fa6a-4009-98bd-bd742307d0e8?inc=url-rels&fmt=json", + "time": 424, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/25fff225406f7452de82b60beda3c931 b/test/fixtures/25fff225406f7452de82b60beda3c931 new file mode 100644 index 0000000..3d9bdb7 Binary files /dev/null and b/test/fixtures/25fff225406f7452de82b60beda3c931 differ diff --git a/test/fixtures/25fff225406f7452de82b60beda3c931.headers b/test/fixtures/25fff225406f7452de82b60beda3c931.headers new file mode 100644 index 0000000..25cfedc --- /dev/null +++ b/test/fixtures/25fff225406f7452de82b60beda3c931.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:45 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1147", + "x-ratelimit-reset": "1508394947", + "server": "Plack::Handler::Starlet", + "etag": "W/\"f11743900c546b3137d19347dbb672e1\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/8110eff2-51f0-42ba-9de5-7857576e9f6a?inc=url-rels&fmt=json", + "time": 369, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/2694cd9eea8687ccbda862aab56a0e78 b/test/fixtures/2694cd9eea8687ccbda862aab56a0e78 new file mode 100644 index 0000000..82ecf82 Binary files /dev/null and b/test/fixtures/2694cd9eea8687ccbda862aab56a0e78 differ diff --git a/test/fixtures/2694cd9eea8687ccbda862aab56a0e78.headers b/test/fixtures/2694cd9eea8687ccbda862aab56a0e78.headers new file mode 100644 index 0000000..65cc004 --- /dev/null +++ b/test/fixtures/2694cd9eea8687ccbda862aab56a0e78.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:45 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1151", + "x-ratelimit-reset": "1508394947", + "server": "Plack::Handler::Starlet", + "etag": "W/\"a7c64b03fdf2eeefe4fd599df5fe102b\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/b5f8b0b3-e7ee-4db2-a612-8b326ee28d1f?inc=url-rels&fmt=json", + "time": 367, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/2ae8ed6772af1b8fa844a5ac6d2b12b8 b/test/fixtures/2ae8ed6772af1b8fa844a5ac6d2b12b8 new file mode 100644 index 0000000..63c9793 Binary files /dev/null and b/test/fixtures/2ae8ed6772af1b8fa844a5ac6d2b12b8 differ diff --git a/test/fixtures/2ae8ed6772af1b8fa844a5ac6d2b12b8.headers b/test/fixtures/2ae8ed6772af1b8fa844a5ac6d2b12b8.headers new file mode 100644 index 0000000..74794b7 --- /dev/null +++ b/test/fixtures/2ae8ed6772af1b8fa844a5ac6d2b12b8.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:23 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1129", + "x-ratelimit-reset": "1508394925", + "server": "Plack::Handler::Starlet", + "etag": "W/\"5a0e28a18580315e9c99186aec796a62\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/40b9bd0d-e22f-41f8-885b-04bda967b3b9?inc=url-rels&fmt=json", + "time": 353, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/2b7cd5ca496a1d302cc587411cd36ad4 b/test/fixtures/2b7cd5ca496a1d302cc587411cd36ad4 new file mode 100644 index 0000000..5cf034b Binary files /dev/null and b/test/fixtures/2b7cd5ca496a1d302cc587411cd36ad4 differ diff --git a/test/fixtures/2b7cd5ca496a1d302cc587411cd36ad4.headers b/test/fixtures/2b7cd5ca496a1d302cc587411cd36ad4.headers new file mode 100644 index 0000000..6694c78 --- /dev/null +++ b/test/fixtures/2b7cd5ca496a1d302cc587411cd36ad4.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:34:51 GMT", + "content-type": "application/json; charset=UTF-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "892", + "x-ratelimit-reset": "1508394891", + "last-modified": "Thu, 19 Oct 2017 06:07:26 GMT", + "server": "Jetty(9.3.10.v20160621)", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label?limit=50&query=Sony&fmt=json", + "time": 695, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/2dd9912677b480dba99a99c809078688 b/test/fixtures/2dd9912677b480dba99a99c809078688 new file mode 100644 index 0000000..28c6b87 Binary files /dev/null and b/test/fixtures/2dd9912677b480dba99a99c809078688 differ diff --git a/test/fixtures/2dd9912677b480dba99a99c809078688.headers b/test/fixtures/2dd9912677b480dba99a99c809078688.headers new file mode 100644 index 0000000..36c91dc --- /dev/null +++ b/test/fixtures/2dd9912677b480dba99a99c809078688.headers @@ -0,0 +1,24 @@ +{ + "statusCode": 404, + "headers": { + "server": "nginx/1.10.1 (Ubuntu)", + "date": "Thu, 19 Oct 2017 05:57:19 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "vary": "Accept-Encoding", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://webservice.fanart.tv:80/v3/music/0cf56645-50ec-4411-aeb6-c9f4ce0f8edb?api_key=d9e25d5beda1027a1674c1585882309e", + "time": 338, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "webservice.fanart.tv", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/2de45192ad9def59746abf53a0eaf6c7 b/test/fixtures/2de45192ad9def59746abf53a0eaf6c7 new file mode 100644 index 0000000..8f51c27 Binary files /dev/null and b/test/fixtures/2de45192ad9def59746abf53a0eaf6c7 differ diff --git a/test/fixtures/2de45192ad9def59746abf53a0eaf6c7.headers b/test/fixtures/2de45192ad9def59746abf53a0eaf6c7.headers new file mode 100644 index 0000000..29d8aea --- /dev/null +++ b/test/fixtures/2de45192ad9def59746abf53a0eaf6c7.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:23 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1136", + "x-ratelimit-reset": "1508394925", + "server": "Plack::Handler::Starlet", + "etag": "W/\"dbae95183be39fd1f26f596c251b5246\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/f4d67253-85e1-41c6-844e-89812260213a?inc=url-rels&fmt=json", + "time": 377, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/322500542e74bfc6c6a5fb3b8d1329dd b/test/fixtures/322500542e74bfc6c6a5fb3b8d1329dd new file mode 100644 index 0000000..78411f5 Binary files /dev/null and b/test/fixtures/322500542e74bfc6c6a5fb3b8d1329dd differ diff --git a/test/fixtures/322500542e74bfc6c6a5fb3b8d1329dd.headers b/test/fixtures/322500542e74bfc6c6a5fb3b8d1329dd.headers new file mode 100644 index 0000000..2547183 --- /dev/null +++ b/test/fixtures/322500542e74bfc6c6a5fb3b8d1329dd.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:07 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "871", + "x-ratelimit-reset": "1508394907", + "server": "Plack::Handler::Starlet", + "etag": "W/\"87ba73bcb03c83b5125bb95855eb7cda\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/1c6f3ffb-2749-4bec-9c1e-19ea5aa19140?inc=url-rels&fmt=json", + "time": 409, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/37d33226e906bc384a86f29fedc03834 b/test/fixtures/37d33226e906bc384a86f29fedc03834 new file mode 100644 index 0000000..0c0afbe Binary files /dev/null and b/test/fixtures/37d33226e906bc384a86f29fedc03834 differ diff --git a/test/fixtures/37d33226e906bc384a86f29fedc03834.headers b/test/fixtures/37d33226e906bc384a86f29fedc03834.headers new file mode 100644 index 0000000..c55cdbd --- /dev/null +++ b/test/fixtures/37d33226e906bc384a86f29fedc03834.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:13 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "941", + "x-ratelimit-reset": "1508394913", + "server": "Plack::Handler::Starlet", + "etag": "W/\"364609669454551f3b99fad914a54aec\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/109aa079-5217-47f5-b6f5-e40e9afa935c?inc=url-rels&fmt=json", + "time": 389, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/3b60588b620d7e73852e4800525e40d6 b/test/fixtures/3b60588b620d7e73852e4800525e40d6 new file mode 100644 index 0000000..d8cbc62 Binary files /dev/null and b/test/fixtures/3b60588b620d7e73852e4800525e40d6 differ diff --git a/test/fixtures/3b60588b620d7e73852e4800525e40d6.headers b/test/fixtures/3b60588b620d7e73852e4800525e40d6.headers new file mode 100644 index 0000000..5c79c7c --- /dev/null +++ b/test/fixtures/3b60588b620d7e73852e4800525e40d6.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:07 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "870", + "x-ratelimit-reset": "1508394907", + "server": "Plack::Handler::Starlet", + "etag": "W/\"4a13a9d27f1097c5addaf8b988d85e3b\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/12c53048-be97-403d-805d-bc69c71211e4?inc=url-rels&fmt=json", + "time": 430, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/3dd3f9a8efe08f8d1adb70cd6ece87d9 b/test/fixtures/3dd3f9a8efe08f8d1adb70cd6ece87d9 new file mode 100644 index 0000000..1fbf032 Binary files /dev/null and b/test/fixtures/3dd3f9a8efe08f8d1adb70cd6ece87d9 differ diff --git a/test/fixtures/3dd3f9a8efe08f8d1adb70cd6ece87d9.headers b/test/fixtures/3dd3f9a8efe08f8d1adb70cd6ece87d9.headers new file mode 100644 index 0000000..3818067 --- /dev/null +++ b/test/fixtures/3dd3f9a8efe08f8d1adb70cd6ece87d9.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 05:18:58 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1057", + "x-ratelimit-reset": "1508390339", + "server": "Plack::Handler::Starlet", + "etag": "W/\"adab6dc914918eb0b54ccaf2843c96e7\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/artist/5b11f4ce-a62d-471e-81fc-a69a8278c7da?fmt=json", + "time": 391, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/40170c882e89aaeeb705e1191c889d0c b/test/fixtures/40170c882e89aaeeb705e1191c889d0c new file mode 100644 index 0000000..850d5dd Binary files /dev/null and b/test/fixtures/40170c882e89aaeeb705e1191c889d0c differ diff --git a/test/fixtures/40170c882e89aaeeb705e1191c889d0c.headers b/test/fixtures/40170c882e89aaeeb705e1191c889d0c.headers new file mode 100644 index 0000000..27d0adf --- /dev/null +++ b/test/fixtures/40170c882e89aaeeb705e1191c889d0c.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:40 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1063", + "x-ratelimit-reset": "1508394941", + "server": "Plack::Handler::Starlet", + "etag": "W/\"a224eed715188abc91892fbdc3948c1e\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/ff32ff7c-fc67-4047-81f9-8a8ce2c412b5?inc=url-rels&fmt=json", + "time": 425, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/411c0b53f75e4380eae0424fdecb902e b/test/fixtures/411c0b53f75e4380eae0424fdecb902e new file mode 100644 index 0000000..3ce3630 Binary files /dev/null and b/test/fixtures/411c0b53f75e4380eae0424fdecb902e differ diff --git a/test/fixtures/411c0b53f75e4380eae0424fdecb902e.headers b/test/fixtures/411c0b53f75e4380eae0424fdecb902e.headers new file mode 100644 index 0000000..7d0ee2b --- /dev/null +++ b/test/fixtures/411c0b53f75e4380eae0424fdecb902e.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:51 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "844", + "x-ratelimit-reset": "1508394951", + "server": "Plack::Handler::Starlet", + "etag": "W/\"eb316a92ae0abd7b01965bab4751ef29\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/place/b5297256-8482-4cba-968a-25db61563faf?inc=url-rels&fmt=json", + "time": 386, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/45904a407101915f2a3273f907166537 b/test/fixtures/45904a407101915f2a3273f907166537 new file mode 100644 index 0000000..9d8aa33 Binary files /dev/null and b/test/fixtures/45904a407101915f2a3273f907166537 differ diff --git a/test/fixtures/45904a407101915f2a3273f907166537.headers b/test/fixtures/45904a407101915f2a3273f907166537.headers new file mode 100644 index 0000000..c3157ec --- /dev/null +++ b/test/fixtures/45904a407101915f2a3273f907166537.headers @@ -0,0 +1,43 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:23:11 GMT", + "content-type": "application/json; charset=utf-8", + "content-length": "725", + "connection": "keep-alive", + "server": "mw1202.eqiad.wmnet", + "x-powered-by": "HHVM/3.18.6-dev", + "x-content-type-options": "nosniff", + "cache-control": "private, must-revalidate, max-age=0", + "p3p": "CP=\"This is not a P3P policy! See https://commons.wikimedia.org/wiki/Special:CentralAutoLogin/P3P for more info.\"", + "content-encoding": "gzip", + "x-frame-options": "DENY", + "content-disposition": "inline; filename=\"api-result.json\"", + "vary": "Accept-Encoding,Treat-as-Untrusted,X-Forwarded-Proto,Cookie,Authorization", + "backend-timing": "D=53160 t=1508394191609579", + "x-varnish": "179186442, 410024931, 381596374, 684593716", + "via": "1.1 varnish-v4, 1.1 varnish-v4, 1.1 varnish-v4, 1.1 varnish-v4", + "accept-ranges": "bytes", + "age": "0", + "x-cache": "cp1053 pass, cp2013 pass, cp4028 pass, cp4018 pass", + "x-cache-status": "pass", + "strict-transport-security": "max-age=106384710; includeSubDomains; preload", + "set-cookie": [ + "WMF-Last-Access=19-Oct-2017;Path=/;HttpOnly;secure;Expires=Mon, 20 Nov 2017 00:00:00 GMT", + "GeoIP=US:WA:Seattle:47.61:-122.30:v4; Path=/; secure; Domain=.wikimedia.org" + ], + "x-analytics": "ns=-1;special=Badtitle;https=1;nocookies=1", + "x-client-ip": "66.235.47.149" + }, + "url": "http://commons.wikimedia.org:443/w/api.php?action=query&titles=File%3A2_Portuguese_guitars.jpg&prop=imageinfo&iiprop=url%7Csize%7Ccanonicaltitle%7Cuser%7Cextmetadata&format=json", + "time": 366, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "commons.wikimedia.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/475fed802529221edd39de95047235c3 b/test/fixtures/475fed802529221edd39de95047235c3 new file mode 100644 index 0000000..e0d86d1 Binary files /dev/null and b/test/fixtures/475fed802529221edd39de95047235c3 differ diff --git a/test/fixtures/475fed802529221edd39de95047235c3.headers b/test/fixtures/475fed802529221edd39de95047235c3.headers new file mode 100644 index 0000000..5bb40d2 --- /dev/null +++ b/test/fixtures/475fed802529221edd39de95047235c3.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:07 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "873", + "x-ratelimit-reset": "1508394907", + "server": "Plack::Handler::Starlet", + "etag": "W/\"c20be201e36692617d165d7a9e40ca3c\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/bcec5d01-a698-4d58-809e-22455e12fc87?inc=url-rels&fmt=json", + "time": 397, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/499d62f35c5f6fd86e3a29f69785cff2 b/test/fixtures/499d62f35c5f6fd86e3a29f69785cff2 new file mode 100644 index 0000000..54aec55 Binary files /dev/null and b/test/fixtures/499d62f35c5f6fd86e3a29f69785cff2 differ diff --git a/test/fixtures/499d62f35c5f6fd86e3a29f69785cff2.headers b/test/fixtures/499d62f35c5f6fd86e3a29f69785cff2.headers new file mode 100644 index 0000000..64ff555 --- /dev/null +++ b/test/fixtures/499d62f35c5f6fd86e3a29f69785cff2.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:29 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "849", + "x-ratelimit-reset": "1508394929", + "server": "Plack::Handler::Starlet", + "etag": "W/\"363eaed607a787b5972abffcbf1a68dd\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/af180d86-b1f7-4a52-b8b7-8e9b97a89812?inc=url-rels&fmt=json", + "time": 414, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/4b802038a4994a768903c9df4bc309fb b/test/fixtures/4b802038a4994a768903c9df4bc309fb new file mode 100644 index 0000000..da9742d Binary files /dev/null and b/test/fixtures/4b802038a4994a768903c9df4bc309fb differ diff --git a/test/fixtures/4b802038a4994a768903c9df4bc309fb.headers b/test/fixtures/4b802038a4994a768903c9df4bc309fb.headers new file mode 100644 index 0000000..da64cdd --- /dev/null +++ b/test/fixtures/4b802038a4994a768903c9df4bc309fb.headers @@ -0,0 +1,24 @@ +{ + "statusCode": 200, + "headers": { + "server": "nginx/1.10.1 (Ubuntu)", + "date": "Thu, 19 Oct 2017 05:57:18 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "vary": "Accept-Encoding", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://webservice.fanart.tv:80/v3/music/albums/f5093c06-23e3-404f-aeaa-40f72885ee3a?api_key=d9e25d5beda1027a1674c1585882309e", + "time": 470, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "webservice.fanart.tv", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/4fc501bed2b7d643f741185069aace22 b/test/fixtures/4fc501bed2b7d643f741185069aace22 new file mode 100644 index 0000000..97d2157 Binary files /dev/null and b/test/fixtures/4fc501bed2b7d643f741185069aace22 differ diff --git a/test/fixtures/4fc501bed2b7d643f741185069aace22.headers b/test/fixtures/4fc501bed2b7d643f741185069aace22.headers new file mode 100644 index 0000000..3389c11 --- /dev/null +++ b/test/fixtures/4fc501bed2b7d643f741185069aace22.headers @@ -0,0 +1,43 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:52 GMT", + "content-type": "application/json; charset=utf-8", + "content-length": "844", + "connection": "keep-alive", + "server": "mw1314.eqiad.wmnet", + "x-powered-by": "HHVM/3.18.6-dev", + "x-content-type-options": "nosniff", + "cache-control": "private, must-revalidate, max-age=0", + "p3p": "CP=\"This is not a P3P policy! See https://commons.wikimedia.org/wiki/Special:CentralAutoLogin/P3P for more info.\"", + "content-encoding": "gzip", + "x-frame-options": "DENY", + "content-disposition": "inline; filename=\"api-result.json\"", + "vary": "Accept-Encoding,Treat-as-Untrusted,X-Forwarded-Proto,Cookie,Authorization", + "backend-timing": "D=180917 t=1508394951803664", + "x-varnish": "558013596, 239477161, 538442496, 692692485", + "via": "1.1 varnish-v4, 1.1 varnish-v4, 1.1 varnish-v4, 1.1 varnish-v4", + "accept-ranges": "bytes", + "age": "0", + "x-cache": "cp1055 pass, cp2016 pass, cp4027 pass, cp4018 pass", + "x-cache-status": "pass", + "strict-transport-security": "max-age=106384710; includeSubDomains; preload", + "set-cookie": [ + "WMF-Last-Access=19-Oct-2017;Path=/;HttpOnly;secure;Expires=Mon, 20 Nov 2017 00:00:00 GMT", + "GeoIP=US:WA:Seattle:47.61:-122.30:v4; Path=/; secure; Domain=.wikimedia.org" + ], + "x-analytics": "ns=-1;special=Badtitle;https=1;nocookies=1", + "x-client-ip": "66.235.47.149" + }, + "url": "https://commons.wikimedia.org:443/w/api.php?action=query&titles=File%3AParamount_Theater_in_Seattle_showing_Wicked.jpg&prop=imageinfo&iiprop=url%7Csize%7Ccanonicaltitle%7Cuser%7Cextmetadata&format=json", + "time": 482, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "commons.wikimedia.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/535ab3a418fb2b5ac0c9476546cc72d8 b/test/fixtures/535ab3a418fb2b5ac0c9476546cc72d8 new file mode 100644 index 0000000..53fefe2 Binary files /dev/null and b/test/fixtures/535ab3a418fb2b5ac0c9476546cc72d8 differ diff --git a/test/fixtures/535ab3a418fb2b5ac0c9476546cc72d8.headers b/test/fixtures/535ab3a418fb2b5ac0c9476546cc72d8.headers new file mode 100644 index 0000000..31560dc --- /dev/null +++ b/test/fixtures/535ab3a418fb2b5ac0c9476546cc72d8.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:21:19 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1100", + "x-ratelimit-reset": "1508394081", + "server": "Plack::Handler::Starlet", + "etag": "W/\"66a98f563e6ccb625877a93c6d9bbf70\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/instrument/43f378cf-b099-46da-8ec3-a39b6f5e5258?inc=url-rels&fmt=json", + "time": 417, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/537dbabc1ce057385edd9d8c4599c077 b/test/fixtures/537dbabc1ce057385edd9d8c4599c077 new file mode 100644 index 0000000..2620519 Binary files /dev/null and b/test/fixtures/537dbabc1ce057385edd9d8c4599c077 differ diff --git a/test/fixtures/537dbabc1ce057385edd9d8c4599c077.headers b/test/fixtures/537dbabc1ce057385edd9d8c4599c077.headers new file mode 100644 index 0000000..09bfcdd --- /dev/null +++ b/test/fixtures/537dbabc1ce057385edd9d8c4599c077.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 05:19:02 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1139", + "x-ratelimit-reset": "1508390343", + "server": "Plack::Handler::Starlet", + "etag": "W/\"9d42ff7893c5df984e2663e63452ecc8\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/artist/5b11f4ce-a62d-471e-81fc-a69a8278c7da?inc=url-rels&fmt=json", + "time": 646, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/56d55db80170ca90872e69c2f8b7837d b/test/fixtures/56d55db80170ca90872e69c2f8b7837d new file mode 100644 index 0000000..40a134e Binary files /dev/null and b/test/fixtures/56d55db80170ca90872e69c2f8b7837d differ diff --git a/test/fixtures/56d55db80170ca90872e69c2f8b7837d.headers b/test/fixtures/56d55db80170ca90872e69c2f8b7837d.headers new file mode 100644 index 0000000..0bdcc8d --- /dev/null +++ b/test/fixtures/56d55db80170ca90872e69c2f8b7837d.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:45 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1149", + "x-ratelimit-reset": "1508394947", + "server": "Plack::Handler::Starlet", + "etag": "W/\"617cbc165ab61233624d13e6cae69d84\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/5b80fc5d-4d8c-4e87-beae-3fd824d9fe5b?inc=url-rels&fmt=json", + "time": 374, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/5740cf0df41918fee30a22a1bce2791e b/test/fixtures/5740cf0df41918fee30a22a1bce2791e new file mode 100644 index 0000000..421f93a Binary files /dev/null and b/test/fixtures/5740cf0df41918fee30a22a1bce2791e differ diff --git a/test/fixtures/5740cf0df41918fee30a22a1bce2791e.headers b/test/fixtures/5740cf0df41918fee30a22a1bce2791e.headers new file mode 100644 index 0000000..a5ecaac --- /dev/null +++ b/test/fixtures/5740cf0df41918fee30a22a1bce2791e.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:34:56 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1041", + "x-ratelimit-reset": "1508394897", + "server": "Plack::Handler::Starlet", + "etag": "W/\"bdc94f120bd461fed1e982add84fb7b7\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/10920823-9ed8-45d9-adb3-69fc22475ab0?inc=url-rels&fmt=json", + "time": 395, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/5c1b9b2cd173095ad489f4a6e36a911d b/test/fixtures/5c1b9b2cd173095ad489f4a6e36a911d new file mode 100644 index 0000000..89f6c69 Binary files /dev/null and b/test/fixtures/5c1b9b2cd173095ad489f4a6e36a911d differ diff --git a/test/fixtures/5c1b9b2cd173095ad489f4a6e36a911d.headers b/test/fixtures/5c1b9b2cd173095ad489f4a6e36a911d.headers new file mode 100644 index 0000000..1964aa0 --- /dev/null +++ b/test/fixtures/5c1b9b2cd173095ad489f4a6e36a911d.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:07 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "872", + "x-ratelimit-reset": "1508394907", + "server": "Plack::Handler::Starlet", + "etag": "W/\"fec4e176315a83b00c8eec1e56f8ef76\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/0331bcea-3905-4893-9874-1d3f10480625?inc=url-rels&fmt=json", + "time": 419, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/5f54da66d9a88167f9dda7f1c00d73f3 b/test/fixtures/5f54da66d9a88167f9dda7f1c00d73f3 new file mode 100644 index 0000000..8085359 --- /dev/null +++ b/test/fixtures/5f54da66d9a88167f9dda7f1c00d73f3 @@ -0,0 +1 @@ +{"name":"electric lap steel guitar","disambiguation":"","description":"","relations":[],"type-id":"cc00f97f-cf3d-3ae2-9163-041cb1a0d726","id":"3c5349ca-cf82-4537-851f-1957ac88bced","type":"String instrument"} \ No newline at end of file diff --git a/test/fixtures/5f54da66d9a88167f9dda7f1c00d73f3.headers b/test/fixtures/5f54da66d9a88167f9dda7f1c00d73f3.headers new file mode 100644 index 0000000..20eba07 --- /dev/null +++ b/test/fixtures/5f54da66d9a88167f9dda7f1c00d73f3.headers @@ -0,0 +1,27 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:23:00 GMT", + "content-type": "application/json; charset=utf-8", + "content-length": "208", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1031", + "x-ratelimit-reset": "1508394181", + "server": "Plack::Handler::Starlet", + "etag": "\"7d8d675681384099008f144a36235860\"", + "access-control-allow-origin": "*" + }, + "url": "http://musicbrainz.org:80/ws/2/instrument/3c5349ca-cf82-4537-851f-1957ac88bced?inc=url-rels&fmt=json", + "time": 345, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/5fba37b7b6619c61e3092bead860e8c9 b/test/fixtures/5fba37b7b6619c61e3092bead860e8c9 new file mode 100644 index 0000000..8036c82 Binary files /dev/null and b/test/fixtures/5fba37b7b6619c61e3092bead860e8c9 differ diff --git a/test/fixtures/5fba37b7b6619c61e3092bead860e8c9.headers b/test/fixtures/5fba37b7b6619c61e3092bead860e8c9.headers new file mode 100644 index 0000000..c736b0d --- /dev/null +++ b/test/fixtures/5fba37b7b6619c61e3092bead860e8c9.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:21:19 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1102", + "x-ratelimit-reset": "1508394081", + "server": "Plack::Handler::Starlet", + "etag": "W/\"eb604ce68120353f13a010701d2e0c27\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/instrument/4a5a2a59-f5a8-4dc1-95b8-f3b3fb3cf2b6?inc=url-rels&fmt=json", + "time": 361, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/6176ff6a5cf47eed252cc9d9219c75dc b/test/fixtures/6176ff6a5cf47eed252cc9d9219c75dc new file mode 100644 index 0000000..3c21846 Binary files /dev/null and b/test/fixtures/6176ff6a5cf47eed252cc9d9219c75dc differ diff --git a/test/fixtures/6176ff6a5cf47eed252cc9d9219c75dc.headers b/test/fixtures/6176ff6a5cf47eed252cc9d9219c75dc.headers new file mode 100644 index 0000000..c80bfe9 --- /dev/null +++ b/test/fixtures/6176ff6a5cf47eed252cc9d9219c75dc.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:18 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1059", + "x-ratelimit-reset": "1508394919", + "server": "Plack::Handler::Starlet", + "etag": "W/\"729e37be7e2f850fde53437233a27d91\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/dafaa904-e2ca-46a1-8cd8-d0d84af5711b?inc=url-rels&fmt=json", + "time": 376, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/6526571b8ee23f940317e3232190179b b/test/fixtures/6526571b8ee23f940317e3232190179b new file mode 100644 index 0000000..bc635a5 Binary files /dev/null and b/test/fixtures/6526571b8ee23f940317e3232190179b differ diff --git a/test/fixtures/6526571b8ee23f940317e3232190179b.headers b/test/fixtures/6526571b8ee23f940317e3232190179b.headers new file mode 100644 index 0000000..181ade2 --- /dev/null +++ b/test/fixtures/6526571b8ee23f940317e3232190179b.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:18 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1061", + "x-ratelimit-reset": "1508394919", + "server": "Plack::Handler::Starlet", + "etag": "W/\"09e752fda201b4bbfc3df490c135400b\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/763a1446-3496-45c8-b7ae-7096360e4731?inc=url-rels&fmt=json", + "time": 384, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/6e3eeb66969aa4c71c2595d514f127f5 b/test/fixtures/6e3eeb66969aa4c71c2595d514f127f5 new file mode 100644 index 0000000..275a2d0 --- /dev/null +++ b/test/fixtures/6e3eeb66969aa4c71c2595d514f127f5 @@ -0,0 +1 @@ +{"video":false,"id":"1109d8da-ce4a-4739-9414-242dc3e9b81c","title":"Despacito","length":229213,"disambiguation":""} \ No newline at end of file diff --git a/test/fixtures/6e3eeb66969aa4c71c2595d514f127f5.headers b/test/fixtures/6e3eeb66969aa4c71c2595d514f127f5.headers new file mode 100644 index 0000000..b105a8d --- /dev/null +++ b/test/fixtures/6e3eeb66969aa4c71c2595d514f127f5.headers @@ -0,0 +1,27 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:08:35 GMT", + "content-type": "application/json; charset=utf-8", + "content-length": "115", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1087", + "x-ratelimit-reset": "1508393316", + "server": "Plack::Handler::Starlet", + "etag": "\"66af6626fd1c219d44ec95a1bd80ca48\"", + "access-control-allow-origin": "*" + }, + "url": "http://musicbrainz.org:80/ws/2/recording/1109d8da-ce4a-4739-9414-242dc3e9b81c?fmt=json", + "time": 504, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/6f630e7326d44cc51431dceffbb437a4 b/test/fixtures/6f630e7326d44cc51431dceffbb437a4 new file mode 100644 index 0000000..b329cb6 Binary files /dev/null and b/test/fixtures/6f630e7326d44cc51431dceffbb437a4 differ diff --git a/test/fixtures/6f630e7326d44cc51431dceffbb437a4.headers b/test/fixtures/6f630e7326d44cc51431dceffbb437a4.headers new file mode 100644 index 0000000..80262f1 --- /dev/null +++ b/test/fixtures/6f630e7326d44cc51431dceffbb437a4.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:07 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "874", + "x-ratelimit-reset": "1508394907", + "server": "Plack::Handler::Starlet", + "etag": "W/\"acd4b456656be0a6e6782a70433b00e4\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/400facc8-2f30-4c1f-a1fa-53639bbeaff8?inc=url-rels&fmt=json", + "time": 358, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/70ae1dbdd83a22e8c04c74809d45b345 b/test/fixtures/70ae1dbdd83a22e8c04c74809d45b345 new file mode 100644 index 0000000..987e2f1 Binary files /dev/null and b/test/fixtures/70ae1dbdd83a22e8c04c74809d45b345 differ diff --git a/test/fixtures/70ae1dbdd83a22e8c04c74809d45b345.headers b/test/fixtures/70ae1dbdd83a22e8c04c74809d45b345.headers new file mode 100644 index 0000000..17f579a --- /dev/null +++ b/test/fixtures/70ae1dbdd83a22e8c04c74809d45b345.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:34 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "936", + "x-ratelimit-reset": "1508394935", + "server": "Plack::Handler::Starlet", + "etag": "W/\"f5ff9aea83a2b9308c7d08384489be6a\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/e29d84e8-096c-4f86-83a4-992401236199?inc=url-rels&fmt=json", + "time": 353, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/7295737c14813766abe7f6d7c8a4e4c0 b/test/fixtures/7295737c14813766abe7f6d7c8a4e4c0 new file mode 100644 index 0000000..8cae859 Binary files /dev/null and b/test/fixtures/7295737c14813766abe7f6d7c8a4e4c0 differ diff --git a/test/fixtures/7295737c14813766abe7f6d7c8a4e4c0.headers b/test/fixtures/7295737c14813766abe7f6d7c8a4e4c0.headers new file mode 100644 index 0000000..1f10046 --- /dev/null +++ b/test/fixtures/7295737c14813766abe7f6d7c8a4e4c0.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:35 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "937", + "x-ratelimit-reset": "1508394935", + "server": "Plack::Handler::Starlet", + "etag": "W/\"a39cf40253327e9022dfe7a2355eab52\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/09729b9b-c3e0-4680-97df-f1327b5fdfba?inc=url-rels&fmt=json", + "time": 385, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/759a630311f32c04c63c7556ca7a19d9 b/test/fixtures/759a630311f32c04c63c7556ca7a19d9 new file mode 100644 index 0000000..de0ccef Binary files /dev/null and b/test/fixtures/759a630311f32c04c63c7556ca7a19d9 differ diff --git a/test/fixtures/759a630311f32c04c63c7556ca7a19d9.headers b/test/fixtures/759a630311f32c04c63c7556ca7a19d9.headers new file mode 100644 index 0000000..f085f9b --- /dev/null +++ b/test/fixtures/759a630311f32c04c63c7556ca7a19d9.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:21:14 GMT", + "content-type": "application/json; charset=UTF-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1019", + "x-ratelimit-reset": "1508394075", + "last-modified": "Thu, 19 Oct 2017 05:35:42 GMT", + "server": "Jetty(9.3.10.v20160621)", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/instrument?limit=10&query=guitar&fmt=json", + "time": 464, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/771b51c0fbd414533c20f2d95e571dc9 b/test/fixtures/771b51c0fbd414533c20f2d95e571dc9 new file mode 100644 index 0000000..c673963 Binary files /dev/null and b/test/fixtures/771b51c0fbd414533c20f2d95e571dc9 differ diff --git a/test/fixtures/771b51c0fbd414533c20f2d95e571dc9.headers b/test/fixtures/771b51c0fbd414533c20f2d95e571dc9.headers new file mode 100644 index 0000000..5cc9fda --- /dev/null +++ b/test/fixtures/771b51c0fbd414533c20f2d95e571dc9.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:34:56 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1039", + "x-ratelimit-reset": "1508394897", + "server": "Plack::Handler::Starlet", + "etag": "W/\"781a65878131bde9ea9fb9bd8ae30361\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/99b364b4-8934-4eae-b0ff-555a5d950d7d?inc=url-rels&fmt=json", + "time": 398, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/79471f371a264a0176df177479190ddc b/test/fixtures/79471f371a264a0176df177479190ddc new file mode 100644 index 0000000..5369481 Binary files /dev/null and b/test/fixtures/79471f371a264a0176df177479190ddc differ diff --git a/test/fixtures/79471f371a264a0176df177479190ddc.headers b/test/fixtures/79471f371a264a0176df177479190ddc.headers new file mode 100644 index 0000000..f5b85c6 --- /dev/null +++ b/test/fixtures/79471f371a264a0176df177479190ddc.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:21:25 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "852", + "x-ratelimit-reset": "1508394085", + "server": "Plack::Handler::Starlet", + "etag": "W/\"537aebfba34970387608fbbe367e008b\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/instrument/1e49948d-7522-4444-aa5d-633dfbeffb1f?inc=url-rels&fmt=json", + "time": 352, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/7b053660a24a2db5139e8e7ffc3a9225 b/test/fixtures/7b053660a24a2db5139e8e7ffc3a9225 new file mode 100644 index 0000000..8e58115 Binary files /dev/null and b/test/fixtures/7b053660a24a2db5139e8e7ffc3a9225 differ diff --git a/test/fixtures/7b053660a24a2db5139e8e7ffc3a9225.headers b/test/fixtures/7b053660a24a2db5139e8e7ffc3a9225.headers new file mode 100644 index 0000000..92d2823 --- /dev/null +++ b/test/fixtures/7b053660a24a2db5139e8e7ffc3a9225.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:13 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "940", + "x-ratelimit-reset": "1508394913", + "server": "Plack::Handler::Starlet", + "etag": "W/\"6c83a76f1d4f7e0250d64dc9e1c3758a\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/5a46f735-6c98-4cfe-a9bc-72f9be7162c5?inc=url-rels&fmt=json", + "time": 396, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/7e4ef1a9130fb6e4fb62cd29edd6974f b/test/fixtures/7e4ef1a9130fb6e4fb62cd29edd6974f new file mode 100644 index 0000000..f0b326f Binary files /dev/null and b/test/fixtures/7e4ef1a9130fb6e4fb62cd29edd6974f differ diff --git a/test/fixtures/7e4ef1a9130fb6e4fb62cd29edd6974f.headers b/test/fixtures/7e4ef1a9130fb6e4fb62cd29edd6974f.headers new file mode 100644 index 0000000..b45e693 --- /dev/null +++ b/test/fixtures/7e4ef1a9130fb6e4fb62cd29edd6974f.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:23:11 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "845", + "x-ratelimit-reset": "1508394191", + "server": "Plack::Handler::Starlet", + "etag": "W/\"01cb1288a220538faa953a7098a8ab7d\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/instrument/87d5bd6a-8d14-4ed0-befa-b90379536634?inc=url-rels&fmt=json", + "time": 350, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/8619ae4dc1a5c3e3cf04ac05ede71e99 b/test/fixtures/8619ae4dc1a5c3e3cf04ac05ede71e99 new file mode 100644 index 0000000..b8fb493 Binary files /dev/null and b/test/fixtures/8619ae4dc1a5c3e3cf04ac05ede71e99 differ diff --git a/test/fixtures/8619ae4dc1a5c3e3cf04ac05ede71e99.headers b/test/fixtures/8619ae4dc1a5c3e3cf04ac05ede71e99.headers new file mode 100644 index 0000000..7f17502 --- /dev/null +++ b/test/fixtures/8619ae4dc1a5c3e3cf04ac05ede71e99.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:21:19 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1099", + "x-ratelimit-reset": "1508394081", + "server": "Plack::Handler::Starlet", + "etag": "W/\"85986fbe45e9964c2e7921f634e7c0f5\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/instrument/7ee8ebf5-3aed-4fc8-8004-49f4a8c45a87?inc=url-rels&fmt=json", + "time": 398, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/892adb119a9924a464f3443d9f3b03a9 b/test/fixtures/892adb119a9924a464f3443d9f3b03a9 new file mode 100644 index 0000000..6793bcc Binary files /dev/null and b/test/fixtures/892adb119a9924a464f3443d9f3b03a9 differ diff --git a/test/fixtures/892adb119a9924a464f3443d9f3b03a9.headers b/test/fixtures/892adb119a9924a464f3443d9f3b03a9.headers new file mode 100644 index 0000000..8fd03ab --- /dev/null +++ b/test/fixtures/892adb119a9924a464f3443d9f3b03a9.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:34 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "939", + "x-ratelimit-reset": "1508394935", + "server": "Plack::Handler::Starlet", + "etag": "W/\"f0d943fbdc5b86162b0632f264f43f03\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/5b49bfd8-fbf9-4b89-80a6-760ab79000c7?inc=url-rels&fmt=json", + "time": 365, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/8c969c07759e225e55132955258d912f b/test/fixtures/8c969c07759e225e55132955258d912f new file mode 100644 index 0000000..a6ddded Binary files /dev/null and b/test/fixtures/8c969c07759e225e55132955258d912f differ diff --git a/test/fixtures/8c969c07759e225e55132955258d912f.headers b/test/fixtures/8c969c07759e225e55132955258d912f.headers new file mode 100644 index 0000000..f51cc25 --- /dev/null +++ b/test/fixtures/8c969c07759e225e55132955258d912f.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:34:56 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1038", + "x-ratelimit-reset": "1508394897", + "server": "Plack::Handler::Starlet", + "etag": "W/\"f9cb1a156d5839b1168c2efa27e4b6ce\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/a789c5e2-2dc5-47f2-bb97-12c23e5805d2?inc=url-rels&fmt=json", + "time": 372, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/8cabf5fae5f37ac12bc602d38e0d7cdb b/test/fixtures/8cabf5fae5f37ac12bc602d38e0d7cdb new file mode 100644 index 0000000..87d7c63 Binary files /dev/null and b/test/fixtures/8cabf5fae5f37ac12bc602d38e0d7cdb differ diff --git a/test/fixtures/8cabf5fae5f37ac12bc602d38e0d7cdb.headers b/test/fixtures/8cabf5fae5f37ac12bc602d38e0d7cdb.headers new file mode 100644 index 0000000..29a5985 --- /dev/null +++ b/test/fixtures/8cabf5fae5f37ac12bc602d38e0d7cdb.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:34:56 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1037", + "x-ratelimit-reset": "1508394897", + "server": "Plack::Handler::Starlet", + "etag": "W/\"615741c2b715c735f459e0f26633d273\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/3a6f9906-2194-4bdd-84e0-6b6d7a2a7051?inc=url-rels&fmt=json", + "time": 480, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/973e11ce912c0bc44d3fad7d08d9c41d b/test/fixtures/973e11ce912c0bc44d3fad7d08d9c41d new file mode 100644 index 0000000..3e9aaaf Binary files /dev/null and b/test/fixtures/973e11ce912c0bc44d3fad7d08d9c41d differ diff --git a/test/fixtures/973e11ce912c0bc44d3fad7d08d9c41d.headers b/test/fixtures/973e11ce912c0bc44d3fad7d08d9c41d.headers new file mode 100644 index 0000000..9a79ab9 --- /dev/null +++ b/test/fixtures/973e11ce912c0bc44d3fad7d08d9c41d.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:23:05 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1142", + "x-ratelimit-reset": "1508394187", + "server": "Plack::Handler::Starlet", + "etag": "W/\"058d3673dae62cfe3f65ef90931d5440\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/instrument/41d2c709-81e2-415c-9456-a0a3d14f48bd?inc=url-rels&fmt=json", + "time": 365, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/981e4a18c54b89e2537b7660cf8ed3bd b/test/fixtures/981e4a18c54b89e2537b7660cf8ed3bd new file mode 100644 index 0000000..a601db9 Binary files /dev/null and b/test/fixtures/981e4a18c54b89e2537b7660cf8ed3bd differ diff --git a/test/fixtures/981e4a18c54b89e2537b7660cf8ed3bd.headers b/test/fixtures/981e4a18c54b89e2537b7660cf8ed3bd.headers new file mode 100644 index 0000000..edb1525 --- /dev/null +++ b/test/fixtures/981e4a18c54b89e2537b7660cf8ed3bd.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:01 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1124", + "x-ratelimit-reset": "1508394903", + "server": "Plack::Handler::Starlet", + "etag": "W/\"3aae701831ecfae8e3206cdb69451285\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/6bb88a42-87e9-48eb-97a2-4e15aea0929c?inc=url-rels&fmt=json", + "time": 386, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/989521e0ddda97a5a15e7564e4a02100 b/test/fixtures/989521e0ddda97a5a15e7564e4a02100 new file mode 100644 index 0000000..a8c110c Binary files /dev/null and b/test/fixtures/989521e0ddda97a5a15e7564e4a02100 differ diff --git a/test/fixtures/989521e0ddda97a5a15e7564e4a02100.headers b/test/fixtures/989521e0ddda97a5a15e7564e4a02100.headers new file mode 100644 index 0000000..e5838b1 --- /dev/null +++ b/test/fixtures/989521e0ddda97a5a15e7564e4a02100.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:21:14 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "939", + "x-ratelimit-reset": "1508394075", + "server": "Plack::Handler::Starlet", + "etag": "W/\"98358a436ef941331f2696c965215054\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/instrument/63021302-86cd-4aee-80df-2270d54f4978?inc=url-rels&fmt=json", + "time": 349, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/989db6ea639b5dc2f24377b312932f27 b/test/fixtures/989db6ea639b5dc2f24377b312932f27 new file mode 100644 index 0000000..0e89c4d Binary files /dev/null and b/test/fixtures/989db6ea639b5dc2f24377b312932f27 differ diff --git a/test/fixtures/989db6ea639b5dc2f24377b312932f27.headers b/test/fixtures/989db6ea639b5dc2f24377b312932f27.headers new file mode 100644 index 0000000..91773c5 --- /dev/null +++ b/test/fixtures/989db6ea639b5dc2f24377b312932f27.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:22:50 GMT", + "content-type": "application/json; charset=UTF-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1180", + "x-ratelimit-reset": "1508394171", + "last-modified": "Thu, 19 Oct 2017 06:09:33 GMT", + "server": "Jetty(9.3.10.v20160621)", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/instrument?limit=20&query=guitar&fmt=json", + "time": 1315, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/9c392f735dfc18f1ebae5057d4810503 b/test/fixtures/9c392f735dfc18f1ebae5057d4810503 new file mode 100644 index 0000000..55486b6 Binary files /dev/null and b/test/fixtures/9c392f735dfc18f1ebae5057d4810503 differ diff --git a/test/fixtures/9c392f735dfc18f1ebae5057d4810503.headers b/test/fixtures/9c392f735dfc18f1ebae5057d4810503.headers new file mode 100644 index 0000000..f0aa7ac --- /dev/null +++ b/test/fixtures/9c392f735dfc18f1ebae5057d4810503.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:21:19 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1104", + "x-ratelimit-reset": "1508394081", + "server": "Plack::Handler::Starlet", + "etag": "W/\"b4e51ec8503dac60a12a593d8edfeb4e\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/instrument/921330d6-eb1b-4e59-b4b6-824ebcdb89c2?inc=url-rels&fmt=json", + "time": 372, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/a95dc0c2cbed192f29e448ff0ab981f2 b/test/fixtures/a95dc0c2cbed192f29e448ff0ab981f2 new file mode 100644 index 0000000..0541e65 Binary files /dev/null and b/test/fixtures/a95dc0c2cbed192f29e448ff0ab981f2 differ diff --git a/test/fixtures/a95dc0c2cbed192f29e448ff0ab981f2.headers b/test/fixtures/a95dc0c2cbed192f29e448ff0ab981f2.headers new file mode 100644 index 0000000..7e518bc --- /dev/null +++ b/test/fixtures/a95dc0c2cbed192f29e448ff0ab981f2.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:18 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1062", + "x-ratelimit-reset": "1508394919", + "server": "Plack::Handler::Starlet", + "etag": "W/\"f48d87f07def24296f1633d0dacb1530\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/8d30f719-996a-45bf-bf67-c0d390c67bc9?inc=url-rels&fmt=json", + "time": 378, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/aa96a948b688bc7d7aa7726a61cbc4e5 b/test/fixtures/aa96a948b688bc7d7aa7726a61cbc4e5 new file mode 100644 index 0000000..f53febd Binary files /dev/null and b/test/fixtures/aa96a948b688bc7d7aa7726a61cbc4e5 differ diff --git a/test/fixtures/aa96a948b688bc7d7aa7726a61cbc4e5.headers b/test/fixtures/aa96a948b688bc7d7aa7726a61cbc4e5.headers new file mode 100644 index 0000000..64ddc78 --- /dev/null +++ b/test/fixtures/aa96a948b688bc7d7aa7726a61cbc4e5.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:21:25 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "853", + "x-ratelimit-reset": "1508394085", + "server": "Plack::Handler::Starlet", + "etag": "W/\"2376346af4535d7bd2e1b7d2b78fcaba\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/instrument/4a10b219-65ac-4b6c-950d-acc8461266c7?inc=url-rels&fmt=json", + "time": 365, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/aabb63c196e05819a62f5c4236dee819 b/test/fixtures/aabb63c196e05819a62f5c4236dee819 new file mode 100644 index 0000000..1dc681c Binary files /dev/null and b/test/fixtures/aabb63c196e05819a62f5c4236dee819 differ diff --git a/test/fixtures/aabb63c196e05819a62f5c4236dee819.headers b/test/fixtures/aabb63c196e05819a62f5c4236dee819.headers new file mode 100644 index 0000000..2c2de7d --- /dev/null +++ b/test/fixtures/aabb63c196e05819a62f5c4236dee819.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:23:05 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1140", + "x-ratelimit-reset": "1508394187", + "server": "Plack::Handler::Starlet", + "etag": "W/\"98f19046886ad40fe0f999cc8cc348d7\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/instrument/4ffe5341-4d63-4b1f-8b00-b008954bc7a4?inc=url-rels&fmt=json", + "time": 465, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/acaca90fe77e40a25bd38b95282272c8 b/test/fixtures/acaca90fe77e40a25bd38b95282272c8 new file mode 100644 index 0000000..b6b1499 Binary files /dev/null and b/test/fixtures/acaca90fe77e40a25bd38b95282272c8 differ diff --git a/test/fixtures/acaca90fe77e40a25bd38b95282272c8.headers b/test/fixtures/acaca90fe77e40a25bd38b95282272c8.headers new file mode 100644 index 0000000..e4de796 --- /dev/null +++ b/test/fixtures/acaca90fe77e40a25bd38b95282272c8.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:23:11 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "844", + "x-ratelimit-reset": "1508394191", + "server": "Plack::Handler::Starlet", + "etag": "W/\"304bb6fa72676f2ca4fff82f88020cec\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/instrument/c2bfcf82-356c-4606-9dd7-51efd1b11bec?inc=url-rels&fmt=json", + "time": 326, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/ad5041074ea5fe6a4f5046944b60f216 b/test/fixtures/ad5041074ea5fe6a4f5046944b60f216 new file mode 100644 index 0000000..a93e6fd Binary files /dev/null and b/test/fixtures/ad5041074ea5fe6a4f5046944b60f216 differ diff --git a/test/fixtures/ad5041074ea5fe6a4f5046944b60f216.headers b/test/fixtures/ad5041074ea5fe6a4f5046944b60f216.headers new file mode 100644 index 0000000..73391ae --- /dev/null +++ b/test/fixtures/ad5041074ea5fe6a4f5046944b60f216.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:34:51 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1159", + "x-ratelimit-reset": "1508394893", + "server": "Plack::Handler::Starlet", + "etag": "W/\"90bed3e68171d9b7bb9b1d3f38c25cbd\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/f9ada3ae-3081-44df-8581-ca27a3462b68?inc=url-rels&fmt=json", + "time": 376, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/af29a78d9191b600ced4f7f04570c4ee b/test/fixtures/af29a78d9191b600ced4f7f04570c4ee new file mode 100644 index 0000000..00e16da Binary files /dev/null and b/test/fixtures/af29a78d9191b600ced4f7f04570c4ee differ diff --git a/test/fixtures/af29a78d9191b600ced4f7f04570c4ee.headers b/test/fixtures/af29a78d9191b600ced4f7f04570c4ee.headers new file mode 100644 index 0000000..b2859a5 --- /dev/null +++ b/test/fixtures/af29a78d9191b600ced4f7f04570c4ee.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:29 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "853", + "x-ratelimit-reset": "1508394929", + "server": "Plack::Handler::Starlet", + "etag": "W/\"4827e57d43a4c72be2bf5691a822c0ef\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/256a9a1e-53c8-4a59-a924-9e559f3f174d?inc=url-rels&fmt=json", + "time": 389, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/af7dae80c814d6fc8e5a6d4ff4f6ab96 b/test/fixtures/af7dae80c814d6fc8e5a6d4ff4f6ab96 new file mode 100644 index 0000000..76718be Binary files /dev/null and b/test/fixtures/af7dae80c814d6fc8e5a6d4ff4f6ab96 differ diff --git a/test/fixtures/af7dae80c814d6fc8e5a6d4ff4f6ab96.headers b/test/fixtures/af7dae80c814d6fc8e5a6d4ff4f6ab96.headers new file mode 100644 index 0000000..2ae22aa --- /dev/null +++ b/test/fixtures/af7dae80c814d6fc8e5a6d4ff4f6ab96.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:13 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "942", + "x-ratelimit-reset": "1508394913", + "server": "Plack::Handler::Starlet", + "etag": "W/\"5a9e1ae8bb44aaae6e743ec03da8f8b7\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/bf519cd2-4e1e-46bf-948b-615f75424606?inc=url-rels&fmt=json", + "time": 391, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/b2757f369119107b417af16a5b5cc57c b/test/fixtures/b2757f369119107b417af16a5b5cc57c new file mode 100644 index 0000000..1f377ef Binary files /dev/null and b/test/fixtures/b2757f369119107b417af16a5b5cc57c differ diff --git a/test/fixtures/b2757f369119107b417af16a5b5cc57c.headers b/test/fixtures/b2757f369119107b417af16a5b5cc57c.headers new file mode 100644 index 0000000..2cc2f38 --- /dev/null +++ b/test/fixtures/b2757f369119107b417af16a5b5cc57c.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:12 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "943", + "x-ratelimit-reset": "1508394913", + "server": "Plack::Handler::Starlet", + "etag": "W/\"c548d1a2f11e5d0129011c8af825f9b8\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/e2609faf-7e1e-4ce6-84bd-73146ad62ee8?inc=url-rels&fmt=json", + "time": 356, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/b4bc218a89b1ed34a74924a42db92b8a b/test/fixtures/b4bc218a89b1ed34a74924a42db92b8a new file mode 100644 index 0000000..9d8aa33 Binary files /dev/null and b/test/fixtures/b4bc218a89b1ed34a74924a42db92b8a differ diff --git a/test/fixtures/b4bc218a89b1ed34a74924a42db92b8a.headers b/test/fixtures/b4bc218a89b1ed34a74924a42db92b8a.headers new file mode 100644 index 0000000..9438eae --- /dev/null +++ b/test/fixtures/b4bc218a89b1ed34a74924a42db92b8a.headers @@ -0,0 +1,43 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:23:11 GMT", + "content-type": "application/json; charset=utf-8", + "content-length": "725", + "connection": "keep-alive", + "server": "mw1202.eqiad.wmnet", + "x-powered-by": "HHVM/3.18.6-dev", + "x-content-type-options": "nosniff", + "cache-control": "private, must-revalidate, max-age=0", + "p3p": "CP=\"This is not a P3P policy! See https://commons.wikimedia.org/wiki/Special:CentralAutoLogin/P3P for more info.\"", + "content-encoding": "gzip", + "x-frame-options": "DENY", + "content-disposition": "inline; filename=\"api-result.json\"", + "vary": "Accept-Encoding,Treat-as-Untrusted,X-Forwarded-Proto,Cookie,Authorization", + "backend-timing": "D=53160 t=1508394191609579", + "x-varnish": "179186442, 410024931, 381596374, 684593716", + "via": "1.1 varnish-v4, 1.1 varnish-v4, 1.1 varnish-v4, 1.1 varnish-v4", + "accept-ranges": "bytes", + "age": "0", + "x-cache": "cp1053 pass, cp2013 pass, cp4028 pass, cp4018 pass", + "x-cache-status": "pass", + "strict-transport-security": "max-age=106384710; includeSubDomains; preload", + "set-cookie": [ + "WMF-Last-Access=19-Oct-2017;Path=/;HttpOnly;secure;Expires=Mon, 20 Nov 2017 00:00:00 GMT", + "GeoIP=US:WA:Seattle:47.61:-122.30:v4; Path=/; secure; Domain=.wikimedia.org" + ], + "x-analytics": "ns=-1;special=Badtitle;https=1;nocookies=1", + "x-client-ip": "66.235.47.149" + }, + "url": "https://commons.wikimedia.org:443/w/api.php?action=query&titles=File%3A2_Portuguese_guitars.jpg&prop=imageinfo&iiprop=url%7Csize%7Ccanonicaltitle%7Cuser%7Cextmetadata&format=json", + "time": 369, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "commons.wikimedia.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/b5b153f3c2c39a5cf25fdc0ee96d0fce b/test/fixtures/b5b153f3c2c39a5cf25fdc0ee96d0fce new file mode 100644 index 0000000..7a2fa15 Binary files /dev/null and b/test/fixtures/b5b153f3c2c39a5cf25fdc0ee96d0fce differ diff --git a/test/fixtures/b5b153f3c2c39a5cf25fdc0ee96d0fce.headers b/test/fixtures/b5b153f3c2c39a5cf25fdc0ee96d0fce.headers new file mode 100644 index 0000000..1d6b828 --- /dev/null +++ b/test/fixtures/b5b153f3c2c39a5cf25fdc0ee96d0fce.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:40 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1061", + "x-ratelimit-reset": "1508394941", + "server": "Plack::Handler::Starlet", + "etag": "W/\"710293a5e2f07fbb89ea7c73e9d70438\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/c118e3db-36e7-4293-a65f-701732df7ca6?inc=url-rels&fmt=json", + "time": 395, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/b63c630cd8a47258d3cd45635adfe2fd b/test/fixtures/b63c630cd8a47258d3cd45635adfe2fd new file mode 100644 index 0000000..f45ed6e Binary files /dev/null and b/test/fixtures/b63c630cd8a47258d3cd45635adfe2fd differ diff --git a/test/fixtures/b63c630cd8a47258d3cd45635adfe2fd.headers b/test/fixtures/b63c630cd8a47258d3cd45635adfe2fd.headers new file mode 100644 index 0000000..5ebf024 --- /dev/null +++ b/test/fixtures/b63c630cd8a47258d3cd45635adfe2fd.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:23 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1131", + "x-ratelimit-reset": "1508394925", + "server": "Plack::Handler::Starlet", + "etag": "W/\"c575f2d70827f45a1e3e231d7254745d\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/f011bcf8-7785-4000-9469-4d68b01dd683?inc=url-rels&fmt=json", + "time": 365, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/b788432e4977d8a7be60e806b42848dd b/test/fixtures/b788432e4977d8a7be60e806b42848dd new file mode 100644 index 0000000..97d2157 Binary files /dev/null and b/test/fixtures/b788432e4977d8a7be60e806b42848dd differ diff --git a/test/fixtures/b788432e4977d8a7be60e806b42848dd.headers b/test/fixtures/b788432e4977d8a7be60e806b42848dd.headers new file mode 100644 index 0000000..0f96b77 --- /dev/null +++ b/test/fixtures/b788432e4977d8a7be60e806b42848dd.headers @@ -0,0 +1,43 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:52 GMT", + "content-type": "application/json; charset=utf-8", + "content-length": "844", + "connection": "keep-alive", + "server": "mw1314.eqiad.wmnet", + "x-powered-by": "HHVM/3.18.6-dev", + "x-content-type-options": "nosniff", + "cache-control": "private, must-revalidate, max-age=0", + "p3p": "CP=\"This is not a P3P policy! See https://commons.wikimedia.org/wiki/Special:CentralAutoLogin/P3P for more info.\"", + "content-encoding": "gzip", + "x-frame-options": "DENY", + "content-disposition": "inline; filename=\"api-result.json\"", + "vary": "Accept-Encoding,Treat-as-Untrusted,X-Forwarded-Proto,Cookie,Authorization", + "backend-timing": "D=180917 t=1508394951803664", + "x-varnish": "558013596, 239477161, 538442496, 692692485", + "via": "1.1 varnish-v4, 1.1 varnish-v4, 1.1 varnish-v4, 1.1 varnish-v4", + "accept-ranges": "bytes", + "age": "0", + "x-cache": "cp1055 pass, cp2016 pass, cp4027 pass, cp4018 pass", + "x-cache-status": "pass", + "strict-transport-security": "max-age=106384710; includeSubDomains; preload", + "set-cookie": [ + "WMF-Last-Access=19-Oct-2017;Path=/;HttpOnly;secure;Expires=Mon, 20 Nov 2017 00:00:00 GMT", + "GeoIP=US:WA:Seattle:47.61:-122.30:v4; Path=/; secure; Domain=.wikimedia.org" + ], + "x-analytics": "ns=-1;special=Badtitle;https=1;nocookies=1", + "x-client-ip": "66.235.47.149" + }, + "url": "http://commons.wikimedia.org:443/w/api.php?action=query&titles=File%3AParamount_Theater_in_Seattle_showing_Wicked.jpg&prop=imageinfo&iiprop=url%7Csize%7Ccanonicaltitle%7Cuser%7Cextmetadata&format=json", + "time": 477, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "commons.wikimedia.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/b8cdd376ffa05b4ed0fa88c8580f6d78 b/test/fixtures/b8cdd376ffa05b4ed0fa88c8580f6d78 new file mode 100644 index 0000000..9e99ed5 Binary files /dev/null and b/test/fixtures/b8cdd376ffa05b4ed0fa88c8580f6d78 differ diff --git a/test/fixtures/b8cdd376ffa05b4ed0fa88c8580f6d78.headers b/test/fixtures/b8cdd376ffa05b4ed0fa88c8580f6d78.headers new file mode 100644 index 0000000..ae6c382 --- /dev/null +++ b/test/fixtures/b8cdd376ffa05b4ed0fa88c8580f6d78.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:29 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "854", + "x-ratelimit-reset": "1508394929", + "server": "Plack::Handler::Starlet", + "etag": "W/\"0ad347c81e9947075579c38d20ee358c\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/53fe2f64-0720-444e-9893-aea7b520ed6f?inc=url-rels&fmt=json", + "time": 361, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/ba515718537dd9c0dcb6332ee59cfead b/test/fixtures/ba515718537dd9c0dcb6332ee59cfead new file mode 100644 index 0000000..2616cc7 Binary files /dev/null and b/test/fixtures/ba515718537dd9c0dcb6332ee59cfead differ diff --git a/test/fixtures/ba515718537dd9c0dcb6332ee59cfead.headers b/test/fixtures/ba515718537dd9c0dcb6332ee59cfead.headers new file mode 100644 index 0000000..406bd17 --- /dev/null +++ b/test/fixtures/ba515718537dd9c0dcb6332ee59cfead.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:13:21 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "843", + "x-ratelimit-reset": "1508393601", + "server": "Plack::Handler::Starlet", + "etag": "W/\"a86182c8c916a7ad0ad769924293ce2b\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/release-group/aa997ea0-2936-40bd-884d-3af8a0e064dc?fmt=json", + "time": 347, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/bb45b9cceba8f0e6f31f18ee670ecb7b b/test/fixtures/bb45b9cceba8f0e6f31f18ee670ecb7b new file mode 100644 index 0000000..e5a2188 Binary files /dev/null and b/test/fixtures/bb45b9cceba8f0e6f31f18ee670ecb7b differ diff --git a/test/fixtures/bb45b9cceba8f0e6f31f18ee670ecb7b.headers b/test/fixtures/bb45b9cceba8f0e6f31f18ee670ecb7b.headers new file mode 100644 index 0000000..5e0ba6a --- /dev/null +++ b/test/fixtures/bb45b9cceba8f0e6f31f18ee670ecb7b.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 05:57:19 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1080", + "x-ratelimit-reset": "1508392640", + "server": "Plack::Handler::Starlet", + "etag": "W/\"4eb4e99b746b418092363473389348cc\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/0cf56645-50ec-4411-aeb6-c9f4ce0f8edb?fmt=json", + "time": 572, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/be14b8e0fa4d1830a0ebe40a016ca6e2 b/test/fixtures/be14b8e0fa4d1830a0ebe40a016ca6e2 new file mode 100644 index 0000000..cc043fc Binary files /dev/null and b/test/fixtures/be14b8e0fa4d1830a0ebe40a016ca6e2 differ diff --git a/test/fixtures/be14b8e0fa4d1830a0ebe40a016ca6e2.headers b/test/fixtures/be14b8e0fa4d1830a0ebe40a016ca6e2.headers new file mode 100644 index 0000000..f62ec7f --- /dev/null +++ b/test/fixtures/be14b8e0fa4d1830a0ebe40a016ca6e2.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:23:05 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1144", + "x-ratelimit-reset": "1508394187", + "server": "Plack::Handler::Starlet", + "etag": "W/\"53a63d6b7c767396afdc9282b6bc82d1\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/instrument/31c3f6cc-d49c-4d63-8b85-576a545d33f2?inc=url-rels&fmt=json", + "time": 361, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/c125b6361991fc5455d24693c30e9063 b/test/fixtures/c125b6361991fc5455d24693c30e9063 new file mode 100644 index 0000000..3b1cd25 --- /dev/null +++ b/test/fixtures/c125b6361991fc5455d24693c30e9063 @@ -0,0 +1 @@ +{"track":[{"idTrack":"34838814","idAlbum":"2284335","idArtist":"131613","idLyric":null,"idIMVDB":"2147483647","strTrack":"Despacito","strAlbum":"Despacito & mis grandes \u00e9xitos","strArtist":"Luis Fonsi","strArtistAlternate":null,"intCD":null,"intDuration":"231573","strGenre":"Latin","strMood":"Sensual","strStyle":"Latin","strTheme":"In Love","strDescriptionEN":"\"Despacito\" (American Spanish: ; English: \"Slowly\") is a single by Puerto Rican singer Luis Fonsi featuring Puerto Rican rapper Daddy Yankee from Fonsi's upcoming studio album. On January 12, 2017, Universal Music Latin released \"Despacito\" and its music video, which shows both artists performing the song in La Perla neighborhood of Old San Juan, Puerto Rico and the local bar La Factor\u00eda. The song's music video is the first video to reach over three billion views on YouTube. The song was written by Luis Fonsi, Erika Ender and Daddy Yankee, and was produced by Andr\u00e9s Torres and Mauricio Rengifo.\n\nIt is a reggaeton-pop song composed in common time with lyrics about having a sexual relationship, performed in a smooth and romantic way. Commercially, the song topped the charts of 47 countries and reached the top 10 of ten others, making it both Fonsi and Daddy Yankee's most successful single to date. It became the first song primarily in Spanish to top the Billboard Hot 100 since \"Macarena\" (Bayside Boys Mix) in 1996. The official video for \"Despacito\" on YouTube received its 1 billionth view on April 20, 2017 after 97 days, becoming the second-fastest video on the site to reach the milestone -- behind Adele's \"Hello\". It received its 2 billionth view on June 16 and its 3 billionth view on August 4 after 154 and 204 days, respectively, making it the fastest video on the site to reach both milestones. With its 3.3 million certified sales plus track-equivalent streams, \"Despacito\" is one of the best-selling Latin singles in the United States.","strTrackThumb":"http://media.theaudiodb.com/images/media/track/thumb/vqqpry1506425784.jpg","strTrackLyrics":"","strMusicVid":"https://www.youtube.com/watch?v=kJQP7kiw5Fk","strMusicVidDirector":"Carlos P\u00e9rez","strMusicVidCompany":"","strMusicVidScreen1":null,"strMusicVidScreen2":null,"strMusicVidScreen3":null,"intMusicVidViews":"2147483647","intMusicVidLikes":"21015918","intMusicVidDislikes":"2168098","intMusicVidFavorites":"0","intMusicVidComments":"1449046","intTrackNumber":"1","intLoved":"1","intScore":"10","intScoreVotes":"1","strMusicBrainzID":"1109d8da-ce4a-4739-9414-242dc3e9b81c","strMusicBrainzAlbumID":"76357b1d-db6e-4dfc-b5fc-ed2544764d90","strMusicBrainzArtistID":"d68fda90-ab8d-4799-be56-317ba4ae700f","strLocked":"unlocked"}]} \ No newline at end of file diff --git a/test/fixtures/c125b6361991fc5455d24693c30e9063.headers b/test/fixtures/c125b6361991fc5455d24693c30e9063.headers new file mode 100644 index 0000000..c4b4830 --- /dev/null +++ b/test/fixtures/c125b6361991fc5455d24693c30e9063.headers @@ -0,0 +1,21 @@ +{ + "statusCode": 200, + "headers": { + "content-type": "application/json", + "server": "Microsoft-IIS/7.0", + "x-powered-by": "PHP/5.6.0, ASP.NET", + "date": "Thu, 19 Oct 2017 06:08:27 GMT", + "content-length": "2708" + }, + "url": "http://www.theaudiodb.com:80/api/v1/json/1/track-mb.php?i=1109d8da-ce4a-4739-9414-242dc3e9b81c", + "time": 320, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "www.theaudiodb.com", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/c1db4dc6ce9581a6fb82f326ef7a72f6 b/test/fixtures/c1db4dc6ce9581a6fb82f326ef7a72f6 new file mode 100644 index 0000000..8cf9607 Binary files /dev/null and b/test/fixtures/c1db4dc6ce9581a6fb82f326ef7a72f6 differ diff --git a/test/fixtures/c1db4dc6ce9581a6fb82f326ef7a72f6.headers b/test/fixtures/c1db4dc6ce9581a6fb82f326ef7a72f6.headers new file mode 100644 index 0000000..4d48a0a --- /dev/null +++ b/test/fixtures/c1db4dc6ce9581a6fb82f326ef7a72f6.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:23:05 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1141", + "x-ratelimit-reset": "1508394187", + "server": "Plack::Handler::Starlet", + "etag": "W/\"9b304fbe4636d23b75081bbfaa3f6517\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/instrument/a1baa57d-6ab4-461e-89df-448d6fd2c597?inc=url-rels&fmt=json", + "time": 353, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/c3211588134d80d9447ef9f05e02690b b/test/fixtures/c3211588134d80d9447ef9f05e02690b new file mode 100644 index 0000000..e8c21a5 Binary files /dev/null and b/test/fixtures/c3211588134d80d9447ef9f05e02690b differ diff --git a/test/fixtures/c3211588134d80d9447ef9f05e02690b.headers b/test/fixtures/c3211588134d80d9447ef9f05e02690b.headers new file mode 100644 index 0000000..89e5ae7 --- /dev/null +++ b/test/fixtures/c3211588134d80d9447ef9f05e02690b.headers @@ -0,0 +1,24 @@ +{ + "statusCode": 200, + "headers": { + "server": "nginx/1.10.1 (Ubuntu)", + "date": "Thu, 19 Oct 2017 05:19:05 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "vary": "Accept-Encoding", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://webservice.fanart.tv:80/v3/music/5b11f4ce-a62d-471e-81fc-a69a8278c7da?api_key=d9e25d5beda1027a1674c1585882309e", + "time": 342, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "webservice.fanart.tv", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/d3eb06ea06d807205b713eac5a9bd710 b/test/fixtures/d3eb06ea06d807205b713eac5a9bd710 new file mode 100644 index 0000000..3a75277 Binary files /dev/null and b/test/fixtures/d3eb06ea06d807205b713eac5a9bd710 differ diff --git a/test/fixtures/d3eb06ea06d807205b713eac5a9bd710.headers b/test/fixtures/d3eb06ea06d807205b713eac5a9bd710.headers new file mode 100644 index 0000000..c9e10d7 --- /dev/null +++ b/test/fixtures/d3eb06ea06d807205b713eac5a9bd710.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:29 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "850", + "x-ratelimit-reset": "1508394929", + "server": "Plack::Handler::Starlet", + "etag": "W/\"d9cc2d9df26f8241bbab4b28e67a09c4\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/b3682bd2-09ba-440c-80e5-1ae17038fd5f?inc=url-rels&fmt=json", + "time": 377, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/d6c3769fa2dfce68ebbdb04a2d2cd559 b/test/fixtures/d6c3769fa2dfce68ebbdb04a2d2cd559 new file mode 100644 index 0000000..a98d449 Binary files /dev/null and b/test/fixtures/d6c3769fa2dfce68ebbdb04a2d2cd559 differ diff --git a/test/fixtures/d6c3769fa2dfce68ebbdb04a2d2cd559.headers b/test/fixtures/d6c3769fa2dfce68ebbdb04a2d2cd559.headers new file mode 100644 index 0000000..f726e5d --- /dev/null +++ b/test/fixtures/d6c3769fa2dfce68ebbdb04a2d2cd559.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:34 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "940", + "x-ratelimit-reset": "1508394935", + "server": "Plack::Handler::Starlet", + "etag": "W/\"0a9dc0aa57fb827013924bd3648264db\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/9a40374c-c95b-47bc-b353-b2b9728848d3?inc=url-rels&fmt=json", + "time": 371, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/dba5a1e96a4962a5370bad858932e11d b/test/fixtures/dba5a1e96a4962a5370bad858932e11d new file mode 100644 index 0000000..8b791d1 Binary files /dev/null and b/test/fixtures/dba5a1e96a4962a5370bad858932e11d differ diff --git a/test/fixtures/dba5a1e96a4962a5370bad858932e11d.headers b/test/fixtures/dba5a1e96a4962a5370bad858932e11d.headers new file mode 100644 index 0000000..e8d0322 --- /dev/null +++ b/test/fixtures/dba5a1e96a4962a5370bad858932e11d.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:02 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1126", + "x-ratelimit-reset": "1508394903", + "server": "Plack::Handler::Starlet", + "etag": "W/\"0a16512769e1a4f191dd672e170a0316\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/e7ab62fb-f702-4a11-b96b-691cc4d82579?inc=url-rels&fmt=json", + "time": 403, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/dbf0c82ddaa7681f0642fba3fb2dd351 b/test/fixtures/dbf0c82ddaa7681f0642fba3fb2dd351 new file mode 100644 index 0000000..f64e1f8 Binary files /dev/null and b/test/fixtures/dbf0c82ddaa7681f0642fba3fb2dd351 differ diff --git a/test/fixtures/dbf0c82ddaa7681f0642fba3fb2dd351.headers b/test/fixtures/dbf0c82ddaa7681f0642fba3fb2dd351.headers new file mode 100644 index 0000000..952cc38 --- /dev/null +++ b/test/fixtures/dbf0c82ddaa7681f0642fba3fb2dd351.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:02 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1125", + "x-ratelimit-reset": "1508394903", + "server": "Plack::Handler::Starlet", + "etag": "W/\"7b5deb5c802465df6fec29fd21f1d34f\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/c9a4ea86-7611-4fff-9f4f-41f18be7e14b?inc=url-rels&fmt=json", + "time": 427, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/dce1cbd3f38b1de0b4fd7cc697131b31 b/test/fixtures/dce1cbd3f38b1de0b4fd7cc697131b31 new file mode 100644 index 0000000..f1bd79f Binary files /dev/null and b/test/fixtures/dce1cbd3f38b1de0b4fd7cc697131b31 differ diff --git a/test/fixtures/dce1cbd3f38b1de0b4fd7cc697131b31.headers b/test/fixtures/dce1cbd3f38b1de0b4fd7cc697131b31.headers new file mode 100644 index 0000000..e7cb370 --- /dev/null +++ b/test/fixtures/dce1cbd3f38b1de0b4fd7cc697131b31.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:23:00 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1030", + "x-ratelimit-reset": "1508394181", + "server": "Plack::Handler::Starlet", + "etag": "W/\"f1ac53727930376cdc4be64008d2c87d\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/instrument/857ff05c-5367-4ba2-9b49-98eefa2badcc?inc=url-rels&fmt=json", + "time": 358, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/df2dc808710d6548a883bbbf3edecb71 b/test/fixtures/df2dc808710d6548a883bbbf3edecb71 new file mode 100644 index 0000000..de26135 Binary files /dev/null and b/test/fixtures/df2dc808710d6548a883bbbf3edecb71 differ diff --git a/test/fixtures/df2dc808710d6548a883bbbf3edecb71.headers b/test/fixtures/df2dc808710d6548a883bbbf3edecb71.headers new file mode 100644 index 0000000..d1af988 --- /dev/null +++ b/test/fixtures/df2dc808710d6548a883bbbf3edecb71.headers @@ -0,0 +1,43 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 05:19:02 GMT", + "content-type": "application/json; charset=utf-8", + "content-length": "993", + "connection": "keep-alive", + "server": "mw1203.eqiad.wmnet", + "x-powered-by": "HHVM/3.18.6-dev", + "x-content-type-options": "nosniff", + "cache-control": "private, must-revalidate, max-age=0", + "p3p": "CP=\"This is not a P3P policy! See https://commons.wikimedia.org/wiki/Special:CentralAutoLogin/P3P for more info.\"", + "content-encoding": "gzip", + "x-frame-options": "DENY", + "content-disposition": "inline; filename=\"api-result.json\"", + "vary": "Accept-Encoding,Treat-as-Untrusted,X-Forwarded-Proto,Cookie,Authorization", + "backend-timing": "D=44564 t=1508390342727140", + "x-varnish": "288262213, 11547095, 566162766, 635099657", + "via": "1.1 varnish-v4, 1.1 varnish-v4, 1.1 varnish-v4, 1.1 varnish-v4", + "accept-ranges": "bytes", + "age": "0", + "x-cache": "cp1068 pass, cp2019 pass, cp4018 pass, cp4018 pass", + "x-cache-status": "pass", + "strict-transport-security": "max-age=106384710; includeSubDomains; preload", + "set-cookie": [ + "WMF-Last-Access=19-Oct-2017;Path=/;HttpOnly;secure;Expires=Mon, 20 Nov 2017 00:00:00 GMT", + "GeoIP=US:WA:Seattle:47.61:-122.30:v4; Path=/; secure; Domain=.wikimedia.org" + ], + "x-analytics": "ns=-1;special=Badtitle;https=1;nocookies=1", + "x-client-ip": "66.235.47.149" + }, + "url": "https://commons.wikimedia.org:443/w/api.php?action=query&titles=File%3ANirvana_around_1992.jpg&prop=imageinfo&iiprop=url%7Csize%7Ccanonicaltitle%7Cuser%7Cextmetadata&format=json", + "time": 344, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "commons.wikimedia.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/e122264f8b96cc604b7507bd30876d15 b/test/fixtures/e122264f8b96cc604b7507bd30876d15 new file mode 100644 index 0000000..8e41c54 Binary files /dev/null and b/test/fixtures/e122264f8b96cc604b7507bd30876d15 differ diff --git a/test/fixtures/e122264f8b96cc604b7507bd30876d15.headers b/test/fixtures/e122264f8b96cc604b7507bd30876d15.headers new file mode 100644 index 0000000..4d82e28 --- /dev/null +++ b/test/fixtures/e122264f8b96cc604b7507bd30876d15.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:23:05 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1143", + "x-ratelimit-reset": "1508394187", + "server": "Plack::Handler::Starlet", + "etag": "W/\"ea5302348b19ea23e930828d75dd6772\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/instrument/17f9f065-2312-4a24-8309-6f6dd63e2e33?inc=url-rels&fmt=json", + "time": 365, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/ea5da6f619d0bfa476d74e66f9b0bab6 b/test/fixtures/ea5da6f619d0bfa476d74e66f9b0bab6 new file mode 100644 index 0000000..e03584f --- /dev/null +++ b/test/fixtures/ea5da6f619d0bfa476d74e66f9b0bab6 @@ -0,0 +1 @@ +{"album":[{"idAlbum":"2162908","idArtist":"111492","idLabel":"43473","strAlbum":"Random Access Memories","strAlbumStripped":"Random Access Memories","strArtist":"Daft Punk","strArtistStripped":"Daft Punk","intYearReleased":"2013","strStyle":"Electronic","strGenre":"House","strLabel":"Columbia","strReleaseFormat":"Album","intSales":"0","strAlbumThumb":"http://www.theaudiodb.com/images/media/album/thumb/random-access-memories-51764651042e5.jpg","strAlbumThumbBack":null,"strAlbumCDart":"http://www.theaudiodb.com/images/media/album/cdart/random-access-memories-5194a5974107d.png","strAlbumSpine":null,"strDescriptionEN":"Random Access Memories is the upcoming fourth studio album by French electronic music duo Daft Punk. It will be released by Daft Life under exclusive license to Columbia Records on May 17, 2013 in Australia, May 20, 2013 in the United Kingdom and on May 21, 2013 in the United States. Work started on the record concurrently with the Tron: Legacy score, without a clear plan as to what its structure would be. Shortly after Daft Punk signed with Columbia, a gradual promotional rollout began for the album including billboards, television advertising and a web series.\nRandom Access Memories pays tribute to the late 1970s and early 80s era of music in the United States, particularly the sound of Los Angeles recordings of the period. Daft Punk recorded the album largely using live instrumentation with session musicians, and limited the use of electronics to drum machines, a modular synthesizer and vintage vocoders. The album also features collaborations with Panda Bear, Julian Casablancas, Todd Edwards, DJ Falcon, Chilly Gonzales, Giorgio Moroder, Nile Rodgers, Paul Williams and Pharrell Williams. Critical reception to the album has generally been positive.","strDescriptionDE":null,"strDescriptionFR":"Random Access Memories est le quatri\u00e8me album studio de Daft Punk, dont la date de sortie officielle est le 20 mai 2013. Il est publi\u00e9 par Daft Life Limited, une filiale de Columbia Records. L'album comprend des collaborations avec plusieurs artistes tels que Nile Rodgers, Paul Williams, Giorgio Moroder, Pharrell Williams, Todd Edwards, DJ Falcon, Chilly Gonzales, Panda Bear et Julian Casablancas et se caract\u00e9rise, en tant qu'hommage au son des ann\u00e9es 1970, par le parti pris d'utiliser des vrais instruments (guitare, basse, batterie, piano, cuivres etc..) en limitant l'usage des machines \u00e9lectroniques. \u00c0 sa publication, l'album rencontre un important succ\u00e8s international, d\u00e9passant d\u00e9j\u00e0 le million d'exemplaires lors de sa premi\u00e8re semaine de vente.\n\nD\u00e8s la premi\u00e8re semaine, l'album se classe premier quasiment partout dans le monde. Random Access Memories semble \u00eatre le plus grand succ\u00e8s de cette ann\u00e9e. V\u00e9ritable buzz mondial, l'album devient le plus vendu dans le monde lors de sa premi\u00e8re semaine de vente.\n\nEn France, l'album se vend lors de la premi\u00e8re semaine \u00e0 plus de 195 000 exemplaires et r\u00e9alise la plus grosse vente num\u00e9rique en une semaine (67 335 exemplaires). Il est dans le m\u00eame temps certifi\u00e9 double disque de platine en seulement sept jours.\n\nAu Royaume-Uni, l'album r\u00e9alise le meilleur d\u00e9marrage de l'ann\u00e9e dans ce pays avec 217 892 exemplaires \u00e9coul\u00e9s en une semaine.\n\nDaft Punk se hisse \u00e9galement en t\u00eate des charts am\u00e9ricains en vendant plus de 330 000 albums lors des sept premiers jours.\n\nDans Rock & Folk, Philippe Man\u0153uvre parle de \u00ab 73 minutes de folie cr\u00e9atrice \u00bb et compare Random Access Memories \u00e0 A Wizard, A True Star, album de Todd Rundgren, dont le groupe a d'ailleurs utilis\u00e9 un morceau dans le film Daft Punk's Electroma. Le journaliste \u00e9voque \u00e9galement un son \u00ab exceptionnel \u00bb et \u00ab tr\u00e8s sophistiqu\u00e9 \u00bb et ajoute que le disque est une prise de risque \u00e9norme, \u00ab pour eux comme pour leur maison de disques \u00bb. Enfin, il qualifie l'album de \u00ab vertigineux, brillant \u00bb et \u00ab exceptionnel \u00bb.\n\nLe magazine fran\u00e7ais Les Inrockuptibles, par la plume de Pierre Siankowski, parle de ce nouvel album comme \u00e9tant l\u2019un \u00ab des chefs-d\u2019\u0153uvre de cette ann\u00e9e 2013 \u00bb.\n\nQuant \u00e0 T\u00e9l\u00e9rama, il accorde \u00e0 l'album ses quatre clefs, \u00e9crivant des Daft Punk qu'\u00ab on les retrouve apais\u00e9s, presque farceurs, c\u00e9l\u00e9brant joyeusement les bacchanales des musiques populaires \u00bb.\n\nPour Lib\u00e9ration, en revanche, Random Access Memories \u00ab est un disque embarrassant de pop funk sans engagement \u00bb et \u00ab qui se contente trop souvent de faire \"\u00e0 la fa\u00e7on de\" \u00bb. Le quotidien consid\u00e8re l'album comme \u00ab pass\u00e9iste \u00bb et s'interroge : \u00ab depuis quand le pass\u00e9 est-il plus int\u00e9ressant que le pr\u00e9sent ? \u00bb. Selon le journal, seul le morceau Touch, \u00ab le Bohemian Rhapsody des Daft Punk \u00bb, m\u00e9rite une v\u00e9ritable attention puisqu'il \u00ab tire vers le haut \u00bb l'album.","strDescriptionCN":null,"strDescriptionIT":null,"strDescriptionJP":null,"strDescriptionRU":null,"strDescriptionES":"Random Access Memories es el cuarto \u00e1lbum de estudio del d\u00fao franc\u00e9s Daft Punk. Fue lanzado oficialmente el 17 de mayo en Australia, lanzado despu\u00e9s en el Reino Unido el 20 de mayo y para Estados Unidos el 21 de mayo de 2013, bajo licencia de Daft Life. El inicio de grabaci\u00f3n de este disco inici\u00f3 cuando el d\u00fao preparaba el soundtrack de la pel\u00edcula Tron: Legacy, sin un plan claro en cuanto a lo que ser\u00eda su estructura. Despu\u00e9s de haber anunciado su nuevo contrato con Columbia Records, Daft Punk empez\u00f3 a promocionar el nuevo \u00e1lbum con cart\u00e9les, anuncios televisivos y series para internet.\n\nRandom Access Memories hace un tributo a la m\u00fasica estadounidense de la \u00e9poca de los 1970s y la primera parte de los 1980s, particularmente al sonido de Los \u00c1ngeles durante esa \u00e9poca. Daft Punk grab\u00f3 el \u00e1lbum en gran parte con orquesta en vivo con sesi\u00f3nes musicales y con un uso limitado de m\u00e1quinas de percusi\u00f3n, sintetizador modular, y con una vendimia de vocoders. El \u00e1lbum contiene un gran n\u00famero de colaboradores, entre ellos se dest\u00e1can: Panda Bear, Chilly Gonzales, DJ Falcon, Julian Casablancas, Todd Edwards, Paul Williams, Pharrell Williams, Nile Rodgers y Ghallmarck. El \u00e1lbum fue recibido con cr\u00edticas positivas.\n\nDurante la primera mitad de 2013, vendi\u00f3 614 000 copias en los Estados Unidos, donde se convirti\u00f3 en el d\u00e9cimo \u00e1lbum m\u00e1s vendido durante dicho periodo.","strDescriptionPT":"Random Access Memories \u00e9 o quarto \u00e1lbum de est\u00fadio da dupla francesa de m\u00fasica eletr\u00f4nica Daft Punk. O lan\u00e7amento foi no dia 21 de maio de 2013 pelas gravadoras Sony Music Entertainment e Columbia Records. O \u00e1lbum contem colabora\u00e7\u00f5es de v\u00e1rios artistas incluindo Nile Rodgers, Paul Williams, Giorgio Moroder, Pharrell Williams, Todd Edwards, DJ Falcon, Panda Bear e Julian Casablancas. O trabalho no \u00e1lbum come\u00e7ou a ser desenvolvido no mesmo tempo em que a dupla criava a Trilha Sonora de Tron Legacy, em 2010, sem um \u00fanico plano de como seria estruturado. Pouco depois que Daft Punk assinou contrato com a gravadora Columbia Records, come\u00e7ou um gradual lan\u00e7amento promocionais do novo \u00e1lbum, incluindo outdoors, comerciais de televis\u00e3o e at\u00e9 s\u00e9ries de internet, como a The Collaborators. A recep\u00e7\u00e3o cr\u00edtica at\u00e9 agora foi geralmente positiva.\n\nDaft Punk fez este \u00e1lbum com a colabora\u00e7\u00e3o do escritor e cantor Paul Williams e com o guitarrista da banda Chic, o aclamado produtor Nile Rodgers. Williams mencionou essa colabora\u00e7\u00e3o em duas entrevistas, que o projeto estaria em produ\u00e7\u00e3o desde 2010. Durante uma entrevista com Rodgers, ele disse que se encontraria com a dupla para discutir o pr\u00f3ximo \u00e1lbum.","strDescriptionSE":null,"strDescriptionNL":null,"strDescriptionHU":null,"strDescriptionNO":null,"strDescriptionIL":null,"strDescriptionPL":null,"intLoved":"2","intScore":"8.7","intScoreVotes":"6","strReview":"","strMood":"Happy","strTheme":null,"strSpeed":"Medium","strLocation":null,"strMusicBrainzID":"aa997ea0-2936-40bd-884d-3af8a0e064dc","strMusicBrainzArtistID":"056e4f3e-d505-4dad-8ec1-d04f521cbb56","strItunesID":null,"strAmazonID":null,"strLocked":"unlocked"}]} \ No newline at end of file diff --git a/test/fixtures/ea5da6f619d0bfa476d74e66f9b0bab6.headers b/test/fixtures/ea5da6f619d0bfa476d74e66f9b0bab6.headers new file mode 100644 index 0000000..f9a88e6 --- /dev/null +++ b/test/fixtures/ea5da6f619d0bfa476d74e66f9b0bab6.headers @@ -0,0 +1,21 @@ +{ + "statusCode": 200, + "headers": { + "content-type": "application/json", + "server": "Microsoft-IIS/7.0", + "x-powered-by": "PHP/5.6.0, ASP.NET", + "date": "Thu, 19 Oct 2017 06:13:14 GMT", + "content-length": "8682" + }, + "url": "http://www.theaudiodb.com:80/api/v1/json/1/album-mb.php?i=aa997ea0-2936-40bd-884d-3af8a0e064dc", + "time": 596, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "www.theaudiodb.com", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/ea7434f5608f1a1ac1e0d509a624f2db b/test/fixtures/ea7434f5608f1a1ac1e0d509a624f2db new file mode 100644 index 0000000..3bdcd2c Binary files /dev/null and b/test/fixtures/ea7434f5608f1a1ac1e0d509a624f2db differ diff --git a/test/fixtures/ea7434f5608f1a1ac1e0d509a624f2db.headers b/test/fixtures/ea7434f5608f1a1ac1e0d509a624f2db.headers new file mode 100644 index 0000000..79207c9 --- /dev/null +++ b/test/fixtures/ea7434f5608f1a1ac1e0d509a624f2db.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:40 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1066", + "x-ratelimit-reset": "1508394941", + "server": "Plack::Handler::Starlet", + "etag": "W/\"af24e70973baa0dfcbe4dd20af338460\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/88651d67-c6c9-4f45-a87d-cdec93fc6aeb?inc=url-rels&fmt=json", + "time": 369, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/ec5161eb0cf63cbaa64db8cf2e7727fc b/test/fixtures/ec5161eb0cf63cbaa64db8cf2e7727fc new file mode 100644 index 0000000..a06e047 Binary files /dev/null and b/test/fixtures/ec5161eb0cf63cbaa64db8cf2e7727fc differ diff --git a/test/fixtures/ec5161eb0cf63cbaa64db8cf2e7727fc.headers b/test/fixtures/ec5161eb0cf63cbaa64db8cf2e7727fc.headers new file mode 100644 index 0000000..f617327 --- /dev/null +++ b/test/fixtures/ec5161eb0cf63cbaa64db8cf2e7727fc.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:24 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1134", + "x-ratelimit-reset": "1508394925", + "server": "Plack::Handler::Starlet", + "etag": "W/\"d8c6216ea85c51e7d02abcec8c148e5e\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/a6251e5b-67f7-40c2-9484-5e890bf277d6?inc=url-rels&fmt=json", + "time": 458, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/ecefe1f444a1e1e90f3158416eb2da95 b/test/fixtures/ecefe1f444a1e1e90f3158416eb2da95 new file mode 100644 index 0000000..b4f6550 Binary files /dev/null and b/test/fixtures/ecefe1f444a1e1e90f3158416eb2da95 differ diff --git a/test/fixtures/ecefe1f444a1e1e90f3158416eb2da95.headers b/test/fixtures/ecefe1f444a1e1e90f3158416eb2da95.headers new file mode 100644 index 0000000..1b80f19 --- /dev/null +++ b/test/fixtures/ecefe1f444a1e1e90f3158416eb2da95.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:23 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1130", + "x-ratelimit-reset": "1508394925", + "server": "Plack::Handler::Starlet", + "etag": "W/\"2fb9470ccadb03ca885ad143c7bd6afb\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/ae5ad711-8232-4c3d-84d0-ca76116c095b?inc=url-rels&fmt=json", + "time": 378, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/f71ea9601bb094d68114cdfa9da584ac b/test/fixtures/f71ea9601bb094d68114cdfa9da584ac new file mode 100644 index 0000000..1006f89 Binary files /dev/null and b/test/fixtures/f71ea9601bb094d68114cdfa9da584ac differ diff --git a/test/fixtures/f71ea9601bb094d68114cdfa9da584ac.headers b/test/fixtures/f71ea9601bb094d68114cdfa9da584ac.headers new file mode 100644 index 0000000..4b825df --- /dev/null +++ b/test/fixtures/f71ea9601bb094d68114cdfa9da584ac.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:02 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1128", + "x-ratelimit-reset": "1508394903", + "server": "Plack::Handler::Starlet", + "etag": "W/\"5f37b2c85f2ad9f57d9d88b0ed68ebb1\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/93abac35-42d9-4c55-a9f4-3aae018eb899?inc=url-rels&fmt=json", + "time": 417, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/f9ccd6365663fd88cef3a99afb0db0de b/test/fixtures/f9ccd6365663fd88cef3a99afb0db0de new file mode 100644 index 0000000..b93e9df Binary files /dev/null and b/test/fixtures/f9ccd6365663fd88cef3a99afb0db0de differ diff --git a/test/fixtures/f9ccd6365663fd88cef3a99afb0db0de.headers b/test/fixtures/f9ccd6365663fd88cef3a99afb0db0de.headers new file mode 100644 index 0000000..b0e1b3e --- /dev/null +++ b/test/fixtures/f9ccd6365663fd88cef3a99afb0db0de.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:35:45 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "1148", + "x-ratelimit-reset": "1508394947", + "server": "Plack::Handler::Starlet", + "etag": "W/\"bf782afe1a74abfbf223b477aad1d0e1\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/label/20a21219-341a-4df1-a25e-70ed1d7e3aeb?inc=url-rels&fmt=json", + "time": 372, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/faae9e2018b271b5f0908a41d07847ad b/test/fixtures/faae9e2018b271b5f0908a41d07847ad new file mode 100644 index 0000000..68bed54 --- /dev/null +++ b/test/fixtures/faae9e2018b271b5f0908a41d07847ad @@ -0,0 +1 @@ +{"artists":[{"idArtist":"111319","strArtist":"Nirvana","strArtistStripped":null,"strArtistAlternate":"","strLabel":null,"idLabel":null,"intFormedYear":"1988","intBornYear":null,"intDiedYear":"1994","strDisbanded":"Yes","strStyle":"Rock/Pop","strGenre":"Rock","strMood":"Sad","strWebsite":"www.nirvana.com","strFacebook":"www.facebook.com/Nirvana","strTwitter":"twitter.com/Nirvana","strBiographyEN":"Nirvana was an American rock band that was formed by singer and guitarist Kurt Cobain and bassist Krist Novoselic in Aberdeen, Washington, in 1987. Nirvana went through a succession of drummers, the longest-lasting being Dave Grohl, who joined the band in 1990. Despite releasing only three full-length studio albums in their seven-year career, Nirvana has come to be regarded as one of the most influential and important rock bands of the modern era.\nIn the late 1980s Nirvana established itself as part of the Seattle grunge scene, releasing its first album Bleach for the independent record label Sub Pop in 1989. The band eventually came to develop a sound that relied on dynamic contrasts, often between quiet verses and loud, heavy choruses. After signing to major label DGC Records, Nirvana found unexpected success with \"Smells Like Teen Spirit\", the first single from the band's second album Nevermind (1991). Nirvana's sudden success widely popularized alternative rock as a whole, and the band's frontman Cobain found himself referred to in the media as the \"spokesman of a generation\", with Nirvana being considered the \"flagship band\" of Generation X. In response, Nirvana's third studio album, In Utero (1993), featured an abrasive, less-mainstream sound and challenged the group's audience. The album did not match the sales figures of Nevermind, but was still a commercial success and critically acclaimed.\nNirvana's brief run ended following the death of Kurt Cobain in 1994, but various posthumous releases have been issued since, overseen by Novoselic, Grohl, and Cobain's widow Courtney Love. Since its debut, the band has sold over 25 million records in the United States alone, and over 75 million records worldwide, making them one of the best-selling bands of all time. Nirvana was inducted into the Rock and Roll Hall of Fame in 2014, in its first year of eligibility.","strBiographyDE":"Der Verantwortliche, der 1992 bei MTV den Song \"Smells Like Teen Spirit\" auf Heavy Rotation setzt, ist sich wohl kaum bewusst, dass er damit den Schalter f\u00fcr ein neues Zeitalter des Alternative-Rocks umlegen w\u00fcrde. Was immer ihn dazu getrieben hat, auf dieses aus dem \u00fcblichen Musikvideo-Rahmen fallende Pferd zu setzen, es war ein beispielloser kommerzieller Gl\u00fccksgriff.\n\nMit einem langweiligen Sporthallen-Video, in dem meist ein zerzauster Typ seine schulterlangen, blonden Haare in die Kamera wuschelt und lustlos einen einfachen Vier-Akkord-Riff-Song hinschmettert, treffen ein paar ahnungslose Gammler aus Seattle den Nerv der Zeit und werden bald zum Sprachrohr einer ganzen Generation.\n\nOb das so gewollt war, ist strittig. Gitarrist, S\u00e4nger und Songwriter Kurt Cobain hat es sich wohl nicht zum Ziel gesetzt, f\u00fcr Millionen von Teenager in ihrer Depri-und-nicht-verstanden-Phase als Role-Model herzuhalten. Andererseits k\u00e4mpft er seit seinen Anfangstagen als Musiker verbissen, h\u00f6llisch selbstbewusst (\"Ich wusste immer dass ich etwas besonderes mache.\") und ohne R\u00fccksicht auf Verluste f\u00fcr ein Leben in Ruhm, Ehre und jeder Menge Rock'n'Roll.\nIn seinen High School-Tagen \u00e4ndern sich seine Vorlieben von Heavy Metal zun\u00e4chst \nhin zu amerikanischem Hardcore. Black Flag z\u00e4hlen sp\u00e4ter neben den Pixies zu seinen absoluten Lieblings-Bands.\n\n\u00dcber seine Kiffer- und Abh\u00e4ng-Kumpels lernt Cobain die Heavy Punks der Melvins aus dem nahe liegenden Ort Olympia kennen. Sie sind cool, rauchen eine Menge Joints und haben nichts mit den Leuten aus der Football-Mannschaft zu tun, von denen sich Kurt nach und nach abgrenzt. Cobain himmelt die Melvins an und wird durch sie endg\u00fcltig vom Punkrock angefixt.\n\nNebenbei spielt er bereits in einigen Punk-Bands, darunter bei Fecal Matter, bei denen Melvins-Drummer Dale Crover Bass zupft. Durch Melvins-Kopf King Buzzo kommt Kurt 1985 in Kontakt mit dem Bassisten Krist Novoselic, der zwar in relativ beh\u00fcteten Verh\u00e4ltnissen aufgewachsen ist, aber in Sachen Punk-Rock-Interesse und High-School-Desinteresse mit Cobain auf einer Wellenl\u00e4nge liegt.\n\nSie schlie\u00dfen sich zusammen und durchlaufen dabei eine Vielzahl von Formationen und Bands, bis sie als Skid Row in der Besetzung Kurt (Gitarre, Gesang), Krist (Bass) und Aaron Burckhard (Drums) musizieren. Bei ihren ersten Auftritten spielt die Band bereits erste Versionen von Songs wie \"Spank Thru\", \"Beeswax\" oder \"Floyd The Barber\", die sich sp\u00e4ter auf dem Nirvana-Deb\u00fct \"Bleach\" wiederfinden.\n\nDie Formation bleibt, gem\u00e4\u00df ihrem Lifestyle von Drogen und Abgesifftheit (Kurt lebt einige Zeit sogar unter einer Br\u00fccke in Aberdeen und ern\u00e4hrt sich haupts\u00e4chlich von Fisch, Bier und S\u00fc\u00dfigkeiten), nicht lange zusammen. F\u00fcr Burckhard ist Nirvana, wie sich Skid Row mittlerweile nennen, ein Spa\u00df.\n\nF\u00fcr Krist und Kurt ist die Band hingegen alles andere als nur ein Zeitvertreib. \"Sie wollten jeden Tag proben. Das war ein bisschen viel\", res\u00fcmiert Burckhard sein Engagement. Er verl\u00e4sst Nirvana, Kurt und Krist stehen ohne Drummer da. Ein Zustand, an den sie sich gew\u00f6hnen.\n\nKurt zieht nach Olympia, und Nirvana nehmen 1988 mit ihrem alten Kumpel Dale Crover am Schlagzeug ihr erstes Demo auf. Produziert wird es vom Seattler Hausproduzenten Jack Endino, der damals praktisch alles unter seine Fittiche nimmt, was auf den Seattle-Label Sub Pop erscheint. Bruce Pavitt und Jonathan Poemann, die Sub Pop-Gr\u00fcnder, werden auf Nirvana aufmerksam und verschaffen ihnen einige Gigs.\n\nNachdem Dale Crover mit King Buzzo nach San Francisco zieht, stehen sie wieder einmal ohne Schlagzeuger da. Auf Crovers Tipp wird Dave Foster eingestellt, ein Redneck mit Schnauzbart aus Aberdeen. Von Anfang ist aber klar, dass sein Einsatz nur von kurzer Dauer sein wird. Foster ist zu sehr Macho, zu sehr Proll, als dass er sich mit dem Punkrock-Style von Krist und Kurt, die zeitweise auch zu dritt mit Novoselic' Freundin Shelli in einem Haus wohnen, anfreunden k\u00f6nnte.\n\nAls Foster einen Nebenbuhler krankenhausreif schl\u00e4gt und f\u00fcr ein Jahr ins Gef\u00e4ngnis wandert, kommt aushilfsweise Aaron Burckhard wieder kurz ins Boot. Chad Channig, der dann f\u00fcr l\u00e4ngere Zeit fester Nirvana-Drummer ist, ersetzt ihn. Zwei Monate nach Channings Einstieg nehmen Nirvana ihrer erste Single f\u00fcr Sub Pop auf.\n\n\"Love Buzz\", eine Coverversion von Shocking Blue auf der A-Seite und der eigene Song \"Big Cheese\" auf der B-Seite. Die 7\" erscheint nur in einer kleinen Auflage von tausend Exemplaren \u00fcber den legend\u00e4ren Sub Pop-Singles-Club.\n\nF\u00fcr l\u00e4cherliche sechshundert Dollar spielen Nirvana 1989 ihr Deb\u00fct-Album \"Bleach\" ein. Jason Evermann wird auf der R\u00fcckseite des Booklets zwar als zweiter Gitarrist genannt, in Wirklichkeit ist auf \"Bleach\" aber kein einziger Ton von ihm zu h\u00f6ren. Er war nur bei einigen Live-Shows vierter Mann, bevor er Nirvana Ende 1989 verl\u00e4sst, um bei Soundgarden einzusteigen, die neben Mudhoney als eine von wenigen Bands aus Seattle zu dieser Zeit schon \u00fcberregionalen Erfolg haben.\n\nObwohl alles andere als leicht verdaulich, belegt \"Bleach\" gute Platzierungen in den College-Radio-Charts und mausert sich zum Liebling der amerikanischen Indie-Szene. Kurts Songwriter-Qualit\u00e4ten sind auf dem Deb\u00fct noch lange nicht auf ihrem H\u00f6hepunkt angelangt, lassen aber das Potenztial, das in ihm steckt, erahnen. Songs wie \"About A Girl\" gehen schon deutlich in eine Richtung, die Nirvana zwei Jahre sp\u00e4ter weltweit bekannt macht. Noch sind sie in den Staaten aber nicht viel mehr als eine Underground-Tipp.\n\nDie englische Presse ist da nat\u00fcrlich schon etwas weiter. Angefixt durch andere Seattle-Bands haben die Insulaner Grunge schon l\u00e4ngst als das n\u00e4chste gro\u00dfe Ding ausgemacht. Durch den gro\u00dfen Support von Indie-Stars wie Sonic Youth und Dinosaur Jr. werden Nirvana in England schnell zu viel versprechenden Newcomern. Sp\u00e4testens als Cobain & Co. mit Tad auf England-Tour gehen, sind Holzf\u00e4ller-Hemden in aller Munde.\n\nNirvana nehmen mit Butch Vig, dem Starproduzenten und sp\u00e4teren Garbage-Drummer, ein Demo auf, mit dem sie sich bei verschiedenen Major-Labels bewerben wollen, die sich jedoch schon heftig um die Band rei\u00dfen. Im Mai 1990 verl\u00e4sst Chad Channings die Band. Kurt und Krist sind schon lange mit seinem Spiel unzufrieden, da sie es f\u00fcr zu undynamisch halten. Mit Dan Peters von Mudhoney finden sie kurzfristig und f\u00fcr eine Single (\"Sliver/Dive\") Ersatz.\n\nKing Buzzo spielt dann erneut Schicksal f\u00fcr Nirvana. Er gibt dem jungen Drummer Dave Grohl, der damals in der Hardcore-Band Scream spielt, die Telefonnummer von Novoselic. Grohl ruft tats\u00e4chlich an, obwohl er von Nirvana nicht wirklich begeistert ist. \"Sie rissen mich nicht gerade vom Hocker.\"\n\nAls er die Zusage von Kurt und Chris hat, steigt er dennoch mitsamt Drumkit und ein paar Klamotten ins Flugzeug und fliegt nach Seattle. Bei der ersten gemeinsamen Probe l\u00e4uft alles glatt. \"Nach zwei Minuten wussten wir, dass er der richtige Schlagzeuger war\", erz\u00e4hlt Novoselic sp\u00e4ter \u00fcber Grohls Drumming, das endlich die gew\u00fcnschte H\u00e4rte hat. Grohl zieht zusammen mit Cobain in ein Haus, bald darauf spielen Nirvana ihre erste Show mit dem neuen Schlagzeuger aus Washington \u2013 nach nur einem Tag ist das Konzert ausverkauft.\n\n\u00dcber Sonic Youth stellen Nirvana Kontakt zu Geffen Records her, bei denen sie im April 1991 einen Deal unterschreiben. Zusammen mit Butch Vig nimmt die Band in Los Angeles ihr zweites Album \"Nevermind\" auf, das nach einer Europa-Tournee mit Sonic Youth im September 1991 erscheint. Als eine der letzten Bands aus Seattle, die mit einem Major-Album auf den Markt kommt, sind die Erwartungen auf Seiten der Plattenfirma aber eher mittelm\u00e4\u00dfig.\n\n\"Nevermind\" steigt auf Platz 144 der amerikanischen Charts ein und wird bereits im Oktober vergoldet. Das Video zur ersten Single \"Smells Like Teen Spirit\" (ein Satz den Bikini Kill-S\u00e4ngerin Kathleen Hanna an Cobains Wand spr\u00fcht und damit Kurts K\u00f6rperd\u00fcfte mit dem eines Deodorants vergleicht) l\u00e4uft auf den Clip-Kan\u00e4len rauf und runter und hilft kr\u00e4ftig mit, dass sich das Album nach einer kurzen Tour mit den Red Hot Chili Peppers und Pearl Jam pro Woche unglaubliche 300.000 mal verkauft.\n\nDie Platte ist um einiges h\u00e4rter als alles, was sich damals auf dem Mainstream-Markt tummelt. Sie bringt die Verschmelzung von Punk und Metal, Grunge, den Massen n\u00e4her und schubst sogar Michael Jackson mit \"Dangerous\" von ersten Platz der Album-Charts. F\u00fchrt Alternative Rock davor noch ein Leben in der Nische, haben die Medien danach mit Nirvana und vor allem mit Cobain ihren ersten abgewrackten Rockstar, der sich herrlich medial ausschlachten l\u00e4sst.\n\nZu Beginn spielen Nirvana das Spiel der Stars kr\u00e4ftig mit und provozieren, wo sie nur k\u00f6nnen. Legend\u00e4r sind ihre effektiv in Szene gesetzten, selbstzerst\u00f6rerischen Auftritte, bei denen meist nicht mal ein Becken stehen bleibt. Nirvana p\u00f6beln in TV-Shows und bieten der Welt das Bild, das man von ihnen verlangt.\n\nIhrer Anh\u00e4ngerschaft geben sie ein Gef\u00fchl der Identifikation und der Revolte. Cobain macht jedoch nicht auf Verst\u00e4ndnis f\u00fcr die gelangweilte Jugend. Er lebt eher genau das aus, was sich viele w\u00fcnschen: die komplette Verneinung: \"Here we are now, entertain us.\"\n\nAls Cobain dann auch noch mit der Hole-Frontfrau Courntey Love anbandelt, hat die Presse ihr Vorzeige-Paar. Im Februar 1992 heiraten Cobain und Love auf Hawaii. Love ist bereits hochschwanger und bringt am 18. August 1992 die gemeinsame Tochter Frances Bean auf die Welt.\n\nZwei Wochen sp\u00e4ter berichtet das Boulevard-Magazin Vanity Fair, Love habe w\u00e4hrend ihrer Schwangerschaft Heroin genommen. Daraufhin wird den Eltern das Sorgerecht f\u00fcr einen Monat entzogen und erst nach einem heftigen Rechtsstreit wieder zur\u00fcck gegeben.\n\nCobain zieht sich immer mehr zur\u00fcck und flieht in Alkohol und Drogen. Er nimmt t\u00e4glich Heroin f\u00fcr vierhundert Dollar, da der Bankautomat nicht mehr an einem Tag ausgibt. Weil Cobain vollkommen unf\u00e4hig ist, einen Nachfolger f\u00fcr \"Nevermind\" aufzunehmen, ver\u00f6ffentlicht Geffen im Dezember 1992 die B-Seiten und Rarit\u00e4ten-Sammlung \"Incesticide\", um Nirvana im Gespr\u00e4ch zu halten. Es wird auf Wunsch der Band nicht promotet, erreicht aber trotzdem Platz 39 der amerikanischen Charts.\n\nBei ihrem n\u00e4chsten Longplayer entscheiden sich Nirvana f\u00fcr Steve Albini als Produzenten. Albini hat sich bereits mit Platten der Breeders oder den Pixies einen guten Namen gemacht. Im Februar 1993 nehmen Nirvana in Minnesota ihr drittes Album auf. Eigentlich ist geplant, ihm den Titel \"I Hate Myself And I Want To Die\" zu geben. Das empfindet die Plattenfirma aber als zu hart und lehnt es ab. Schlie\u00dflich tauft man es auf \"In Utero\".\n\nAlbinis grober Sound st\u00f6\u00dft bei Geffen ebenfalls auf Ablehnung. Nach dem utopischen Verkaufszahlen des Vorg\u00e4ngers ist der Druck gro\u00df, das Album wird von R.E.M.-Produzent Scott Litt noch mal gemixt, da Geffen die urspr\u00fcnglichen Aufnahmen unter kommerziellen Gesichtspunkten f\u00fcr untragbar h\u00e4lt. Ab den Sessions mit Albini bis zum endg\u00fcltigen Release am 21.September 1993 zieht sich der Streit zwischen Band und Firma auf knapp sechs Monate.\n\n\"In Utero\" entwickelt sich zum Schlag ins Gesicht von MTV und Radiostationen. Bis auf wenige Songs wie \"All Apologies\" oder \"Pennyroyal Tea\" ist es ein verzerrter Wutausbruch, mit dem Cobain dem Pop-Appeal den Riegel vorschiebt. Einen \"Smells Like Teen Spirit\"-Nachfolger sucht man vergebens, trotzdem schie\u00dft die Platte von 0 auf 1 in die Charts.\n\nBei der folgenden Tournee lassen sich Nirvana durch die L.A.-Punk-Legende Pat Smear (The Germs, sp\u00e4ter f\u00fcr eine Platte auch bei den Foo Fighters) an der zweiten Gitarre unterst\u00fctzen. Die Tour l\u00e4uft relativ erfolgreich, auch wenn einige Shows nicht ausverkauft sind.\n\nAm 18. November 1993 spielen Nirvana ein MTV Unplugged-Konzert, das ein Jahr sp\u00e4ter als CD ver\u00f6ffentlicht wird. Es zeigt Nirvana von einer unbekannten Seite mit einem ungew\u00f6hnlichen Fokus auf Perfektion.\n\nAm 1.M\u00e4rz 1994 spielen Nirvana ihr letztes Konzert im M\u00fcnchner Terminal Eins. Danach verbringt Cobain mit Courtney Love einige Tage in Rom, wo er wieder einen Zusammenbruch erleidet. Die Mixtur aus Champagner und dem valium\u00e4hnlichen Rohypnol wird an die Medien als \u00dcberdosis verkauft, ist in Wirklichkeit aber bereits ein geheim gehaltener Selbstmordversuch.\n\nZur\u00fcck in Seattle verbessert sich Kurts Gem\u00fctslage nicht. Am 18. M\u00e4rz muss Courtney Love die Polizei in ihr Haus rufen, da Cobain sich im Badezimmer eingeschlossen hat und damit droht, sich umzubringen.\n\nDer Nirvana-S\u00e4nger begibt sich in das Exodus Recovery Center in Marina del Ray bei Los Angeles, um seinen Drogenkonsum und die Psyche in den Griff zu bekommen. Bereits nach zwei Tagen flieht er aus der Anstalt und geht zur\u00fcck nach Seattle. Dort angekommen, verbarrikadiert er sich am 5. April 1994 in einem Raum \u00fcber seiner Garage und schie\u00dft sich eine Dosis Heroin in den Arm, nach der ein normaler Mensch bereits klinisch tot sein m\u00fcsste.\n\nMit einer Schrotflinte, die er im M\u00e4rz zusammen mit seinem Freund Dylan Carlson gekauft hatte, um sich gegen Einbrecher zu sch\u00fctzen, schie\u00dft er sich danach in den Mund. Erst drei Tage sp\u00e4ter wird seine Leiche von einem Elektriker gefunden. Allen Spekulationen um den Tod Cobains zum Trotz wird als Todesursache offiziell Selbstmord angegeben.\n\nAm Abend des 10. April versammeln sich Tausende Jugendliche in der Innenstadt von Seattle, um Abschied zu nehmen. Courtney Love liest dabei den von ihrem Ehemann zur\u00fcck gelassenen Abschiedsbrief vor. Sp\u00e4ter wird er sogar auf T-Shirts und Poster abgedruckt. Kurt Cobains Leichnam wird einge\u00e4schert, die Garage, in der er sich das Leben nahm, zwei Jahre sp\u00e4ter abgerissen, um den Ort nicht zu einem Pilgerort verkommen zu lassen.\n\nNach Cobains Tod wird neben dem Unplugged-Album auch das Live Video \"Live! Tonight! Sold Out!\" ver\u00f6ffentlicht. Als 1996 das Live-Album \"From The Muddy Banks Of The Whiskah\" erscheint, sind die verbleibenden Nirvana-Mitglieder bereits anderweitig besch\u00e4ftigt. Dave Grohl wechselt bei seiner eigenen Band den Foo Fighters \u00e4u\u00dferst erfolgreich von den Drums an die Gitarre und den Gesang, w\u00e4hrend Krist Novoselic mit Sweet 75, von der Au\u00dfenwelt kaum beachtet, weiter musiziert.\n\n1997 gr\u00fcnden Grohl und Novoselic zusammen mit Courtney Love ein Nirvana Partnership, um den Nachlass der Band zu verwalten. Die traute Dreisamkeit entwickelt sich allerdings zum Desaster und resultiert in einem endlosen Rechtsstreit zwischen den Parteien Grohl/Novoselic und Love, die darauf pocht, die Songs ihres Ehemannes allein zu verwalten. Erst 2002 erscheint das Best Of-Album und nicht wie eigentlich geplant eine weitere Rarit\u00e4ten-Box. Es enth\u00e4lt mit \"You Know You're Right\" einen einzigen neuen Song, den Novoselic nach der letzten Nirvana Studiosession in seinem Keller bunkert.\n\nLove ist das nicht genug. Sie ver\u00f6ffentlicht kurz vor Weihnachten 2002 die Tageb\u00fccher ihres Mannes. Tageb\u00fccher ist jedoch eine falsche Beschreibung, es handelt sich aber eher um eine Ansammlung von Notizzetteln, Songtext-Fragmenten oder wirren Kritzeleien.\n\nKrist Novoselic gibt 2003 seinen R\u00fcckzug von der Musik bekannt, nachdem sein Comeback-Versuch mit seiner neuen Band Eyes Adrift (zusammen mit dem Ex-Sublime-Drummer Bug Gaugh und Ex-Meat Puppets Curt Kirkwood) missgl\u00fcckt. Er will sich nun der Politik widmen.\n\nDave Grohl ist dagegen Rockstar geblieben. Neben seiner Hauptbet\u00e4tigung bei den Foo Fighters klopft er noch hier und da auf die Becken. Seine ber\u00fchmtesten Zwischeneinlagen sind die bei den Queens Of The Stone Age, Killing Joke, Nine Inch Nails und Them Crooked Vultures.","strBiographyFR":"Nirvana est un groupe de rock am\u00e9ricain form\u00e9 en 1987 \u00e0 Aberdeen (\u00c9tat de Washington) par le chanteur-guitariste Kurt Cobain et le bassiste Krist Novoselic. Le groupe a connu une succession de batteurs, le dernier et plus important d'entre eux ayant \u00e9t\u00e9 Dave Grohl, qui a rejoint le groupe en 1990.\n\nAvec le single Smells Like Teen Spirit tir\u00e9 de son second album, Nevermind en 1991, Nirvana devint mondialement populaire et mit en lumi\u00e8re un sous-genre du rock alternatif appel\u00e9 le grunge, compos\u00e9 de nombreux groupes de Seattle tels Alice in Chains, Pearl Jam et Soundgarden. Leur succ\u00e8s en fit le genre musical dominant sur les radios et cha\u00eenes de t\u00e9l\u00e9vision musicales aux \u00c9tats-Unis durant la premi\u00e8re moiti\u00e9 des ann\u00e9es 1990. Kurt Cobain fut alors consid\u00e9r\u00e9 comme le \u00ab porte-parole de toute une g\u00e9n\u00e9ration \u00bb et Nirvana comme le groupe embl\u00e9matique de la \u00ab G\u00e9n\u00e9ration X \u00bb. Cobain n'\u00e9tait pas \u00e0 l'aise avec toute cette attention et pr\u00e9f\u00e9ra se concentrer sur la musique du groupe, pensant que sa vision artistique avait \u00e9t\u00e9 mal interpr\u00e9t\u00e9e par le public. Il d\u00e9fia alors l'audience du groupe avec son troisi\u00e8me album studio \u00e0 tendance plus \"underground\" : In Utero (1993).\n\nLa courte existence de Nirvana prit fin avec la mort de Kurt Cobain en avril 1994 mais la popularit\u00e9 du groupe perdura dans les ann\u00e9es qui suivirent. En 2002, You Know You're Right, une d\u00e9mo inachev\u00e9e du groupe datant de la derni\u00e8re session d'enregistrement, se pla\u00e7a en t\u00eate des listes d'\u00e9coute des radios partout dans le monde. Depuis ses d\u00e9buts, le groupe a vendu plus de 50 millions de disques \u00e0 travers le monde, dont 25 millions aux seuls \u00c9tats-Unis. Nirvana est souvent consid\u00e9r\u00e9 comme l'un des groupes les plus populaires et les plus importants de ces 20 derni\u00e8res ann\u00e9es.","strBiographyCN":"\u6d85\u69c3\u4e50\u961f\uff08Nirvana\uff09\u662f\u4e00\u652f\u7f8e\u56fd\u7684\u6416\u6efe\u4e50\u961f\uff0c\u4e8e1987\u5e74\u5728\u534e\u76db\u987f\u5dde\u7684\u963f\u4f2f\u4e01\u7ec4\u5efa\u3002\u901a\u8fc7\u4ed6\u4eec\u4e13\u8f91Nevermind\u88e1\u7684Lithium\u548cSmells Like Teen Spirit\u4e24\u9996\u4f5c\u54c1\u6253\u5165\u7f8e\u56fd\u4e3b\u6d41\u97f3\u4e50\u3002\u7531\u4e8e\u5f53\u65f6\u4e3b\u6d41\u5a92\u4f53\u7684\u4e0d\u53cb\u597d\uff0c\u4ed6\u4eec\u6240\u5904\u7684\u97f3\u4e50\u6d41\u6d3e\u88ab\u79f0\u4e3a\u5783\u573e\u6447\u6eda\uff08Grunge\uff0c\u539f\u672c\u662f\u7f8e\u56fd\u4fda\u8bed\uff0c\u6709\u4e4f\u5473\u3001\u4e11\u964b\u548c\u810f\u4e71\u7b49\u8bbd\u523a\u610f\u5473\uff0c\u4e8b\u5b9e\u4e0a\u6d85\u69c3\u7684\u97f3\u4e50\u98ce\u683c\u662f\u7531\u670b\u514b\u548c\u53e6\u7c7b\u6447\u6eda\u53d1\u5c55\u51fa\u6765\u7684\u4e00\u4e2a\u5206\u652f\uff09\u3002\u4e0e\u4ed6\u4eec\u5728\u897f\u96c5\u56fe\u7684\u540c\u7c7b\u7231\u4e3d\u4e1d\u56da\u5f92 (Alice in Chains)\uff0c\u73cd\u73e0\u679c\u91ac\uff08Pearl Jam\uff09\u548c\u97f3\u5712\uff08Soundgarden\uff09\u4e00\u8d77\uff0c\u6d85\u69c3\u4e50\u961f\u628a\u5927\u4f17\u7684\u7126\u70b9\u805a\u96c6\u5230Grunge\u97f3\u4e50\u4e0a\u6765\uff0c\u4f7fGrunge\u97f3\u4e50\u572820\u4e16\u7eaa90\u5e74\u4ee3\u4e2d\u524d\u671f\u5728\u5e7f\u64ad\u548c\u97f3\u4e50\u7535\u89c6\u7684\u64ad\u653e\u7387\u4e0a\u5360\u636e\u4e86\u7edf\u6cbb\u6027\u7684\u5730\u4f4d\u3002 \u79d1\u7279\u00b7\u67ef\u672c\uff08Kurt Cobain\uff09\u8207Krist Novoselic\u76f8\u8b58\u65bc1985\u5e74\uff0c\u7576\u6642\u4ed6\u5011\u540c\u6a23\u662f\u4e00\u500b\u540d\u53ebThe Melvins\u7684Grunge\u6a02\u5718\u6b4c\u8ff7\uff0c\u4e26\u7d93\u5e38\u5728\u6a02\u5718\u7684\u6392\u7df4\u7a7a\u9593\u9644\u8fd1\u5f98\u5f8a\u3002\u5169\u500b\u4eba\u89ba\u5f97\u53ef\u4ee5\u958b\u59cb\u7d44\u81ea\u5df1\u7684\u6a02\u5718\uff0c\u65bc\u662f\u62db\u52df\u4e86\u9f13\u624bAaron Burckhard\uff0c\u5275\u9020\u4e86\u7b2c\u4e00\u500bNirvana\u7684\u5178\u578b\u3002\u525b\u958b\u59cb\u7684\u5e7e\u500b\u6708\uff0c\u5169\u500b\u4eba\u8207\u8a31\u591a\u7684\u9f13\u624b\u5171\u4e8b\uff0c\u5305\u62ecThe Melvins\u7684\u9f13\u624bDale Crover\uff0c\u7b2c\u4e00\u500bDemo\u88e1\u9762\u5373\u662f\u4ed6\u5728\u6253\u9f13\u3002\u540c\u6642\uff0c\u6a02\u5718\u4e5f\u7528\u904e\u4e00\u7cfb\u5217\u7684\u540d\u5b57\uff0c\u76f4\u5230\u4ed6\u5011\u57281988\u5e742\u6708\u5b9a\u4e0b\u4f86Nirvana\u9019\u500b\u540d\u5b57\u4e4b\u524d\uff0c\u4ed6\u5011\u7528\u904eSkid Row\u3001Pen Cap Chew\uff0c\u548cTed Ed Fred\u7b49\u4f5c\u70ba\u5718\u540d\u3002\u5169\u500b\u6708\u5f8c\uff0c\u6a02\u5718\u4e5f\u78ba\u5b9a\u4e86\u9f13\u624b\u7684\u4f4d\u7f6e\u7531Chad Channing\u64d4\u4efb\u3002\nNirvana\u7b2c\u4e00\u5f35\u6b63\u5f0f\u767c\u884c\u7684\u4f5c\u54c1\u662f1988\u5e74\u767c\u884c\u7684\u55ae\u66f2Love Buzz/Big Cheese\u30021989\u5e74\u6a02\u5718\u5728Sub Pop\u5531\u7247\u516c\u53f8\u767c\u884c\u4e86\u4ed6\u5011\u7684\u9996\u5f35\u5c08\u8f2fBleach\uff08\u53f0\u7063\u7ffb\u8b6f\u70ba\u201c\u6f02\u767d\u201d\uff09\u3002 1989\u5e74\u76848\u67088\u865f\uff0c1000\u5f35Bleach\u7684\u767d\u8272\u5531\u7247\u5728Lamefest\u5168\u6578\u552e\u5149\uff0c\u9019\u5f35\u5c08\u8f2f\u5c55\u73fe\u51fa\u9ad8\u5ea6\u88abThe Melvins\u3001Mudhoney\u3001Black Sabbath\u3001Led Zeppelin\u7b49\u5718\u5f71\u97ff\u7684\u4e00\u9762\u3002Krist Novoselic\u57282001\u5e74\u63a5\u53d7Rolling Stone\u63a1\u8a2a\u6642\u8868\u793a\uff0c\u6a02\u5718\u66fe\u7d93\u5728\u5de1\u8ff4\u7684\u6642\u5019\u5728\u8eca\u4e0a\u653e\u904e\u4e00\u6372\u9304\u97f3\u5e36\u4f86\u807d\uff0c\u7576\u6642\u9304\u97f3\u5e36\u7684\u4e00\u9762\u662fThe Smithereens\u7684\u4e00\u5f35\u5c08\u8f2f\uff0c\u53e6\u4e00\u9762\u5247\u662f\u9ed1\u91d1\u5c6c\u6a02\u5718Celtic Frost\u7684\u5c08\u8f2f\uff0c\u63a1\u8a2a\u8a18\u9304\u4e2d\u5beb\u5230\uff0c\u9019\u5f35\u300c\u5408\u8f2f\u300d\u6216\u8a31\u5c0d\u4ed6\u5011\u5f71\u97ff\u5f88\u5927\u3002\u300c\u6f02\u767d\u300d\u9019\u5f35\u5c08\u8f2f\u5728\u5927\u5b78\u96fb\u53f0\u9593\u88ab\u5ee3\u6cdb\u559c\u611b\uff0c\u4f46\u4e5f\u4e9b\u5fae\u6697\u793a\u4e86\u4ed6\u5011\u5169\u5e74\u5f8c\u7684\u627e\u5c0b\u81ea\u6211\u3002\n\u8a79\u68ee\u00b7\u827e\u5f17\u66fc(Jason Everman)\u5728\u300c\u6f02\u767d\u300d\u5c08\u8f2f\u4e2d\u540d\u5217\u7b2c\u4e8c\u4f4d\u5409\u4ed6\u624b\uff0c\u4f46\u5be6\u969b\u4e0a\u4ed6\u4e26\u6c92\u6709\u53c3\u8207\u9304\u88fd\uff0c\u800c\u662f\u51fa\u8cc7\u5e6b\u52a9Nirvana\u5b8c\u6210\u9304\u97f3\uff0c\u5c08\u8f2f\u5171\u82b1\u4e86606.17\u5143\u7f8e\u91d1\u3002\u5c08\u8f2f\u5b8c\u6210\u4e4b\u5f8c\uff0cEverman\u77ed\u66ab\u7684\u6210\u70ba\u6a02\u5718\u7684\u7b2c\u4e8c\u5409\u4ed6\u624b\uff0c\u4f46\u5728\u96a8\u5f8c\u6a02\u5718\u9996\u6b21\u7684\u5168\u7f8e\u5de1\u8ff4\u6642\u88ab\u89e3\u96c7\u3002\u4e0d\u4e45\u5f8c\uff0c\u4ed6\u77ed\u66ab\u7684\u5e6bSoundgarden\u5f48\u594f\u8c9d\u65af\uff0c\u76f4\u5230\u52a0\u5165Mind Funk\u70ba\u6b62\u3002\n\u52301990\u5e74\u4ee3\u65e9\u671f\uff0c\u6a02\u5718\u958b\u59cb\u8207\u88fd\u4f5c\u4ebaButch Vig\u5171\u4e8b\u300c\u6f02\u767d\u300d\u5c08\u8f2f\u4e4b\u5f8c\u7684\u9304\u97f3\u6d3b\u52d5\u3002\u5728\u9019\u6bb5\u671f\u9593Kurt\u548cKrist\u4e86\u89e3\u5230Chad\u4e26\u4e0d\u662f\u6a02\u5718\u771f\u6b63\u9700\u8981\u7684\u9f13\u624b\uff0c\u800c\u4ed6\u4e5f\u5728\u9019\u6bb5\u671f\u9593\u904e\u5f8c\u96e2\u968a\u3002\u7d93\u904e\u4e86\u77ed\u66ab\u7d66The Melvins\u9f13\u624bDale Crover\u4ee3\u6253\u5f8c\u7684\u5e7e\u500b\u661f\u671f\uff0c\u6a02\u5718\u96c7\u7528\u4e86Mudhoney\u7684\u9f13\u624bDan Peters\uff0c\u4e26\u8207\u4ed6\u9304\u88fd\u4e86\u300aSliver\u300b\u9019\u9996\u6b4c\u3002\u9019\u5e74\u7684\u5e74\u5c3e\uff0cThe Melvins\u7684Buzz Osborne\u4ecb\u7d39\u6234\u592b\u00b7\u683c\u7f85\u723e\uff08Dave Grohl\uff09\u7d66\u4ed6\u5011\u2500Dave Grohl\u7684\u6a02\u5718Scream\u7a81\u7136\u89e3\u6563\uff0c\u800c\u4ed6\u6b63\u5728\u5c0b\u8993\u65b0\u6a02\u5718\uff0c\u6b63\u597dNirvana\u4e5f\u662f\u8ddf\u96a8Scream\u7684\u66f2\u98a8\u3002","strBiographyIT":"I Nirvana sono stati un gruppo grunge statunitense formatosi ad Aberdeen (Washington) nel 1987 e attivo sino al 1994, anno della morte del leader Kurt Cobain. Principali artefici del successo del genere grunge[2] e in generale dell'alternative rock[1][2], furono una delle band pi\u00f9 innovatrici, note e influenti nella musica dei primi anni novanta. Fondatori e membri del gruppo sin dall'esordio furono Kurt Cobain (voce e chitarra) e il bassista Krist Novoselic. Vari batteristi hanno invece militato nel gruppo, tra i quali il primo di rilevante importanza fu Chad Channing, con cui il gruppo registr\u00f2 l'album d'esordio Bleach (1989) e il successivo demo di Butch Vig, che port\u00f2 i Nirvana all'attenzione delle major. Channing venne successivamente sostituito a causa della scarsa potenza sonora e della vacillante solidit\u00e0 ritmica. La formazione definitiva fu raggiunta verso la fine del 1990, quando Dave Grohl, ex batterista degli Scream, si un\u00ec al gruppo.\nDal debutto ad oggi la band ha venduto quasi 70 milioni di dischi[4], di cui 25 milioni solo negli Stati Uniti. I Nirvana sono stati inseriti al 30\u00ba posto nella lista dei 100 migliori artisti secondo Rolling Stone[5].","strBiographyJP":"\u30cb\u30eb\u30f4\u30a1\u30fc\u30ca (Nirvana) \u306f\u3001\u30a2\u30e1\u30ea\u30ab\u306e\u30d0\u30f3\u30c9\u30021980\u5e74\u4ee3\u7d42\u76e4\u306b\u30b7\u30fc\u30f3\u306b\u51fa\u73fe\u3057\u30011994\u5e74\u306e\u30ab\u30fc\u30c8\u81ea\u6bba\u306b\u3088\u308b\u6d3b\u52d5\u505c\u6b62\u307e\u3067\u306e\u6570\u5e74\u306b\u4e98\u3063\u3066\u3001\u5168\u4e16\u754c\u306e\u82e5\u8005\u4e16\u4ee3\u306e\u5727\u5012\u7684\u306a\u652f\u6301\u3092\u53d7\u3051\u305f\u3002\u5f7c\u306e\u6b7b\u4ea1\u5f8c\u3082\u4e16\u754c\u4e2d\u306e\u30df\u30e5\u30fc\u30b8\u30b7\u30e3\u30f3\u306b\u591a\u5927\u306a\u5f71\u97ff\u3092\u4e0e\u3048\u7d9a\u3051\u3066\u3044\u308b\u3002\u5358\u8a9e\u300c\u30cb\u30eb\u30f4\u30a1\u30fc\u30ca\u300d\u306b\u306f\u3001\u4ecf\u6559\u7528\u8a9e\u306e\u6d85\u69c3\u306e\u5883\u5730\u3068\u3044\u3046\u610f\u5473\u5408\u3044\u3068\u300c\u751f\u3051\u8d04\u300d\u3068\u3044\u3046\u610f\u5473\u5408\u3044\u304c\u3042\u308b\u3002\n\u300c\u30b9\u30e1\u30eb\u30ba\u30fb\u30e9\u30a4\u30af\u30fb\u30c6\u30a3\u30fc\u30f3\u30fb\u30b9\u30d4\u30ea\u30c3\u30c8\u300d\u306e\u7206\u767a\u7684\u30d2\u30c3\u30c8\u306b\u3088\u308a\u30d0\u30f3\u30c9\u306f\u4e00\u6c17\u306b\u6709\u540d\u306b\u306a\u308a\u30011990\u5e74\u4ee3\u4ee5\u964d\u306e\u30ed\u30c3\u30af\u306b\u7d76\u5927\u306a\u5f71\u97ff\u3092\u4e0e\u3048\u3001\u3057\u3070\u3057\u3070\u30aa\u30eb\u30bf\u30ca\u30c6\u30a3\u30f4\u30fb\u30ed\u30c3\u30af\u30b7\u30fc\u30f3\u306b\u304a\u3044\u3066\u300e\u30cb\u30eb\u30f4\u30a1\u30fc\u30ca\u4ee5\u964d\u300f\u3068\u3044\u3046\u8a00\u3044\u65b9\u3092\u3055\u308c\u308b\u3002\n\u5168\u4e16\u754c\u3067\u306e\u30c8\u30fc\u30bf\u30eb\u30bb\u30fc\u30eb\u30b9\u306f\u3001\u7d047500\u4e07\u679a[1][2]\u3002\n\u300c\u30ed\u30fc\u30ea\u30f3\u30b0\u30fb\u30b9\u30c8\u30fc\u30f3\u306e\u9078\u3076\u6b74\u53f2\u4e0a\u6700\u3082\u5049\u5927\u306a100\u7d44\u306e\u30a2\u30fc\u30c6\u30a3\u30b9\u30c8\u300d\u306b\u304a\u3044\u3066\u7b2c30\u4f4d\u3002","strBiographyRU":"Nirvana \u2014 \u0430\u043c\u0435\u0440\u0438\u043a\u0430\u043d\u0441\u043a\u0430\u044f \u0440\u043e\u043a-\u0433\u0440\u0443\u043f\u043f\u0430, \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u0430\u044f \u0432\u043e\u043a\u0430\u043b\u0438\u0441\u0442\u043e\u043c \u0438 \u0433\u0438\u0442\u0430\u0440\u0438\u0441\u0442\u043e\u043c \u041a\u0443\u0440\u0442\u043e\u043c \u041a\u043e\u0431\u0435\u0439\u043d\u043e\u043c \u0438 \u0431\u0430\u0441\u0438\u0441\u0442\u043e\u043c \u041a\u0440\u0438\u0441\u0442\u043e\u043c \u041d\u043e\u0432\u043e\u0441\u0435\u043b\u0438\u0447\u0435\u043c \u0432 \u0410\u0431\u0435\u0440\u0434\u0438\u043d\u0435, \u0448\u0442\u0430\u0442 \u0412\u0430\u0448\u0438\u043d\u0433\u0442\u043e\u043d, \u0432 1987 \u0433\u043e\u0434\u0443. \u0412 \u0441\u043e\u0441\u0442\u0430\u0432\u0435 \u043a\u043e\u043b\u043b\u0435\u043a\u0442\u0438\u0432\u0430 \u0441\u043c\u0435\u043d\u0438\u043b\u0438\u0441\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0431\u0430\u0440\u0430\u0431\u0430\u043d\u0449\u0438\u043a\u043e\u0432; \u0434\u043e\u043b\u044c\u0448\u0435 \u0432\u0441\u0435\u0445 \u0441 \u0433\u0440\u0443\u043f\u043f\u043e\u0439 \u0438\u0433\u0440\u0430\u043b \u0443\u0434\u0430\u0440\u043d\u0438\u043a \u0414\u044d\u0439\u0432 \u0413\u0440\u043e\u043b, \u043f\u0440\u0438\u0441\u043e\u0435\u0434\u0438\u043d\u0438\u0432\u0448\u0438\u0439\u0441\u044f \u043a \u041a\u043e\u0431\u0435\u0439\u043d\u0443 \u0438 \u041d\u043e\u0432\u043e\u0441\u0435\u043b\u0438\u0447\u0443 \u0432 1990 \u0433\u043e\u0434\u0443.\n\n\u0412 1989 \u0433\u043e\u0434\u0443 Nirvana \u0441\u0442\u0430\u043b\u0430 \u0447\u0430\u0441\u0442\u044c\u044e \u0441\u0438\u044d\u0442\u043b\u0441\u043a\u043e\u0439 \u043c\u0443\u0437\u044b\u043a\u0430\u043b\u044c\u043d\u043e\u0439 \u0441\u0446\u0435\u043d\u044b, \u0432\u044b\u043f\u0443\u0441\u0442\u0438\u0432 \u043d\u0430 \u0438\u043d\u0434\u0438-\u043b\u0435\u0439\u0431\u043b\u0435 Sub Pop \u0434\u0435\u0431\u044e\u0442\u043d\u044b\u0439 \u0430\u043b\u044c\u0431\u043e\u043c Bleach. \u041f\u043e\u0441\u043b\u0435 \u043f\u043e\u0434\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u0441 \u043a\u0440\u0443\u043f\u043d\u044b\u043c \u043b\u0435\u0439\u0431\u043b\u043e\u043c DGC Records (\u0430\u043d\u0433\u043b.)\u0440\u0443\u0441\u0441\u043a. Nirvana \u043f\u0440\u0438\u043e\u0431\u0440\u0435\u043b\u0430 \u043d\u0435\u043e\u0436\u0438\u0434\u0430\u043d\u043d\u044b\u0439 \u0443\u0441\u043f\u0435\u0445 \u0441 \u043f\u0435\u0441\u043d\u0435\u0439 \u00abSmells Like Teen Spirit\u00bb \u0441\u043e \u0441\u0432\u043e\u0435\u0433\u043e \u0432\u0442\u043e\u0440\u043e\u0433\u043e \u0430\u043b\u044c\u0431\u043e\u043c\u0430 Nevermind, \u0432\u044b\u043f\u0443\u0449\u0435\u043d\u043d\u043e\u0433\u043e \u0432 1991 \u0433\u043e\u0434\u0443. \u0412\u043f\u043e\u0441\u043b\u0435\u0434\u0441\u0442\u0432\u0438\u0438 Nirvana \u0432\u043e\u0448\u043b\u0430 \u0432 \u043c\u0443\u0437\u044b\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u043c\u0435\u0439\u043d\u0441\u0442\u0440\u0438\u043c, \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u0438\u0437\u043e\u0432\u0430\u0432 \u043f\u043e\u0434\u0436\u0430\u043d\u0440 \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u0440\u043e\u043a\u0430, \u043d\u0430\u0437\u0432\u0430\u043d\u043d\u044b\u0439 \u0433\u0440\u0430\u043d\u0436\u0435\u043c. \u041a\u0443\u0440\u0442 \u041a\u043e\u0431\u0435\u0439\u043d \u0441\u0434\u0435\u043b\u0430\u043b\u0441\u044f \u0432 \u0433\u043b\u0430\u0437\u0430\u0445 \u0421\u041c\u0418 \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043c\u0443\u0437\u044b\u043a\u0430\u043d\u0442\u043e\u043c, \u0430 \u00ab\u0433\u043e\u043b\u043e\u0441\u043e\u043c \u043f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u044f\u00bb, \u0430 Nirvana \u0441\u0442\u0430\u043b\u0430 \u0444\u043b\u0430\u0433\u043c\u0430\u043d\u043e\u043c \u00ab\u043f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u044f \u0425\u00bb. \u0412 1993 \u0433\u043e\u0434\u0443 \u0432\u044b\u0448\u0435\u043b \u0442\u0440\u0435\u0442\u0438\u0439 \u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0441\u0442\u0443\u0434\u0438\u0439\u043d\u044b\u0439 \u0430\u043b\u044c\u0431\u043e\u043c \u0433\u0440\u0443\u043f\u043f\u044b, In Utero, \u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u0441 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0432 \u043c\u0443\u0437\u044b\u043a\u0430\u043b\u044c\u043d\u043e\u043c \u043f\u043b\u0430\u043d\u0435 \u0441\u0438\u043b\u044c\u043d\u043e \u043e\u0442\u043b\u0438\u0447\u0430\u043b\u0438\u0441\u044c \u043e\u0442 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0445 \u0440\u0430\u0431\u043e\u0442 \u043a\u043e\u043b\u043b\u0435\u043a\u0442\u0438\u0432\u0430.\n\n\u041d\u0435\u0434\u043e\u043b\u0433\u0430\u044f, \u043d\u043e \u044f\u0440\u043a\u0430\u044f \u0438\u0441\u0442\u043e\u0440\u0438\u044f \u0433\u0440\u0443\u043f\u043f\u044b \u043f\u0440\u0435\u0440\u0432\u0430\u043b\u0430\u0441\u044c \u0432 \u0441\u0432\u044f\u0437\u0438 \u0441\u043e \u0441\u043c\u0435\u0440\u0442\u044c\u044e \u041a\u0443\u0440\u0442\u0430 \u041a\u043e\u0431\u0435\u0439\u043d\u0430 5 \u0430\u043f\u0440\u0435\u043b\u044f 1994 \u0433\u043e\u0434\u0430, \u043d\u043e \u0432 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0433\u043e\u0434\u044b \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u043e\u0441\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043b\u0438\u0448\u044c \u0440\u043e\u0441\u043b\u0430. \u0412 2002 \u0433\u043e\u0434\u0443 \u043d\u0435\u0437\u0430\u0432\u0435\u0440\u0448\u0451\u043d\u043d\u0430\u044f \u0434\u0435\u043c\u043e\u0437\u0430\u043f\u0438\u0441\u044c \u043f\u0435\u0441\u043d\u0438 \u00abYou Know You\u2019re Right\u00bb, \u043d\u0430\u0434 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0433\u0440\u0443\u043f\u043f\u0430 \u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0430 \u043d\u0435\u0437\u0430\u0434\u043e\u043b\u0433\u043e \u0434\u043e \u0441\u043c\u0435\u0440\u0442\u0438 \u041a\u043e\u0431\u0435\u0439\u043d\u0430, \u0437\u0430\u043d\u044f\u043b\u0430 \u043f\u0435\u0440\u0432\u044b\u0435 \u0441\u0442\u0440\u043e\u0447\u043a\u0438 \u043c\u0438\u0440\u043e\u0432\u044b\u0445 \u0445\u0438\u0442-\u043f\u0430\u0440\u0430\u0434\u043e\u0432. \u0421\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0432\u044b\u0445\u043e\u0434\u0430 \u0434\u0435\u0431\u044e\u0442\u043d\u043e\u0433\u043e \u0430\u043b\u044c\u0431\u043e\u043c\u0430 \u0437\u0430\u043f\u0438\u0441\u0438 Nirvana \u0431\u044b\u043b\u0438 \u043f\u0440\u043e\u0434\u0430\u043d\u044b \u0432 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0435 \u0431\u043e\u043b\u0435\u0435 25 \u043c\u0438\u043b\u043b\u0438\u043e\u043d\u043e\u0432 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u043e\u0432 \u0432 \u0421\u0428\u0410 \u0438 \u0431\u043e\u043b\u0435\u0435 50 \u043c\u0438\u043b\u043b\u0438\u043e\u043d\u043e\u0432 \u043f\u043e \u0432\u0441\u0435\u043c\u0443 \u043c\u0438\u0440\u0443.","strBiographyES":"Nirvana fue un grupo estadounidense de Grunge, procedente de Aberdeen, Washington. Con el \u00e9xito del sencillo \"Smells Like Teen Spirit\", del \u00e1lbum Nevermind (1991), Nirvana escal\u00f3 las listas musicales en todo el mundo e inici\u00f3 la explosi\u00f3n de lo que hasta ese momento era punk underground y rock alternativo en la escena musical mundial, en un movimiento al que los medios de la \u00e9poca se referir\u00edan como \"grunge\". Otras bandas de la escena musical de Seattle como Pearl Jam, Alice in Chains y Soundgarden tambi\u00e9n obtuvieron popularidad y, como resultado, el rock alternativo se convirti\u00f3 en un g\u00e9nero dominante en la radio y la televisi\u00f3n musical durante la primera mitad de la d\u00e9cada de 1990.\n\nKurt Cobain, l\u00edder de la banda, se encontr\u00f3 a s\u00ed mismo referido en los medios de comunicaci\u00f3n como \"la voz de una generaci\u00f3n\", y a Nirvana como la \"banda s\u00edmbolo\" de la \"Generaci\u00f3n X\". Cobain se sent\u00eda inc\u00f3modo con la atenci\u00f3n que se les brindaba y decidi\u00f3 enfocar la atenci\u00f3n del p\u00fablico hacia la m\u00fasica de la banda, retando a la audiencia con su tercer \u00e1lbum de estudio In Utero. Aunque la popularidad de Nirvana disminuy\u00f3 en los meses siguientes a la publicaci\u00f3n del \u00e1lbum, buena parte de su audiencia alab\u00f3 el interior \"oscuro\" de la banda, en especial despu\u00e9s de su presentaci\u00f3n en MTV Unplugged.\n\nLa corta carrera de Nirvana concluy\u00f3 con la muerte de Cobain en 1994, pero su popularidad creci\u00f3 a\u00fan m\u00e1s en los a\u00f1os posteriores. Ocho a\u00f1os despu\u00e9s de la muerte de Cobain, \"You Know You're Right\", un demo nunca terminado que la banda hab\u00eda grabado dos meses antes de la muerte de Cobain, escalaba las listas de radio y m\u00fasica de todo el mundo. En 2004 fueron rankeados en el puesto #27 en la lista de los 100 mejores artistas de todos los tiempos de la revista Rolling Stone y en puesto #14 seg\u00fan la revista Vh1. Desde su debut, la banda ha vendido m\u00e1s de 50 millones de \u00e1lbumes a nivel mundial, incluyendo 10 millones de ejemplares de Nevermind en los Estados Unidos y 30 millones en todo el mundo. Su m\u00fasica contin\u00faa siendo emitida por estaciones de radio de todo el mundo.","strBiographyPT":"Nirvana foi uma banda americana de rock formada pelo vocalista e guitarrista Kurt Cobain e pelo baixista Krist Novoselic em Aberdeen em 1987 . V\u00e1rios bateristas passaram pelo Nirvana, sendo o que mais tempo ficou na banda foi Dave Grohl, que entrou em 1990.\n\nNo final da d\u00e9cada de 1980 o Nirvana se estabeleceu como parte da cena grunge de Seattle, lan\u00e7ando seu primeiro \u00e1lbum, Bleach, pela gravadora independente Sub Pop em 1989. A banda eventualmente chegou a desenvolver um som que se baseava em contrastes din\u00e2micos, muitas vezes entre versos calmos e barulhentos, e refr\u00f5es pesados. Depois de assinar com a gravadora DGC Records, o grupo encontrou o sucesso inesperado com \"Smells Like Teen Spirit\", o primeiro single do segundo \u00e1lbum da banda, Nevermind (1991). O sucesso repentino da banda amplamente popularizou o rock alternativo como um todo, e como o vocalista da banda, Cobain se encontrou referido na m\u00eddia como o \"porta-voz de uma gera\u00e7\u00e3o\", com o Nirvana sendo considerado a \"principal banda\" da Gera\u00e7\u00e3o X. O terceiro \u00e1lbum de est\u00fadio do Nirvana, In Utero (1993), desafiou a audi\u00eancia do grupo, apresentando um som abrasivo, menos mainstream.\n\nA breve dura\u00e7\u00e3o do Nirvana terminou ap\u00f3s o suic\u00eddio de Cobain em 1994, mas v\u00e1rios lan\u00e7amentos p\u00f3stumos t\u00eam sido emitidos desde ent\u00e3o, supervisionados por Novoselic, Grohl e pela vi\u00fava de Cobain, Courtney Love. Desde a sua estreia, a banda j\u00e1 vendeu mais de 50 milh\u00f5es de \u00e1lbuns em todo o mundo, sendo que 25 milh\u00f5es foram vendidos s\u00f3 no Estados Unidos (dados at\u00e9 2002).","strBiographySE":"Nirvana var en amerikansk rockgrupp, bildad av s\u00e5ngaren/gitarristen Kurt Cobain och basisten Krist Novoselic i Aberdeen, Washington 1987. Nirvana hade under sin verksamma tid en rad trumslagare, med Dave Grohl (som ansl\u00f6t 1990) som l\u00e4ngst kvarvarande.\n\nNirvana fick sitt kommersiella genombrott med singeln Smells Like Teen Spirit fr\u00e5n albumet Nevermind som sl\u00e4pptes 1991. Albumet innebar ett stort uppsving f\u00f6r grungen, en subgenre till alternative rock. Andra grungeband fr\u00e5n Seattle som Pearl Jam, Soundgarden och Alice in Chains \u00f6kade ocks\u00e5 i popularitet i och med Nirvanas framg\u00e5ngar och som ett resultat blev Alternative rock den dominanta musikstilen i radio och TV i USA under tidigt 1990-tal. Som Nirvanas f\u00f6rgrundsfigur omn\u00e4mndes Cobain av medier som en \u201dtalesman f\u00f6r en generation\u201d och Nirvana var ett band som \u201drepresenterade Generation X\u201d. Nirvana sl\u00e4ppte sitt sista studioalbum, In Utero 1993.\n\nNirvanas korta karri\u00e4r slutade med Cobains d\u00f6d i april 1994, men trots detta \u00f6kade bandets popularitet under \u00e5ren som f\u00f6ljde. 2002 sl\u00e4pptes singeln You Know You\u2019re Right, en ofullbordad demo fr\u00e5n bandets sista session, i samband med utgivningen av best-of-albumet; Nirvana. Sedan deras debut har Nirvana s\u00e5lt \u00f6ver 50 miljoner skivor v\u00e4rlden \u00f6ver. Nirvana spelas \u00e4n idag frekvent av radiostationer v\u00e4rlden runt.","strBiographyNL":"Nirvana was een Amerikaanse rockband die in 1987 werd opgericht in Aberdeen, Washington door zanger en gitarist Kurt Cobain en bassist Krist Novoselic. De band kende een reeks verschillende drummers van wie Dave Grohl, die in 1990 bij de band kwam, de langstzittende was.\n\nDe band vestigde zichzelf binnen de muziek-scene van Seattle door in 1989 hun debuutalbum Bleach uit te brengen op het indie-label Sub Pop. Nadat de band tekende bij het grote label DGC Records, kende het onverwacht succes met de single \"Smells Like Teen Spirit\", van zijn tweede album Nevermind (1991). Hierop betrad Nirvana de mainstream en nam het het genre 'grunge' hierin mee. Frontman Kurt Cobain werd door de media bestempeld als \"stem van een generatie\", terwijl Nirvana gezien werd als vaandeldrager voor Generatie X.\n\nCobain voelde zich ongemakkelijk bij alle aandacht en legde zich toe op de bands muziek, vindende dat de boodschap en artistieke visie van de band verkeerd werden ge\u00efnterpreteerd door het grote publiek dat hij uitdaagde met hun derde album In Utero (1993).\n\nMet Cobains dood in april 1994 kwam er een einde aan het korte bestaan van Nirvana. De bands invloed en populariteit bleven echter intact in de jaren die volgden. Het nummer \"You Know You're Right\", een nooit eerder uitgebrachte demo, stond in 2002 hoog in radio-playlists over de gehele wereld. De band verkocht sinds zijn debuut wereldwijd meer dan vijftig miljoen platen, waarvan meer dan 25 miljoen in de Verenigde Staten.","strBiographyHU":"A Nirvana egy amerikai rockegy\u00fcttes volt, amelyet Kurt Cobain \u00e9nekes \u00e9s git\u00e1ros alap\u00edtott Krist Novoselic basszusgit\u00e1rossal a Washington \u00e1llambeli Aberdeen-ben. A kezdeti id\u0151szakban t\u00f6bb dobossal zen\u00e9ltek majd 1990-ben csatlakozott hozz\u00e1juk Dave Grohl, akivel kialakult a Nirvana v\u00e9gs\u0151 fel\u00e1ll\u00e1sa.\nAz egy\u00fcttes a Seattle-i zenei sz\u00ednt\u00e9ren alapozta meg h\u00edrnev\u00e9t a f\u00fcggetlen Sub Pop lemezkiad\u00f3n\u00e1l 1989-ben megjelent, Bleach c\u00edm\u0171 els\u0151 album\u00e1val. Miut\u00e1n a nagykiad\u00f3s DGC Recordshoz szerz\u0151dtek, Smells Like Teen Spirit c\u00edm\u0171 daluk a m\u00e1sodik, 1991-es Nevermind albumr\u00f3l, nem v\u00e1rt nagy sikert aratott. A Nirvana ezzel bel\u00e9pett a mainstreambe, \u00e9s r\u00e1ir\u00e1ny\u00edtotta a figyelmet az alternat\u00edv rock egyik alm\u0171faj\u00e1ra, a grunge-ra, amely azt\u00e1n az 1990-es \u00e9vek els\u0151 fel\u00e9ben uralta a zeneipart. Kurt Cobaint, a Nirvana frontember\u00e9t, a m\u00e9dia \u201egener\u00e1ci\u00f3ja sz\u00f3sz\u00f3l\u00f3j\u00e1nak\u201d ki\u00e1ltotta ki, a Nirvan\u00e1t pedig az X-gener\u00e1ci\u00f3 \u201ez\u00e1szl\u00f3shaj\u00f3j\u00e1nak\u201d.[1] Cobain k\u00e9nyelmetlen\u00fcl \u00e9rezte mag\u00e1t a r\u00e1 ir\u00e1nyul\u00f3 figyelemt\u0151l, \u00e9s ink\u00e1bb a zen\u00e9re \u00f6sszpontos\u00edtott. Abban a hitben, hogy az egy\u00fcttes \u00fczenet\u00e9t \u00e9s m\u0171v\u00e9szi v\u00edzi\u00f3j\u00e1t f\u00e9lre\u00e9rtelmezt\u00e9k, kih\u00edv\u00e1s el\u00e9 \u00e1ll\u00edtotta a zenekar k\u00f6z\u00f6ns\u00e9g\u00e9t az 1993-as In Utero c\u00edm\u0171 harmadik st\u00fadi\u00f3albumukkal.\nA Nirvana r\u00f6vid p\u00e1lyafut\u00e1sa Kurt Cobain 1994 \u00e1prilisi hal\u00e1l\u00e1val \u00e9rt v\u00e9get, de az egy\u00fcttes n\u00e9pszer\u0171s\u00e9ge \u00e9s hat\u00e1sa kitartott a k\u00f6vetkez\u0151 \u00e9vekben is. 2002-ben egy befejezetlen dem\u00f3felv\u00e9tel\u00fck a zenekar utols\u00f3 id\u0151szak\u00e1b\u00f3l You Know You're Right c\u00edmmel a r\u00e1di\u00f3s j\u00e1tsz\u00e1si list\u00e1k \u00e9l\u00e9re ker\u00fclt vil\u00e1gszerte. Az egy\u00fcttes 1989-es bemutatkoz\u00e1sa \u00f3ta, csak az Egyes\u00fclt \u00c1llamokban, t\u00f6bb mint 25 milli\u00f3 albumot adott el, vil\u00e1gszerte pedig t\u00f6bb mint 50 milli\u00f3t.[2][3]","strBiographyNO":"Nirvana var et amerikansk Grunge-band fra Aberdeen, Washington. Med hiten \u00abSmells Like Teen Spirit\u00bb og albumet Nevermind ble de verdenskjente i 1991. Musikken kan beskrives som en blanding mellom hardrock/metal, indie/alternativ rock og blues med punkens \u00abgj\u00f8r-det-selv\u00bb-ideologi i bunnen , og ble kalt grunge. Grunge betyr rett og slett \u00abgrums\u00bb og beskriver den karkteristiske, \u00abgrumsete\u00bb gitarlyden flere av Seattle-banda hadde. Andre Seattle-baserte grungeband som Alice in Chains, Pearl Jam og Soundgarden \u00f8kte ogs\u00e5 i popularitet, og alternativ rock ble en popul\u00e6r musikksjanger fra tidlig p\u00e5 1990-tallet og utover.\n\nSom Nirvanas frontfigur ble Kurt Cobain betegnet som talspersonen for den s\u00e5kalte generasjon x. Cobain likte ikke oppmerksomheten og pr\u00f8vde \u00e5 skifte fokuset p\u00e5 bandets musikk, og utfordret med tredjealbumet In Utero. Mens Nirvanas popularitet dalte noe i m\u00e5nedene f\u00f8r lanseringen, hyllet kjernepublikumet bandets m\u00f8rkere side, delvis etter MTV Unplugged-konserten i 1993.\n\nEtter Kurt Cobains d\u00f8d i 1994 ble Nirvana oppl\u00f8st, men bandets popularitet har \u00f8kt i \u00e5rene etter. \u00c5tte \u00e5r etter Cobains endelikt ble \u00abYou Know You're Right\u00bb lansert. Det er Nirvanas siste studioinnspilling, spilt inn bare to m\u00e5neder f\u00f8r det tragiske d\u00f8dsfallet inntraff. Denne sangen toppet spillelistene p\u00e5 radiokanaler verden rundt. Siden debuten har Nirvana solgt over 50 millioner album, inkludert ti millioner av Nevermind i USA.","strBiographyIL":"\u05e0\u05d9\u05e8\u05d5\u05d5\u05e0\u05d4 (Nirvana) \u05d4\u05d9\u05d9\u05ea\u05d4 \u05dc\u05d4\u05e7\u05ea \u05d2\u05e8\u05d0\u05e0\u05d2' \u05d0\u05de\u05e8\u05d9\u05e7\u05d0\u05d9\u05ea \u05e4\u05d5\u05e4\u05d5\u05dc\u05e8\u05d9\u05ea \u05de\u05d0\u05d1\u05e8\u05d3\u05d9\u05df, \u05d5\u05d5\u05e9\u05d9\u05e0\u05d2\u05d8\u05d5\u05df. \u05d4\u05dc\u05d4\u05e7\u05d4 \u05e4\u05e8\u05e6\u05d4 \u05d0\u05dc \u05d4\u05d6\u05e8\u05dd \u05d4\u05de\u05e8\u05db\u05d6\u05d9 \u05d1\u05e2\u05d6\u05e8\u05ea \u05d4\u05e1\u05d9\u05e0\u05d2\u05dc \"Smells Like Teen Spirit\" \u05de\u05ea\u05d5\u05da \u05d0\u05dc\u05d1\u05d5\u05de\u05d4 \u05de-1991, Nevermind, \u05db\u05d0\u05e9\u05e8 \u05d4\u05d9\u05d0 \u05e1\u05d5\u05d7\u05e4\u05ea \u05d0\u05d7\u05e8\u05d9\u05d4 \u05d6\u05e8\u05dd \u05e9\u05dc \u05dc\u05d4\u05e7\u05d5\u05ea \u05e4\u05d0\u05e0\u05e7 \u05e8\u05d5\u05e7 \u05d5\u05e8\u05d5\u05e7 \u05d0\u05dc\u05d8\u05e8\u05e0\u05d8\u05d9\u05d1\u05d9, \u05e9\u05d4\u05ea\u05e7\u05e9\u05d5\u05e8\u05ea \u05e0\u05d4\u05d2\u05d4 \u05dc\u05db\u05e0\u05d5\u05ea \u05d1\u05e9\u05dd \"\u05d2\u05e8\u05d0\u05e0\u05d2'\". \u05dc\u05d4\u05e7\u05d5\u05ea \u05d2\u05e8\u05d0\u05e0\u05d2' \u05d0\u05d7\u05e8\u05d5\u05ea \u05db\u05d2\u05d5\u05df \u05d0\u05dc\u05d9\u05e1 \u05d0\u05d9\u05df \u05e6'\u05d9\u05d9\u05e0\u05e1, \u05e4\u05e8\u05dc \u05d2'\u05d0\u05dd \u05d5\u05e1\u05d0\u05d5\u05e0\u05d3\u05d2\u05d0\u05e8\u05d3\u05df \u05e0\u05d4\u05e0\u05d5 \u05d0\u05e3 \u05d4\u05df \u05de\u05e2\u05dc\u05d9\u05d9\u05d4 \u05d1\u05e4\u05d5\u05e4\u05d5\u05dc\u05e8\u05d9\u05d5\u05ea \u05e9\u05dc\u05d4\u05df, \u05d5\u05db\u05ea\u05d5\u05e6\u05d0\u05d4 \u05de\u05db\u05da \u05d4\u05e4\u05da \u05d4\u05e8\u05d5\u05e7 \u05d4\u05d0\u05dc\u05d8\u05e8\u05e0\u05d8\u05d9\u05d1\u05d9 \u05dc\u05d6'\u05d0\u05e0\u05e8 \u05d3\u05d5\u05de\u05d9\u05e0\u05e0\u05d8\u05d9 \u05d1\u05e8\u05d3\u05d9\u05d5 \u05d5\u05d1\u05d8\u05dc\u05d5\u05d5\u05d9\u05d6\u05d9\u05d4 \u05e9\u05dc \u05d0\u05e8\u05e6\u05d5\u05ea \u05d4\u05d1\u05e8\u05d9\u05ea \u05e9\u05dc \u05ea\u05d7\u05d9\u05dc\u05ea \u05e2\u05d3 \u05d0\u05de\u05e6\u05e2 \u05e9\u05e0\u05d5\u05ea \u05d4\u05ea\u05e9\u05e2\u05d9\u05dd.\n\u05db\u05de\u05e0\u05d4\u05d9\u05d2 \u05d4\u05dc\u05d4\u05e7\u05d4 \u05ea\u05d5\u05d0\u05e8 \u05dc\u05e2\u05ea\u05d9\u05dd \u05e7\u05d5\u05e8\u05d8 \u05e7\u05d5\u05d1\u05d9\u05d9\u05df \u05d1\u05ea\u05e7\u05e9\u05d5\u05e8\u05ea \u05db\"\u05d3\u05d5\u05d1\u05e8\u05d5 \u05e9\u05dc \u05d3\u05d5\u05e8 \u05e9\u05dc\u05dd\", \u05d1\u05e2\u05d5\u05d3 \u05e9\u05e0\u05d9\u05e8\u05d5\u05d5\u05e0\u05d4 \u05d6\u05db\u05ea\u05d4 \u05dc\u05db\u05d9\u05e0\u05d5\u05d9 \"\u05e1\u05e4\u05d9\u05e0\u05ea \u05d4\u05d3\u05d2\u05dc \u05e9\u05dc \u05d3\u05d5\u05e8 \u05d4-X\". \u05e7\u05d5\u05d1\u05d9\u05d9\u05df \u05d7\u05e9 \u05e9\u05dc\u05d0 \u05d1\u05e0\u05d5\u05d7 \u05e2\u05dd \u05ea\u05e9\u05d5\u05de\u05ea \u05d4\u05dc\u05d1 \u05d4\u05de\u05d5\u05e4\u05e8\u05d6\u05ea \u05dc\u05d4 \u05d6\u05db\u05d4 \u05dc\u05d3\u05e2\u05ea\u05d5, \u05d5\u05d4\u05e4\u05e0\u05d4 \u05d0\u05ea \u05e2\u05d9\u05e7\u05e8 \u05ea\u05e9\u05d5\u05de\u05ea \u05dc\u05d1\u05d5 \u05dc\u05d9\u05e6\u05d9\u05e8\u05d4, \u05db\u05d0\u05e9\u05e8 \u05d4\u05d5\u05d0 \u05de\u05d0\u05ea\u05d2\u05e8 \u05d0\u05ea \u05e7\u05d4\u05dc\u05d4 \u05e9\u05dc \u05d4\u05dc\u05d4\u05e7\u05d4 \u05e2\u05dd \u05d0\u05dc\u05d1\u05d5\u05de\u05d4 \u05d4\u05e9\u05dc\u05d9\u05e9\u05d9 In Utero. \u05e2\u05dc \u05d0\u05e3 \u05e9\u05d4\u05e4\u05d5\u05e4\u05d5\u05dc\u05e8\u05d9\u05d5\u05ea \u05e9\u05dc \u05d4\u05dc\u05d4\u05e7\u05d4 \u05d3\u05e2\u05db\u05d4 \u05d1\u05d4\u05d3\u05e8\u05d2\u05d4 \u05dc\u05d0\u05d7\u05e8 \u05d9\u05e6\u05d9\u05d0\u05ea\u05d5 \u05e9\u05dc \u05d0\u05dc\u05d1\u05d5\u05dd \u05d6\u05d4, \u05d4\u05de\u05e9\u05d9\u05da \u05d2\u05e8\u05e2\u05d9\u05df \u05d4\u05de\u05e2\u05e8\u05d9\u05e6\u05d9\u05dd \u05e9\u05dc\u05d4 \u05dc\u05d4\u05e2\u05e8\u05d9\u05da \u05d0\u05ea \u05d4\u05e6\u05d3 \u05d4\u05e4\u05d7\u05d5\u05ea \u05e7\u05d5\u05de\u05d5\u05e0\u05d9\u05e7\u05d8\u05d9\u05d1\u05d9 \u05e9\u05dc\u05d4, \u05d1\u05de\u05d9\u05d5\u05d7\u05d3 \u05dc\u05d0\u05d7\u05e8 \u05d4\u05d5\u05e4\u05e2\u05ea\u05d4 \u05d1\u05de\u05e1\u05d2\u05e8\u05ea MTV Unplugged \u05d1-1993.\n\u05ea\u05e7\u05d5\u05e4\u05ea \u05e7\u05d9\u05d5\u05de\u05d4 \u05d4\u05e7\u05e6\u05e8\u05d4 \u05e9\u05dc \u05e0\u05d9\u05e8\u05d5\u05d5\u05e0\u05d4 \u05d1\u05d0\u05d4 \u05dc\u05e7\u05d9\u05e6\u05d4 \u05dc\u05d0\u05d7\u05e8 \u05de\u05d5\u05ea\u05d5 \u05e9\u05dc \u05e7\u05d5\u05d1\u05d9\u05d9\u05df \u05d1-1994, \u05d0\u05da \u05d4\u05e4\u05d5\u05e4\u05d5\u05dc\u05e8\u05d9\u05d5\u05ea \u05e9\u05dc\u05d4 \u05d4\u05dc\u05db\u05d4 \u05d5\u05d4\u05ea\u05e2\u05e6\u05de\u05d4 \u05d1\u05e9\u05e0\u05d9\u05dd \u05e9\u05dc\u05d0\u05d7\u05e8 \u05de\u05db\u05df. \u05e9\u05de\u05d5\u05e0\u05d4 \u05e9\u05e0\u05d9\u05dd \u05dc\u05d0\u05d7\u05e8 \u05de\u05d5\u05ea\u05d5 \u05e9\u05dc \u05e7\u05d5\u05d1\u05d9\u05d9\u05df \u05d4\u05d2\u05d9\u05e2 \u05e7\u05dc\u05d8\u05ea \u05d3\u05de\u05d5 \u05d1\u05e9\u05dd \"You Know You're Right\" \u05e9\u05d4\u05dc\u05d4\u05e7\u05d4 \u05d4\u05e7\u05dc\u05d9\u05d8\u05d4 \u05d7\u05d5\u05d3\u05e9\u05d9\u05d9\u05dd \u05d8\u05e8\u05dd \u05de\u05d5\u05ea\u05d5 \u05e9\u05dc \u05e7\u05d5\u05d1\u05d9\u05d9\u05df, \u05dc\u05de\u05e7\u05d5\u05dd \u05d4\u05e8\u05d0\u05e9\u05d5\u05df \u05d1\u05de\u05e6\u05e2\u05d3\u05d9\u05dd \u05d1\u05e8\u05d7\u05d1\u05d9 \u05d4\u05e2\u05d5\u05dc\u05dd. \u05de\u05d0\u05d6 \u05d0\u05dc\u05d1\u05d5\u05dd \u05d4\u05d1\u05db\u05d5\u05e8\u05d4 \u05e9\u05dc\u05d4 \u05de\u05db\u05e8\u05d4 \u05d4\u05dc\u05d4\u05e7\u05d4 \u05de\u05e2\u05dc \u05d7\u05de\u05d9\u05e9\u05d9\u05dd \u05de\u05d9\u05dc\u05d9\u05d5\u05df \u05d0\u05dc\u05d1\u05d5\u05de\u05d9\u05dd \u05d1\u05e8\u05d7\u05d1\u05d9 \u05d4\u05e2\u05d5\u05dc\u05dd, \u05de\u05ea\u05d5\u05db\u05dd \u05de\u05e2\u05dc \u05e2\u05e9\u05e8\u05d4 \u05de\u05d9\u05dc\u05d9\u05d5\u05df \u05e2\u05d5\u05ea\u05e7\u05d9\u05dd \u05e9\u05dc Nevermind \u05d1\u05d0\u05e8\u05e6\u05d5\u05ea \u05d4\u05d1\u05e8\u05d9\u05ea \u05dc\u05d1\u05d3\u05d4. \u05e0\u05d9\u05e8\u05d5\u05d5\u05e0\u05d4 \u05e0\u05d4\u05e0\u05d9\u05ea \u05de\u05e0\u05d5\u05db\u05d7\u05d5\u05ea \u05d7\u05d6\u05e7\u05d4 \u05d5\u05de\u05ea\u05de\u05e9\u05db\u05ea \u05d1\u05ea\u05d7\u05e0\u05d5\u05ea \u05e8\u05d3\u05d9\u05d5 \u05d1\u05e8\u05d7\u05d1\u05d9 \u05d4\u05e2\u05d5\u05dc\u05dd.","strBiographyPL":"Nirvana \u2013 ameryka\u0144ski zesp\u00f3\u0142 grunge'owy, za\u0142o\u017cony przez wokalist\u0119 i gitarzyst\u0119 Kurta Cobaina i basist\u0119 Krista Novoselica w Aberdeen (USA) w 1987. Zesp\u00f3\u0142 w ci\u0105gu siedmiu lat swojej kariery zatrudnia\u0142 kilku perkusist\u00f3w (ostatnim by\u0142 Dave Grohl, kt\u00f3ry do\u0142\u0105czy\u0142 do grupy w 1990).\n\nNirvana zdoby\u0142a og\u00f3lno\u015bwiatow\u0105 s\u0142aw\u0119 po wydaniu albumu Nevermind oraz pierwszego singla promuj\u0105cego p\u0142yt\u0119, \"Smells Like Teen Spirit\" (1991) oraz sta\u0142a si\u0119 jednym z prekursor\u00f3w podgatunku muzyki rockowej, grunge. Inne grupy pochodz\u0105ce z Seattle r\u00f3wnie\u017c odegra\u0142y du\u017c\u0105 rol\u0119 na scenie rockowej w latach 80. i 90., Pearl Jam i Soundgarden. Dzi\u0119ki dzia\u0142alno\u015bci tych zespo\u0142\u00f3w grunge i rock alternatywny sta\u0142y si\u0119 najcz\u0119\u015bciej nadawanymi przez stacje radiowe gatunkami muzycznymi na pocz\u0105tku lat 90. Wokalista zespo\u0142u, Kurt Cobain, zyska\u0142 miano \"przedstawiciela nowego pokolenia\", za\u015b Nirvana sta\u0142a si\u0119 jednym z niewielu zespo\u0142\u00f3w kojarzonych z Generacj\u0105 X\n\n. Wobec medialnego zamieszania Cobain skupi\u0142 si\u0119 w pe\u0142ni na muzyce zespo\u0142u, gdy\u017c uwa\u017ca\u0142, i\u017c wizja artystyczna oraz przekaz zespo\u0142u zosta\u0142y \u017ale zinterpretowane przez odbiorc\u00f3w.\n\nZesp\u00f3\u0142 zosta\u0142 rozwi\u0105zany po \u015bmierci Cobaina w 1994, ale popularno\u015b\u0107 Nirvany po tym wydarzeniu jeszcze bardziej wzros\u0142a. W 2002 wydano nieuko\u0144czone przez zesp\u00f3\u0142 demo \"You Know You're Right\", kt\u00f3re okaza\u0142o si\u0119 mi\u0119dzynarodowym hitem i uplasowa\u0142o si\u0119 na szczytach list przeboj\u00f3w. Do marca 2009 zesp\u00f3\u0142 sprzeda\u0142 ponad 25 milion\u00f3w album\u00f3w w Stanach Zjednoczonych oraz ponad 50 milion\u00f3w na ca\u0142ym \u015bwiecie.","strGender":"Male","intMembers":"3","strCountry":"Washington, USA","strCountryCode":"US","strArtistThumb":"http://www.theaudiodb.com/images/media/artist/thumb/ryppyp1363124444.jpg","strArtistLogo":"http://www.theaudiodb.com/images/media/artist/logo/xyryvu1363124407.png","strArtistFanart":"http://media.theaudiodb.com/images/media/artist/fanart/nirvana-4ddaf131354a8.jpg","strArtistFanart2":"http://media.theaudiodb.com/images/media/artist/fanart/ussvpr1342344599.jpg","strArtistFanart3":"http://media.theaudiodb.com/images/media/artist/fanart/uusxqw1342344614.jpg","strArtistBanner":"http://www.theaudiodb.com/images/media/artist/banner/wppvrr1365966313.jpg","strMusicBrainzID":"5b11f4ce-a62d-471e-81fc-a69a8278c7da","strLastFMChart":"http://www.last.fm/music/Nirvana/+charts?rangetype=6month","strLocked":"unlocked"}]} \ No newline at end of file diff --git a/test/fixtures/faae9e2018b271b5f0908a41d07847ad.headers b/test/fixtures/faae9e2018b271b5f0908a41d07847ad.headers new file mode 100644 index 0000000..4e5fee2 --- /dev/null +++ b/test/fixtures/faae9e2018b271b5f0908a41d07847ad.headers @@ -0,0 +1,21 @@ +{ + "statusCode": 200, + "headers": { + "content-type": "application/json", + "server": "Microsoft-IIS/7.0", + "x-powered-by": "PHP/5.6.0, ASP.NET", + "date": "Thu, 19 Oct 2017 05:18:51 GMT", + "content-length": "57277" + }, + "url": "http://www.theaudiodb.com:80/api/v1/json/1/artist-mb.php?i=5b11f4ce-a62d-471e-81fc-a69a8278c7da", + "time": 890, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "www.theaudiodb.com", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/fd213f6dd613d91b8c059cad39261cb8 b/test/fixtures/fd213f6dd613d91b8c059cad39261cb8 new file mode 100644 index 0000000..b411adf Binary files /dev/null and b/test/fixtures/fd213f6dd613d91b8c059cad39261cb8 differ diff --git a/test/fixtures/fd213f6dd613d91b8c059cad39261cb8.headers b/test/fixtures/fd213f6dd613d91b8c059cad39261cb8.headers new file mode 100644 index 0000000..471eea7 --- /dev/null +++ b/test/fixtures/fd213f6dd613d91b8c059cad39261cb8.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Thu, 19 Oct 2017 06:21:14 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "1200", + "x-ratelimit-remaining": "940", + "x-ratelimit-reset": "1508394075", + "server": "Plack::Handler::Starlet", + "etag": "W/\"e6a8aed6a6fbbd790a6a73d51b6e2521\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/instrument/00beaf8e-a781-431c-8130-7c2871696b7d?inc=url-rels&fmt=json", + "time": 376, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/6.1.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/helpers/client/cover-art-archive.js b/test/helpers/client/cover-art-archive.js index 0c509bd..af978a8 100644 --- a/test/helpers/client/cover-art-archive.js +++ b/test/helpers/client/cover-art-archive.js @@ -1,6 +1,6 @@ import path from 'path' import sepia from 'sepia' -import { CoverArtArchive } from '../../../src/api' +import CoverArtArchiveClient from '../../../src/extensions/cover-art-archive/client' sepia.fixtureDir(path.join(__dirname, '..', '..', 'fixtures')) @@ -8,4 +8,4 @@ const options = process.env.VCR_MODE === 'playback' ? { limit: Infinity, period: 0 } : {} -export default new CoverArtArchive(options) +export default new CoverArtArchiveClient(options) diff --git a/test/helpers/context.js b/test/helpers/context.js index e530fba..0dd5688 100644 --- a/test/helpers/context.js +++ b/test/helpers/context.js @@ -1,9 +1,7 @@ import createLoaders from '../../src/loaders' import client from './client/musicbrainz' -import coverArtClient from './client/cover-art-archive' export default { client, - coverArtClient, - loaders: createLoaders(client, coverArtClient) + loaders: createLoaders(client) } diff --git a/test/schema.js b/test/schema.js index fffb6ef..d735ed9 100644 --- a/test/schema.js +++ b/test/schema.js @@ -1145,224 +1145,3 @@ test('entities support tags', testData, ` t.true(artists[0].tags.edges.some(edge => edge.node.name === 'blues rock')) t.true(artists[0].tags.edges.some(edge => edge.node.count > 0)) }) - -test('releases have a cover art summary', testData, ` - { - lookup { - release(mbid: "b84ee12a-09ef-421b-82de-0441a926375b") { - coverArt { - artwork - darkened - count - } - } - } - } -`, (t, data) => { - const { coverArt } = data.lookup.release - t.true(coverArt.artwork) - t.false(coverArt.darkened) - t.true(coverArt.count >= 10) -}) - -test('releases have a set of cover art images', testData, ` - { - lookup { - release(mbid: "b84ee12a-09ef-421b-82de-0441a926375b") { - coverArt { - front - back - images { - front - back - types - approved - edit - comment - fileID - image - thumbnails { - small - large - } - } - } - } - } - } -`, (t, data) => { - const { coverArt } = data.lookup.release - t.is(coverArt.front, 'http://archive.org/download/mbid-b84ee12a-09ef-421b-82de-0441a926375b/mbid-b84ee12a-09ef-421b-82de-0441a926375b-1611507818.jpg') - t.is(coverArt.back, 'http://archive.org/download/mbid-b84ee12a-09ef-421b-82de-0441a926375b/mbid-b84ee12a-09ef-421b-82de-0441a926375b-13536418798.jpg') - t.true(coverArt.images.length >= 10) - t.true(coverArt.images.some(image => image.front === true)) - t.true(coverArt.images.some(image => image.back === true)) - t.true(coverArt.images.some(image => image.types.indexOf('Front') >= 0)) - t.true(coverArt.images.some(image => image.types.indexOf('Back') >= 0)) - t.true(coverArt.images.some(image => image.types.indexOf('Liner') >= 0)) - t.true(coverArt.images.some(image => image.types.indexOf('Poster') >= 0)) - t.true(coverArt.images.some(image => image.types.indexOf('Medium') >= 0)) - t.true(coverArt.images.some(image => image.edit === 18544122)) - t.true(coverArt.images.some(image => image.comment === '')) - t.true(coverArt.images.some(image => image.fileID === '1611507818')) - t.true(coverArt.images.some(image => image.image === 'http://coverartarchive.org/release/b84ee12a-09ef-421b-82de-0441a926375b/13536422691.jpg')) - t.true(coverArt.images.every(image => image.approved === true)) - t.true(coverArt.images.every(image => image.thumbnails.small)) - t.true(coverArt.images.every(image => image.thumbnails.large)) -}) - -test('can request a size for front and back cover art', testData, ` - { - lookup { - release(mbid: "b84ee12a-09ef-421b-82de-0441a926375b") { - coverArt { - front(size: LARGE) - back(size: SMALL) - fullFront: front(size: FULL) - } - } - } - } -`, (t, data) => { - const { coverArt } = data.lookup.release - t.is(coverArt.front, 'http://archive.org/download/mbid-b84ee12a-09ef-421b-82de-0441a926375b/mbid-b84ee12a-09ef-421b-82de-0441a926375b-1611507818_thumb500.jpg') - t.is(coverArt.back, 'http://archive.org/download/mbid-b84ee12a-09ef-421b-82de-0441a926375b/mbid-b84ee12a-09ef-421b-82de-0441a926375b-13536418798_thumb250.jpg') - t.is(coverArt.fullFront, 'http://archive.org/download/mbid-b84ee12a-09ef-421b-82de-0441a926375b/mbid-b84ee12a-09ef-421b-82de-0441a926375b-1611507818.jpg') -}) - -test('release groups have a front cover art image', testData, ` - { - lookup { - releaseGroup(mbid: "f5093c06-23e3-404f-aeaa-40f72885ee3a") { - coverArt { - artwork - front - images { - front - image - } - release { - mbid - title - } - } - } - } - } -`, (t, data) => { - const { coverArt } = data.lookup.releaseGroup - t.true(coverArt.artwork) - t.is(coverArt.front, 'http://coverartarchive.org/release/25fbfbb4-b1ee-4448-aadf-ae3bc2e2dd27/1675312275.jpg') - t.is(coverArt.release.mbid, '25fbfbb4-b1ee-4448-aadf-ae3bc2e2dd27') - t.is(coverArt.release.title, 'The Dark Side of the Moon') - t.is(coverArt.images.length, 1) - t.true(coverArt.images[0].front) -}) - -test('release groups have different cover art sizes available', testData, ` - { - lookup { - releaseGroup(mbid: "f5093c06-23e3-404f-aeaa-40f72885ee3a") { - coverArt { - small: front(size: SMALL) - large: front(size: LARGE) - } - } - } - } -`, (t, data) => { - const { coverArt } = data.lookup.releaseGroup - t.is(coverArt.small, 'http://coverartarchive.org/release/25fbfbb4-b1ee-4448-aadf-ae3bc2e2dd27/1675312275-250.jpg') - t.is(coverArt.large, 'http://coverartarchive.org/release/25fbfbb4-b1ee-4448-aadf-ae3bc2e2dd27/1675312275-500.jpg') -}) - -test('can retrieve cover art in searches', testData, ` - { - search { - releases(query: "You Want It Darker") { - edges { - node { - coverArt { - artwork - darkened - front - back - images { - image - } - } - } - } - } - } - } -`, (t, data) => { - const releases = data.search.releases.edges.map(edge => edge.node) - t.is(releases.length, 25) - t.true(releases.some(release => release.coverArt.artwork === true)) - t.true(releases.every(release => release.coverArt.darkened === false)) - t.true(releases.some(release => release.coverArt.images.length > 0)) - t.true(releases.some(release => release.coverArt.front === null)) - t.true(releases.some(release => release.coverArt.back === null)) -}) - -test('cover art release field does not make a request unless necessary', testData, ` - { - lookup { - release(mbid: "b84ee12a-09ef-421b-82de-0441a926375b") { - coverArt { - release { - mbid - } - } - } - } - } -`, (t, data) => { - // TODO: Add ability to check how many requests were made to fulfill a query. - const { coverArt } = data.lookup.release - t.is(coverArt.release.mbid, 'b84ee12a-09ef-421b-82de-0441a926375b') -}) - -test('cover art fields can be calculated instead of making another request', testData, ` - { - search { - releases(query: "reid:b84ee12a-09ef-421b-82de-0441a926375b", first: 1) { - edges { - node { - coverArt { - artwork - count - } - } - } - } - } - } -`, (t, data) => { - // TODO: Add ability to check how many requests were made to fulfill a query. - const releases = data.search.releases.edges.map(edge => edge.node) - t.is(releases.length, 1) - t.true(releases[0].coverArt.artwork) - t.is(releases[0].coverArt.count, 10) -}) - -test('cover art is not fetched if the count is 0', testData, ` - { - lookup { - release(mbid: "c0f74d5a-7534-414d-8b90-0ebe6c5da19e") { - coverArt { - count - images { - image - } - } - } - } - } -`, (t, data) => { - // TODO: Add ability to check how many requests were made to fulfill a query. - const { coverArt } = data.lookup.release - t.is(coverArt.count, 0) - t.deepEqual(coverArt.images, []) -}) diff --git a/yarn.lock b/yarn.lock index fc83b22..ef8a867 100644 --- a/yarn.lock +++ b/yarn.lock @@ -157,6 +157,17 @@ anymatch@^1.3.0: arrify "^1.0.0" micromatch "^2.1.5" +apollo-link@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/apollo-link/-/apollo-link-0.8.0.tgz#efce6b35ae9ea5f6966a87054ba4893a5b6d960a" + dependencies: + apollo-utilities "^0.2.0-beta.0" + zen-observable "^0.6.0" + +apollo-utilities@^0.2.0-beta.0: + version "0.2.0-rc.0" + resolved "https://registry.yarnpkg.com/apollo-utilities/-/apollo-utilities-0.2.0-rc.0.tgz#5ac93a839c5688e8f655dc7d5789a5d878f4351f" + append-transform@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-0.4.0.tgz#d76ebf8ca94d276e247a36bad44a4b74ab611991" @@ -1705,6 +1716,10 @@ decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" +deep-diff@^0.3.8: + version "0.3.8" + resolved "https://registry.yarnpkg.com/deep-diff/-/deep-diff-0.3.8.tgz#c01de63efb0eec9798801d40c7e0dae25b582c84" + deep-equal@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" @@ -1769,6 +1784,10 @@ depd@1.1.1, depd@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" +deprecated-decorator@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/deprecated-decorator/-/deprecated-decorator-0.1.6.tgz#00966317b7a12fe92f3cc831f7583af329b86c37" + destroy@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" @@ -2602,10 +2621,11 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.4: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" -graphql-markdown@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/graphql-markdown/-/graphql-markdown-2.2.0.tgz#8f3feb29c5368fea6fa922571b3cf3562109ab5c" +graphql-markdown@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/graphql-markdown/-/graphql-markdown-3.1.0.tgz#ff8fb91864388b359622f92637c8f1edbee70618" dependencies: + deep-diff "^0.3.8" graphql "^0.11.7" minimist "^1.2.0" node-fetch "^1.7.1" @@ -2615,6 +2635,14 @@ graphql-relay@^0.5.2: version "0.5.3" resolved "https://registry.yarnpkg.com/graphql-relay/-/graphql-relay-0.5.3.tgz#56a78ac07c87d89795a34db6b8e9681b827be5b5" +graphql-tools@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/graphql-tools/-/graphql-tools-2.5.1.tgz#542c48d4f9a532e09280ae216084813ea7ba4b18" + dependencies: + apollo-link "^0.8.0" + deprecated-decorator "^0.1.6" + uuid "^3.1.0" + graphql@^0.11.7: version "0.11.7" resolved "https://registry.yarnpkg.com/graphql/-/graphql-0.11.7.tgz#e5abaa9cb7b7cccb84e9f0836bf4370d268750c6" @@ -5384,3 +5412,7 @@ yargs@~3.10.0: cliui "^2.1.0" decamelize "^1.0.0" window-size "0.1.0" + +zen-observable@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.6.0.tgz#8a6157ed15348d185d948cfc4a59d90a2c0f70ee"