From 898ec78a6fcaefe689ca0bb96fc6b7a062f951e8 Mon Sep 17 00:00:00 2001 From: Brian Beck Date: Thu, 19 Oct 2017 01:00:21 -0700 Subject: [PATCH] Add a schema extension API and several extensions (#42) * Add a schema extension API and several extensions * Update graphql-markdown to use new diffSchema function * Update Node support --- .gitignore | 1 + .travis.yml | 8 +- README.md | 26 +- circle.yml | 3 +- docs/extensions/README.md | 227 ++++++ docs/extensions/cover-art-archive.md | 378 +++++++++ docs/extensions/fanart-tv.md | 473 +++++++++++ docs/extensions/mediawiki.md | 404 +++++++++ docs/extensions/the-audio-db.md | 766 ++++++++++++++++++ docs/schema.md | 143 ---- docs/types.md | 391 --------- extensions/cover-art-archive.js | 1 + extensions/fanart-tv.js | 1 + extensions/mediawiki.js | 1 + extensions/the-audio-db.js | 1 + package.json | 12 +- schema.json | 470 +---------- scripts/build-extension-docs.js | 66 ++ src/api/client.js | 8 +- src/api/index.js | 5 +- src/api/musicbrainz.js | 6 + src/context.js | 27 + .../cover-art-archive/client.js} | 30 +- src/extensions/cover-art-archive/index.js | 36 + src/extensions/cover-art-archive/loaders.js | 53 ++ src/extensions/cover-art-archive/prologue.md | 12 + src/extensions/cover-art-archive/resolvers.js | 75 ++ src/extensions/cover-art-archive/schema.js | 121 +++ src/extensions/fanart-tv/client.js | 60 ++ src/extensions/fanart-tv/index.js | 34 + src/extensions/fanart-tv/loader.js | 51 ++ src/extensions/fanart-tv/prologue.md | 14 + src/extensions/fanart-tv/resolvers.js | 63 ++ src/extensions/fanart-tv/schema.js | 127 +++ src/extensions/mediawiki/client.js | 54 ++ src/extensions/mediawiki/index.js | 34 + src/extensions/mediawiki/loader.js | 22 + src/extensions/mediawiki/prologue.md | 24 + src/extensions/mediawiki/resolvers.js | 80 ++ src/extensions/mediawiki/schema.js | 108 +++ src/extensions/the-audio-db/client.js | 70 ++ src/extensions/the-audio-db/index.js | 34 + src/extensions/the-audio-db/loader.js | 28 + src/extensions/the-audio-db/prologue.md | 14 + src/extensions/the-audio-db/resolvers.js | 107 +++ src/extensions/the-audio-db/schema.js | 231 ++++++ src/index.js | 38 +- src/loaders.js | 37 +- src/schema.js | 45 +- src/types/cover-art-image.js | 72 -- src/types/cover-art.js | 188 ----- src/types/release-group.js | 9 - src/types/release.js | 15 - src/util.js | 4 + .../cover-art-archive/client.js} | 5 +- test/extensions/cover-art-archive/schema.js | 174 ++++ test/extensions/fanart-tv/schema.js | 128 +++ .../fanart-tv/snapshots/schema.js.md | 424 ++++++++++ .../fanart-tv/snapshots/schema.js.snap | Bin 0 -> 3645 bytes test/extensions/mediawiki/schema.js | 101 +++ .../mediawiki/snapshots/schema.js.md | 580 +++++++++++++ .../mediawiki/snapshots/schema.js.snap | Bin 0 -> 5112 bytes test/extensions/the-audio-db/schema.js | 118 +++ .../the-audio-db/snapshots/schema.js.md | 125 +++ .../the-audio-db/snapshots/schema.js.snap | Bin 0 -> 5244 bytes .../fixtures/09158487d72de391f789b038b8e5d137 | Bin 0 -> 521 bytes .../09158487d72de391f789b038b8e5d137.headers | 29 + .../fixtures/0978572ac8e46f70600f576c9e36f019 | Bin 0 -> 519 bytes .../0978572ac8e46f70600f576c9e36f019.headers | 29 + .../fixtures/0afc244749f3fddc9a96823dd9b2a898 | Bin 0 -> 721 bytes .../0afc244749f3fddc9a96823dd9b2a898.headers | 29 + .../fixtures/0bc1bed2d611a955f254756470f98df4 | Bin 0 -> 661 bytes .../0bc1bed2d611a955f254756470f98df4.headers | 29 + .../fixtures/0c643a69d0dd86ae242e226c1d85469e | Bin 0 -> 305 bytes .../0c643a69d0dd86ae242e226c1d85469e.headers | 29 + .../fixtures/0d366b2eeee8615a4b25b8e601c6020a | Bin 0 -> 644 bytes .../0d366b2eeee8615a4b25b8e601c6020a.headers | 29 + .../fixtures/0e99fc598c63fd29efff1916c1284bbf | Bin 0 -> 568 bytes .../0e99fc598c63fd29efff1916c1284bbf.headers | 29 + .../fixtures/1bd080df7553608290b4e67175a1a6dc | Bin 0 -> 783 bytes .../1bd080df7553608290b4e67175a1a6dc.headers | 29 + .../fixtures/1bd60b1a1ed81102d4d7271e2237e1bf | Bin 0 -> 507 bytes .../1bd60b1a1ed81102d4d7271e2237e1bf.headers | 29 + .../fixtures/1ca35d44ecbebc340e09347b6f40c6f7 | 1 + .../1ca35d44ecbebc340e09347b6f40c6f7.headers | 27 + .../fixtures/1cd29fc131359a049232fbae39509f53 | Bin 0 -> 993 bytes .../1cd29fc131359a049232fbae39509f53.headers | 43 + .../fixtures/2025c61957af1edf111c891d3271ffbc | Bin 0 -> 235 bytes .../2025c61957af1edf111c891d3271ffbc.headers | 29 + .../fixtures/23aba1f4957dd22a5b21bd71c8dc9be3 | Bin 0 -> 747 bytes .../23aba1f4957dd22a5b21bd71c8dc9be3.headers | 29 + .../fixtures/24013351b3e17570d846426ee2b36c7a | 1 + .../24013351b3e17570d846426ee2b36c7a.headers | 27 + .../fixtures/25fff225406f7452de82b60beda3c931 | Bin 0 -> 549 bytes .../25fff225406f7452de82b60beda3c931.headers | 29 + .../fixtures/2694cd9eea8687ccbda862aab56a0e78 | Bin 0 -> 497 bytes .../2694cd9eea8687ccbda862aab56a0e78.headers | 29 + .../fixtures/2ae8ed6772af1b8fa844a5ac6d2b12b8 | Bin 0 -> 301 bytes .../2ae8ed6772af1b8fa844a5ac6d2b12b8.headers | 29 + .../fixtures/2b7cd5ca496a1d302cc587411cd36ad4 | Bin 0 -> 6280 bytes .../2b7cd5ca496a1d302cc587411cd36ad4.headers | 29 + .../fixtures/2dd9912677b480dba99a99c809078688 | Bin 0 -> 68 bytes .../2dd9912677b480dba99a99c809078688.headers | 24 + .../fixtures/2de45192ad9def59746abf53a0eaf6c7 | Bin 0 -> 515 bytes .../2de45192ad9def59746abf53a0eaf6c7.headers | 29 + .../fixtures/322500542e74bfc6c6a5fb3b8d1329dd | Bin 0 -> 889 bytes .../322500542e74bfc6c6a5fb3b8d1329dd.headers | 29 + .../fixtures/37d33226e906bc384a86f29fedc03834 | Bin 0 -> 318 bytes .../37d33226e906bc384a86f29fedc03834.headers | 29 + .../fixtures/3b60588b620d7e73852e4800525e40d6 | Bin 0 -> 727 bytes .../3b60588b620d7e73852e4800525e40d6.headers | 29 + .../fixtures/3dd3f9a8efe08f8d1adb70cd6ece87d9 | Bin 0 -> 369 bytes .../3dd3f9a8efe08f8d1adb70cd6ece87d9.headers | 29 + .../fixtures/40170c882e89aaeeb705e1191c889d0c | Bin 0 -> 1003 bytes .../40170c882e89aaeeb705e1191c889d0c.headers | 29 + .../fixtures/411c0b53f75e4380eae0424fdecb902e | Bin 0 -> 909 bytes .../411c0b53f75e4380eae0424fdecb902e.headers | 29 + .../fixtures/45904a407101915f2a3273f907166537 | Bin 0 -> 725 bytes .../45904a407101915f2a3273f907166537.headers | 43 + .../fixtures/475fed802529221edd39de95047235c3 | Bin 0 -> 713 bytes .../475fed802529221edd39de95047235c3.headers | 29 + .../fixtures/499d62f35c5f6fd86e3a29f69785cff2 | Bin 0 -> 744 bytes .../499d62f35c5f6fd86e3a29f69785cff2.headers | 29 + .../fixtures/4b802038a4994a768903c9df4bc309fb | Bin 0 -> 806 bytes .../4b802038a4994a768903c9df4bc309fb.headers | 24 + .../fixtures/4fc501bed2b7d643f741185069aace22 | Bin 0 -> 844 bytes .../4fc501bed2b7d643f741185069aace22.headers | 43 + .../fixtures/535ab3a418fb2b5ac0c9476546cc72d8 | Bin 0 -> 352 bytes .../535ab3a418fb2b5ac0c9476546cc72d8.headers | 29 + .../fixtures/537dbabc1ce057385edd9d8c4599c077 | Bin 0 -> 3373 bytes .../537dbabc1ce057385edd9d8c4599c077.headers | 29 + .../fixtures/56d55db80170ca90872e69c2f8b7837d | Bin 0 -> 502 bytes .../56d55db80170ca90872e69c2f8b7837d.headers | 29 + .../fixtures/5740cf0df41918fee30a22a1bce2791e | Bin 0 -> 755 bytes .../5740cf0df41918fee30a22a1bce2791e.headers | 29 + .../fixtures/5c1b9b2cd173095ad489f4a6e36a911d | Bin 0 -> 1030 bytes .../5c1b9b2cd173095ad489f4a6e36a911d.headers | 29 + .../fixtures/5f54da66d9a88167f9dda7f1c00d73f3 | 1 + .../5f54da66d9a88167f9dda7f1c00d73f3.headers | 27 + .../fixtures/5fba37b7b6619c61e3092bead860e8c9 | Bin 0 -> 441 bytes .../5fba37b7b6619c61e3092bead860e8c9.headers | 29 + .../fixtures/6176ff6a5cf47eed252cc9d9219c75dc | Bin 0 -> 506 bytes .../6176ff6a5cf47eed252cc9d9219c75dc.headers | 29 + .../fixtures/6526571b8ee23f940317e3232190179b | Bin 0 -> 767 bytes .../6526571b8ee23f940317e3232190179b.headers | 29 + .../fixtures/6e3eeb66969aa4c71c2595d514f127f5 | 1 + .../6e3eeb66969aa4c71c2595d514f127f5.headers | 27 + .../fixtures/6f630e7326d44cc51431dceffbb437a4 | Bin 0 -> 340 bytes .../6f630e7326d44cc51431dceffbb437a4.headers | 29 + .../fixtures/70ae1dbdd83a22e8c04c74809d45b345 | Bin 0 -> 326 bytes .../70ae1dbdd83a22e8c04c74809d45b345.headers | 29 + .../fixtures/7295737c14813766abe7f6d7c8a4e4c0 | Bin 0 -> 543 bytes .../7295737c14813766abe7f6d7c8a4e4c0.headers | 29 + .../fixtures/759a630311f32c04c63c7556ca7a19d9 | Bin 0 -> 2265 bytes .../759a630311f32c04c63c7556ca7a19d9.headers | 29 + .../fixtures/771b51c0fbd414533c20f2d95e571dc9 | Bin 0 -> 777 bytes .../771b51c0fbd414533c20f2d95e571dc9.headers | 29 + .../fixtures/79471f371a264a0176df177479190ddc | Bin 0 -> 349 bytes .../79471f371a264a0176df177479190ddc.headers | 29 + .../fixtures/7b053660a24a2db5139e8e7ffc3a9225 | Bin 0 -> 475 bytes .../7b053660a24a2db5139e8e7ffc3a9225.headers | 29 + .../fixtures/7e4ef1a9130fb6e4fb62cd29edd6974f | Bin 0 -> 211 bytes .../7e4ef1a9130fb6e4fb62cd29edd6974f.headers | 29 + .../fixtures/8619ae4dc1a5c3e3cf04ac05ede71e99 | Bin 0 -> 344 bytes .../8619ae4dc1a5c3e3cf04ac05ede71e99.headers | 29 + .../fixtures/892adb119a9924a464f3443d9f3b03a9 | Bin 0 -> 506 bytes .../892adb119a9924a464f3443d9f3b03a9.headers | 29 + .../fixtures/8c969c07759e225e55132955258d912f | Bin 0 -> 533 bytes .../8c969c07759e225e55132955258d912f.headers | 29 + .../fixtures/8cabf5fae5f37ac12bc602d38e0d7cdb | Bin 0 -> 495 bytes .../8cabf5fae5f37ac12bc602d38e0d7cdb.headers | 29 + .../fixtures/973e11ce912c0bc44d3fad7d08d9c41d | Bin 0 -> 345 bytes .../973e11ce912c0bc44d3fad7d08d9c41d.headers | 29 + .../fixtures/981e4a18c54b89e2537b7660cf8ed3bd | Bin 0 -> 1010 bytes .../981e4a18c54b89e2537b7660cf8ed3bd.headers | 29 + .../fixtures/989521e0ddda97a5a15e7564e4a02100 | Bin 0 -> 340 bytes .../989521e0ddda97a5a15e7564e4a02100.headers | 29 + .../fixtures/989db6ea639b5dc2f24377b312932f27 | Bin 0 -> 3756 bytes .../989db6ea639b5dc2f24377b312932f27.headers | 29 + .../fixtures/9c392f735dfc18f1ebae5057d4810503 | Bin 0 -> 346 bytes .../9c392f735dfc18f1ebae5057d4810503.headers | 29 + .../fixtures/a95dc0c2cbed192f29e448ff0ab981f2 | Bin 0 -> 582 bytes .../a95dc0c2cbed192f29e448ff0ab981f2.headers | 29 + .../fixtures/aa96a948b688bc7d7aa7726a61cbc4e5 | Bin 0 -> 344 bytes .../aa96a948b688bc7d7aa7726a61cbc4e5.headers | 29 + .../fixtures/aabb63c196e05819a62f5c4236dee819 | Bin 0 -> 349 bytes .../aabb63c196e05819a62f5c4236dee819.headers | 29 + .../fixtures/acaca90fe77e40a25bd38b95282272c8 | Bin 0 -> 207 bytes .../acaca90fe77e40a25bd38b95282272c8.headers | 29 + .../fixtures/ad5041074ea5fe6a4f5046944b60f216 | Bin 0 -> 742 bytes .../ad5041074ea5fe6a4f5046944b60f216.headers | 29 + .../fixtures/af29a78d9191b600ced4f7f04570c4ee | Bin 0 -> 545 bytes .../af29a78d9191b600ced4f7f04570c4ee.headers | 29 + .../fixtures/af7dae80c814d6fc8e5a6d4ff4f6ab96 | Bin 0 -> 656 bytes .../af7dae80c814d6fc8e5a6d4ff4f6ab96.headers | 29 + .../fixtures/b2757f369119107b417af16a5b5cc57c | Bin 0 -> 324 bytes .../b2757f369119107b417af16a5b5cc57c.headers | 29 + .../fixtures/b4bc218a89b1ed34a74924a42db92b8a | Bin 0 -> 725 bytes .../b4bc218a89b1ed34a74924a42db92b8a.headers | 43 + .../fixtures/b5b153f3c2c39a5cf25fdc0ee96d0fce | Bin 0 -> 787 bytes .../b5b153f3c2c39a5cf25fdc0ee96d0fce.headers | 29 + .../fixtures/b63c630cd8a47258d3cd45635adfe2fd | Bin 0 -> 316 bytes .../b63c630cd8a47258d3cd45635adfe2fd.headers | 29 + .../fixtures/b788432e4977d8a7be60e806b42848dd | Bin 0 -> 844 bytes .../b788432e4977d8a7be60e806b42848dd.headers | 43 + .../fixtures/b8cdd376ffa05b4ed0fa88c8580f6d78 | Bin 0 -> 719 bytes .../b8cdd376ffa05b4ed0fa88c8580f6d78.headers | 29 + .../fixtures/ba515718537dd9c0dcb6332ee59cfead | Bin 0 -> 201 bytes .../ba515718537dd9c0dcb6332ee59cfead.headers | 29 + .../fixtures/bb45b9cceba8f0e6f31f18ee670ecb7b | Bin 0 -> 276 bytes .../bb45b9cceba8f0e6f31f18ee670ecb7b.headers | 29 + .../fixtures/be14b8e0fa4d1830a0ebe40a016ca6e2 | Bin 0 -> 344 bytes .../be14b8e0fa4d1830a0ebe40a016ca6e2.headers | 29 + .../fixtures/c125b6361991fc5455d24693c30e9063 | 1 + .../c125b6361991fc5455d24693c30e9063.headers | 21 + .../fixtures/c1db4dc6ce9581a6fb82f326ef7a72f6 | Bin 0 -> 394 bytes .../c1db4dc6ce9581a6fb82f326ef7a72f6.headers | 29 + .../fixtures/c3211588134d80d9447ef9f05e02690b | Bin 0 -> 3353 bytes .../c3211588134d80d9447ef9f05e02690b.headers | 24 + .../fixtures/d3eb06ea06d807205b713eac5a9bd710 | Bin 0 -> 537 bytes .../d3eb06ea06d807205b713eac5a9bd710.headers | 29 + .../fixtures/d6c3769fa2dfce68ebbdb04a2d2cd559 | Bin 0 -> 513 bytes .../d6c3769fa2dfce68ebbdb04a2d2cd559.headers | 29 + .../fixtures/dba5a1e96a4962a5370bad858932e11d | Bin 0 -> 552 bytes .../dba5a1e96a4962a5370bad858932e11d.headers | 29 + .../fixtures/dbf0c82ddaa7681f0642fba3fb2dd351 | Bin 0 -> 588 bytes .../dbf0c82ddaa7681f0642fba3fb2dd351.headers | 29 + .../fixtures/dce1cbd3f38b1de0b4fd7cc697131b31 | Bin 0 -> 350 bytes .../dce1cbd3f38b1de0b4fd7cc697131b31.headers | 29 + .../fixtures/df2dc808710d6548a883bbbf3edecb71 | Bin 0 -> 993 bytes .../df2dc808710d6548a883bbbf3edecb71.headers | 43 + .../fixtures/e122264f8b96cc604b7507bd30876d15 | Bin 0 -> 383 bytes .../e122264f8b96cc604b7507bd30876d15.headers | 29 + .../fixtures/ea5da6f619d0bfa476d74e66f9b0bab6 | 1 + .../ea5da6f619d0bfa476d74e66f9b0bab6.headers | 21 + .../fixtures/ea7434f5608f1a1ac1e0d509a624f2db | Bin 0 -> 334 bytes .../ea7434f5608f1a1ac1e0d509a624f2db.headers | 29 + .../fixtures/ec5161eb0cf63cbaa64db8cf2e7727fc | Bin 0 -> 852 bytes .../ec5161eb0cf63cbaa64db8cf2e7727fc.headers | 29 + .../fixtures/ecefe1f444a1e1e90f3158416eb2da95 | Bin 0 -> 566 bytes .../ecefe1f444a1e1e90f3158416eb2da95.headers | 29 + .../fixtures/f71ea9601bb094d68114cdfa9da584ac | Bin 0 -> 414 bytes .../f71ea9601bb094d68114cdfa9da584ac.headers | 29 + .../fixtures/f9ccd6365663fd88cef3a99afb0db0de | Bin 0 -> 516 bytes .../f9ccd6365663fd88cef3a99afb0db0de.headers | 29 + .../fixtures/faae9e2018b271b5f0908a41d07847ad | 1 + .../faae9e2018b271b5f0908a41d07847ad.headers | 21 + .../fixtures/fd213f6dd613d91b8c059cad39261cb8 | Bin 0 -> 345 bytes .../fd213f6dd613d91b8c059cad39261cb8.headers | 29 + test/helpers/client/cover-art-archive.js | 4 +- test/helpers/context.js | 4 +- test/schema.js | 221 ----- yarn.lock | 38 +- 253 files changed, 8341 insertions(+), 1601 deletions(-) create mode 100644 docs/extensions/README.md create mode 100644 docs/extensions/cover-art-archive.md create mode 100644 docs/extensions/fanart-tv.md create mode 100644 docs/extensions/mediawiki.md create mode 100644 docs/extensions/the-audio-db.md create mode 100644 extensions/cover-art-archive.js create mode 100644 extensions/fanart-tv.js create mode 100644 extensions/mediawiki.js create mode 100644 extensions/the-audio-db.js create mode 100644 scripts/build-extension-docs.js create mode 100644 src/context.js rename src/{api/cover-art-archive.js => extensions/cover-art-archive/client.js} (50%) create mode 100644 src/extensions/cover-art-archive/index.js create mode 100644 src/extensions/cover-art-archive/loaders.js create mode 100644 src/extensions/cover-art-archive/prologue.md create mode 100644 src/extensions/cover-art-archive/resolvers.js create mode 100644 src/extensions/cover-art-archive/schema.js create mode 100644 src/extensions/fanart-tv/client.js create mode 100644 src/extensions/fanart-tv/index.js create mode 100644 src/extensions/fanart-tv/loader.js create mode 100644 src/extensions/fanart-tv/prologue.md create mode 100644 src/extensions/fanart-tv/resolvers.js create mode 100644 src/extensions/fanart-tv/schema.js create mode 100644 src/extensions/mediawiki/client.js create mode 100644 src/extensions/mediawiki/index.js create mode 100644 src/extensions/mediawiki/loader.js create mode 100644 src/extensions/mediawiki/prologue.md create mode 100644 src/extensions/mediawiki/resolvers.js create mode 100644 src/extensions/mediawiki/schema.js create mode 100644 src/extensions/the-audio-db/client.js create mode 100644 src/extensions/the-audio-db/index.js create mode 100644 src/extensions/the-audio-db/loader.js create mode 100644 src/extensions/the-audio-db/prologue.md create mode 100644 src/extensions/the-audio-db/resolvers.js create mode 100644 src/extensions/the-audio-db/schema.js delete mode 100644 src/types/cover-art-image.js delete mode 100644 src/types/cover-art.js rename test/{api/cover-art-archive.js => extensions/cover-art-archive/client.js} (90%) create mode 100644 test/extensions/cover-art-archive/schema.js create mode 100644 test/extensions/fanart-tv/schema.js create mode 100644 test/extensions/fanart-tv/snapshots/schema.js.md create mode 100644 test/extensions/fanart-tv/snapshots/schema.js.snap create mode 100644 test/extensions/mediawiki/schema.js create mode 100644 test/extensions/mediawiki/snapshots/schema.js.md create mode 100644 test/extensions/mediawiki/snapshots/schema.js.snap create mode 100644 test/extensions/the-audio-db/schema.js create mode 100644 test/extensions/the-audio-db/snapshots/schema.js.md create mode 100644 test/extensions/the-audio-db/snapshots/schema.js.snap create mode 100644 test/fixtures/09158487d72de391f789b038b8e5d137 create mode 100644 test/fixtures/09158487d72de391f789b038b8e5d137.headers create mode 100644 test/fixtures/0978572ac8e46f70600f576c9e36f019 create mode 100644 test/fixtures/0978572ac8e46f70600f576c9e36f019.headers create mode 100644 test/fixtures/0afc244749f3fddc9a96823dd9b2a898 create mode 100644 test/fixtures/0afc244749f3fddc9a96823dd9b2a898.headers create mode 100644 test/fixtures/0bc1bed2d611a955f254756470f98df4 create mode 100644 test/fixtures/0bc1bed2d611a955f254756470f98df4.headers create mode 100644 test/fixtures/0c643a69d0dd86ae242e226c1d85469e create mode 100644 test/fixtures/0c643a69d0dd86ae242e226c1d85469e.headers create mode 100644 test/fixtures/0d366b2eeee8615a4b25b8e601c6020a create mode 100644 test/fixtures/0d366b2eeee8615a4b25b8e601c6020a.headers create mode 100644 test/fixtures/0e99fc598c63fd29efff1916c1284bbf create mode 100644 test/fixtures/0e99fc598c63fd29efff1916c1284bbf.headers create mode 100644 test/fixtures/1bd080df7553608290b4e67175a1a6dc create mode 100644 test/fixtures/1bd080df7553608290b4e67175a1a6dc.headers create mode 100644 test/fixtures/1bd60b1a1ed81102d4d7271e2237e1bf create mode 100644 test/fixtures/1bd60b1a1ed81102d4d7271e2237e1bf.headers create mode 100644 test/fixtures/1ca35d44ecbebc340e09347b6f40c6f7 create mode 100644 test/fixtures/1ca35d44ecbebc340e09347b6f40c6f7.headers create mode 100644 test/fixtures/1cd29fc131359a049232fbae39509f53 create mode 100644 test/fixtures/1cd29fc131359a049232fbae39509f53.headers create mode 100644 test/fixtures/2025c61957af1edf111c891d3271ffbc create mode 100644 test/fixtures/2025c61957af1edf111c891d3271ffbc.headers create mode 100644 test/fixtures/23aba1f4957dd22a5b21bd71c8dc9be3 create mode 100644 test/fixtures/23aba1f4957dd22a5b21bd71c8dc9be3.headers create mode 100644 test/fixtures/24013351b3e17570d846426ee2b36c7a create mode 100644 test/fixtures/24013351b3e17570d846426ee2b36c7a.headers create mode 100644 test/fixtures/25fff225406f7452de82b60beda3c931 create mode 100644 test/fixtures/25fff225406f7452de82b60beda3c931.headers create mode 100644 test/fixtures/2694cd9eea8687ccbda862aab56a0e78 create mode 100644 test/fixtures/2694cd9eea8687ccbda862aab56a0e78.headers create mode 100644 test/fixtures/2ae8ed6772af1b8fa844a5ac6d2b12b8 create mode 100644 test/fixtures/2ae8ed6772af1b8fa844a5ac6d2b12b8.headers create mode 100644 test/fixtures/2b7cd5ca496a1d302cc587411cd36ad4 create mode 100644 test/fixtures/2b7cd5ca496a1d302cc587411cd36ad4.headers create mode 100644 test/fixtures/2dd9912677b480dba99a99c809078688 create mode 100644 test/fixtures/2dd9912677b480dba99a99c809078688.headers create mode 100644 test/fixtures/2de45192ad9def59746abf53a0eaf6c7 create mode 100644 test/fixtures/2de45192ad9def59746abf53a0eaf6c7.headers create mode 100644 test/fixtures/322500542e74bfc6c6a5fb3b8d1329dd create mode 100644 test/fixtures/322500542e74bfc6c6a5fb3b8d1329dd.headers create mode 100644 test/fixtures/37d33226e906bc384a86f29fedc03834 create mode 100644 test/fixtures/37d33226e906bc384a86f29fedc03834.headers create mode 100644 test/fixtures/3b60588b620d7e73852e4800525e40d6 create mode 100644 test/fixtures/3b60588b620d7e73852e4800525e40d6.headers create mode 100644 test/fixtures/3dd3f9a8efe08f8d1adb70cd6ece87d9 create mode 100644 test/fixtures/3dd3f9a8efe08f8d1adb70cd6ece87d9.headers create mode 100644 test/fixtures/40170c882e89aaeeb705e1191c889d0c create mode 100644 test/fixtures/40170c882e89aaeeb705e1191c889d0c.headers create mode 100644 test/fixtures/411c0b53f75e4380eae0424fdecb902e create mode 100644 test/fixtures/411c0b53f75e4380eae0424fdecb902e.headers create mode 100644 test/fixtures/45904a407101915f2a3273f907166537 create mode 100644 test/fixtures/45904a407101915f2a3273f907166537.headers create mode 100644 test/fixtures/475fed802529221edd39de95047235c3 create mode 100644 test/fixtures/475fed802529221edd39de95047235c3.headers create mode 100644 test/fixtures/499d62f35c5f6fd86e3a29f69785cff2 create mode 100644 test/fixtures/499d62f35c5f6fd86e3a29f69785cff2.headers create mode 100644 test/fixtures/4b802038a4994a768903c9df4bc309fb create mode 100644 test/fixtures/4b802038a4994a768903c9df4bc309fb.headers create mode 100644 test/fixtures/4fc501bed2b7d643f741185069aace22 create mode 100644 test/fixtures/4fc501bed2b7d643f741185069aace22.headers create mode 100644 test/fixtures/535ab3a418fb2b5ac0c9476546cc72d8 create mode 100644 test/fixtures/535ab3a418fb2b5ac0c9476546cc72d8.headers create mode 100644 test/fixtures/537dbabc1ce057385edd9d8c4599c077 create mode 100644 test/fixtures/537dbabc1ce057385edd9d8c4599c077.headers create mode 100644 test/fixtures/56d55db80170ca90872e69c2f8b7837d create mode 100644 test/fixtures/56d55db80170ca90872e69c2f8b7837d.headers create mode 100644 test/fixtures/5740cf0df41918fee30a22a1bce2791e create mode 100644 test/fixtures/5740cf0df41918fee30a22a1bce2791e.headers create mode 100644 test/fixtures/5c1b9b2cd173095ad489f4a6e36a911d create mode 100644 test/fixtures/5c1b9b2cd173095ad489f4a6e36a911d.headers create mode 100644 test/fixtures/5f54da66d9a88167f9dda7f1c00d73f3 create mode 100644 test/fixtures/5f54da66d9a88167f9dda7f1c00d73f3.headers create mode 100644 test/fixtures/5fba37b7b6619c61e3092bead860e8c9 create mode 100644 test/fixtures/5fba37b7b6619c61e3092bead860e8c9.headers create mode 100644 test/fixtures/6176ff6a5cf47eed252cc9d9219c75dc create mode 100644 test/fixtures/6176ff6a5cf47eed252cc9d9219c75dc.headers create mode 100644 test/fixtures/6526571b8ee23f940317e3232190179b create mode 100644 test/fixtures/6526571b8ee23f940317e3232190179b.headers create mode 100644 test/fixtures/6e3eeb66969aa4c71c2595d514f127f5 create mode 100644 test/fixtures/6e3eeb66969aa4c71c2595d514f127f5.headers create mode 100644 test/fixtures/6f630e7326d44cc51431dceffbb437a4 create mode 100644 test/fixtures/6f630e7326d44cc51431dceffbb437a4.headers create mode 100644 test/fixtures/70ae1dbdd83a22e8c04c74809d45b345 create mode 100644 test/fixtures/70ae1dbdd83a22e8c04c74809d45b345.headers create mode 100644 test/fixtures/7295737c14813766abe7f6d7c8a4e4c0 create mode 100644 test/fixtures/7295737c14813766abe7f6d7c8a4e4c0.headers create mode 100644 test/fixtures/759a630311f32c04c63c7556ca7a19d9 create mode 100644 test/fixtures/759a630311f32c04c63c7556ca7a19d9.headers create mode 100644 test/fixtures/771b51c0fbd414533c20f2d95e571dc9 create mode 100644 test/fixtures/771b51c0fbd414533c20f2d95e571dc9.headers create mode 100644 test/fixtures/79471f371a264a0176df177479190ddc create mode 100644 test/fixtures/79471f371a264a0176df177479190ddc.headers create mode 100644 test/fixtures/7b053660a24a2db5139e8e7ffc3a9225 create mode 100644 test/fixtures/7b053660a24a2db5139e8e7ffc3a9225.headers create mode 100644 test/fixtures/7e4ef1a9130fb6e4fb62cd29edd6974f create mode 100644 test/fixtures/7e4ef1a9130fb6e4fb62cd29edd6974f.headers create mode 100644 test/fixtures/8619ae4dc1a5c3e3cf04ac05ede71e99 create mode 100644 test/fixtures/8619ae4dc1a5c3e3cf04ac05ede71e99.headers create mode 100644 test/fixtures/892adb119a9924a464f3443d9f3b03a9 create mode 100644 test/fixtures/892adb119a9924a464f3443d9f3b03a9.headers create mode 100644 test/fixtures/8c969c07759e225e55132955258d912f create mode 100644 test/fixtures/8c969c07759e225e55132955258d912f.headers create mode 100644 test/fixtures/8cabf5fae5f37ac12bc602d38e0d7cdb create mode 100644 test/fixtures/8cabf5fae5f37ac12bc602d38e0d7cdb.headers create mode 100644 test/fixtures/973e11ce912c0bc44d3fad7d08d9c41d create mode 100644 test/fixtures/973e11ce912c0bc44d3fad7d08d9c41d.headers create mode 100644 test/fixtures/981e4a18c54b89e2537b7660cf8ed3bd create mode 100644 test/fixtures/981e4a18c54b89e2537b7660cf8ed3bd.headers create mode 100644 test/fixtures/989521e0ddda97a5a15e7564e4a02100 create mode 100644 test/fixtures/989521e0ddda97a5a15e7564e4a02100.headers create mode 100644 test/fixtures/989db6ea639b5dc2f24377b312932f27 create mode 100644 test/fixtures/989db6ea639b5dc2f24377b312932f27.headers create mode 100644 test/fixtures/9c392f735dfc18f1ebae5057d4810503 create mode 100644 test/fixtures/9c392f735dfc18f1ebae5057d4810503.headers create mode 100644 test/fixtures/a95dc0c2cbed192f29e448ff0ab981f2 create mode 100644 test/fixtures/a95dc0c2cbed192f29e448ff0ab981f2.headers create mode 100644 test/fixtures/aa96a948b688bc7d7aa7726a61cbc4e5 create mode 100644 test/fixtures/aa96a948b688bc7d7aa7726a61cbc4e5.headers create mode 100644 test/fixtures/aabb63c196e05819a62f5c4236dee819 create mode 100644 test/fixtures/aabb63c196e05819a62f5c4236dee819.headers create mode 100644 test/fixtures/acaca90fe77e40a25bd38b95282272c8 create mode 100644 test/fixtures/acaca90fe77e40a25bd38b95282272c8.headers create mode 100644 test/fixtures/ad5041074ea5fe6a4f5046944b60f216 create mode 100644 test/fixtures/ad5041074ea5fe6a4f5046944b60f216.headers create mode 100644 test/fixtures/af29a78d9191b600ced4f7f04570c4ee create mode 100644 test/fixtures/af29a78d9191b600ced4f7f04570c4ee.headers create mode 100644 test/fixtures/af7dae80c814d6fc8e5a6d4ff4f6ab96 create mode 100644 test/fixtures/af7dae80c814d6fc8e5a6d4ff4f6ab96.headers create mode 100644 test/fixtures/b2757f369119107b417af16a5b5cc57c create mode 100644 test/fixtures/b2757f369119107b417af16a5b5cc57c.headers create mode 100644 test/fixtures/b4bc218a89b1ed34a74924a42db92b8a create mode 100644 test/fixtures/b4bc218a89b1ed34a74924a42db92b8a.headers create mode 100644 test/fixtures/b5b153f3c2c39a5cf25fdc0ee96d0fce create mode 100644 test/fixtures/b5b153f3c2c39a5cf25fdc0ee96d0fce.headers create mode 100644 test/fixtures/b63c630cd8a47258d3cd45635adfe2fd create mode 100644 test/fixtures/b63c630cd8a47258d3cd45635adfe2fd.headers create mode 100644 test/fixtures/b788432e4977d8a7be60e806b42848dd create mode 100644 test/fixtures/b788432e4977d8a7be60e806b42848dd.headers create mode 100644 test/fixtures/b8cdd376ffa05b4ed0fa88c8580f6d78 create mode 100644 test/fixtures/b8cdd376ffa05b4ed0fa88c8580f6d78.headers create mode 100644 test/fixtures/ba515718537dd9c0dcb6332ee59cfead create mode 100644 test/fixtures/ba515718537dd9c0dcb6332ee59cfead.headers create mode 100644 test/fixtures/bb45b9cceba8f0e6f31f18ee670ecb7b create mode 100644 test/fixtures/bb45b9cceba8f0e6f31f18ee670ecb7b.headers create mode 100644 test/fixtures/be14b8e0fa4d1830a0ebe40a016ca6e2 create mode 100644 test/fixtures/be14b8e0fa4d1830a0ebe40a016ca6e2.headers create mode 100644 test/fixtures/c125b6361991fc5455d24693c30e9063 create mode 100644 test/fixtures/c125b6361991fc5455d24693c30e9063.headers create mode 100644 test/fixtures/c1db4dc6ce9581a6fb82f326ef7a72f6 create mode 100644 test/fixtures/c1db4dc6ce9581a6fb82f326ef7a72f6.headers create mode 100644 test/fixtures/c3211588134d80d9447ef9f05e02690b create mode 100644 test/fixtures/c3211588134d80d9447ef9f05e02690b.headers create mode 100644 test/fixtures/d3eb06ea06d807205b713eac5a9bd710 create mode 100644 test/fixtures/d3eb06ea06d807205b713eac5a9bd710.headers create mode 100644 test/fixtures/d6c3769fa2dfce68ebbdb04a2d2cd559 create mode 100644 test/fixtures/d6c3769fa2dfce68ebbdb04a2d2cd559.headers create mode 100644 test/fixtures/dba5a1e96a4962a5370bad858932e11d create mode 100644 test/fixtures/dba5a1e96a4962a5370bad858932e11d.headers create mode 100644 test/fixtures/dbf0c82ddaa7681f0642fba3fb2dd351 create mode 100644 test/fixtures/dbf0c82ddaa7681f0642fba3fb2dd351.headers create mode 100644 test/fixtures/dce1cbd3f38b1de0b4fd7cc697131b31 create mode 100644 test/fixtures/dce1cbd3f38b1de0b4fd7cc697131b31.headers create mode 100644 test/fixtures/df2dc808710d6548a883bbbf3edecb71 create mode 100644 test/fixtures/df2dc808710d6548a883bbbf3edecb71.headers create mode 100644 test/fixtures/e122264f8b96cc604b7507bd30876d15 create mode 100644 test/fixtures/e122264f8b96cc604b7507bd30876d15.headers create mode 100644 test/fixtures/ea5da6f619d0bfa476d74e66f9b0bab6 create mode 100644 test/fixtures/ea5da6f619d0bfa476d74e66f9b0bab6.headers create mode 100644 test/fixtures/ea7434f5608f1a1ac1e0d509a624f2db create mode 100644 test/fixtures/ea7434f5608f1a1ac1e0d509a624f2db.headers create mode 100644 test/fixtures/ec5161eb0cf63cbaa64db8cf2e7727fc create mode 100644 test/fixtures/ec5161eb0cf63cbaa64db8cf2e7727fc.headers create mode 100644 test/fixtures/ecefe1f444a1e1e90f3158416eb2da95 create mode 100644 test/fixtures/ecefe1f444a1e1e90f3158416eb2da95.headers create mode 100644 test/fixtures/f71ea9601bb094d68114cdfa9da584ac create mode 100644 test/fixtures/f71ea9601bb094d68114cdfa9da584ac.headers create mode 100644 test/fixtures/f9ccd6365663fd88cef3a99afb0db0de create mode 100644 test/fixtures/f9ccd6365663fd88cef3a99afb0db0de.headers create mode 100644 test/fixtures/faae9e2018b271b5f0908a41d07847ad create mode 100644 test/fixtures/faae9e2018b271b5f0908a41d07847ad.headers create mode 100644 test/fixtures/fd213f6dd613d91b8c059cad39261cb8 create mode 100644 test/fixtures/fd213f6dd613d91b8c059cad39261cb8.headers 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 0000000000000000000000000000000000000000..2ae87992b0b983f7b8763b24ab58ac01f27dbf80 GIT binary patch literal 3645 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 PjJET?#Yt{!Np1iDTtNT8 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..94f0e471ad2c08f5914d20dc3f58abc9d1ded61b GIT binary patch literal 5112 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 aE5-!Ir`8oaY3qui{r?vk8#vu{WB>qI!vMno literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..f78ef6e9aaa0db0923500edfae2674d34314c4e5 GIT binary patch literal 5244 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 L%j(p!?E?S+;ztTN literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..29ac8ad5dfcf1f6fdaa354f6e4571d9cc2797449 GIT binary patch literal 519 zcmV+i0{HzOiwFP!000001C3Hki`y^|{wu0ZEqFGzEL(Pt3uO!2J(WF`9`qQc0!Ipx z+z>+kdu4C-MQQ0xjAp+19&@J7&@EMC!!2tB3h!*W*2;!FMlotXq&!=26Ql(==M9kyQM!WnnKLrobes*rTX*aeaNJ+A|)@B3CU^*nG=2>kM|_aDmmk1Jdt3@ziy0PegmF% J`LBcn001`8|7`#O literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..f449869ad0116c679c3766246b3985b295ba4657 GIT binary patch literal 721 zcmV;?0xta@iwFP!000001C^B9ZsRr(hF?X{wI`;;b9&dCUM<=p*sCHaco=$#RV0I= zY6OOXzC+)zPg2s>Ch^88TEKvz;bCUJ|K}WAlhCyH$2R)*zGX@~)SU$(xB^Ov1g)e5 zsks%3bLO;aH|;#745N9%a^&+EGy3Ksn~ZZ=`yd?W31}w-bl@gmLifM5pC8)CP3z-q zo^0GLCdX+kN88hl;9x8c%`Q#Le$(`X@W223tNiI7nh*zU#;Hj-pqX)QzF@+Vafkt7 z-kY&@hhuH89w;jocX7OYa;U$)1j`OAdvaQ^RT>kilv6&MBMtOjO$2g)J^E>WQ4wv$%W119Y-U)`~!q0<xxWOz zn{)z##jqFpks z#C%NXR*A!u4kr2b%`W)E3`^a6JiXLg`z*U_shf+g7eH%#3L&~^hGs4XEGds4+;%(j zddVSvjoxJQU4|P4yi%9kD~XDN*S!SB6#;7mEik;3qUR#4Z|9wI*V108{ync%pmRde zOC)`Lr`8)_Ryi=#cE!%7NI?wiC_Q`XO3Zmx^IMB|Q`&9o$M#prMb9*APdB_#LH-}H z{sXp^^S-1o|4!i*GVf4(+ZRJC!GLL7Ol}GSCW)6;b-{3Q8}i3)zZjU)zIUAj#aVeX znjlz9L}ANav33x~*xN91ynAWm6=r?lzrTIl@63OCe8KQ@ily7)*lt}@Wat(^~#d(|%(N}HUw2V1D*LnPK9>U{gRGt0-2JR=V_yqs} DsBvYN literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..09e8d8396c4dd2d15fcd0d68dc27b634dc9141a3 GIT binary patch literal 661 zcmV;G0&4vqiwFP!000001HDwqZrd;v{1t;|znF`-`PM^@1q!6-rO1KHqeDcN3@tGN z!~b4Nu@k#65VR`Xt%3b?uuJ(Dq84r8AiMclt-z+=6wLhGdiV#)L{l zLCTbqkP{twJAj!&dTVqt8o2ZUD#s&ukr)WYjJDDnPBod$VSy)C_qZ%X9fm2XLXg^S z@48qpZx${xIxY{N80_2T)eSGRL2RH8u34SUMTfE&)Sy^WP;pg(!w{f6F{`~~%WMDiBkQx;R>6!M5yrm?59lI=O(pZJ+10pDM5&`y6(o zuXF#Do6XdOm>c(!-MJ4^*(j-IAeBU@jFMn^#Q{?g!eUh1&1Jvd+@!Gr}wFgns9mX#rOixv0ctMkO-Wp_|~jZ$U7nfX)BKiIF_q zlgHb_XU$y1a_KaOBprfCG=NW1f)HFA<5;X!6e0{4Q1<0OxWEV0HKs?VYFdflE>pO7TVN+<^=!%%923J literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..3c968ae6aa37e4cb032c42c9b06427950d813ea4 GIT binary patch literal 305 zcmV-10nYv(iwFP!0000017(oSZo?oDgkQzt?2Y&_80RS>rE1TMSvyD$jto9jQQo}} zrR^cdWj3Nl^n>iJK)_y2pg38;PI1uM_gV_2 ztars_T-VKqh?!FDxvX&xdG|F6gp>!Rgz97gmlE?5y8d8q_<+L1nsSVi9O6W$1Fc^y< zwRc8nqb8hc)i4pH8^*ekqdC-CVvrWN0xk+c(Ni&;a7px>*fH+Q@_76J<+2|kfK zN|xIsO_2b-ahVx@^Zx^$Q9JhSi1yzeHmE(`R(_cJlAq8X-F-zH)L9oh@I#1b-%njv zPudh=JlY=Z&&b85tqVkq)PNZfQgdP-VnF+nr?_mEdqV(oblISB$OU?Ps0GpIPxrg~ zp?|7Lf1k8-BG!p1D+v%UIB+TyI7R|!f|I4z3m-&{Elgold9i%Dwf&VYdv}jxntCJRP=_ z+`6emc(mO#Yja*?$Vd4rm>%E8EJx>N1l)E45DcI+n?HW4vt6w|-tRR>YR8 zZ8^228HNRsvhMJ+blV@t=H_&w9y4huP;OEk%Ot=k$Lo~h7)*59#rQw%T>I#TW_ZtB z$3#+^QgDe?CkWToTr43uMVXf@M(tiZ`G(Wa#rcSwvw*J!ek)*khF`$*j;Dzzh5lWP#ADG&=9r&mB3);4iWjEwzN94_LZhg?zbMT6|N<#=3 eQU4)g2q(fQ<-_v3y<_d=;qnW)-9fB)1pojzTSH&~ literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..4b81f6f2537903c12514630839d2270ce9607970 GIT binary patch literal 568 zcmV-80>}LyiwFP!000001C^6akJ>O0hW`rknSnS?9GmN^QV;E3daOA3W6W9&HgcRI zg!u1uvMhyaS8Z>Z$&CHJ&y3H+`a$ir-;FB!7|4c@B}v%N(Lgre&m^A?Sn|<1Z@lUk zgU?usRL;rkF(dp`{fMRZd|8qqj>#aHgx2TR(=b@F31i0&ynWXmPzck>?@owZcb*rLY(>)Hw$r&^GPOK`GjTEU%=tez+J0OiW$h+fBu z$NEO+(P?XI+F2<?eg7sF~pQ1sQo12>BR?Cau4C}LZv{I^jz%rUBX4YI=q z7l(@c literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..51ec791c4ae5e19ee91b5b75c251d7581ff67140 GIT binary patch literal 783 zcmV+q1MvJGiwFP!000001D%ykkK-s1hW|>$In@CJ26A6%N29sy9#?(fqsX9kOl0GY zT2cP{Vkgs^^vBHh-moaBdY^hJpGcP?!g#Pf*`A2QU8;+I>bf<-K42i*XuA=Yugk`H zO~yPF=T4d*uDX^z0{Va|NC>VL zD2xuEDIx@qrnN|UgUuW}_Gu*BzaH1b=czBlb3Oa@k9p^?Y!FHt#ifw6<)lV+)?o)e z2mGNkq|xqO+D*2kT-B34mzC{TX@3|}U)HNb9t$*->eV>8F@VHP?K9eGXAmNFza6};Aa4Xx>Y-i>6&It?Dd4;WIZJLD1r3lHgxR#7Wxr1Kzb z6TtDvfVWI5Bb{!jst4{mc&+L7!nv^8=;cZ-Jj#YeFhW}pPMeCDItZ#!LMY1_vPI{m zuzKQqDTi^p*&L6@hilyrKJPaR)J-D|;|)3ANQJ*`H_d`i=Na^X{>nJ!;b@0I?u>Q1 z(HoIb9R&yLovC^Q1MQH5RM?`Ijw#oYcO~8IhluwI+aITtWp{&8t~pjgML& z|7pF?c`B2`kIje;L&_)v+1AM@+O`EJgoj|X)GFA>t@`-IUaw#JJ&ibQ=5f4C<7NDQ zwvq3_dky#w=Ho3a!6Rq3ZNMlL)nBo#E7^dM+%wLcVz|73xv*LOn1QpZmo2ks?b)WiWYSZ44Wl3`W5H_68zCBI(4=89pd{N9S$ml1HTJcFw&emStvcvM*Fo2F z)e6p;?nUaE#}L8G17=3vMKr}O%7}By{o~uXSss+zFEYB(r-H0w9)Z?v3-u}?Ysvy2 z&gF$o&Fd;jkiZ&K0qZ&mg4!Ms4YeH?x?}VWaX0$oI@G_ob4&A@9h^m&C+V|f^ybC3 z6ec&eRt__kMB(1~OX~a%^-mvn#XWhJ!!PIe1s?I96vMb5i}49V5g)P0ps8f{?dy+} zbH0#;8h@9?GAB>c^Gh1#;llxg)6y3K2bA;bQwmp@Ea7y!P0DR2ng*1m8d%K)C|b2( zRo776QbeKF%`8D9=zzw>i_1$Gve5;BaoXP9xt4AcjpO9>MvsTPL2>hEGx0D literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..de261359e6f66840a6e502e3dafda988046fdd2c GIT binary patch literal 993 zcmV<710MVziwFP!000001GQCcZ`w!@{wu5fluFpf20}q??5|DW7+VkW13&i%8 z?ZX}^#d)y(HQAfZ^&ig`q(NOOK|(*OK*G-A5D8gNmFDXP-zMlXB3zO_PSiwc$=Pyy zWI@1;JE-LqGb#Rer|x!nC3yU#N!h`MXf%U4BxJlGRu{(Nqibigyw*78qo5Jvz^yW+_X1RWW8Axk(@wPHvjG0VcE$>(%U_tKKj0>0E z0CEf27&O`Co&tH0++{MbNZeFa-!zaHe^=x{tDZ4nOy+W^igg~ypH7_*-&?tgR1tz) z;0BZS6+vp`KrnJ4V1ieI&wwyn(kdywVIywF>Tx&dv1R^Ikr>xQS&L6xB(Bk(5rXw?<7p$ z*$5narGb={^E_geBAO+R`_FSeY%OiE#Q#tJpmG6w`D501{(GO? zVzfa!(?G1V)^6O`je=vAB1fA`T6_%7)*WsIG zM|#$3J}%tQc!QLo>OH}q;OuY}oO}3MV4Ek^xVWp}EWC{-4|=b8ci*KAjqNq5b|TAQRjvRU+`)=QY&(pf(nsq)_Ri%hfpK8KmLkDd1ps}f|p*dYx8PhFn l@3Tu`-YY#nrH(E3-tazied|`gegQq7!`*KI008BBYp?(S literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..7528ad5c24570e044a6600cd8f99d87ecea8e4e9 GIT binary patch literal 747 zcmVmPS3r=P?KVSVP{&j-lNd^kcFdZhOjD6j~&^tNx1@1OgK8Mkm-Xd2cAoRZ_^n3&F9o^ ze7DWgJ`HAT(`GVb>dI;KG|yS>JdZX?a6=?uOcgLgYp~KQpqArcFxMn^SMYSeh?GEP zYK2rGd6)YdA9h9l({|UVc0|V)FpFDBwXoCx6NCfvoPowZLUd73ttt1jcpsX%-J-fj zqvYIXjzCi{a%Gu3v?310w0KZK$6`=b=v9AwqaV~cKz3B^|r`jc;3!!C*((mddMu*k@ zV$DmP)95XwO}FW;LtA`hA}UQO*vK+?!gU6ZB}A(zbCQLi?U`-owq9ni@PEN{K|17J z+Ll$yP;aMS)i$e{BU~t*50&ehuCKHO5m1J(9u$$l&PG88WTp)Rg0eT^MCBGN3@GExn!D~A#d+1nEo{>27-0W zD`%Xo^LBUw+6D$f1sR;MMA?$v=W(}6X{)`@`6h*dkoj;{aLN)Qg^|IE^SHmX268)# zJ#S6=3C6d^{$z_U>pvfs2`mgJ3b>3p#Q8%AhAIsTI~;h8WnS=q54#LHCvd3pQ(abb}VEA0X8q37W+!m*?A zm}nK{-|=h`lJJz^*xgfI<*N3c#BChN>eJ(#w6O^=Y_TJ&JqevBt8Q%DIk90KyK^!1 z!!&8I9l~Kw;?SMpDYTel-<5Jtd`!WWlB`J6ryV9w<|JcUhYa~?8>ar4+Dp%+;A5V; z{+S z^&o;|U}<20+&Fq(5j|V33HC3652>+YoN7OlW@lYy%4~4u+~XISum|r?sj=S6jxZa1$=9HnsP1*Ia@1AC_?%vMs#v!`dn=XfxF?O5K<=KmS zj63XJ&faCe_|AV^@-KKy0gIC->~UI58hYSVDPYe!OM>L}d(f0T-m1MIimiewu3d0Y zqiBGe+JRA?LE{wKhI6T{BqjR+H#V+EJRQI_BfT)*Kaj^M1lNyUPEUpH;ml+xtwPf< nkhG~lFpE(8AYqDCORYlPC?r?^#?hjmi4WfZJO&>Kb_4(bu+tRN literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..82ecf82eeea9a11c7be8e5fc4516f4e7bb4e7457 GIT binary patch literal 497 zcmV?u$h_Eh$ukEc}Bk%J^R zgpmJUDRGu;>8;0y-n<#j%!Rn4i)8cTeMJI}GP%i@@j}oWvhnjcu82%2I5j6+78UND ze>~1%B%4bH$7v24$%gz)=@>Wb_33naF)r$9A7AuzSdUWSxTahPD#(hse4o_9>fSI7 zZA&?@&I*uf7=W>wQdwJr*pusuBpLRYKnFA~Wn9K*ftXKNIY!J2=VRes`112z&L@O% z0d@Id9_GUMQnHD7T;G!kc&XH2W0Jd3f8A59Qy{#W-X2Elg&WROmYc@r-CG`@CzI(L%9vOYFAqh_ zZt~~q%l5U}&e7@Wt4|n`bpC)oRl5{q$_>!fR)$}goZnZkVVaNSq_YU|D1E8K5>N^= zuAb}kRG*xzi~do-IE4iND?tX7g?+j6=3PRQ5wg^GF^F-YQ8WtrzT-e?JwQ%=fD&@g nyN+qW$-l#MaRS=(Jv2Axit-ZUU+O=zUax-u-XkZ)X9EBL@W}Y9 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..63c97939805aca8c0ef5e8f377af4f22759fe494 GIT binary patch literal 301 zcmV+|0n+{-iwFP!000001AUNBYr`-M#lK3?IbwDlw@Ge;jhzOAja|kLQmk|a*C}yw zD5c+hPXDlt!fv+op7hf@K=7Sl+EIk&01}-zXgUf>3SimzT#i!+#oRhSj|D{93N-NA z$Nk;?+xy~qO1@pZOdNdr@^J$NwEYyvVV_kGkNN9&K0)*GS-`m83Hm$>q$Xz#D-`1t znyRu$S}|6-HqI(-Ox4cTSz9Wu*(ryzTy|LMuEMNmR3$sAS8Fz0XKf&sfNk&OicN#i zeAxy0Nro-OeU_$v81bg+Q;$ZkR;W)?X6E^T%`=!b5Qa4Pp!2@J$y8Z=3Rq)3qNV3a%VJjyLQqW4xn&shoe|ZFovsv*^U=m!@-l}+UCp2=I*#>la0Z| zk0z!!*!IvZXfqs5P`j#mmysPhs7shu`qG-~jm>t}d$4QrE?iw(-+hpXO9{o8Cn$N% zP7;z|sTUGAOa{YAvOD%kFC-=z?|9n_@SgE*hVo}8y>VjRGCjEH`@^XlJ%Pu*{u#J5 zFx_ic59Uiy;kYLXF^4f?B-6+Ul_5iTYBWimS7AO0pZ&~m)OU}2&c9h2bFt)Y7-KJZ zG~O|T_@d0iBB{*CI!7-WMiYSOG+hM5 z^hVvwr@v3(ok``T$r-)14!+5afo-=Y4r;Efm!Ev+{byf$_t`hT|Lmg=K6&@Ud8euc zr`Lx!p}Bc5#pD4)BC{7yMrL6BTI^`0Y&_iU7fa}@#P+=zB)dEH?RwkL#lhst!(rd` z1`iTD+|Gt;Z@(EU=j#`%z@$kDB35w3sgNjR#34m+Fw|IKotX2x8`H-Xc%0<(nY(^% z>q;bPX=xX3SNPPcCa&=!i+S}j9T;T+@Yl$?90jKmYvMhu{3;hu{CxPdd)v z@thG%>AqaKD2#1fKOd(H!5T8tqSP2T5G(f4GTCuRgnFU#C`qvvvWOBRVfuxqh&n3} zmw}=z)1Y)yOPLo63rFWDxwD(~d*g?GRKQ7^F3!u9^?RRA?(GizIJtG}dJR@86?!|p zIN&vm8B-+XLa4Pj&j)DQqogvbrn1%PYOmdXBgx-(|MtdKsV8-1hdqJk&dGc$w;J+h zr_89}?+5@os0Zlo*wh!8?T>#J+x3<-{P<@MsJJ_-FWs4;wg7x)(g2(wMU-ezlrjf8 z689LTS?VNcN)ih)pOF`P-*Ez8y82D+K7sqN_k;bte~G`J{(66JZ~y5p_xFCW z|MXY+o!`!T)v3+O)}TOXAq=XCwM+bCfO>mCZJscg8cVHlQ%66v-6yDjq;>(t!uWNgyio(i5IF zIZ7&ga!!qj9}RNeSMM}gRc>90xAFSDTN_(j$z#)h6eX#D;?EOHJq+b^W2tje zC;Lx-vcLDM{ipw(7kq91=?D9JKaD^3{;ifjwQkx0LC5r24*R=6G*j?Z&hMNh^*px*oQGJlMF**t#!%B_dVb(;Bkvu9HKVNLtP5|b;R1E*J$ku6w^mr=pIb}%!w17;_?90flZQUXEL4fA zE0pyHiAl2I=P$)Du#1;Lob$zuRBfb-F(N-=n-GV*!Q zJ=uoW&m;1=V|=Y)E@s2?(qt(O8441E_HIBhWjY1AXksmQiVC?fJW=*d=ON*$Cp*7g z8RmF58~0of)>&K@Tbmon{hOB(h&Y5aUrLbCarBih6&$$Y(a31_nVginIV5|?jWY^Q>CiY*F=CN zhUDog%{2t=ZAZ@E42@Zx4m~{Hf?W=|BP*Q6>`k+q{`{}s`{dWZ{N$g$`seR`>)GG_ z;@LNUz0kjgO0zzG;o+$p)|vHII6$pQwL;v1N~y5+h*BV)p8xT~T>O)j(m!o@`?+`7%`ZR%HVe0rnn5IVJ4{SfY6U++4CE=|tVCp_y&#kWyc zekPe|r@W|F@#qzJZ@Xs0Va5o^BZHX60&%5T^lWfM918?YF`QCy3|X|8;(Q?||HUJu zQDd8mJlX-F0@Y^fY!ps|;b`0RbB%VI;E!_oG&AFSB}4srm~Ewm+xC*F46|B!Q&Z_I zBWUv_@ZKTpzjCky_I{ZE{kujn*{=O_8Bxq%J>j5^dc+DNh8wRImg)3rm2XQ9S4PdP zm1bYmIQpCX{HGm|Y-C{_tFPRGn@vug<8M{YzU6b5zw2-kYNxAQ<1Bhr26DCJTqrXw zIMZo8?o5;xJWtN<*~RpIn+6s_hN$Ek@yuJKE%AtGZ-g;K6JAK)uPQ7;wOEQb2B0n^ zcix&@uJg8aXjV~MO8&H2m@U^=K9!Ur4$EFN?!{0YSh{*apSf|ntj{<`j5b6d!DK)z zP2*+Stgs5dZ{Vv?Ud2uP8+BB-k8=E9yI9fze1lOlxaH$~I0DAG5%GkLOXQFLfJ-z&qxWK}s|Ti7eJe!q-rf>V#9{K!(K5X->o%OoQx z0B00fI*YNN4`ue&Qa|VSj~R-6?e-g2YLjf&?{D3^yMF7&dUEH=t-_qPZg2)3prskY zckaEB+`6%uT$pw0;^GjxG+RYJ%si!lrdS6Pko2HNaO+c~c;*m5fv3i$)O&S0?EghS zh-ncQll3cGokT#X;T+U2RswGvAi*&GD>%Hs^2F8KsJsCb80HU)eNfXh-Xt*6wPyXkF#EMe8VnKSyv;I}3X5f7Yus)BIC*1O5p1*D z&F=ZR7+b3z#?xZW{Nc;r%~Qmd+wY4W!PfOxq3}CU>WzjmdTI?o(GaApQ^;YbxCufM zlC_26EajsHdgZbeCMGS~uFh&nwM527w(4@j9z=%+z?h7tArl4Q+#5c6Qr+wu?=@r~ zu~H)5{JKl-QT=9?WyL3Qh#VdTvsT(cI~_?eI+$v2aXe^D5&#Ed0cFO-Eg*mnZM^cX zU=3E&yqEB)yBjYqXH3(=^Wlz|YrLd=%x+4qjTe*qH%p_R-CU`%BvWPx=P6=br-%!y zz^*kONvu{X`)e{PH>R+dgSqKO_eK4yjQ4f1}<^E2fc~ugHlvvb~A~2Ub6BF zC;-gyE}2Emb5z|Hd}Q5~hybpGm%tHVGA-hmgEj(62x1s3%RQ*r#Ume@H^)}clv@vG z3?l(S|EP9*Y_&>t!$Hp39>f4pe!icW>Jj>dB=q_oB*82bKZ%TV2=Ojg2CL~ zR4$$-)Ks<#lqkn=kOcHDoq{Y7ptEKnm0+JZrm;^g}2T_Af2=?6+<9aN5N zaURHiNZ~5CXlHCS4Y7u0v}&*lM3|Hc;swm73~{@LrO}GvNO+}j7O0di?TCn}3a~z! zfT}k>!h$K)dd|Bs_%YLZYU8gz%8S0T|MbWEPk*z&_vLxtj?r@EdpDNT&j=!JoCC4X0F_3C zZcg{bEiYNA;Sw+*nGFg_slZgn7=t`XH5l!w$}n;8AL~ZSYVh!->EW|2oW1j^1)ncZ zX(~W!z}(v9-4b9 zPTkGoI4?|}U5r^QD_`x&M6+mM^3vV)+t)Xe3+r_!5;as?DLgsObmp)_p3?jj426^e z?FaMB84da`%Q`B+Cp}B7VkW)pN82W6ONAKWM#X<3q@ckWM407>5m1CO@4-Cr!e%50 z;!MGRGJj^VTZeZ~E9jkEczNSuJ;9qRu9W1)3*%sQB1J)O$88?Qo0utpy-P!D?@p`T9`{V|aZF_Hk~&## zG>7oL$}x$Yq)ghF_-S|m2y2T}>L>~}HCbRRWu3WhN`rD4ohDivu=)&*Y7tU}xfjf|!o zX)lBhED*^Hhn3cZ;##fFrXVx#iqVtEmd)c3b|IHz*)2CPWaG zmNc8^vUg7|M0QW+Yhlt#Z`!Be%Dhv zpRtiFCx6h1ys^s%T!`j*>%4RVxh$S11=*5&o~YDTqP7qtRzZ~IaIN%CS3x;swt@8Q5>Zd|^8`K8M-rwH0j zhItO!0%F#y7P1SNORSNVF76A6N9d*Apuju;RU6G^HlK)Dw@U+^-|v=eCSuHxc1+N0 zGod$N9*#l3gJ!G1qsX|<0?cv9Lfp!yG~m(1^JcNhqy|=J8_&UMhsSFpGw$_sh03%? zW4To)6}N^hgbSeKU+9%j)jhbm z+Fg9pDNFhXGuE;C8K3C3GhEnJstw0Xa*M1M8G;3FQN{#A83m1)D#ev!Cx+tvn}y9= zt)_IL#hF3yd}Q2JKX`duV77F;tkB}ZF$Fc#8M4erO+;a&r3)w!Mr9^~3z_MPrt1%5 z=2IuGw%BA&@awlK1gD@2aF-(E9Y-t#ffR8hKe5o*)PtE=_()Fv+)^i|_fD)S9X@(_ z$w~tN6zIhR2RlEFgmYk6Y7##i8B!{=O{pPAg(O=A0Jf|d0824%RrVLQZL^?KD+wmN zSTvZoDsdpn9Ki}CNf7Zvzyb8ZEP%Gd0F+9>a`(2N=xjaq&X+CbgPSM(JXq7vlJ#pH zCve(g70cLD?Gy(y0_)Tw9#o1HGaPA6IVO~)L?00Wm|Zc#u&stJ>fr;A89 z2OGTG<|I@$h~B!fdE;K5A>N_tN?C+bsUR*ULZ%k9SkTsxQPLr>!mVa8CgG2W5w--y z>>SOD?P0OdW)2LnZ=_B)m0ZB|Gqb^8m8n=Iy0aGjNH$VQ_=X-W|DYxPh=acJ~KiyhWSk}0`4*Ei}`TB8` z&&}7%7z7clGHPA?LMuazNDx!RbL1t-yii0jUCzKqNe26orpxmy^^ z!CcjnWL|bgf$9EmoW#$a_M#KyEi*_=Ke4?SZ7#r1(M+UDAs6BiI-U}wSxjWfuyTX} z+ft1Op0t7=sAmI{95fzxHGGz~E-0;)!)~NiB+KFvHyTuJ#+8gxj3XRm{_RR_P2t*2n%}A))P1Im6Xxx z&C_JL?}`j zqp9~4#7`jtao6|8<6U2$iqslPTa&oY{6Q4PX7tEUqRQ79O-&Cee%75Z&h@#<{%*Uq ztZ9T@>aN1>rr1zIi3XV-w;?-VFoue_qt!d&q-RqTt2>tgHaXlr2`-jCp+04#GebGn zyHD2fl>~Ye4pulIowA^CM#aqME+?lbcRF~{c*a00&Em-8mD)5qIs!fN(XTF+1)$IN zM5cMvup6Wf@{CG@Kf1b#E&8LRD%)W&WATL9Q89C7%;TE$^|XGV W$7%hu-hq!+u`(=3)iJgPY6bvipc)MT literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..8f51c27dda2b6ac805a9795fd43912b23d277c6e GIT binary patch literal 515 zcmV+e0{s0SiwFP!000001HF^Gj@vL0MSo?%TC?U`l)H2(12~%|*n&?l0a-FADu!YB z-$Tj|*ugd_l1`B3-kEzwb3(l~z6U!xkJiK7_YF$E*Ex>Egw{V#C?EG8qC;yWOsCqQ zTA;#M;F>xxED&IlsJ0VEQQV>iP2-%b2b;W$xyZ^ZKR90;g6=2ZAmg`jxHX$okJcx& zG;l&;EqMo=G6I|^4T^^rj4&Jr-?f1RROh?2D2k7q_tSc{IvftKE>3pbPOo;{t(H(L z+O>jVbZ(H&IYl#PUo*WoDC@NK`Dw;`3H;LiTnkS{=wkA=!YD;yOb4A@sjW=vyqAub zfVV(b>uX7kcW(YU#Xs{sQnkvNz-$1ILup8*1MM6K<3vYHkQ}q_Z>VxgTe(pEzZBo^ zif^;&>3p#@S31&rYq$`)Iw3zJF+ZacLsEoJ!B=Y03yjKgvD<@=A9uR86@bCLBi zc$oHjs6#(Mcv|t}_Rr6)KCz7ZxJ1KPu$GoH;J9X7!UXPQO9cZZd_6NO%b9Txs#Ang zi78=vAvMI?x!nI=-)Se9!Qh$0z?2f82{xce$DF`~F=dO^j`NVyv0~Vu^KaNDFqdTn F0017607?J= literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..78411f551ca1f5f606045f5821e0c52930f8ca75 GIT binary patch literal 889 zcmV-<1BUz`iwFP!000001Fe-!Z{s!)hX0DHb7+fSBAIJZpbNCY7HuzG>|yxjC89`y zM6Kfn{_hn_DWrhDk?>&M!LO~OUZn#R;ub?AM4-OpXO zECX&LbW_-0)jmydXVYeeoQ8734^=gz9$b%t>hGReF9fa&J3t4}X=RYT5W zvU3jPJ9KlvV~_ij8p>Ica9c}jw2E30Caog^m?xG;N_b1PGSX_+D2zW1^XLL`WAG{C zG5k~#Bd9Sv{lkyna=xFg*X!+eyFx5(*i0)o+^v_&*Su|o(s*#m+gPfZZX%&ZaLg+V zftE8OxwjmI0ELzBUzAd6|5|X5!5v7)Vcf##>!*4O`lqD$;UM3k+9zPom)~DKzR&0s z={e{hf|9o>qreN0301!v?Ml4a@Kl4H42g!;(11u zH-=c(NQ9_bqIv6yGc*JzENEJQzsYPGT!OCZL*5SKZT*_~`zYUbLIfA=Fx)Pc7r!rd z|Mar*0A58&BZ=q%A~PJ1N^FC@j(Z(i0H=`i(q+!- zw@tUnLx$BbZq{Y9{zFMj)X>F@=bO4@ZDK+?8Y( zXXVmMs?Xo^s`@SaRf#tB$8ggyX7cd}Fa{`cyc+LI^nq~NwuCO%EQv}HUk}~PWBCTC z#95{y0%&oxdC76YVjuV3Go@I4da+|SJlXCK@u+JfYHkTrI3>{+ju=M+PR;-lo1>wk PsrUZ@YE;cuzz6^UZ^yQ( literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..0c0afbe15ec562f74d89ff06a0024d829f697462 GIT binary patch literal 318 zcmV-E0m1$siwFP!000001C>#+Zi6ro{S|aG*V;H>V9VZ0k=k^rGT8V?EjcE_W4r(L??FGUxM)c}L3Eoa2 zj>=gDfA{=BvnBzYRm3!Ps4G#U&_be?f@5C_Q!;5f#%SS&0R^urp(=yM_J?rx<~ipd7cf=k@UzD%al zLmQT4dew-syKnL``1x`B`j$OU!FJi#cBm52@>SR{v~uwkHf{<(JIK z8%kz-LWX?CfJ``(@1Fap7m4sgT@Ar^geFnH{! zZ4-^6y!$D8?2tj>B6-o5zpMWGs@+FYbxqZg?WfOc606QV_-Z$}zG@q?CI7r%!%Q8+YEJmNl$ufbZIm&=>rJI zB6wa>K2G8T@#nQJcFd~iAbu=x~oOoFB4)U`tnW7;o$zwfr2&EaskMRK9t zb+_2tP3?TDH(VL@q&_;(dcA2M2npj(iGsG;vhr}S~00g zYknepr2)@yT_-w2oRV@XwG9q$a-on3H3BTd{)EyhD<$Hgero(x;D_p46< zg!LSplLmw?qV|TCP8NUe>#uMAS9g0Z=|>}OUh*5mZtl!9;5Syx1N`Q#SM$o<{k-ym z&nqwP7qMNomN<8d#?nR1&p()viFtgH45wJBQyz>p3WC)>;VcAc$?5cYk+UFqAq@Cr z@xm88f+-}v4MEwUDWfzAvVQiMUOq;l9hyErPOmynryqWLOD|i1yRX|iR?Uu_{s%IO J{39C%000;;WTpTB literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..1fbf0324463aa716ec5fd04438f4b015bb4b3448 GIT binary patch literal 369 zcmV-%0gnD3iwFP!0000018q^uYAZ1e{gt3~1orryU02<86SBIL;)iB1q@LiJxlls? z{dy)hEu=NxNJl!-Il2Os^yVvhIF#jl-b2che-C+B{G7)E2XJiKosPSqE@hxy@Fl?> z&bcR?F1{69R|-mSnCn7&2sGrijXP_R@mAa5Ep`%F`wBkykf)L-IQ#*2d%P3UYAYDL zHgK(1f%9HQLa)1o(r`k{``AL~ZD(vW$v5(09bR#5x$PgvrOfrCF`SMKpT;_4@$b|U zFS-8pW$pTrxH)jW1E-Q_O1tCiXPO>Z9(Uqu26y)sPnyL%X-3ssjb?FyO9s`k zD;rM~Rr&98?IdlQCQYNaGuXi8JBMRl@+Jmk!!xw`!%J>)8R;PxMN#K>IkrB3Xve0R zACVdXngO?WxsL;^Y+R0zVmFQOUDkFf8wbo_$RO*nL7+wh7MtI)Z$GnPv_td}`c2k_ z?D5C2JHY`+!_nCBYuhreHPNU4u@OvwI&W<=_I*}gC0U3CfiB_@_O&q%e5eM1ut z-Pk*1u16me^-|aLf_B;C?j3dho6_^}uvo0u>wDUh>z2d4>sE`o?1kW^s0|H_v{EjG z=86}{WL;Y(Ee{M-t(jNao6>lYrp~F#sR}laP_{NY7|n#Tj!6)n*)nieR@~@XStAOa zPcVCQdyb*&*UC2F=DR8v>S1fU64hEV!$!5f(tCFAVGnc&)TVGu^kdDdsxlxe^n30A@$HixGIVA zf@@#b%(_C6B)VdztUPlyM|9GH;bzD4%oc8?aNDXkMnPJ~l(3&cJQ9c>6Nqm=4+eG$ z9d{_0gNIuO`D8m2S-B%g|?z zx-KXL9WXS!q)44IpsXbGQbH9_leA~7ddTVk4sF*xeNbupE2g{T0zY!bSe^hZuP4z`=je(pka?O%Lj8tlu? zw{OS#_pb4=UD7wM8{5=x4im@cxSw*qvM|?qJa+Alyevb>p%SdtNbssq(UT&}snYS1 zTg}lQ0xpD7grFS@t|Ge>QZvIt%?ucdJtw)aY68?FOfr4A2_EL5i;k}8Qbb42Rnz6i zFseW^l$DiWLfEa@!fM*!f2K|L ZNAmZlQ{6N&4($%>_J59tWFR36000B{?G^w4 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..3ce3630294bd17473ef3bcad4e9adb5f31202c2e GIT binary patch literal 909 zcmV;819JQyiwFP!000001Fcotj^j2A{guGaVPah^=L7n@#TMO%Vlkj3Dsk7b16$dk z7|g$yPMpb1o5=#(K1$-{@EnqQF7jUof+iN5BE(u&P9R{V5~z|KpjIUq6DuQyQZD*p zSzwF{MGq;zc6 z_TBb+4?@b7QbK82yfE;AaPl1cA;S!6MtnngyEtPLCB|UA0jqoh?KMGND*}p6`O*X_ zQ()WJjJWsB_Q;^P=1no>``6_ycH1O^@qpcghq_3dD`7j*ayk{8?%1}=!qc{y{6sAs zlnP2Qg`EWB%ipOxPN4>B&+(a*Kc0)@&`u#Q*z4d-BKAuvf;JSPCQJ~?DDu8kw)E!! zV}BgN6mysJVce|Or_*W0=tI99SE1jpTlCbfl`bn;O%N^)5C)1(o~m8GX(JJYE-^T8 zF|eGvX3AvnU}UJvXjo`nP7XM1DZ^aNgnRi9CYY?D@yAT?9oyqs^_O@2%pu;wm?^uw zzXq7N`TEM-T-jN+fx;|K>W32!k;{92o8vO*=)qrD7M4+c^Y^9i3jWHOB23PT>W|2UON?|rYNKU?pDQWR{}6a z?%7y5<1l%L@rT;+*lDAx07;?+U3*qh1Otwb(wB8*eO0^?+3aykAJBM*{fBDJwEu+s z?`XeM-F+qIE+6yuz%SJ0@hrpPO8%8rEliziUqM+p4;p!hP-+FzMxzZXOFCSqa^|pR zlIn<1kv5=9vVe8e;FZwIk*~5o?9^}4bBJ! zC@e}}lMLy{{ahJAE_pHSYhHm^vkaB+fXbEDltw4>j@k!9{;=^TwtsRPO@kjX<3l|z z)sS`4TH(NJQSxWRC3(evlaVBOvj;;WJ)D8dH?R2bGD+}Ot~iQC{_v5wU3FDEX+r5^ j`1o76!o4l6UzM`TD0`lQ|GLy)zP|hoKsH6tlL!C+{#wV0 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..9d8aa333ce05f281f48cbbe4e3d9eb108e2b2104 GIT binary patch literal 725 zcmV;`0xJC>P?#?{(K7C;kH*prrqRhbn3mJ3SV+HD&g)dA zKH4)RWAh`I36h{cgC>WqRF`2v00pJgXrzsSwVc)|_0Li|!#dzxWz3zH#i1o49e>1*YlyLAs@Yd@cs3Yj=i#qa?}|l&P1w*dN}ja zc=6KIniEG_gVqHIv*N{WkP|ya!)24yNvAL}p)-(JM2dgRexnzu{)HW*&^bjNNwGm@ zlQ*^}J-ZmJ1B(tiQ<$Ql$==XO&4aC&fui!8x^hpKTsU#gwLZLID2yj3!n0|RRZ%(CC}tw#TIQ|mQQ2KB00?qmu^1pjnyuW4U}%WXw2%~lVoeYoi_UwS^@ z;ve~RiZOL9T-tG8AEI;HZ?Tief}_|e(rZnJSD*_0e|Sg6D2yuGa~JSfp|YQ(C3wVh z4Lbn`vV2yy8&^TcJA*DjlWXy8Wo{d+e?sO(sOy)>CV~O_P}2;oP3ClZOTXz~TKz<+ H&IbShsKs9F literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..e0d86d16a12a9746d93ba2e2d607e9ce0a78f281 GIT binary patch literal 713 zcmV;)0yh00iwFP!000001C>-wkJ~m7{VRgbp0!9yBDJ>yIV1sE6i9AC5BwN<*=R*W zq-rb-|Mv`KZR1TgNOF^g^Yz}mnR6Y|6jFWv>7QL4j?Z6X@CfOsr~3X}+y({lX9$t?LFBGc{j$ot1=cp9t43mB&L;WF6Pt~7G3buN$sX+B^ z$~aFthdAkx{_Gv4oN-(&rJZxFbDo1)GQxj)T#$@ss*|6N2!RUMof(w$N&@eUg;sM1 zMtBCIXG#v8QM{4g^tt<*bc5`|jJDLIgg(wEJv)lYdOl!=Qj6@%Jl6k{aK*Mc*cn~O zvfg#z@B%6W*8=Z;H!oOO1z|kLiBDKb=l@E+iWd z>CVQ-{YvY;Z>8Y%rEpsOU)0^2+=8xvuWep-=Nq~_vPSt_}#z9{VJFJ3!&`) znC-*95by{06XWMqNbmmoSe9@l_5I(4!e3|YTNS+2$jwGN z&ZHX#Ft(xbYuSSmy#qTiMB9=&nEDZ)l=io7#n#~4IJz($$Z!>)B`G_)Qo0`$w5}{( zGazu@b{#VAttvNxmPJ3Ba9H$)|4po>n5!jWrBkJ=b?tUlLag!w*(Q2jeVr#601jQI`?l9>^8xGYalZ%axE|6%AWh vE@_RlfJU)FdD-=Yu&<#g@hO5}eGhEC#bscn=vQ{Hg)Wybh;LZ60|o#9&b(n! literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..54aec554f8c5f64dda6b803d37711d0f393ae179 GIT binary patch literal 744 zcmVg9a#&MK2e<7?LBGjUpM6 zTq6kl?n^3m{%U8_J5eG>XTEbtKC(771mg}nws~aKMT%_GU^~*XjM%2zx9yU7+NL~% ziMqDH9Xl>r8oM;I&A;FCW1h#b5spV!fftPhjYfiZ-h!jr*A`vvgk($BqNf%@AL(4X z!~6WqzV+S1;_H4)VR5_nZ5n^1ZoByF2D7%m7hk%t%B#nInBY$q;6PY9d%bX;k-x<> z;=NDXJx-}F-LcYD4@y)Oh*@K4kloy}@6R&Ni|3wY^jbP)Avh&L1!=)+RGE;dU1LpE zt58@C)Xx7X+=|XVY@GHA9JkJoJ?x5{{m^DHr$OH| zDI{zcW15I9-`N?{K;hJB(+>w6;!Jcu1cES7Ow$vCQVr(*8WP+!S^)-MXHTO5=ShLF zR8cTqSYNScNv~@ZT^aj8PxbT5AJeqktk;LbVKv_Gey)D*)@O{!9hb^iptxy3HwFPK zB#_cdE*o-|8+JS{-=TZY>lMmRD;l$;>5!(0hE?eA*WbS0-pFTNwV>#^fJlu4%{hX% z8bR7x6e7mgs@VH^qb|_CY|D!WCQ4yrU4swYWDjfwPE`>?7DqvQbi%zvVC?4rbTl3M z;qF}q3c(NZ_6F{CT*bi#1Npwcdt#P1;=B)Ew&9yyVg>hB=m4Aqfp)P1j9LIWZEY1} zu#vOlMbq9U_*#!2X84o*F5B=~XMfA)2biyCbJk0>t(^@5IQJ2>r3kJZEES?eR8~i= z*z%e&hjf=BPPpoa?Ya!s{|KRkk;430QZJG}SN}ie)@*GG-4$3(Lm~#jDBv#RIp_B`G aLFo70G(41p{PyA%aQqLhStzR$2LJ#!kZVH# literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..da9742d2c6cb0af52fe75386f4c0f4cc78e524a5 GIT binary patch literal 806 zcmV+>1KIo^iwFP!000001J&8hZW|#G0N{I`BJ#OwGcXL02k5!?DysNxw((Eobt1J< z-o5NvX=J6FY$dwEKG`hT?56={){hsL`L)>EO1ByWezq)Z_4ZXiJhA;Tbht#5|s1YHYMN zze|d1En^h+WW>ui`Q1a@=WAb2uJy0SS1rS+TY}ds@ zw@h|x_lM=-VRd}B+T3@oUro97)yqs*hnv_0yT5I^HpFI^n!aJP+ie>R(K}??5iwl; zxcfdfzjb>Xd%y+2;#H5Q*Mr`K0IoR~l~G7xlTX%?w3;SSPyq=ofT%VJLM60GioCIt zBt!uT5|Z=UB%~Bz81cM4gxMrOD{g9&5Ryp@7(g&o z`25R<#XnbRpbUx`xrS-JnT@kN(sAb;*UP)@`%*a8Beb1A9zG)-y7t#lcmrbv0&kGi zl}Sd1G7z4ZByol{g(U0CWDYsqNn#S@=#lgcIr=o9EaVW9GgcJuN)90@$w^4lLh@b7 znL?6tAXC%gHd4j@bR{)$n;eCjT~abt)9N-hSGT|w5l&m(wMZg?tSKZJcy7^XCM-KQ zNSd*Vm;xyn1DC4^Uj}mY?#e>uwVm&=B1vNv1|1QkEVN6`DLG?3H%-zx1f@+G$(eGX zUQ$;UlL}0Th!V<3j^^#fB@sq{>q8_pAVW`*cp1sjIQb8fb**ka7CHkFZ_DGBPIrRti}Nn`uIP7qV}tRw;QepJ&wDYzsPq{4iJpOs|) kEEnoJyK~Q!v?hulD|ym#{pZuM{psTAH)p-cAY3E>0EQuar2qf` literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..97d2157340ee8e060813d2802682173297ada5bb GIT binary patch literal 844 zcmV-S1GD@eiwFP!000001Ep4LPuoZo{VSvS)Jk!jIDvu%S+QYPT4`IV22`zQh z@h$d@J2S4KH2=MK5@VduLfw9d;(6S2&VAZBXAx59{Am&(o0QxFc!9MybAPcDPGO?8E8Ie(Ax8j}9UVo9h@ zKeA=DEkng>TUOh$mhI|8j~8MI)@vFM4-XGU`}_XcZz5^C-|KNjcj(U{LH#OSk7G{2 z1`2J_X&(xnX(_V%6I54v9gxz3p~KTGE9uNqpm;ot_M*e#IO_2V6PNNh+VjFvz-8)q zJUSQ;dRz*n6%yoc3N1}W#;J3Kjl-}kGA)vRh1Zxvf}*d@GW4s$uR=<4u9XdCC?V{g zzXYr_SUA*bo3_UN4sZC2rP89JbK`!BFGQ8VO}|KsKV)ezIc_SY$Kl51;6x&v@O5)a zD$dE)KYtck=`#=whI_%_AQ%kUU_ahFjH6dRr@A!KAFqi#W6%ImQZY$D`KDR*_}Stk zNcTo;!*@+v4m7@{jMu(}z-NBau>eBv@+T>iDv$ z98mqH9Uh8wr#=nLU(^YDdC8f~gtdf0;lqm7>yD*$wcD-+Sj%qm#OYBeCQa^tR^_Hf z<}dQn`oZzEw9RGKx;)uzdFuZ6!t7fv@blD1_P#&P3@%a8;Cs|3uY%E#MT2-0#pBVl zcvC~ZxHig>Eret-Xo=^O1bk@qbZL&%w+OvE9iqow7gw3uY&5+#hsu>%!9JIhcH_cPPff z;b&m=U|=WC8C;aUGlE$vr~pqgyoSznEu44osYK(y1|E2wDWMZy9g_>QRaVV#uid!M zj?YQ9v9RIdHn1Y>>cCVNx5mGHw}qc~75<}(nXbA3 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..53fefe21c6972855b7785c8afddc2817bb2a6aa0 GIT binary patch literal 352 zcmV-m0iXUKiwFP!00000167gBZo?oDMSrDYok`5YVEh+VmsJ)#1{c+FBEYq(DF0qa z`cRj1nRDmPa3u+6Q{s8aWPH66Q%Z_^p6p2ZydXqhH7W)f zob%v9uYva{Ky$6Z_8l_I`hHNV0VYjYpm7yi(_FRRQSf2rwGF)9b_5rX)i{_r<6}?- zw)h^sDW+159k1j*+*&Fa7ZMZ|9)x!TXsskj<|sp{JE0nqFrU}tn$cS+mpmR0+qUh0 zO!wzB9a?dCR#a2gks9McfJ^9OsUW#0Bjd8p^Nv`Y;__2`@AlVvJN^cLsVgqiQ(SUM z>j{_g?|9C2UC=7j<8cq%AOlS$hfYvusp-68vH~8nOY!pk3r&dGoNSy{^QYYn1rJ;e yE`aUo9|-9U4Cpu*uB{9`_N*Uj?_y3ZoSRL~(V6*aT4UXU+`a%W7Ovh70ssJmzog^< literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..26205198e18bf405870f4651604e896aadf04dae GIT binary patch literal 3373 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 DxNxyK literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..40a134eef381543a7752d5fdfc47834dba2808a5 GIT binary patch literal 502 zcmV%skJ}&+{wo%zRx%qKgRy<9w3RAVJ?*jD1CJp^wZQ`1 zD2npm3wdm_(q4LlVdi7L#|fq53TQ&#{H(3pqZ$R6MY7&SH2pjwa2ic+o97ydl!BF8 z0{lnJ8|3%Xxh@TmTa1_^)F_FthlFpSTbMIoxnP@n5R>D;&A>5XQei5H#8+W@MFk*mgsg9sWu2vH<@ zeIxz2uY|pISK-dD1t*F{+WjVOV9uvXxXLbTurAfr8UT}~VO88@wAzYr%qX)pfa5A$ z;r;;mrg{n+)K`yC880MkboRDb^dVsqyJPiZi&j-%U4oE=bqlyueR>ABi17P! z^=0>xKmFf+5kQpvZ1lKm`yRJgd416aJ%2|ZvA_F5IpdNMhKcAK+z~3UZ1Rcmf%i-k zHICiCjc)&<_q^`a^9?hns4*%#O!bg6203jK1mMo-flxgfVDeokX=l1t^dzSNXpW-k s^NA5mS*O~rmAr*w`XyHvW_J(lde>R`&86(vR0yB{0;~eQT~q@A0JJXo%m4rY literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..421f93aefc899c2b808695c34d393f10c829b48c GIT binary patch literal 755 zcmVhF>Mn+GB~Nc=NWaE{mY6;w*;b(1$p(WJq+4 zAn?1Fw4KCFoCF2B^B8me=I7|S@zY_<^HZ~F{(Nj!P1>iW+5Gim)ePup06zt4Hp(co zYVy;bAcf-U6gSdw1R+@uBJ=`G7a~L-B{zomfkH`!GhwrNZkB1zFyfACl`&-s504o$ zEyd@Pzt3fQV?9~sKq+ZJh)#nwT7$OIDI;a?ttq}CEx2=Od%&EgvBcH*WdgyJ0(Ksu z&Qu5dak{2vo#mb30xSgsy$lvGI04E=&v~yUy6&yJ$7y_e_-(*tNgjuD`tgO+?QkFb zh7<{wJ&qLvjivH<7=~5-SqN<+4hyXsN842UX4ZDi>Ha`74QH!XtwayAC-5_clrIj4 zd8kD$-~`jgTL&nMSKqq`7DMqTG!CQELg;hOOP&((Gw1!XY1`xRxGv@Wv|ZMI+O=mD zv_{F=*P8&OD~pIm1DDQ2k34`Ak%3Um)a@AF)dCskEoG>2C8%~-M3M8H+#wVEjl-dC z=K1s<$PKA0n~QPHcRTiLy6ZZwwXQRq)iIO5a*We_#5t5%?jpPqxR6mB&cQ`d=3~7n z^K}ZM(_DBZh>Uy3yvmbQk42ptq32eDu}*^Y-Y{--5RQFhUXUO5!-QddOuy2u^n&YY z-nP}+SF5G54Q=S#sxAK_tzp_u>;1TGKA`&)?>mP7+R1m2?=gHuU3>Ykh)VdsuI|e! zQ;f+c93GZ(DBhv(La(AMixS$aB6nioY&jMzauGaHZ&Btl}by0oA z`lUW1vChPD_Ru?9^dA@)M*?J#0D0+{cIp%T->l;Mr%*9|iKXf!V8%N*zr+7O=;jTG zmceK;0)pkb+*8wmLnX>Gg4c>m70;*oo4dtKXSH(#LD>>(%4@=|BvoB3UmP;M75Mqx ldSUVUfZ9K_RJ@m>Ii224!|%KOoW|Uo{sE)h4Ho?d003%RfQJA8 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..89f6c69bf75d5ae60e8298c7513795c38b6f9b7b GIT binary patch literal 1030 zcmV+h1o`_PiwFP!000001GQGkZsSG}{S|?y1W-xrz1#Nz5(5Jym}4-9UaA$w6e(~S zK`{L9DbkWH+wwNR90YJ_73(eax^IiR$_V|=H^tR$flVr|nz62zMZir(&kE)ogHjgD z=_S(Z?CT!ymPKsGX6O#I7W zTtbR0nAaSfK?y=25Ut=K zA~z7E7f@Q}Y&J?e5vR3%3xa74Y;JGDHt|CEQq}uys5YY?s&-IR*$6iTO>kP|LxYr-ML~JS!uHr;A3#4 zSYluU3Mz^kqYBIfT|6iA0`^N3y~W2n+_yPbvGVnzuLhjSyHMe*{s%j{SpBtDF3WY< zyC;@uPPfyTp13}G7Fo%9s#!X6~ioPcf2x#L%`kbB=ub`sI36P0`uRspjjKbicvgWixzmreAf;kIgoP z73r{UyUkjQlUsDmNJ*+8bLTcEJ3&0kFMbG)Bd_p?(y1OC}4d_-$hvIebyTbHv+wRQ`|74j ze(G4=MDRFqsKc$~2CW&QJlPpu>x{W%jR6)S(@RG2lE!grTbisI{ALzgSHC;>TVKn1 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..3c218468730d0865d1fcc5795315a9fb7fe4dc46 GIT binary patch literal 506 zcmVCV3Ql2;ibU*Z zN~h_N=jZczuid1=aoVde=G#ws*|uF-upM)nv}KDOB3Gar!J$^XgkEY3wUAOZwX`)B z?7CxVIT_d-jqE#NI{{@Q71UU2kd@_7wY(F3Bk6O&ZU$1{>r=pZZOCtNn9Ppi(WrF@ z(%2Bs7&U2bBY=uVyF?iZNpp1mF?qsxH0iHArWBo=lUZpzZ)M)8@13li-pJuM4)bcd zT(4yFIIf~kAD{B4;Fs)+SNpA@nBYG-8VyJ3jx*lpAjT*3%Pu=bH)3?dl3_NYpDn61 zM-y|h+{%aeA=4rAA!YMqGMqB>nH$OI(<{8sVbIPW*<1W|Wh;&?tx1@gpxc&SO$l{V zDPD0YxLHZM$-6s|!C3U#j{pDw literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..bc635a5e6e119b1f682a7ea1a7f8d8c754685d3c GIT binary patch literal 767 zcmV?FZreH#{S`xNPeh9E?C;_(FM_Tvy5Q3xDoX}M)i478 zdr3uU?8a`|ohZx<&zw1j^U_RX$}s4?ZyuYcaX4-M9kNf_=J?%j{;A(t$6@b>+-w`2 zylx&}u9ChCF?+Xp$~yb0#N7EEUHM6+vR+{WoHGf8AOT7W0YWjuC1cboS!1UW2<99x z*wK~r$N!rzPtDhD@|P6OI>{;OfCR;XT8&Ez zR^SN1U8i_Jj5U>m*S<@}bIyn9v2BmXKlyEA z{4Nf!{hzllm&a>B)?k9HK_Hw&K$$RLu;ZWv>0BoQ?}+;dXvH%{zhLo0YsYjLQxQ!Y zhcLF7BZ~0DbKdtKv0X6O6{-lcfNVz!gPee(&VY7AOKzN&l;0S^Cxf~g>N@-9IOQ>& zHdB%JFXH$!IeidfrS-lxg2zY(NHOZJo|G7 zmC3(1^^J>vtAJzt7M;$zx!3j;GxsMen3KXw0#0?JIHuUfRN+$U3iBP~VR;NMO-2b3 z%1H$x6zfxsJV?bfut1UbDmYBK`>uZj{xGIpTMzAjSTaR_o$dM7LmMyFf*#z)#a+y0 zrv7q8Y!0*O_IcGI)Al44*EUJ_ZldK@YXK{`{rl%;dPaqe*pjIEe<9J001|=c$WYG literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..b329cb6a2e246920d7411b817e035fab1b8e47c5 GIT binary patch literal 340 zcmV-a0jvHWiwFP!0000019ef$Zo?oD{1wF6+ki=(IK4HONU3_svC3i1BSNyl!f>#n z{CmM_QdMm)2xfO?XNN0|^Qgfpx^t=TD~drQ-Cb!xC=(kYl`)`EZb6t%LR%{dqQQo3 z6tYHfT2Y6C&fN#^F65Yx3@JO|(Ai7EXuZqDjM>S9;7tQHNU!uncOP{B4lSqWicUU6 z_(SMH;@_mhk)ChW;{0y=*F5Qm5#3yoG1viv?Pr2yK$i^4n1T+gOo_pEDf;k2lqb$d zk|s@XBIt-6GSS8CAn1M(Eu+uHkh5Rc9y{GHw(d6Uc&|yHTnuyB=9oo#Ycx#RQOQ<2 zrE|P7Bwdw9ZsKjrfY(r$JUe}{ZUHx2U>umBx1R~^Ur(!(cQbiJMc$%%DtQ&PHDh_r m{AINf4AznxKyDD8MI+j-(`d~0```W(yL|$)y)9!M0ssIJtD?dH literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..987e2f13bcc9487c09231657a61536b63ac5cb78 GIT binary patch literal 326 zcmV-M0lEGkiwFP!000001C>#+PQx%1{FTTPNPS?(iDPGjg`prJL0M1-JAN&eQm2ZO zp{n}tyo44Z!NU07-Pw2dj%+yW5rStmLt}j@9S4-2gVeeNE4TwKjPxZJQtE~+*cUf9 zUKgl=8`VIu(F(M*1sIbTT;x&-V~E>Yhb=UnM^?wNZArZkiPi6n^IRDrD_JPECSuqi zq`i%-J~E8{LU*_g@iNdJ3E9{-;c3C5-O;n`rHhB#yVtkuX-uKXo=4Y)^bz7VyIL); zv&X^Tkdvkx3%9#F%0OlC2@VXW8ay6?dQ_9t;)g*1yo)I(&h%7@)hK+;AnZF1=aJn-H$d7KRM#gOZ&x9zFNDhI$Oi*_-(@~9Vdto#pA=_FtOjP8EZO3^S3Z`lA##?YL7`jOv zwA;@rI-iaiD_Edmi6*xFd13K{0sz zuY%nl-xagWFOa#Tvp$?uK=z;{Bivn!%m1}KH|d$SCtM%A!HNr%60|AXUsaqh$TgG*|f6eP~u{z>5`pTgVk-xNtZ_2YT1UTrdef3d;h+;Hu>>CwLh z*ezT*lu}euOP%(KN@%*i1S!yh<#i==Ytd?zH3m|d-LoI#CJ#05I^avU+&*jBWz#~0 zQ5`ajmjzD2K81^jzQWcv*nuK!ptiP!o+F30?&{ZQrQgrniQLWj>?q5uC(|E&o{S8Llk+)F<007II2l4;_ literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..de0ccefc59c313b21aeb3f6ed0224ab9c8ecb332 GIT binary patch literal 2265 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..c673963e2dabe484aaed7fe6c6020bee7aa08361 GIT binary patch literal 777 zcmV+k1NQtMiwFP!000001GQCIZ{s!){wo2WGZrb{e%l{Vphb&rfkja87&>fa$AI5kCBWZ@{;v7- z$DdcfEK?3wzb?MZ({1i|k8rK^TnR70SS~=IL+~^ukWxAst)x-MXSm->H{Ts<$mI;j zax`LhhE@^XKlfN--MGUUE?1VZd%j;t3BztWvpHh8Fq4My=*HTKo98k6Wk&ewx~1}Y ze|kz7MvQrWV6tW{%#An=%NT0v+j%}r+om}lkDE)GO&In~=R9@|V^T@}$cypPC>{kk z9Tf-_ELfuzNaL7AE44|SoL;nZQEgSI3+Mt69z5ntu4FW{(gzT(jo^7=z!fvvN^e@K zNfoj-{sPqL`WsGoTflRfv}s%LiI)OQm{Nc$NM5%*D2{0ST7gv}-$J|)doCo5j0{Bp zse=JwRYB6y2V zyr9A$J=0#1H+sF6@_RJ5oa*Ev0_D2U+$scHYJicRMw&GD&aTp2tv(f+-2C-yb+Z0e z*7;fI@NpX`wW=up zUYwUwRy^k3nR_^a2e5(kd*r-(OEHZ7OBkmV=RJ=pKSdsBEu5hHI0282 z9dw?Ci8o-l57}XyhvDjhAwPns+S*&|(0Zj&Dy~pVt&9o?(xD_SQHxq)Q3-1V6)s1FHPA$R6Z)C%|9<`hy`|M>3IYHC3%;xJ literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..8e581159cceabdfbe4e01afffca8345bb316e3fb GIT binary patch literal 475 zcmV<10VMt(iwFP!000001BFsaj@vL0{EEP{dn`(#Ncsr@5(LOG$bqX(fR+rB8pRm+ z?`dl6S&~C;TDq!h=@(M27YD(T194JW*6S8rZ(HbvV4!HLK~ULS*3!NghU|!$m#L&H zIZR88I}$D-lfzHawsh<$XPpq_*N#M`T?8{*_ZXbi8K23IdAc@VmmEy0wy^dN)?BBl#+s8io54sPXPbmYBL}6<|sLH-|y$Ns$}u&l43QJT%MO?D&kbi zB_HY&So5Gd3%d6d`jKK&OpC7NIdw=%qn`O!v=?e?C^ R{pwsIw?EX?cnU28000qh>gxai literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..f0b326f38eb437d67695acdc4d1f66c7bbf99b3e GIT binary patch literal 211 zcmV;^04)C>iwFP!0000016__mZo?oDMX!QbXCfRN9OnexcUg5YFxVZ*h6u1CtLoi@ ztwgQ5{eS+O_bmg?US4Hbrx?VzaKR)GlBs5wj?R`0!iAa^T2BhB9}sM>bl0D?F}kg{ zWxZ{L_mVh_f*!_BJY}jR- zQ)=kD0oyeN0 N=K;vA{&E)q006u6X$AlQ literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..b8fb49364cb5c9611429516269d842b4a957f95e GIT binary patch literal 344 zcmV-e0jK^SiwFP!00000167dSZiFBZgE+Cv?_|!|NQ6-*KZTie9~;prMc*$8^7wfq^Rz?*)I_j8k&ck#OG1D2xMbnBA4$@2 zfb>rY!Ga~7)8h;%_`Lw`SO4v;PWpByU0BBPN#8X~9LWu!9wnsYvUSE-YFwje-2kVm zR*LowgQ~BZMhbyI4}%X6N9!Y)oC|q3#Z^a(lI+}VB#wk~hYiW3+WzKH>tk1n4 q7X9L11scPcQ^H|^warcyRb^XK#!J(enpsh`Wd8$Qbz}+*0ssJ@1*s4K literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..6793bccc4791afe8242454604da0a3921cd22a9b GIT binary patch literal 506 zcmV%skJB&^{wu*JkTPwaPTb>4NF3k-N3@6Wt5{0o%66zq z)&I^ov`azDflK6xXXbnP!e%@ewqsxXd@epM(W&D7oJ>gQ=7X72@%AZTbkn=yW74=` zB~yNxQ#jMi(`PCtXAQ(7&TMyKX4Y&sFVj@!qoKm$6ivyb**ofBO;rhYEt#V$*2_*v zt4FZX3h3l0V62eCz$=u4sH#d083Co4KzVKMyVLn-U|rF*wylvjAO_Px%Ppr<-$2*5 zs%~pJ)I@^djxMs@*XNQ&9}@hxW()?iz7^AUM0~I#^n>8gj@*E(hX%MJK+=c39%)9q zhzIHR3nu5Y_RJ%CXlu@)UiD;7*~Pzj5&91|QTv~Dwk^(gA=v}E``{<-<~=nBGp$JZ z{&F|`wJeq}y=YNQHTEMC9o=f^ctcu{E8tRCBT&(|TX#pl1eF25rF4wD?e=s!ZAhZ> z`?yj5uw7HyHll9@&s2YB)JrjvT>~_|RM26gLAJK0wCZsXy&Rh=$BZcjCzoVy0<{Z9 z-K?`doG|FeF8Geql6x=L7c*{rSo!!66NbG>pn}mZ{fgoC>o%4B$N^-54{g`yS2CP^ wDu_%$W*dyASXCEGG;fNdj|u2~k40Q$blPD!7v2{CdS&eT6AHhHBYgt^01tZlz5oCK literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..a6ddded46ea1c220022296ad0c3f9dc662b9268d GIT binary patch literal 533 zcmV+w0_y!AiwFP!000001C^6aZ`&{ohW|?8bJ*y^vZ>sLU3(aic9$UsebA`@#|~t9 zK@jA>Pj-_v#WJA1*nsqsdijt%73sLAVpaSYZ5xJHip8QZkxa2V6+<5rbY?f*zjPsy ze^@7zXvi8L2D7taJDL>wE(`Km@cCb&cBHw5s!|A2vKlnjHPl+!3Y99I#;pBM+A#DW zc~t=i*ZX|5`c=HFi_Lj48-@7^(#9)k8Ibf0B%%VtnFZupdd0Yu=yI+|?QCvJa=Hmu zHXCZN2BEBj(g+V$HXLNdadL@*)j2$wxTORxk`L*vKug<@YwgCiU0lIs5U$@&-iLmS zjy?oX=dW@fBDo8zrjG{`eHM(dok&M|3(j}1DeZ^Va(Or$9xu5cUB6ql#!|Z!6$({f zS$idn7gB>TQbEbl0kRB_&^spbSCcC;I+Icic1#4nO*>9hPv^e{Uh0^f%!VmvZcIDS zP27Yq_u%v?C|{y{2iiYiZz$fc@)et literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..87d7c63c6dbd0ec8dda5c4242f6529b3e5e55fd8 GIT binary patch literal 495 zcmV2k7UPu{yFMW@yjBB@EVGbR`OLiS&-MA?J$WbfB` zu1UgpunBau#--ettJgS_{WUi&VU4<=eM{-I?3?C%KJScMbT}+K9gfY6%FYezI?>A9 z=uEDa+)C_61zKweBazDc9sy6HG4xE&RZFwOQIVzgll>MwxJ4Z2d5^ zQIh-jL->ohH^MhBTUW917ftd0wa!@4>XJpSm_j^bG~|T{?(%yjM=^~8Sg$m2WCm0> zQRoIb3fZgdMUdMaXu+d$hZQ%p)z9v`oi9}im9iE3${kP9`BYa_%C@1bq5SvHU-?2C zn$MVtJsykJPr+ZRkL%)e^$tB6tUh?XdqmpdFlB@R7?m8jG6qI&TNu<}1TqwDPjl_; zCJW06eVN`pDN?wA<};GlY*SowwA&JtiWVpX%F9sP;@uXM4y#Y`^13I_ggR8C(Hf-W z19WO&Acw(%7&>mmX#2L~MNQca(81W}#A1T~8a_P)V6<4A+)48;F>W)JVc8^SCX*VO l>FLA_ihj^Skhc_{LkvEJXUNZoe`ZH+w?DU_L=ig!000`b?)U%z literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..3e9aaafac2c639b4085dc4295388d9af237fdf4b GIT binary patch literal 345 zcmV-f0jB;RiwFP!0000016`5JZiFxlMSrErdOQ%4K*C>CT~=K|eq-r8u8xOj#Q7v`NztJiYXDNEmZ=A1=ACTvHm*JkOO}IWSVyfF%mg zWhb@uxi-?Udz)DMer3~nj*h@Z@*(}V%cZV6=X|!S3?4dMo)Q2hr>iqq$PX>j|sOm7<)=^7v?zR9HxwH=S1+0!%W%Ybv^7_d%Zyl zC9JMZ1?W_UL?uBhs-e_`4d+s5+w71xu-x&P(q(FkVp*2sWBu_Q`(g`ecd4RH3*kq;p!^l7UvyK&hhxqb!3mQemSdh8bVX zimGp_zPS4OZC2D(iqNlYQ(Qe1u|Xxxx~^yW81W<7x{tHM#oG!c3PuP8N{Yu>5vtxU zU3I&*L)GU0n)aevuDYrj(1LH*&CuQB^@mURSz8xt@NI}Y{f%AXx%kpH_ZJ`6edRAc zN8fg#N9iusqtfi+Lt%%ZtK52slgGpTD#948a7L@76)@pEl$Hf>JW=41YGs7ejHu#F zC|fT=)kQz~pW1F?yHIQ`-~~qL+uMGtVfSL))fuTS_U*d!S?v2Ttop0PVzb%IrzdmY zE*E3W3(89bEn}WNrc86Mhy+1Z_BdxM3Jum9nFtBo3Yx(kYkJA_jkUFp&IZO zueLrMTfNE*PwXf^(oPlI?o}VA|*PN97*7?W^JILUF0BCl+g=Em6OMaA7}G4D<_Eh zWkh)9KUNDoEwIQ|ZD)swU)}usu&j6F6jVeO%MwbWEw+qEz%qr+!$)d`5 zJSRzMYKwRC^3BK`;Ccx88D5Us3E@sEM?q=nFdC!Lj$jaInW%9oY3zMx>pWQ>UEAJm zfx@XV4vpQ+cqc25()pHtsYJk8t2qS2uxANPz*)(m#1tvXgiPicX0LT?Q{7d;4z@S~ zQc&-FnILEzp>zQorb%d0DCd|IiA8xH$eq%8+ubhm$Kr2I4cAiqnwI%u9cB9~)M4LK zLO<+$ujgk}mw)g}%`R_#9}oDunGQFE?PbyqDq6US01> zICxib=cpmr$7c#{G2OG1_nJ6qPPIR&-MM47kUFa;4=!kf1s#Ar1G%iOq8)?$3&})^degEekOLFR_a`E(~bGusj7Jl09MI gUtNX3Vex2wYhAc-G}{=?cS^R7c-lYf zm%x!8x6!36a(>WgW>ZK6jdUK0qL!{wp0CwB<*-&tZ)(puN(UuU0VdZaNR`_zN9pQ9 mi$C%=1|0jBFwQA1CmPfBcr%{5&@cF4yZi!nmhHR(0ssJt+@J;k literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..0e89c4d90a0137cb28a1986db58307db15fb0486 GIT binary patch literal 3756 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 WX-8Amj-}Gq-}*l@hs?q~f&c(M`EOtV literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..55486b630fd7b8fa28ae80255bb4c1bbedc2d7c4 GIT binary patch literal 346 zcmV-g0j2&QiwFP!0000016`5HZiFxpM1N)EGakIKnZJl~jOO5_O{_35@)8sw{yk=f zOq3kk>Z;dOUXg*Iy}Ly>PpC(zKpsZ9PXYCBE0QsKr&5G{yc8%(KS0Fs>jrr}`7tYC zGGI_|+DZrd;r{1t;|Z%m30k-im0?*)vUiX8ZK2*{K{Q85C; z|6WpY+@wgG_M*dTcXnoWct+*<=+PE^pUn`bN1xFeWk2W=$26hsk2CVgp>3LnVU2Vt zIhwh6c+$h{>;Lm*-5Pvt33{0P8Wo-QzQ7fB&O-&9#yMLLHhULKt=3Ze53!CRZj|hU z?4jev0@IxXLjwUSi0lAnMzK%E+EUhR@Jl>t4USOelmwefbdA}i)$Y$n8N%)rp z-2!)cXv!yjFmXTYtNaQw#Nc5%>eQGo-KfJv0A_#*y1|t^``->xEz1RxJ~T$VF+H!o zj)!BVlULtT{T3b5!KbqNa_~7?-SRV~cs!#%+v2hxK5+Q(q9o>=-biYFn*9}Z6>lHB|1eZW5?x8-X9@@(hl5=L2MDKOq zr&zpO?TT)3yUBWAzP!znSK4uEFnH=PP$@ZRf(=NbsN421A$J4-01T!bp#T5? literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..f53febdc12cf11ed187b18e9eea6abff13a53a8d GIT binary patch literal 344 zcmV-e0jK^SiwFP!00000167dAZi6roMSmsoI!?^XVE&@&vdUsS9;j6U$e5xE<=;Cb zL}_>P&^>eKuEO~VuGY6RL_hSR7UC%4&q&fcZV;7fOxZ|mGAA>jRGLI*QsoKS1e7aN z%>qXg20y+CJzR;aksNe~DH3&ucJ>hh?*euATa&0iR>8BDqQpSX$A{Qb>zUKfUB_r2 z2zPKZgav}z9r9rDU*16kotg`UWm|7(!GImiFP*zoTGt%eF*m1RS6ArPC&oalmU^~+b#fOS^F`ozgke|E&H~9 vP-%{bF?(DKJG&Kk4n)K8a25@?W{&o{swlo*3a(A3IJx}-)J3@94*~!H=-Q)t literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..b6b14993a806f9b41f36480a8a4bd6e03d1eec4c GIT binary patch literal 207 zcmV;=05Ja_iwFP!0000016_{6Zo?oDM1KWw&Q@S2xXu^!-eZ*m>;hfMhRA@TsLH>W zCXpibI+{0ce&psCTREp9k6)*qWRgdTg9{km2N(|qVQ-XynP`H8_JOq1+If^aNnGse zIJWyh=VGf+>c%O05*BkSl~KgT)o#6CuV)Vr0V);dDFB9%V6=XKS(_2mUZc}i(KMJ2 zB)j^@>}!O4!Hv&P<40bWd;yo~`d=vela`{maQzmqXXWkrq|=}GL~#16u0BWPn2;JMz~!JX9Y({#kvTr|7Cbh8$9cI2^)| z$%ag0%Jl!4#%YKX*?qmkPmkuE0S^)al}vM5*S@1#;gy!^(lds+ ztf8Q^rNHY33~zkU9eLc4{BR6(@n``+wq2mYhmOj+ZK##XP|ZZGv|_9gzC=G>3U}i? zRE zQ$S^q_94?E5L3*l#~kIi;46Biu|B9)Pz8;mHPkgq)r`7^c`dmL8U!gCrg2WL#Q2u; zaoTOSr_<>MIlFN`-MI0vU6gN?RE;S}p6sbh!N>gc0?(9`HM;F|ONFuyvkH%tI!g0-YPV+wA4!EQ_^NPZ227i(_v1BVr<4f{A;AgutNbv$m)SE>9a*ems|Twh^z zir=G$3^!xiZ_8o(Su)18)|YP6UPIklY5RSt=uNH{o#YC;7i%Nb6t1>?RH^De>+t=&uhgb0Ru!#oU9R|Y((fuiR>PPp1XIPXf@(Sj7du?u(`@N7 Y<5iq0xQB>`K9I+M0Kr?lU>F7f06{2j%m4rY literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..00e16da41ac5a6e02967d1c3f9bb73d2a15f3f3f GIT binary patch literal 545 zcmV++0^a=}iwFP!000001C5hUkJB&^#lMR238YSIC$XLM1`-0aa6)@p?ZJ*G#Zu~2 zwnJ5|_PaA_yMGWMaZ4P}oA;Y}dEg00Tf!7G-`+iNTS^LUE(kyEI3pcCJg#^-9T0-& zTdrK!nxQpNDc3_|D-W(7B-C2Arc3M<9P)OvIUbK|A96qK z^17e)o6$NPH+5}v%L&8bE=0bK^Ej@!4+;APoa%=u9c}Xb+1dh3=ZmWgJ-u9oFLX~T z7YnaY9`BdKR3O^@QuTd`C-!a5p=Tds!BlLBdyIv>y}fzIz81eG!Lv{3Cy!6MV;B(f z!Nz4O*J+kC zbq=I;-au=OYOK^CL}j41RR>OcTDoflTG6x;mtno;yp5rtXE!14{Ip+$@&vWi8sr)5 zZ0Xa7#mV0*$az1_v7{4yql;H7mD0Ae5<%5{OMz1z*sf}zL#4WbqGuY2HF!~?RW@P7`usP!!c1Q^C=N(&y&hqSX@WG}N jn+EpJ^?r%{`XxJ`r_mE9e}?~$SUmm$uH)+iLUb7VWs?T-3tl*ns#l+GHGoC zsAUP`!z4l`B4P|yjuFUL(T|Y$98)d0M8%DLpLNMFLpYH%9aWoUV>% zR+GK8T10`Lq<+VwWtz9ZE26uyP4@7DNYPZJuC;2Lk~OB|_~JHyY`a+ZgdJxxD<8J& zd{}?1s-h{ob2tr6SY;P>R`JxC8Q&1C8VXee&t_(uchdb35_|z1TspN+1*b4$-coKfnJd zi=uvx{2o$S>YRM&^<*_5_@-bVk#*?pheUS9BFbwxuVnXjA+G%BVmRDi4DNh0ODhed zozh85py@?wq#<3+C21%#Evw7ADVl_^yz(>gcjI6cdgUU7D6HFoi|CD0tG_-E|Ele+ q0Wu_EaxxZqV;Etv2Iu8T!AZe>rwM0aNRfZ|bovE*MgQs51ONcVoIw`= literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..1f377ef9b53eb5044ebfd47027cb920f4adcaa6d GIT binary patch literal 324 zcmV-K0lWSmiwFP!000001D#P#Yr`-M{VPGI4JsCYH@R(eY%qH2arEHCN-;~Ek~oJ_ z`rqfIEn~3Lzz6B+S$cXpgCBz*q5Ryhpzfy-hZB^r`G6JpmTjle*V$``G(_t|MNN!JV!*Ll&{1`RPnS(C=KtQ;D_q_$3TqIGKa zABpjFBwU6_(FkTW$HI_Ap&Okd#Zf9zGr=mulG5vk#D4Ev=ffcZb|5?N=f@re(;C@g z-t6XV?f$ldG|E(pE96$^D7ds(>P?#?{(K7C;kH*prrqRhbn3mJ3SV+HD&g)dA zKH4)RWAh`I36h{cgC>WqRF`2v00pJgXrzsSwVc)|_0Li|!#dzxWz3zH#i1o49e>1*YlyLAs@Yd@cs3Yj=i#qa?}|l&P1w*dN}ja zc=6KIniEG_gVqHIv*N{WkP|ya!)24yNvAL}p)-(JM2dgRexnzu{)HW*&^bjNNwGm@ zlQ*^}J-ZmJ1B(tiQ<$Ql$==XO&4aC&fui!8x^hpKTsU#gwLZLID2yj3!n0|RRZ%(CC}tw#TIQ|mQQ2KB00?qmu^1pjnyuW4U}%WXw2%~lVoeYoi_UwS^@ z;ve~RiZOL9T-tG8AEI;HZ?Tief}_|e(rZnJSD*_0e|Sg6D2yuGa~JSfp|YQ(C3wVh z4Lbn`vV2yy8&^TcJA*DjlWXy8Wo{d+e?sO(sOy)>CV~O_P}2;oP3ClZOTXz~TKz<+ H&IbShsKs9F literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..7a2fa1567c92fb4e93ed41d4ea5a11b3bf34dd05 GIT binary patch literal 787 zcmV+u1MK`CiwFP!000001D%!2j@vdAhF?X{+Q$|}iWg@U6a~8RDnJpS=z^C+mxwG5 zB&yE9@B{TZ`eLON&BRXRbda4c;Nkhd|L5VQOwUhP?#tg|>q2)dH}eMwE`MXxQ=)kd zN+1KuJ@Ubs?Y*7zbwAx@>j03(a4j+qQ zG(&Jf_s>Q2#fR8E7l&~Ow)nM6*e4yj6Lu-rwQ=lH|C|dRKIYe4ZQfug_kUbU>~e?Q z*tVNer_={CCY=8KxhV}EL-+D??AvmGDQ7*Zl9Cxk0ENmbxbfbv!+y6rpU>MY)5hblwehr@747PVbIHnUW~TciCa^uakn*}*B{!Jq?7eOW z+`Ld;YRu4jva6<-<(G}`>U_1MF-i(A1=NkPz;x}vP*1WkL<-dySy!Tb?Pb|< z(tm>p{?_d{fx29;o6B0?x4@iboH$#7uz~=ynU$)H293xWtF&Xa_#W88Ysk)?CSxaJ z+tcUW4XFQZ?g78(eXv2d#Sjwy97T_$lAck})~HO;5s(HcGy*x=90Or^`Avu(hV6#o z8zkLW>1raJQebS=vkKl+jq;4-cr+ZCL<2bz5^61E!!#;Ko5}P$mfxP%SGE(&w^9F* zlDRQ!rLS16LAs^_=1_t3LIOqR9j`T?RfURyLVep;1&eQ54V3?3PAZ`Y3x{o9hV z7K>{J6`sO^Y>0h=PM@ZR9u3{%@b5p9%1!ZM`+i$EEPmPkzMb;iqn_w4>koG^pjb&$ zTL)Zu3X}*7hU5za1u@v<{;0z8zJb>Q-`yQk(IMt4oC5(H-E8@E1LVV2w!tF|Pr93$ zxunYQr!LhF_)l9Dx+aiIWHDZ7{au*ujp~&X77KP7bB? z-KV787;LbUk@QRYe)+0mPBE+Q?Y&U*<;)O+>J+yw80`^Q2Lx@c0Y~V;QmcbO(%SZ_ zQ2n^1dAdl${zbyUc^;r21FJ4A!*HJ{)#t?zF@NwRqKOAL$1y#2hM3*S$K$dkMJp0F zu~XeuC3jl8_mfLKOMXK`s|jmk!4P{vLjsF|!8mMmTVg|GM4QKHhF=5n2%72|Xro*a zR`NeFZpGLB*D+moPfL#d?qMXRQh z@h$d@J2S4KH2=MK5@VduLfw9d;(6S2&VAZBXAx59{Am&(o0QxFc!9MybAPcDPGO?8E8Ie(Ax8j}9UVo9h@ zKeA=DEkng>TUOh$mhI|8j~8MI)@vFM4-XGU`}_XcZz5^C-|KNjcj(U{LH#OSk7G{2 z1`2J_X&(xnX(_V%6I54v9gxz3p~KTGE9uNqpm;ot_M*e#IO_2V6PNNh+VjFvz-8)q zJUSQ;dRz*n6%yoc3N1}W#;J3Kjl-}kGA)vRh1Zxvf}*d@GW4s$uR=<4u9XdCC?V{g zzXYr_SUA*bo3_UN4sZC2rP89JbK`!BFGQ8VO}|KsKV)ezIc_SY$Kl51;6x&v@O5)a zD$dE)KYtck=`#=whI_%_AQ%kUU_ahFjH6dRr@A!KAFqi#W6%ImQZY$D`KDR*_}Stk zNcTo;!*@+v4m7@{jMu(}z-NBau>eBv@+T>iDv$ z98mqH9Uh8wr#=nLU(^YDdC8f~gtdf0;lqm7>yD*$wcD-+Sj%qm#OYBeCQa^tR^_Hf z<}dQn`oZzEw9RGKx;)uzdFuZ6!t7fv@blD1_P#&P3@%a8;Cs|3uY%E#MT2-0#pBVl zcvC~ZxHig>Eret-Xo=^O1bk@qbZL&%w+OvE9iqow7gw3uY&5+#hsu>%!9JIhcH_cPPff z;b&m=U|=WC8C;aUGlE$vr~pqgyoSznEu44osYK(y1|E2wDWMZy9g_>QRaVV#uid!M zj?YQ9v9RIdHn1Y>>cCVNx5mGHw}qc~75<}(nXbA3 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..9e99ed56433140728c460ca806ef885f8c10c017 GIT binary patch literal 719 zcmV;=0xqTk|a~5cE*=)+7xQAcvwTI5V8h zAhKkPMsXL${`YXac6Z%w(p-8HM4RNxhp%{S<|!98!Va68=G`>jtzIp2@~dCQg1JB% zcQ}^S5APuzVEl3QYYCfX-9ScYZjMcwCnmWuj59w4oSU29oA)1@Kh{l1GwfWtU7)0C zq}r5~0zDNs(t7l)2Njv@de1r&1dHB)i&ARqH2wFi=%H`Ty>t?foqm4JEU(R;&T!7S zUpM7$UjuJ)x=kYttKaez7Jrgc>y4=vq3n#qNo0LJHaL>XaTx|G0QnXRJJ(tA(EJ_q z8AB=$W6jf&Jzj;Nl$_jBkbQ<>scMgpf~FXgPb6qg1)GX0qd!xMQ$9cr6m>|dFG@%h zlB@{BjO&vUf}ioBGo^hjWq-5X9u9}iOgr4w6>j{r+myrh0^WJ8MAXPkP@Jh&SOzVR z%%jy^YdR5}ykKLejEKDLqLK`}>zRVUS?5qPZPB3Dj$3D*4twHxzdruQ_~j$!Re%Bx zX8P?}rq7{&vYBU)U-7z@^bKNZ&VDocVS{0*u!z|n#=8y7`@eqrl*aIK8u3qxzMx(0 zUTS-x+4a%(UXX(U1ykC!WaA!LPh^4v(~=2uCmhX&W+X2388DO@tmg z-E+sk;*Co9|99yjeM)sn-)GP>;L~WWvYi&>7~WgMl=5VtpcIo9T{R&WSTX)%8S~k{ zm%f`R-)`&6_APIFu8r!x#nbB0S?nYWJsDe(qZw^MQv2Yo5rnnx{_WMT94bF8W65{* zntXV?Mc;iLhZK>`KgpZPVs?GTAEpr5j!di2y{+Gi^0Sy3>*%p`+1R+_77L^{tMT?w~q-1008G4 BWTyZC literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..2616cc71f68b593b04d241b4e41aeb95c93c9cde GIT binary patch literal 201 zcmV;)05<<0iwFP!0000017(h}Y6CG4M1RGo_JU3;>+an71KgwyDOTE55S;FeBo`*+ z-y<6v3@K-r$D1E@DJfIALAzZ<9o1>^*R1xcrMBGj2d%v2-6;gAb$6D$l_a$fs)TLj z7g^Qu^J}j-RmwhnU#X>S?RX!)3m|bXn&RigB7GBl}TWp+YCK6IkbG`d7;r&ix0;o()i*0RRB^tc9Zh literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..cc043fc778e14434913819fd607d67d1f830adee GIT binary patch literal 344 zcmV-e0jK^SiwFP!00000165GVZi6ro{FTV(I5GGE<}a!qs~-GVQ>(;8#xAN5|6T*B z(jI4ac4u}L6x0n+hqQ`5jR8)5_DMx_M%GX2rhT7P@?$8H!bKQ%G@8i@K19;f%_a9@4+*gG%4`%`(Sf;|?(UPj6LHg;6O*uX6(YrG^Z}YgxBA5zHfr z8{@2^E!yoyw;*3!5hy~W0g6S{O3WH-u{Jee%^NEi7d1e;|8V3k8y_j%r|x>4=lSv* z;4;Skx`FG9V1%}4Ju>3mqhhUa##n3|mzZ*3SW+pA2Z37GoVQJL)Br{9)G)!Hhql_@ z&qzb>!%@>(poPgqe}A_8v@?bfCmUDnsKr!4jb$Y$Caf~LQp7g3C=0umR)#uZ47N-f q%xsahy5*QRLUG0|rLKPV{aPZ0{^Y}yV!lC0X#D|Xkn-US0ssJCouV87 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..8cf9607b2690ffeffae41235055a07c74649c95e GIT binary patch literal 394 zcmV;50d@W#iwFP!00000167jUZo?o9g0d z;h4i$kxm!_#iznebA*(mABW$2uvjF^EMGP&(d=y_{1<1*IlmcgK?nzuh9C)kv0-H z#Ra4N1zP-vx0sP%XylCJ9Kz3(d(9jJ%j3)fpI zmAYlvxVht)^En-MyJcCPAD+)s9Cqtv_oBK+v{iZi6Kf6rexo9`bQlu--Gz|*&KYBQ o7p;P(B?+og3Upght?Rbk_v=s5H286gb$!2n11h2(5@rGb0JyHgbpQYW literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..e8c21a59f4bbc5203e31f59e96606f0b84b3b5c1 GIT binary patch literal 3353 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 b0VzJE z6h-;>Vkc1(wOw>)dFI}^bA~f@$-6{{Z{IgGg_yysJ<@@G4gN&F%*l=9gU=YVa(<6K zlebs$+3j6MLpSulnw=@Fy%H7g#0X>GXb_zqLGy-#u65tlQVMB!=~WRG9nM#cR9zz! zYoV&@4!Ej&(5>m9)}lgH3CSMAy!mAwd3Ang!k#{_^+(aA0GzcgFc^cug#`Who)#L$ zCAHUXH>>P|FIsxp(0n=|tf2(AoT;{kzC!`LwQc!oY7h+{8E3k?hMJVdX|<+i;ppG%&I<1LB}@u=eBe-o9kW7wsIT+Y$y zIpf_`#T{lCBN~^NEjCo+&iQ*B^ri$IteO%&sNtuY=EdWDS$pp7H@n-|IZi9!Iga== z;y0&8_p-CHT&pR!7OFPo;Fc9)Om^iB$hzu^U~#(N8+Ri%jIuZ^&yjjlN8vf5|ULy=7jIa zA*2j-RY{U&ot$who=C9dU(bCxx3dW8p!~ATjWb;=fK^a2`o!`P{pIot%_0Orivs`v DJ#z*r literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..8b791d1d4f784bd260931f08e33b2a086b7c185e GIT binary patch literal 552 zcmV+@0@wW?iwFP!000001C^6aZ{r{khX0DiaTOBd_%p{{t$L_>s(M=GFu>rVIuK!8 zD~j^p7o3kx)8w!>kLCsDedhI^=&kO_>d$&cI^ft*VI`848Mf z-kh}tHbF&Rt=T2NUY=r8h8ip2Wu`b)RhrQp7^A!?IV~F|L@w*BsG6Ydt@HHz6`fW{ z`z;u<+7phgHs?Xm$g58bg@Uff!;FAKi1O+A8mb~ZTGBMlD!PQMp}dq8&3K+7q>yJEYc#tt4dlgOG!n;5Jk?RW_5V<3m6ZsMNfr8sr_-N&pevwL}>C>HJ~udfEFd=G?!9^oHsRX zmOPcg8G|OS>V{?nHjd+5fk1BU$2B#pl#UA{54~S4>&_}4ZT(I_z6R+3;&)iz`4jqq q_gZRjyTq#G_2qZ+_B=~K%EX#(7m6fA9-$8;4}SsKpH{nZ1ONaC1QX%_ literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..f64e1f8f0f1ce131925efe8a332cfd63597f929a GIT binary patch literal 588 zcmV-S0<--eiwFP!000001D#YmZ`&{s{ws!NpDn&5%6os1x_rH8fzq67t3PoLjFprVs77xc3o*SJCxeb!pM`laJw$);@hnW2ZEBVEQ&)^i$U@i+C6^$o*~z z&d0RkM(@UA^Zm!NXx*rG+HI#9FJq`dc^q-^c=zq`^WDS4Vz0Vi&TkiZz=gYFWKfv> z=!#0AsRAYl2i9^1vTQ9_V+ECx@)p}nIy`f#fU4LW&uP$Bb1GR4MluS_&>A#X3`$8F zX=_n6%oOkFoNe^LNL2xu?Pl~GL1MVXHhXy!<@xNCa&i`7%tMlbK8xH~)s48!({pwj zw=UDsvLsN7d@*1*i^zP(VhY{WOQnS%5-F6LQs8y1pfOscqD7;m5-2n)GQikR!DKZ* zV;siKdcEK8SIMI3x8ut6yY*b+npTuDnmKP2MHRLf;Zka*zb!-PM%Gr=K!rBI6>UK? zOMq2G){W4TmUVHpbw+GmKy!)J_F=C=?n}iOoSq`Wlj^3N?(uYGHvwB0&o#Wx?xO2r z<`(DD{@MEt!fAQ@K*B4P@AfsxVQZNR(3YhL2$v~>vI47X%1p%&W&XY{#l0yb zb>W0uMduHLGjkVDzdg2x)!?`J&CNXk-3*y1Zn`mKOkyj7<9@3e?+ax?m30G^K?&Ma8gxtKQ5tmC zGB*EQSC;pjLf>sdKjbu?sn7hBC}Iwmeh|lxSuk}+86NmCMMhxeF*9a@Z;T@`a9*~8 zdfwlUG2X7kg~vG1Rt%RhSpu8Lh0G+(u<{(|yJFo+FVRVGN>xx5jRHj3g4ec`vTdw1 z^-b2DhbKOBz7EIzewwD;6uyGPjJr$f_G__!t1CW*Sne+2w&YN?wYS!R^-4pjr~+MT z4Mr6tjZ~^_npbD5`O{xa&n1j-A(36<;kLh|36tZlp)T}K_m9Z_{Vu0SqVT%$EU$D>BJr;s>Jp0TV9fyw*T^*kM}tk_`eays0e5dLO%4J80Exb--2eap literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..de261359e6f66840a6e502e3dafda988046fdd2c GIT binary patch literal 993 zcmV<710MVziwFP!000001GQCcZ`w!@{wu5fluFpf20}q??5|DW7+VkW13&i%8 z?ZX}^#d)y(HQAfZ^&ig`q(NOOK|(*OK*G-A5D8gNmFDXP-zMlXB3zO_PSiwc$=Pyy zWI@1;JE-LqGb#Rer|x!nC3yU#N!h`MXf%U4BxJlGRu{(Nqibigyw*78qo5Jvz^yW+_X1RWW8Axk(@wPHvjG0VcE$>(%U_tKKj0>0E z0CEf27&O`Co&tH0++{MbNZeFa-!zaHe^=x{tDZ4nOy+W^igg~ypH7_*-&?tgR1tz) z;0BZS6+vp`KrnJ4V1ieI&wwyn(kdywVIywF>Tx&dv1R^Ikr>xQS&L6xB(Bk(5rXw?<7p$ z*$5narGb={^E_geBAO+R`_FSeY%OiE#Q#tJpmG6w`D501{(GO? zVzfa!(?G1V)^6O`je=vAB1fA`T6_%7)*WsIG zM|#$3J}%tQc!QLo>OH}q;OuY}oO}3MV4Ek^xVWp}EWC{-4|=b8ci*KAjqNjdT?{a|s02rVYeiB1 zz2hYJ_HNKT&zw2KjX5kfhf57hVkh2F7l%0=ntHti3o%|BjA(1#okL^R+N7m6 z5I4A%uk6664ta3YZ*ALptvt70IxYbP*WD<2+jrJ<&^jeXYH*>z*@St8*W4EfSwCn@ znwyYH&FdLcrPKquQ(pUa9Jr93;5~?*PqNi~^rLg5M1fLLZN~TjE$sC3#-I`$5k~$O z;))c!-46^C0j4#^hl%8Phy{rQX*DhcK>yKXGM_@QFe`feQf=CLxXcj dPmS(Wk>I>znEiLmYoG>p{|Arj^_M#W005uEv|RuI literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..3bdcd2c04f4e5e6564862066a1ea7e770f05c4a2 GIT binary patch literal 334 zcmV-U0kQrciwFP!000001C>xsO9L?w{VOFWg&j+5T-X#>3b`3WakUI)o$_6x}1|(D5HI#8KZ5nVs>Yef1SxZny}nh%?|ps|N@?A;lFOQs3};;_MZ=tE!3wLO?&_o~ zTL;#mRlKu8qe&V*27lhBN7Q6>yd?H@;;&SG;(xg=>Xf(Kx~>D%Rs!#g1+{b*xX^;O zPE+AnQ6GRaAz)d~EXUkEfMVs03(3C8^@hBiDq@E@OyeQD+2o*nhYSbH*k`QY3xb<1SEOiyn(b!Hw0KZD*I$&{vzPdaSzCB1}6+%R}XHo60`7 zS^|^wH}(-@wP{^9;j*eW{oHlO$0|*InySs8-{>dpR<5ZPN9Cc>tp>?L4OSWn3XNsH zt+kE~1)PR4L+_rDj{Gt7&kw)NQwk5C#+;@+J$&xNioP1LTQrsghsxzVCO>C{e_S^s zZ61y#(mV!)Fk(#kR7`f`7W2i{Ja(nBMPl@p*W5es0THB&8XR{9R1>8&7`S0#Nq!1V zC%)&rn>Oq9e!pK4y)bO2RT!Suo%7hO1?RP>tK)0p{JbltO3p{3Jz_Y6ZijL2##kht zJ~;=g-Y~s}UA}}xxANBL)@Z1e52U+};6=+pG~8&bys4R{NayaIV!bk3dUSj|+~Rc` z>b?!+lxs6^;K`w#b=jr2rR50C|9e@hCuPY%nO#wQsI`U*KIwziidZ+|-O&U>dlt zF8UX1uA{Z&JEkb7Zor5pLa-b$Nbd|c9~ovE7Op+!{V@Kxg#VVZv6>=Mu3#;Vp;8en z69|e)ati5lvc2u`yiYmfxcHlJ|J4usd#rCbFyzrl4N4M4X=MW*X`)qZwA8$2QON%{mG7PWBIBZwT1BJL2#B^Wa18_R z8bKD0LDT)$wANe?;-yoree~;BTOs-DefVHr?%hPu2F;lwCp$~zxlrIOd0rYGc^z6K zQGDd&=V8vX$1CbLTJ_e}l13;-bYL8(5z^Sw2+>U*X?TKW4e1K^ukLfo#oF_PWAS%& zJW|ykzC_DS4`GP-A~g(ipT}o9_2uh@JJ7nQglB*vG7!cndR~|Z!>x#laUo36=tgv} zb=A?!+6WE7h#Ev7TY2dOFgj#ftr{!B0`&dMeU|>kmB;(?VSU+4(*S}u4e+Ic(&-}l eTY0{BFR%BR`PbQZY5I<1b^I4=!PO`#2mk;)60D>E literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..b4f6550f90614bcbf5b0826e98a35108372d6b37 GIT binary patch literal 566 zcmV-60?GX!iwFP!000001Fe%mkJ}&+h5t&#*|Py-Y{;#b+$ycMRWH>Z1{i0N96Q2z zqbSOMFHXGCZq=$))f>i-c{3l6GmF$=3PV4#&G$3Ilwz<`qWSZ=U9qdQo($Pt6t>I}^z7|JVG zDrz!XZ=HOHZ)n@#0(Pr0q>m6=5?r^H1avmjM=wBIlAs!@$tf!uTmLh}45dR$9k{{M zoz1PK$6GKcerSgbdL=CflAeRqS^)}fLC-TOE~M0s%?*sWw_!Ko(#6$2Cg^cL7ypvM ztv`MJw)#A0aP@c(;cEMq!oOEyB%JSPIdR{AZ@B#!ZY>3`l?Elq<|%lF$~}QX-bhpO zMhNwrDZ)5_6m<>a3T=)S+di@9e3x#R`V>#I+f!C{p(V(#qMv(Pg2{x*PwE%3zi0C@ zTl8UxY&cw3jB}x6shYac?0FdiNukf3f-YqVm6INHl`q9%Qwvc$Zj@!0A8x{i;)etP E00oc_w*UYD literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..1006f89dc1f95df5a3877f488da05cc52b2174df GIT binary patch literal 414 zcmV;P0b%|hiwFP!0000016@+flG`8<{1w7kto2+Ae?)TFQ!16i0E3na0u`XBTrU4o zJ|bThuw~b7ZmpSSrl(sMY7{+D-hlww4Xke!XT2N-23+^71Hif&QH-3^ikihldiwFR zqSk0+aREn97m6;=aI3XdftWuu*oYMsI2m_uT`Ma6>QXpAs1Ohy*hKf3tW1Pim}!M% ze11%=pFEM?B`_`$@9deRcO-A$zJCAvhipEm8N#nGM0w(TB5OoqbfJU{A^|e{jN*dQ zXd{UQfi~Zg&I>-)7tGA_2nTa+(KqkTnHYUY>~krgy{RjbFBDP=Myv_hZ?G%o;w4|3 zAWWFpeGOeh+4;e!y)6SOlQJQ9pL2F6KDbv@tU=-@zA^#jZj$z4gP`dD2|O>OgW%&) zk4M%HLb4uO#YCqY*1b04kq=^Q>*Ldwl7jS8%!Q&nXMCHXURz!dd|c7*k!*Igdsy{`%{$EFXYhq+8=#Z686aBMlN})|;<25c0@?k#kO;oPNaOj4X?yT( zN$|2$y`Mo08Yt&?CpbfYpOEev=ToY0}xWOx=%A>Y%?lESlO*Mqex)P=mwBSCym4 zBN`2GPdFAEPA G1ONbYng9?0 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..b411adfaf0fd7cdcd547258c1b9f540e57873ea7 GIT binary patch literal 345 zcmV-f0jB;RiwFP!00000165JmZo?o9{gsL5x`8A>lE0YtIPC$jlcA+aMPSiX_1{O* zi_|x4&c(;Ru*sZ=bP(<<|UA*8`V39Igo6jl2k)mwJli5skEh(jnBUH5d9 r9eOh^bYM67%P!Cda`(IRb68D4cFk);T3qnw$HlJy?t;uD3<3ZEDj29% literal 0 HcmV?d00001 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"