Add support for cover art via the Cover Art Archive (#17)

This commit is contained in:
Brian Beck 2016-12-19 21:21:07 -08:00 committed by GitHub
parent bbf2ab6c30
commit 4cac7ac76c
215 changed files with 3451 additions and 123 deletions

View file

@ -36,6 +36,7 @@
"test:coverage": "cross-env NODE_ENV=test nyc npm run test:only",
"test:only": "cross-env VCR_MODE=playback ava",
"test:record": "cross-env VCR_MODE=record ava",
"test:record-new": "cross-env VCR_MODE=cache ava --serial",
"test:watch": "npm run test:only -- --watch",
"update-schema": "npm run -s print-schema:json > schema.json"
},

View file

@ -1,11 +1,10 @@
import request from 'request'
import retry from 'retry'
import qs from 'qs'
import ExtendableError from 'es6-error'
import RateLimit from './rate-limit'
import pkg from '../package.json'
import RateLimit from '../rate-limit'
import pkg from '../../package.json'
const debug = require('debug')('graphbrainz:api')
const debug = require('debug')('graphbrainz:api/client')
// If the `request` callback returns an error, it indicates a failure at a lower
// level than the HTTP response itself. If it's any of the following error
@ -21,19 +20,20 @@ const RETRY_CODES = {
EAI_AGAIN: true
}
export class MusicBrainzError extends ExtendableError {
export class ClientError extends ExtendableError {
constructor (message, statusCode) {
super(message)
this.statusCode = statusCode
}
}
export default class MusicBrainz {
export default class Client {
constructor ({
baseURL = process.env.MUSICBRAINZ_BASE_URL || 'http://musicbrainz.org/ws/2/',
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
@ -41,8 +41,8 @@ export default class MusicBrainz {
// 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,
limit = 1,
period = 1000,
concurrency = 10,
retries = 10,
// It's OK for `retryDelayMin` to be less than one second, even 0, because
@ -57,6 +57,7 @@ export default class MusicBrainz {
this.baseURL = baseURL
this.userAgent = userAgent
this.extraHeaders = extraHeaders
this.errorClass = errorClass
this.timeout = timeout
this.limiter = new RateLimit({ limit, period, concurrency })
this.retryOptions = {
@ -73,36 +74,48 @@ export default class MusicBrainz {
* `RETRY_CODES`.
*/
shouldRetry (err) {
if (err instanceof MusicBrainzError) {
if (err instanceof this.errorClass) {
return err.statusCode >= 500 && err.statusCode < 600
}
return RETRY_CODES[err.code] || false
}
parseErrorMessage (response, body) {
return typeof body === 'string' && body ? body : `${response.statusCode}`
}
/**
* Send a request without any retrying or rate limiting.
* Use `get` instead.
*/
_get (path, params, info = {}) {
_get (path, options = {}, info = {}) {
return new Promise((resolve, reject) => {
const options = {
options = {
baseUrl: this.baseURL,
url: path,
qs: { ...params, fmt: 'json' },
json: true,
gzip: true,
headers: { 'User-Agent': this.userAgent, ...this.extraHeaders },
timeout: this.timeout
timeout: this.timeout,
...options,
headers: {
'User-Agent': this.userAgent,
...this.extraHeaders,
...options.headers
}
}
debug(`Sending request. url=${path} attempt=${info.currentAttempt}`)
debug(`Sending request. url=${this.baseURL}${path} attempt=${info.currentAttempt}`)
request(options, (err, response, body) => {
if (err) {
debug(`Error: “${err}” url=${this.baseURL}${path}`)
reject(err)
} else if (response.statusCode !== 200) {
const message = (body && body.error) || ''
reject(new MusicBrainzError(message, response.statusCode))
} else if (response.statusCode >= 400) {
const message = this.parseErrorMessage(response, body)
debug(`Error: “${message}” url=${this.baseURL}${path}`)
const ClientError = this.errorClass
reject(new ClientError(message, response.statusCode))
} else if (options.method === 'HEAD') {
resolve(response.headers)
} else {
resolve(body)
}
@ -113,7 +126,7 @@ export default class MusicBrainz {
/**
* Send a request with retrying and rate limiting.
*/
get (path, params) {
get (path, options = {}) {
return new Promise((resolve, reject) => {
const fn = this._get.bind(this)
const operation = retry.operation(this.retryOptions)
@ -121,7 +134,7 @@ export default class MusicBrainz {
// This will increase the priority in our `RateLimit` queue for each
// retry, so that newer requests don't delay this one further.
const priority = currentAttempt
this.limiter.enqueue(fn, [path, params, { currentAttempt }], priority)
this.limiter.enqueue(fn, [path, options, { currentAttempt }], priority)
.then(resolve)
.catch(err => {
if (!this.shouldRetry(err) || !operation.retry(err)) {
@ -131,64 +144,4 @@ export default class MusicBrainz {
})
})
}
stringifyParams (params) {
if (Array.isArray(params.inc)) {
params = {
...params,
inc: params.inc.join('+')
}
}
if (Array.isArray(params.type)) {
params = {
...params,
type: params.type.join('|')
}
}
if (Array.isArray(params.status)) {
params = {
...params,
status: params.status.join('|')
}
}
return qs.stringify(params, {
skipNulls: true,
filter: (key, value) => value === '' ? undefined : value
})
}
getURL (path, params) {
const query = params ? this.stringifyParams(params) : ''
return query ? `${path}?${query}` : path
}
getLookupURL (entity, id, params) {
if (id == null) {
return this.getBrowseURL(entity, params)
}
return this.getURL(`${entity}/${id}`, params)
}
lookup (entity, id, params = {}) {
const url = this.getLookupURL(entity, id, params)
return this.get(url)
}
getBrowseURL (entity, params) {
return this.getURL(entity, params)
}
browse (entity, params = {}) {
const url = this.getBrowseURL(entity, params)
return this.get(url)
}
getSearchURL (entity, query, params) {
return this.getURL(entity, { ...params, query })
}
search (entity, query, params = {}) {
const url = this.getSearchURL(entity, query, params)
return this.get(url)
}
}

View file

@ -0,0 +1,47 @@
import Client, { ClientError } from './client'
export class CoverArtArchiveError extends ClientError {}
export default class CoverArtArchive 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 })
}
parseErrorMessage (response, body) {
if (typeof body === 'string' && body.startsWith('<!')) {
const heading = /<h1>([^<]+)<\/h1>/i.exec(body)
const message = /<p>([^<]+)<\/p>/i.exec(body)
return `${heading ? heading[1] + ': ' : ''}${message ? message[1] : ''}`
}
return super.parseErrorMessage(response, body)
}
getImagesURL (entity, mbid) {
return `${entity}/${mbid}`
}
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}`
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)
}
}

10
src/api/index.js Normal file
View file

@ -0,0 +1,10 @@
import MusicBrainz, { MusicBrainzError } from './musicbrainz'
import CoverArtArchive, { CoverArtArchiveError } from './cover-art-archive'
export {
MusicBrainz as default,
MusicBrainz,
MusicBrainzError,
CoverArtArchive,
CoverArtArchiveError
}

83
src/api/musicbrainz.js Normal file
View file

@ -0,0 +1,83 @@
import qs from 'qs'
import Client, { ClientError } from './client'
export class MusicBrainzError extends ClientError {}
export default class MusicBrainz extends Client {
constructor ({
baseURL = process.env.MUSICBRAINZ_BASE_URL || 'http://musicbrainz.org/ws/2/',
errorClass = MusicBrainzError,
limit = 5,
period = 5500,
...options
} = {}) {
super({ baseURL, errorClass, limit, period, ...options })
}
parseErrorMessage (response, body) {
if (body && body.error) {
return body.error
}
return super.parseErrorMessage(response, body)
}
stringifyParams (params) {
if (Array.isArray(params.inc)) {
params = {
...params,
inc: params.inc.join('+')
}
}
if (Array.isArray(params.type)) {
params = {
...params,
type: params.type.join('|')
}
}
if (Array.isArray(params.status)) {
params = {
...params,
status: params.status.join('|')
}
}
return qs.stringify(params, {
skipNulls: true,
filter: (key, value) => value === '' ? undefined : value
})
}
getURL (path, params) {
const query = params ? this.stringifyParams(params) : ''
return query ? `${path}?${query}` : path
}
getLookupURL (entity, id, params) {
if (id == null) {
return this.getBrowseURL(entity, params)
}
return this.getURL(`${entity}/${id}`, params)
}
lookup (entity, id, params = {}) {
const url = this.getLookupURL(entity, id, params)
return this.get(url, { json: true, qs: { fmt: 'json' } })
}
getBrowseURL (entity, params) {
return this.getURL(entity, params)
}
browse (entity, params = {}) {
const url = this.getBrowseURL(entity, params)
return this.get(url, { json: true, qs: { fmt: 'json' } })
}
getSearchURL (entity, query, params) {
return this.getURL(entity, { ...params, query })
}
search (entity, query, params = {}) {
const url = this.getSearchURL(entity, query, params)
return this.get(url, { json: true, qs: { fmt: 'json' } })
}
}

View file

@ -1,7 +1,7 @@
import express from 'express'
import graphqlHTTP from 'express-graphql'
import compression from 'compression'
import MusicBrainz from './api'
import MusicBrainz, { CoverArtArchive } from './api'
import schema from './schema'
import createLoaders from './loaders'
@ -11,13 +11,17 @@ const formatError = (err) => ({
stack: err.stack
})
const middleware = ({ client = new MusicBrainz(), ...options } = {}) => {
const middleware = ({
client = new MusicBrainz(),
coverArtClient = new CoverArtArchive(),
...options
} = {}) => {
const DEV = process.env.NODE_ENV !== 'production'
const graphiql = DEV || process.env.GRAPHBRAINZ_GRAPHIQL === 'true'
const loaders = createLoaders(client)
const loaders = createLoaders(client, coverArtClient)
return graphqlHTTP({
schema,
context: { client, loaders },
context: { client, coverArtClient, loaders },
pretty: DEV,
graphiql,
formatError: DEV ? formatError : undefined,

View file

@ -5,7 +5,7 @@ import { toPlural } from './types/helpers'
const debug = require('debug')('graphbrainz:loaders')
const ONE_DAY = 24 * 60 * 60 * 1000
export default function createLoaders (client) {
export default function createLoaders (client, coverArtClient) {
// All loaders share a single LRU cache that will remember 8192 responses,
// each cached for 1 day.
const cache = LRUCache({
@ -27,23 +27,6 @@ export default function createLoaders (client) {
// Store the entity type so we can determine what type of object this
// is elsewhere in the code.
entity._type = entityType
entity._inc = params.inc
if (entityType === 'discid' && entity.releases) {
entity.releases.forEach(release => {
release._type = 'release'
release._inc = params.inc
})
} else if (entityType === 'isrc' && entity.recordings) {
entity.recordings.forEach(recording => {
recording._type = 'recording'
recording._inc = params.inc
})
} else if (entityType === 'iswc' && entity.works) {
entity.works.forEach(work => {
work._type = 'work'
work._inc = params.inc
})
}
}
return entity
})
@ -61,7 +44,6 @@ export default function createLoaders (client) {
// Store the entity type so we can determine what type of object this
// is elsewhere in the code.
entity._type = entityType
entity._inc = params.inc
})
return list
})
@ -79,15 +61,45 @@ export default function createLoaders (client) {
// Store the entity type so we can determine what type of object this
// is elsewhere in the code.
entity._type = entityType
entity._inc = params.inc
})
return list
})
}))
}, {
cacheKeyFn: (key) => client.getSearchURL(...key),
cacheKeyFn: key => client.getSearchURL(...key),
cacheMap: cache
})
return { lookup, browse, search }
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 }
}

View file

@ -0,0 +1,72 @@
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 Archives 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.'
}
})
})

188
src/types/cover-art.js Normal file
View file

@ -0,0 +1,188 @@
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 releases 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 releases 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 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 releases 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()
})
})

View file

@ -39,6 +39,29 @@ distinctive name.`,
}
})
export const CoverArtImageSize = new GraphQLEnumType({
name: 'CoverArtImageSize',
description: `The image sizes that may be requested at the [Cover Art
Archive](https://musicbrainz.org/doc/Cover_Art_Archive).`,
values: {
SMALL: {
name: 'Small',
description: 'A maximum dimension of 250px.',
value: 250
},
LARGE: {
name: 'Large',
description: 'A maximum dimension of 500px.',
value: 500
},
FULL: {
name: 'Full',
description: 'The images original dimensions, with no maximum.',
value: null
}
}
})
export const ReleaseStatus = new GraphQLEnumType({
name: 'ReleaseStatus',
description: `A type used to describe the status of releases, e.g. official,

View file

@ -1,6 +1,7 @@
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 {
@ -58,6 +59,14 @@ 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,

View file

@ -1,8 +1,14 @@
import { GraphQLObjectType, GraphQLString, GraphQLList } from 'graphql/type'
import {
GraphQLObjectType,
GraphQLNonNull,
GraphQLString,
GraphQLList
} from 'graphql/type'
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 {
@ -68,6 +74,19 @@ 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.'

9
test/api/client.js Normal file
View file

@ -0,0 +1,9 @@
import test from 'ava'
import Client from '../../src/api/client'
test('parseErrorMessage() returns the body or status code', t => {
const client = new Client()
t.is(client.parseErrorMessage({ statusCode: 500 }, 'something went wrong'), 'something went wrong')
t.is(client.parseErrorMessage({ statusCode: 500 }, ''), '500')
t.is(client.parseErrorMessage({ statusCode: 404 }, {}), '404')
})

View file

@ -0,0 +1,47 @@
import test from 'ava'
import { CoverArtArchiveError } from '../../src/api'
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')
.then(url => {
t.is(url, 'http://archive.org/download/mbid-76df3287-6cda-33eb-8e9a-044b5e15ffdd/mbid-76df3287-6cda-33eb-8e9a-044b5e15ffdd-829521842.jpg')
})
})
test('can retrieve a back image URL', t => {
return client.imageURL('release', '76df3287-6cda-33eb-8e9a-044b5e15ffdd', 'back')
.then(url => {
t.is(url, 'http://archive.org/download/mbid-76df3287-6cda-33eb-8e9a-044b5e15ffdd/mbid-76df3287-6cda-33eb-8e9a-044b5e15ffdd-5769317885.jpg')
})
})
test('can retrieve a list of release images', t => {
return client.images('release', '76df3287-6cda-33eb-8e9a-044b5e15ffdd')
.then(data => {
t.is(data.release, 'http://musicbrainz.org/release/76df3287-6cda-33eb-8e9a-044b5e15ffdd')
t.true(data.images.length >= 3)
data.images.forEach(image => {
t.true(image.approved)
t.truthy(image.image)
t.truthy(image.id)
t.truthy(image.thumbnails.small)
t.truthy(image.thumbnails.large)
})
t.true(data.images.some(image => image.front))
t.true(data.images.some(image => image.back))
t.true(data.images.some(image => image.types.indexOf('Front') !== -1))
t.true(data.images.some(image => image.types.indexOf('Back') !== -1))
t.true(data.images.some(image => image.types.indexOf('Medium') !== -1))
})
})
test('throws an error if given an invalid MBID', t => {
return t.throws(client.images('release', 'xyz'), CoverArtArchiveError)
})
test('uses the default error impementation if there is no HTML error', t => {
t.is(client.parseErrorMessage({ statusCode: 501 }, 'yikes'), 'yikes')
t.is(client.parseErrorMessage({ statusCode: 500 }, ''), '500')
t.is(client.parseErrorMessage({ statusCode: 404 }, null), '404')
})

View file

@ -1,6 +1,6 @@
import test from 'ava'
import MusicBrainz, { MusicBrainzError } from '../src/api'
import client from './helpers/client'
import MusicBrainz, { MusicBrainzError } from '../../src/api'
import client from '../helpers/client/musicbrainz'
test('getLookupURL() generates a lookup URL', t => {
t.is(client.getLookupURL('artist', 'c8da2e40-bd28-4d4e-813a-bd2f51958ba8', {
@ -62,3 +62,9 @@ test('rejects non-MusicBrainz errors', t => {
const client = new MusicBrainz({ baseURL: '$!@#$' })
t.throws(client.get('artist/5b11f4ce-a62d-471e-81fc-a69a8278c7da'), Error)
})
test('uses the default error impementation if there is no JSON error', t => {
t.is(client.parseErrorMessage({ statusCode: 501 }, 'yikes'), 'yikes')
t.is(client.parseErrorMessage({ statusCode: 500 }, {}), '500')
t.is(client.parseErrorMessage({ statusCode: 404 }, null), '404')
})

View file

@ -0,0 +1 @@
See: http://archive.org/download/mbid-76df3287-6cda-33eb-8e9a-044b5e15ffdd/index.json

View file

@ -0,0 +1,24 @@
{
"statusCode": 307,
"headers": {
"date": "Tue, 20 Dec 2016 01:37:47 GMT",
"content-type": "text/plain; charset=utf-8",
"content-length": "86",
"connection": "keep-alive",
"keep-alive": "timeout=15",
"location": "http://archive.org/download/mbid-76df3287-6cda-33eb-8e9a-044b5e15ffdd/index.json",
"access-control-allow-origin": "*",
"server": "4b4c084fb141"
},
"url": "http://coverartarchive.org:80/release/76df3287-6cda-33eb-8e9a-044b5e15ffdd",
"time": 372,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"host": "coverartarchive.org",
"accept-encoding": "gzip, deflate",
"accept": "application/json"
}
}
}

View file

@ -0,0 +1 @@
{"images":[{"edit":41326273,"back":false,"approved":true,"comment":"","types":["Front"],"thumbnails":{"small":"http://coverartarchive.org/release/d5cdb7fd-c7e9-460a-9549-8a369655cc52/14955061405-250.jpg","large":"http://coverartarchive.org/release/d5cdb7fd-c7e9-460a-9549-8a369655cc52/14955061405-500.jpg"},"front":true,"id":"14955061405","image":"http://coverartarchive.org/release/d5cdb7fd-c7e9-460a-9549-8a369655cc52/14955061405.jpg"},{"approved":true,"back":true,"edit":41326275,"id":"14955062822","front":false,"image":"http://coverartarchive.org/release/d5cdb7fd-c7e9-460a-9549-8a369655cc52/14955062822.jpg","thumbnails":{"small":"http://coverartarchive.org/release/d5cdb7fd-c7e9-460a-9549-8a369655cc52/14955062822-250.jpg","large":"http://coverartarchive.org/release/d5cdb7fd-c7e9-460a-9549-8a369655cc52/14955062822-500.jpg"},"comment":"","types":["Back","Spine"]},{"id":"14955064370","front":false,"image":"http://coverartarchive.org/release/d5cdb7fd-c7e9-460a-9549-8a369655cc52/14955064370.jpg","thumbnails":{"large":"http://coverartarchive.org/release/d5cdb7fd-c7e9-460a-9549-8a369655cc52/14955064370-500.jpg","small":"http://coverartarchive.org/release/d5cdb7fd-c7e9-460a-9549-8a369655cc52/14955064370-250.jpg"},"types":["Tray"],"comment":"","approved":true,"back":false,"edit":41326278},{"edit":41326288,"approved":true,"back":false,"thumbnails":{"large":"http://coverartarchive.org/release/d5cdb7fd-c7e9-460a-9549-8a369655cc52/14955066041-500.jpg","small":"http://coverartarchive.org/release/d5cdb7fd-c7e9-460a-9549-8a369655cc52/14955066041-250.jpg"},"comment":"","types":["Booklet"],"image":"http://coverartarchive.org/release/d5cdb7fd-c7e9-460a-9549-8a369655cc52/14955066041.jpg","id":"14955066041","front":false},{"edit":41326294,"back":false,"approved":true,"comment":"","types":["Booklet"],"thumbnails":{"small":"http://coverartarchive.org/release/d5cdb7fd-c7e9-460a-9549-8a369655cc52/14955068047-250.jpg","large":"http://coverartarchive.org/release/d5cdb7fd-c7e9-460a-9549-8a369655cc52/14955068047-500.jpg"},"image":"http://coverartarchive.org/release/d5cdb7fd-c7e9-460a-9549-8a369655cc52/14955068047.jpg","front":false,"id":"14955068047"},{"front":false,"id":"14955069655","image":"http://coverartarchive.org/release/d5cdb7fd-c7e9-460a-9549-8a369655cc52/14955069655.jpg","types":["Booklet"],"comment":"","thumbnails":{"large":"http://coverartarchive.org/release/d5cdb7fd-c7e9-460a-9549-8a369655cc52/14955069655-500.jpg","small":"http://coverartarchive.org/release/d5cdb7fd-c7e9-460a-9549-8a369655cc52/14955069655-250.jpg"},"back":false,"approved":true,"edit":41326297},{"approved":true,"back":false,"edit":41326303,"image":"http://coverartarchive.org/release/d5cdb7fd-c7e9-460a-9549-8a369655cc52/14955071842.jpg","id":"14955071842","front":false,"thumbnails":{"small":"http://coverartarchive.org/release/d5cdb7fd-c7e9-460a-9549-8a369655cc52/14955071842-250.jpg","large":"http://coverartarchive.org/release/d5cdb7fd-c7e9-460a-9549-8a369655cc52/14955071842-500.jpg"},"comment":"","types":["Booklet"]},{"types":["Booklet"],"comment":"","thumbnails":{"small":"http://coverartarchive.org/release/d5cdb7fd-c7e9-460a-9549-8a369655cc52/14955073836-250.jpg","large":"http://coverartarchive.org/release/d5cdb7fd-c7e9-460a-9549-8a369655cc52/14955073836-500.jpg"},"front":false,"id":"14955073836","image":"http://coverartarchive.org/release/d5cdb7fd-c7e9-460a-9549-8a369655cc52/14955073836.jpg","edit":41326306,"back":false,"approved":true},{"edit":41326325,"back":false,"approved":true,"comment":"","types":["Booklet"],"thumbnails":{"large":"http://coverartarchive.org/release/d5cdb7fd-c7e9-460a-9549-8a369655cc52/14955075724-500.jpg","small":"http://coverartarchive.org/release/d5cdb7fd-c7e9-460a-9549-8a369655cc52/14955075724-250.jpg"},"front":false,"id":"14955075724","image":"http://coverartarchive.org/release/d5cdb7fd-c7e9-460a-9549-8a369655cc52/14955075724.jpg"},{"edit":41538992,"approved":true,"back":false,"thumbnails":{"small":"http://coverartarchive.org/release/d5cdb7fd-c7e9-460a-9549-8a369655cc52/15067760321-250.jpg","large":"http://coverartarchive.org/release/d5cdb7fd-c7e9-460a-9549-8a369655cc52/15067760321-500.jpg"},"comment":"Sticker","types":["Sticker"],"image":"http://coverartarchive.org/release/d5cdb7fd-c7e9-460a-9549-8a369655cc52/15067760321.jpg","id":"15067760321","front":false},{"id":"15067761190","front":false,"image":"http://coverartarchive.org/release/d5cdb7fd-c7e9-460a-9549-8a369655cc52/15067761190.jpg","thumbnails":{"large":"http://coverartarchive.org/release/d5cdb7fd-c7e9-460a-9549-8a369655cc52/15067761190-500.jpg","small":"http://coverartarchive.org/release/d5cdb7fd-c7e9-460a-9549-8a369655cc52/15067761190-250.jpg"},"comment":"CD","types":["Medium"],"approved":true,"back":false,"edit":41538996}],"release":"https://musicbrainz.org/release/d5cdb7fd-c7e9-460a-9549-8a369655cc52"}

View file

@ -0,0 +1,27 @@
{
"statusCode": 200,
"headers": {
"server": "nginx/1.4.6 (Ubuntu)",
"date": "Tue, 20 Dec 2016 01:39:56 GMT",
"content-type": "application/json",
"content-length": "4829",
"last-modified": "Fri, 04 Nov 2016 08:01:44 GMT",
"connection": "keep-alive",
"etag": "\"581c4068-12dd\"",
"expires": "Tue, 20 Dec 2016 07:39:56 GMT",
"cache-control": "max-age=21600",
"accept-ranges": "bytes"
},
"url": "http://ia601203.us.archive.org:80/29/items/mbid-d5cdb7fd-c7e9-460a-9549-8a369655cc52/index.json",
"time": 155,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"accept-encoding": "gzip, deflate",
"accept": "application/json",
"referer": "http://archive.org/download/mbid-d5cdb7fd-c7e9-460a-9549-8a369655cc52/index.json",
"host": "ia601203.us.archive.org"
}
}
}

View file

@ -0,0 +1 @@
See: http://archive.org/download/mbid-dd15903e-0ee7-45ec-aba1-2fc7b3a44e19/index.json

View file

@ -0,0 +1,24 @@
{
"statusCode": 307,
"headers": {
"date": "Tue, 20 Dec 2016 01:39:55 GMT",
"content-type": "text/plain; charset=utf-8",
"content-length": "86",
"connection": "keep-alive",
"keep-alive": "timeout=15",
"location": "http://archive.org/download/mbid-dd15903e-0ee7-45ec-aba1-2fc7b3a44e19/index.json",
"access-control-allow-origin": "*",
"server": "d6446ea62189"
},
"url": "http://coverartarchive.org:80/release/dd15903e-0ee7-45ec-aba1-2fc7b3a44e19",
"time": 414,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"host": "coverartarchive.org",
"accept-encoding": "gzip, deflate",
"accept": "application/json"
}
}
}

View file

View file

@ -0,0 +1,25 @@
{
"statusCode": 302,
"headers": {
"server": "nginx/1.4.6 (Ubuntu)",
"date": "Tue, 20 Dec 2016 01:37:47 GMT",
"content-type": "text/html; charset=UTF-8",
"transfer-encoding": "chunked",
"connection": "keep-alive",
"x-powered-by": "PHP/5.5.9-1ubuntu4.20",
"accept-ranges": "bytes",
"location": "http://ia802607.us.archive.org/32/items/mbid-76df3287-6cda-33eb-8e9a-044b5e15ffdd/index.json"
},
"url": "http://archive.org:80/download/mbid-76df3287-6cda-33eb-8e9a-044b5e15ffdd/index.json",
"time": 139,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"accept-encoding": "gzip, deflate",
"accept": "application/json",
"referer": "http://coverartarchive.org/release/76df3287-6cda-33eb-8e9a-044b5e15ffdd",
"host": "archive.org"
}
}
}

Binary file not shown.

View file

@ -0,0 +1,29 @@
{
"statusCode": 200,
"headers": {
"date": "Tue, 20 Dec 2016 01:40: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": "700",
"x-ratelimit-remaining": "577",
"x-ratelimit-reset": "1482198012",
"server": "Plack::Handler::Starlet",
"etag": "W/\"0c725784e392aef95ce4df262002a059\"",
"access-control-allow-origin": "*",
"content-encoding": "gzip"
},
"url": "http://musicbrainz.org:80/ws/2/release/3e2c779e-16e8-459e-8791-2da47a92dce6?fmt=json",
"time": 415,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"host": "musicbrainz.org",
"accept-encoding": "gzip, deflate",
"accept": "application/json"
}
}
}

View file

View file

@ -0,0 +1,25 @@
{
"statusCode": 302,
"headers": {
"server": "nginx/1.4.6 (Ubuntu)",
"date": "Tue, 20 Dec 2016 01:39:57 GMT",
"content-type": "text/html; charset=UTF-8",
"transfer-encoding": "chunked",
"connection": "keep-alive",
"x-powered-by": "PHP/5.5.9-1ubuntu4.20",
"accept-ranges": "bytes",
"location": "http://ia600509.us.archive.org/33/items/mbid-fb98043c-7ac8-4505-ba87-28576836a8d5/index.json"
},
"url": "http://archive.org:80/download/mbid-fb98043c-7ac8-4505-ba87-28576836a8d5/index.json",
"time": 178,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"accept-encoding": "gzip, deflate",
"accept": "application/json",
"referer": "http://coverartarchive.org/release/fb98043c-7ac8-4505-ba87-28576836a8d5",
"host": "archive.org"
}
}
}

Binary file not shown.

View file

@ -0,0 +1,29 @@
{
"statusCode": 200,
"headers": {
"date": "Tue, 20 Dec 2016 01:40: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": "700",
"x-ratelimit-remaining": "423",
"x-ratelimit-reset": "1482198006",
"server": "Plack::Handler::Starlet",
"etag": "W/\"3467a86d0b1b88d5eccfdd5223cf828a\"",
"access-control-allow-origin": "*",
"content-encoding": "gzip"
},
"url": "http://musicbrainz.org:80/ws/2/release/3ee3723e-ed1e-4baa-a718-7f1d9ecb3bec?fmt=json",
"time": 518,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"host": "musicbrainz.org",
"accept-encoding": "gzip, deflate",
"accept": "application/json"
}
}
}

View file

View file

@ -0,0 +1,24 @@
{
"statusCode": 307,
"headers": {
"date": "Tue, 20 Dec 2016 01:37:46 GMT",
"content-type": "text/plain; charset=utf-8",
"content-length": "132",
"connection": "keep-alive",
"keep-alive": "timeout=15",
"location": "http://archive.org/download/mbid-76df3287-6cda-33eb-8e9a-044b5e15ffdd/mbid-76df3287-6cda-33eb-8e9a-044b5e15ffdd-5769317885.jpg",
"access-control-allow-origin": "*",
"server": "d8b8a8eb2a2a"
},
"url": "http://coverartarchive.org:80/release/76df3287-6cda-33eb-8e9a-044b5e15ffdd/back",
"time": 385,
"request": {
"method": "HEAD",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"host": "coverartarchive.org",
"accept-encoding": "gzip, deflate",
"content-length": 0
}
}
}

View file

@ -0,0 +1 @@
See: http://archive.org/download/mbid-533e14a8-519d-4f04-95e8-8a84833f26b1/index.json

View file

@ -0,0 +1,24 @@
{
"statusCode": 307,
"headers": {
"date": "Tue, 20 Dec 2016 01:39:56 GMT",
"content-type": "text/plain; charset=utf-8",
"content-length": "86",
"connection": "keep-alive",
"keep-alive": "timeout=15",
"location": "http://archive.org/download/mbid-533e14a8-519d-4f04-95e8-8a84833f26b1/index.json",
"access-control-allow-origin": "*",
"server": "d6446ea62189"
},
"url": "http://coverartarchive.org:80/release/533e14a8-519d-4f04-95e8-8a84833f26b1",
"time": 504,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"host": "coverartarchive.org",
"accept-encoding": "gzip, deflate",
"accept": "application/json"
}
}
}

View file

View file

@ -0,0 +1,25 @@
{
"statusCode": 302,
"headers": {
"server": "nginx/1.4.6 (Ubuntu)",
"date": "Tue, 20 Dec 2016 01:39:57 GMT",
"content-type": "text/html; charset=UTF-8",
"transfer-encoding": "chunked",
"connection": "keep-alive",
"x-powered-by": "PHP/5.5.9-1ubuntu4.20",
"accept-ranges": "bytes",
"location": "http://ia601208.us.archive.org/31/items/mbid-ee773571-6147-4bfd-8ea1-d666c4d4caef/index.json"
},
"url": "http://archive.org:80/download/mbid-ee773571-6147-4bfd-8ea1-d666c4d4caef/index.json",
"time": 149,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"accept-encoding": "gzip, deflate",
"accept": "application/json",
"referer": "http://coverartarchive.org/release/ee773571-6147-4bfd-8ea1-d666c4d4caef",
"host": "archive.org"
}
}
}

Binary file not shown.

View file

@ -0,0 +1,29 @@
{
"statusCode": 200,
"headers": {
"date": "Tue, 20 Dec 2016 01:39:55 GMT",
"content-type": "application/json; charset=UTF-8",
"transfer-encoding": "chunked",
"connection": "keep-alive",
"keep-alive": "timeout=15",
"vary": "Accept-Encoding",
"x-ratelimit-limit": "700",
"x-ratelimit-remaining": "541",
"x-ratelimit-reset": "1482197996",
"last-modified": "Tue, 20 Dec 2016 01:16:03 GMT",
"server": "Jetty(9.3.10.v20160621)",
"access-control-allow-origin": "*",
"content-encoding": "gzip"
},
"url": "http://musicbrainz.org:80/ws/2/release?query=You%20Want%20It%20Darker&fmt=json",
"time": 415,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"host": "musicbrainz.org",
"accept-encoding": "gzip, deflate",
"accept": "application/json"
}
}
}

View file

@ -0,0 +1,4 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>400 Bad Request</title>
<h1>Bad Request</h1>
<p>invalid MBID specified</p>

View file

@ -0,0 +1,22 @@
{
"statusCode": 400,
"headers": {
"date": "Tue, 20 Dec 2016 01:37:47 GMT",
"content-type": "text/html",
"content-length": "138",
"connection": "keep-alive",
"keep-alive": "timeout=15",
"server": "d6446ea62189"
},
"url": "http://coverartarchive.org:80/release/xyz",
"time": 366,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"host": "coverartarchive.org",
"accept-encoding": "gzip, deflate",
"accept": "application/json"
}
}
}

Binary file not shown.

View file

@ -0,0 +1,29 @@
{
"statusCode": 200,
"headers": {
"date": "Tue, 20 Dec 2016 01:39: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": "700",
"x-ratelimit-remaining": "203",
"x-ratelimit-reset": "1482197998",
"server": "Plack::Handler::Starlet",
"etag": "W/\"08dc9c7327d0e7a8b9ede6ae8509c80b\"",
"access-control-allow-origin": "*",
"content-encoding": "gzip"
},
"url": "http://musicbrainz.org:80/ws/2/release/dd15903e-0ee7-45ec-aba1-2fc7b3a44e19?fmt=json",
"time": 449,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"host": "musicbrainz.org",
"accept-encoding": "gzip, deflate",
"accept": "application/json"
}
}
}

View file

View file

@ -0,0 +1,25 @@
{
"statusCode": 302,
"headers": {
"server": "nginx/1.4.6 (Ubuntu)",
"date": "Tue, 20 Dec 2016 01:39:56 GMT",
"content-type": "text/html; charset=UTF-8",
"transfer-encoding": "chunked",
"connection": "keep-alive",
"x-powered-by": "PHP/5.5.9-1ubuntu4.20",
"accept-ranges": "bytes",
"location": "http://ia601203.us.archive.org/29/items/mbid-d5cdb7fd-c7e9-460a-9549-8a369655cc52/index.json"
},
"url": "http://archive.org:80/download/mbid-d5cdb7fd-c7e9-460a-9549-8a369655cc52/index.json",
"time": 356,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"accept-encoding": "gzip, deflate",
"accept": "application/json",
"referer": "http://coverartarchive.org/release/d5cdb7fd-c7e9-460a-9549-8a369655cc52",
"host": "archive.org"
}
}
}

Binary file not shown.

View file

@ -0,0 +1,29 @@
{
"statusCode": 200,
"headers": {
"date": "Tue, 20 Dec 2016 01:40:22 GMT",
"content-type": "application/json; charset=utf-8",
"transfer-encoding": "chunked",
"connection": "keep-alive",
"keep-alive": "timeout=15",
"vary": "Accept-Encoding",
"x-ratelimit-limit": "700",
"x-ratelimit-remaining": "338",
"x-ratelimit-reset": "1482198022",
"server": "Plack::Handler::Starlet",
"etag": "W/\"c190811eaf16a29a562055fc038d682c\"",
"access-control-allow-origin": "*",
"content-encoding": "gzip"
},
"url": "http://musicbrainz.org:80/ws/2/release/7ff98ba2-d865-49eb-8bbd-23dc9d60f21c?fmt=json",
"time": 400,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"host": "musicbrainz.org",
"accept-encoding": "gzip, deflate",
"accept": "application/json"
}
}
}

Binary file not shown.

View file

@ -0,0 +1,29 @@
{
"statusCode": 200,
"headers": {
"date": "Tue, 20 Dec 2016 01:40: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": "700",
"x-ratelimit-remaining": "422",
"x-ratelimit-reset": "1482198006",
"server": "Plack::Handler::Starlet",
"etag": "W/\"bc27197091616cb74bbc5128fb69a933\"",
"access-control-allow-origin": "*",
"content-encoding": "gzip"
},
"url": "http://musicbrainz.org:80/ws/2/release/533e14a8-519d-4f04-95e8-8a84833f26b1?fmt=json",
"time": 410,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"host": "musicbrainz.org",
"accept-encoding": "gzip, deflate",
"accept": "application/json"
}
}
}

View file

@ -0,0 +1,4 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>404 Not Found</title>
<h1>Not Found</h1>
<p>No cover art found for release 29a43eb0-537d-4af1-8598-8b488c847f2e</p>

View file

@ -0,0 +1,22 @@
{
"statusCode": 404,
"headers": {
"date": "Tue, 20 Dec 2016 01:39:56 GMT",
"content-type": "text/html",
"content-length": "179",
"connection": "keep-alive",
"keep-alive": "timeout=15",
"server": "d6446ea62189"
},
"url": "http://coverartarchive.org:80/release/29a43eb0-537d-4af1-8598-8b488c847f2e",
"time": 506,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"host": "coverartarchive.org",
"accept-encoding": "gzip, deflate",
"accept": "application/json"
}
}
}

View file

@ -0,0 +1 @@
See: http://archive.org/download/mbid-7aa99236-67d1-4996-b5ec-f6a517653fbe/index.json

View file

@ -0,0 +1,24 @@
{
"statusCode": 307,
"headers": {
"date": "Tue, 20 Dec 2016 01:39:57 GMT",
"content-type": "text/plain; charset=utf-8",
"content-length": "86",
"connection": "keep-alive",
"keep-alive": "timeout=15",
"location": "http://archive.org/download/mbid-7aa99236-67d1-4996-b5ec-f6a517653fbe/index.json",
"access-control-allow-origin": "*",
"server": "4b4c084fb141"
},
"url": "http://coverartarchive.org:80/release/7aa99236-67d1-4996-b5ec-f6a517653fbe",
"time": 391,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"host": "coverartarchive.org",
"accept-encoding": "gzip, deflate",
"accept": "application/json"
}
}
}

View file

View file

@ -0,0 +1,25 @@
{
"statusCode": 302,
"headers": {
"server": "nginx/1.4.6 (Ubuntu)",
"date": "Tue, 20 Dec 2016 01:39:57 GMT",
"content-type": "text/html; charset=UTF-8",
"transfer-encoding": "chunked",
"connection": "keep-alive",
"x-powered-by": "PHP/5.5.9-1ubuntu4.20",
"accept-ranges": "bytes",
"location": "http://ia601204.us.archive.org/4/items/mbid-3ee3723e-ed1e-4baa-a718-7f1d9ecb3bec/index.json"
},
"url": "http://archive.org:80/download/mbid-3ee3723e-ed1e-4baa-a718-7f1d9ecb3bec/index.json",
"time": 158,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"accept-encoding": "gzip, deflate",
"accept": "application/json",
"referer": "http://coverartarchive.org/release/3ee3723e-ed1e-4baa-a718-7f1d9ecb3bec",
"host": "archive.org"
}
}
}

Binary file not shown.

View file

@ -0,0 +1,29 @@
{
"statusCode": 200,
"headers": {
"date": "Tue, 20 Dec 2016 01:40: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": "700",
"x-ratelimit-remaining": "579",
"x-ratelimit-reset": "1482198012",
"server": "Plack::Handler::Starlet",
"etag": "W/\"dc7e6d284fbbe310adcd3da8b6a4b24e\"",
"access-control-allow-origin": "*",
"content-encoding": "gzip"
},
"url": "http://musicbrainz.org:80/ws/2/release/22a1945f-185c-4d70-979e-f297b00b0c71?fmt=json",
"time": 414,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"host": "musicbrainz.org",
"accept-encoding": "gzip, deflate",
"accept": "application/json"
}
}
}

View file

@ -0,0 +1,4 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>404 Not Found</title>
<h1>Not Found</h1>
<p>No cover art found for release b2d35202-f793-487f-b796-ad0f1882a777</p>

View file

@ -0,0 +1,22 @@
{
"statusCode": 404,
"headers": {
"date": "Tue, 20 Dec 2016 01:39:57 GMT",
"content-type": "text/html",
"content-length": "179",
"connection": "keep-alive",
"keep-alive": "timeout=15",
"server": "d8b8a8eb2a2a"
},
"url": "http://coverartarchive.org:80/release/b2d35202-f793-487f-b796-ad0f1882a777",
"time": 392,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"host": "coverartarchive.org",
"accept-encoding": "gzip, deflate",
"accept": "application/json"
}
}
}

Binary file not shown.

View file

@ -0,0 +1,29 @@
{
"statusCode": 200,
"headers": {
"date": "Tue, 20 Dec 2016 01:40: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": "700",
"x-ratelimit-remaining": "573",
"x-ratelimit-reset": "1482198012",
"server": "Plack::Handler::Starlet",
"etag": "W/\"f31d3255a73df98fcc757f99355ca3d9\"",
"access-control-allow-origin": "*",
"content-encoding": "gzip"
},
"url": "http://musicbrainz.org:80/ws/2/release/90a00dba-addb-4fdc-af2c-6fbb5d733c39?fmt=json",
"time": 419,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"host": "musicbrainz.org",
"accept-encoding": "gzip, deflate",
"accept": "application/json"
}
}
}

View file

@ -0,0 +1,4 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>404 Not Found</title>
<h1>Not Found</h1>
<p>No cover art found for release 15c88cc0-30f5-4568-bac8-e577e3358023</p>

View file

@ -0,0 +1,22 @@
{
"statusCode": 404,
"headers": {
"date": "Tue, 20 Dec 2016 01:39:55 GMT",
"content-type": "text/html",
"content-length": "179",
"connection": "keep-alive",
"keep-alive": "timeout=15",
"server": "4b4c084fb141"
},
"url": "http://coverartarchive.org:80/release/15c88cc0-30f5-4568-bac8-e577e3358023",
"time": 434,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"host": "coverartarchive.org",
"accept-encoding": "gzip, deflate",
"accept": "application/json"
}
}
}

View file

@ -0,0 +1 @@
See: http://archive.org/download/mbid-32a863b3-a356-4873-8b74-c2039156cb68/index.json

View file

@ -0,0 +1,24 @@
{
"statusCode": 307,
"headers": {
"date": "Tue, 20 Dec 2016 01:39:56 GMT",
"content-type": "text/plain; charset=utf-8",
"content-length": "86",
"connection": "keep-alive",
"keep-alive": "timeout=15",
"location": "http://archive.org/download/mbid-32a863b3-a356-4873-8b74-c2039156cb68/index.json",
"access-control-allow-origin": "*",
"server": "d6446ea62189"
},
"url": "http://coverartarchive.org:80/release/32a863b3-a356-4873-8b74-c2039156cb68",
"time": 495,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"host": "coverartarchive.org",
"accept-encoding": "gzip, deflate",
"accept": "application/json"
}
}
}

Binary file not shown.

View file

@ -0,0 +1,29 @@
{
"statusCode": 200,
"headers": {
"date": "Tue, 20 Dec 2016 01:40:16 GMT",
"content-type": "application/json; charset=utf-8",
"transfer-encoding": "chunked",
"connection": "keep-alive",
"keep-alive": "timeout=15",
"vary": "Accept-Encoding",
"x-ratelimit-limit": "700",
"x-ratelimit-remaining": "217",
"x-ratelimit-reset": "1482198016",
"server": "Plack::Handler::Starlet",
"etag": "W/\"463f2bbcb3f8dfb7e98aea81f2672f23\"",
"access-control-allow-origin": "*",
"content-encoding": "gzip"
},
"url": "http://musicbrainz.org:80/ws/2/release/1724b946-fde3-49e5-adec-5e3f62f14a53?fmt=json",
"time": 417,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"host": "musicbrainz.org",
"accept-encoding": "gzip, deflate",
"accept": "application/json"
}
}
}

Binary file not shown.

View file

@ -0,0 +1,29 @@
{
"statusCode": 200,
"headers": {
"date": "Tue, 20 Dec 2016 01:40: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": "700",
"x-ratelimit-remaining": "296",
"x-ratelimit-reset": "1482198000",
"server": "Plack::Handler::Starlet",
"etag": "W/\"913a1fe119084c569261937e14d21171\"",
"access-control-allow-origin": "*",
"content-encoding": "gzip"
},
"url": "http://musicbrainz.org:80/ws/2/release/0832e770-e7e5-464c-9288-9c407a770842?fmt=json",
"time": 415,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"host": "musicbrainz.org",
"accept-encoding": "gzip, deflate",
"accept": "application/json"
}
}
}

Binary file not shown.

View file

@ -0,0 +1,29 @@
{
"statusCode": 200,
"headers": {
"date": "Tue, 20 Dec 2016 01:39:49 GMT",
"content-type": "application/json; charset=utf-8",
"transfer-encoding": "chunked",
"connection": "keep-alive",
"keep-alive": "timeout=15",
"vary": "Accept-Encoding",
"x-ratelimit-limit": "700",
"x-ratelimit-remaining": "548",
"x-ratelimit-reset": "1482197990",
"server": "Plack::Handler::Starlet",
"etag": "W/\"412565deba857fd28ed53fb04eba9e16\"",
"access-control-allow-origin": "*",
"content-encoding": "gzip"
},
"url": "http://musicbrainz.org:80/ws/2/release/b84ee12a-09ef-421b-82de-0441a926375b?fmt=json",
"time": 467,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"host": "musicbrainz.org",
"accept-encoding": "gzip, deflate",
"accept": "application/json"
}
}
}

View file

@ -0,0 +1 @@
See: http://archive.org/download/mbid-3ee3723e-ed1e-4baa-a718-7f1d9ecb3bec/index.json

View file

@ -0,0 +1,24 @@
{
"statusCode": 307,
"headers": {
"date": "Tue, 20 Dec 2016 01:39:56 GMT",
"content-type": "text/plain; charset=utf-8",
"content-length": "86",
"connection": "keep-alive",
"keep-alive": "timeout=15",
"location": "http://archive.org/download/mbid-3ee3723e-ed1e-4baa-a718-7f1d9ecb3bec/index.json",
"access-control-allow-origin": "*",
"server": "d6446ea62189"
},
"url": "http://coverartarchive.org:80/release/3ee3723e-ed1e-4baa-a718-7f1d9ecb3bec",
"time": 513,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"host": "coverartarchive.org",
"accept-encoding": "gzip, deflate",
"accept": "application/json"
}
}
}

Binary file not shown.

View file

@ -0,0 +1,29 @@
{
"statusCode": 200,
"headers": {
"date": "Tue, 20 Dec 2016 01:40: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": "700",
"x-ratelimit-remaining": "302",
"x-ratelimit-reset": "1482198000",
"server": "Plack::Handler::Starlet",
"etag": "W/\"d62c1c90ac668a9d6a2b70547d7879ce\"",
"access-control-allow-origin": "*",
"content-encoding": "gzip"
},
"url": "http://musicbrainz.org:80/ws/2/release/15c88cc0-30f5-4568-bac8-e577e3358023?fmt=json",
"time": 409,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"host": "musicbrainz.org",
"accept-encoding": "gzip, deflate",
"accept": "application/json"
}
}
}

View file

@ -0,0 +1,4 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>404 Not Found</title>
<h1>Not Found</h1>
<p>No cover art found for release 83dc341f-1854-4319-b008-b6a26709dab8</p>

View file

@ -0,0 +1,22 @@
{
"statusCode": 404,
"headers": {
"date": "Tue, 20 Dec 2016 01:39:56 GMT",
"content-type": "text/html",
"content-length": "179",
"connection": "keep-alive",
"keep-alive": "timeout=15",
"server": "4b4c084fb141"
},
"url": "http://coverartarchive.org:80/release/83dc341f-1854-4319-b008-b6a26709dab8",
"time": 465,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"host": "coverartarchive.org",
"accept-encoding": "gzip, deflate",
"accept": "application/json"
}
}
}

View file

@ -0,0 +1 @@
See: http://archive.org/download/mbid-ee773571-6147-4bfd-8ea1-d666c4d4caef/index.json

View file

@ -0,0 +1,24 @@
{
"statusCode": 307,
"headers": {
"date": "Tue, 20 Dec 2016 01:39:56 GMT",
"content-type": "text/plain; charset=utf-8",
"content-length": "86",
"connection": "keep-alive",
"keep-alive": "timeout=15",
"location": "http://archive.org/download/mbid-ee773571-6147-4bfd-8ea1-d666c4d4caef/index.json",
"access-control-allow-origin": "*",
"server": "d6446ea62189"
},
"url": "http://coverartarchive.org:80/release/ee773571-6147-4bfd-8ea1-d666c4d4caef",
"time": 476,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"host": "coverartarchive.org",
"accept-encoding": "gzip, deflate",
"accept": "application/json"
}
}
}

View file

@ -0,0 +1 @@
{"images":[{"types":["Front","Booklet"],"front":true,"back":false,"edit":29753022,"image":"http://coverartarchive.org/release/90a00dba-addb-4fdc-af2c-6fbb5d733c39/8615474322.jpg","comment":"","approved":true,"id":"8615474322","thumbnails":{"large":"http://coverartarchive.org/release/90a00dba-addb-4fdc-af2c-6fbb5d733c39/8615474322-500.jpg","small":"http://coverartarchive.org/release/90a00dba-addb-4fdc-af2c-6fbb5d733c39/8615474322-250.jpg"}},{"types":["Medium"],"front":false,"back":false,"edit":29753069,"image":"http://coverartarchive.org/release/90a00dba-addb-4fdc-af2c-6fbb5d733c39/8615530709.jpg","comment":"","approved":true,"id":"8615530709","thumbnails":{"large":"http://coverartarchive.org/release/90a00dba-addb-4fdc-af2c-6fbb5d733c39/8615530709-500.jpg","small":"http://coverartarchive.org/release/90a00dba-addb-4fdc-af2c-6fbb5d733c39/8615530709-250.jpg"}},{"types":["Back","Spine"],"front":false,"back":true,"edit":29753023,"image":"http://coverartarchive.org/release/90a00dba-addb-4fdc-af2c-6fbb5d733c39/8615477106.jpg","comment":"","approved":true,"id":"8615477106","thumbnails":{"large":"http://coverartarchive.org/release/90a00dba-addb-4fdc-af2c-6fbb5d733c39/8615477106-500.jpg","small":"http://coverartarchive.org/release/90a00dba-addb-4fdc-af2c-6fbb5d733c39/8615477106-250.jpg"}}],"release":"http://musicbrainz.org/release/90a00dba-addb-4fdc-af2c-6fbb5d733c39"}

View file

@ -0,0 +1,27 @@
{
"statusCode": 200,
"headers": {
"server": "nginx/1.4.6 (Ubuntu)",
"date": "Tue, 20 Dec 2016 01:39:57 GMT",
"content-type": "application/json",
"content-length": "1380",
"last-modified": "Sun, 26 Oct 2014 03:00:42 GMT",
"connection": "keep-alive",
"etag": "\"544c63da-564\"",
"expires": "Tue, 20 Dec 2016 07:39:57 GMT",
"cache-control": "max-age=21600",
"accept-ranges": "bytes"
},
"url": "http://ia802605.us.archive.org:80/15/items/mbid-90a00dba-addb-4fdc-af2c-6fbb5d733c39/index.json",
"time": 93,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"accept-encoding": "gzip, deflate",
"accept": "application/json",
"referer": "http://archive.org/download/mbid-90a00dba-addb-4fdc-af2c-6fbb5d733c39/index.json",
"host": "ia802605.us.archive.org"
}
}
}

View file

@ -0,0 +1 @@
See: http://archive.org/download/mbid-25fbfbb4-b1ee-4448-aadf-ae3bc2e2dd27/index.json

View file

@ -0,0 +1,24 @@
{
"statusCode": 307,
"headers": {
"date": "Tue, 20 Dec 2016 01:39:54 GMT",
"content-type": "text/plain; charset=utf-8",
"content-length": "86",
"connection": "keep-alive",
"keep-alive": "timeout=15",
"location": "http://archive.org/download/mbid-25fbfbb4-b1ee-4448-aadf-ae3bc2e2dd27/index.json",
"access-control-allow-origin": "*",
"server": "4b4c084fb141"
},
"url": "http://coverartarchive.org:80/release-group/f5093c06-23e3-404f-aeaa-40f72885ee3a",
"time": 383,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"host": "coverartarchive.org",
"accept-encoding": "gzip, deflate",
"accept": "application/json"
}
}
}

View file

@ -0,0 +1,4 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>404 Not Found</title>
<h1>Not Found</h1>
<p>No cover art found for release 1724b946-fde3-49e5-adec-5e3f62f14a53</p>

View file

@ -0,0 +1,22 @@
{
"statusCode": 404,
"headers": {
"date": "Tue, 20 Dec 2016 01:39:57 GMT",
"content-type": "text/html",
"content-length": "179",
"connection": "keep-alive",
"keep-alive": "timeout=15",
"server": "d8b8a8eb2a2a"
},
"url": "http://coverartarchive.org:80/release/1724b946-fde3-49e5-adec-5e3f62f14a53",
"time": 410,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"host": "coverartarchive.org",
"accept-encoding": "gzip, deflate",
"accept": "application/json"
}
}
}

View file

View file

@ -0,0 +1,24 @@
{
"statusCode": 307,
"headers": {
"date": "Tue, 20 Dec 2016 01:39:49 GMT",
"content-type": "text/plain; charset=utf-8",
"content-length": "133",
"connection": "keep-alive",
"keep-alive": "timeout=15",
"location": "http://archive.org/download/mbid-b84ee12a-09ef-421b-82de-0441a926375b/mbid-b84ee12a-09ef-421b-82de-0441a926375b-13536418798.jpg",
"access-control-allow-origin": "*",
"server": "4b4c084fb141"
},
"url": "http://coverartarchive.org:80/release/b84ee12a-09ef-421b-82de-0441a926375b/back",
"time": 392,
"request": {
"method": "HEAD",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"host": "coverartarchive.org",
"accept-encoding": "gzip, deflate",
"content-length": 0
}
}
}

Binary file not shown.

View file

@ -0,0 +1,29 @@
{
"statusCode": 200,
"headers": {
"date": "Tue, 20 Dec 2016 01:40: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": "700",
"x-ratelimit-remaining": "428",
"x-ratelimit-reset": "1482198006",
"server": "Plack::Handler::Starlet",
"etag": "W/\"d1bd4c0b88cef71df921aaf373ebec8b\"",
"access-control-allow-origin": "*",
"content-encoding": "gzip"
},
"url": "http://musicbrainz.org:80/ws/2/release/29a43eb0-537d-4af1-8598-8b488c847f2e?fmt=json",
"time": 402,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"host": "musicbrainz.org",
"accept-encoding": "gzip, deflate",
"accept": "application/json"
}
}
}

Binary file not shown.

View file

@ -0,0 +1,29 @@
{
"statusCode": 200,
"headers": {
"date": "Tue, 20 Dec 2016 01:40: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": "700",
"x-ratelimit-remaining": "430",
"x-ratelimit-reset": "1482198006",
"server": "Plack::Handler::Starlet",
"etag": "W/\"47fd9b0e0985095d4a5fb58e02ddb790\"",
"access-control-allow-origin": "*",
"content-encoding": "gzip"
},
"url": "http://musicbrainz.org:80/ws/2/release/060dc665-af64-4e75-8e51-d74eda2ec957?fmt=json",
"time": 392,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"host": "musicbrainz.org",
"accept-encoding": "gzip, deflate",
"accept": "application/json"
}
}
}

View file

View file

@ -0,0 +1,25 @@
{
"statusCode": 302,
"headers": {
"server": "nginx/1.4.6 (Ubuntu)",
"date": "Tue, 20 Dec 2016 01:39:57 GMT",
"content-type": "text/html; charset=UTF-8",
"transfer-encoding": "chunked",
"connection": "keep-alive",
"x-powered-by": "PHP/5.5.9-1ubuntu4.20",
"accept-ranges": "bytes",
"location": "http://ia802605.us.archive.org/15/items/mbid-90a00dba-addb-4fdc-af2c-6fbb5d733c39/index.json"
},
"url": "http://archive.org:80/download/mbid-90a00dba-addb-4fdc-af2c-6fbb5d733c39/index.json",
"time": 185,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"accept-encoding": "gzip, deflate",
"accept": "application/json",
"referer": "http://coverartarchive.org/release/90a00dba-addb-4fdc-af2c-6fbb5d733c39",
"host": "archive.org"
}
}
}

View file

View file

@ -0,0 +1,25 @@
{
"statusCode": 302,
"headers": {
"server": "nginx/1.4.6 (Ubuntu)",
"date": "Tue, 20 Dec 2016 01:39:57 GMT",
"content-type": "text/html; charset=UTF-8",
"transfer-encoding": "chunked",
"connection": "keep-alive",
"x-powered-by": "PHP/5.5.9-1ubuntu4.20",
"accept-ranges": "bytes",
"location": "http://ia902608.us.archive.org/12/items/mbid-533e14a8-519d-4f04-95e8-8a84833f26b1/index.json"
},
"url": "http://archive.org:80/download/mbid-533e14a8-519d-4f04-95e8-8a84833f26b1/index.json",
"time": 202,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"accept-encoding": "gzip, deflate",
"accept": "application/json",
"referer": "http://coverartarchive.org/release/533e14a8-519d-4f04-95e8-8a84833f26b1",
"host": "archive.org"
}
}
}

Binary file not shown.

View file

@ -0,0 +1,29 @@
{
"statusCode": 200,
"headers": {
"date": "Tue, 20 Dec 2016 01:39: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": "700",
"x-ratelimit-remaining": "200",
"x-ratelimit-reset": "1482197998",
"server": "Plack::Handler::Starlet",
"etag": "W/\"43924c0dd2c3e691bc33bebc8ddc9268\"",
"access-control-allow-origin": "*",
"content-encoding": "gzip"
},
"url": "http://musicbrainz.org:80/ws/2/release/3d354599-d9d4-44a8-9584-37e3b0238871?fmt=json",
"time": 416,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"host": "musicbrainz.org",
"accept-encoding": "gzip, deflate",
"accept": "application/json"
}
}
}

View file

@ -0,0 +1 @@
{"release":"https://musicbrainz.org/release/dd15903e-0ee7-45ec-aba1-2fc7b3a44e19","images":[{"id":"14693820293","front":true,"image":"http://coverartarchive.org/release/dd15903e-0ee7-45ec-aba1-2fc7b3a44e19/14693820293.jpg","thumbnails":{"small":"http://coverartarchive.org/release/dd15903e-0ee7-45ec-aba1-2fc7b3a44e19/14693820293-250.jpg","large":"http://coverartarchive.org/release/dd15903e-0ee7-45ec-aba1-2fc7b3a44e19/14693820293-500.jpg"},"types":["Front"],"comment":"","approved":true,"back":false,"edit":40831187},{"thumbnails":{"large":"http://coverartarchive.org/release/dd15903e-0ee7-45ec-aba1-2fc7b3a44e19/15029120792-500.jpg","small":"http://coverartarchive.org/release/dd15903e-0ee7-45ec-aba1-2fc7b3a44e19/15029120792-250.jpg"},"types":["Back","Spine"],"comment":"","image":"http://coverartarchive.org/release/dd15903e-0ee7-45ec-aba1-2fc7b3a44e19/15029120792.jpg","id":"15029120792","front":false,"edit":41462768,"approved":true,"back":true},{"edit":41462773,"approved":true,"back":false,"thumbnails":{"small":"http://coverartarchive.org/release/dd15903e-0ee7-45ec-aba1-2fc7b3a44e19/15029124666-250.jpg","large":"http://coverartarchive.org/release/dd15903e-0ee7-45ec-aba1-2fc7b3a44e19/15029124666-500.jpg"},"types":["Medium"],"comment":"","image":"http://coverartarchive.org/release/dd15903e-0ee7-45ec-aba1-2fc7b3a44e19/15029124666.jpg","id":"15029124666","front":false}]}

View file

@ -0,0 +1,27 @@
{
"statusCode": 200,
"headers": {
"server": "nginx/1.4.6 (Ubuntu)",
"date": "Tue, 20 Dec 2016 01:39:56 GMT",
"content-type": "application/json",
"content-length": "1383",
"last-modified": "Sun, 06 Nov 2016 10:02:39 GMT",
"connection": "keep-alive",
"etag": "\"581effbf-567\"",
"expires": "Tue, 20 Dec 2016 07:39:56 GMT",
"cache-control": "max-age=21600",
"accept-ranges": "bytes"
},
"url": "http://ia801508.us.archive.org:80/17/items/mbid-dd15903e-0ee7-45ec-aba1-2fc7b3a44e19/index.json",
"time": 293,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"accept-encoding": "gzip, deflate",
"accept": "application/json",
"referer": "http://archive.org/download/mbid-dd15903e-0ee7-45ec-aba1-2fc7b3a44e19/index.json",
"host": "ia801508.us.archive.org"
}
}
}

Binary file not shown.

View file

@ -0,0 +1,29 @@
{
"statusCode": 200,
"headers": {
"date": "Tue, 20 Dec 2016 01:40:16 GMT",
"content-type": "application/json; charset=utf-8",
"transfer-encoding": "chunked",
"connection": "keep-alive",
"keep-alive": "timeout=15",
"vary": "Accept-Encoding",
"x-ratelimit-limit": "700",
"x-ratelimit-remaining": "224",
"x-ratelimit-reset": "1482198016",
"server": "Plack::Handler::Starlet",
"etag": "W/\"72d2983f2989ac6c7d1e5404726717fe\"",
"access-control-allow-origin": "*",
"content-encoding": "gzip"
},
"url": "http://musicbrainz.org:80/ws/2/release/83dc341f-1854-4319-b008-b6a26709dab8?fmt=json",
"time": 414,
"request": {
"method": "GET",
"headers": {
"User-Agent": "graphbrainz/4.5.0 ( https://github.com/exogen/graphbrainz )",
"host": "musicbrainz.org",
"accept-encoding": "gzip, deflate",
"accept": "application/json"
}
}
}

View file

@ -0,0 +1 @@
{"release":"https://musicbrainz.org/release/ee773571-6147-4bfd-8ea1-d666c4d4caef","images":[{"comment":"","types":["Front"],"thumbnails":{"large":"http://coverartarchive.org/release/ee773571-6147-4bfd-8ea1-d666c4d4caef/14352438517-500.jpg","small":"http://coverartarchive.org/release/ee773571-6147-4bfd-8ea1-d666c4d4caef/14352438517-250.jpg"},"image":"http://coverartarchive.org/release/ee773571-6147-4bfd-8ea1-d666c4d4caef/14352438517.jpg","front":true,"id":"14352438517","edit":40179297,"back":false,"approved":true}]}

Some files were not shown because too many files have changed in this diff Show more