From aa76cfb79d1b884ad17745b00b5a6629820ae810 Mon Sep 17 00:00:00 2001 From: Mark Baggett Date: Thu, 20 Feb 2025 09:13:19 -0600 Subject: [PATCH 1/5] Use versionless URLs. --- iiify/templates/docs/collections.html | 12 ++++++------ iiify/templates/docs/items.html | 4 ++-- iiify/templates/docs/overview.html | 14 +++++++------- iiify/templates/helper.html | 4 ++-- iiify/templates/helpers/audio.html | 12 ++++++------ iiify/templates/helpers/collection.html | 8 ++++---- iiify/templates/helpers/image.html | 16 ++++++++-------- iiify/templates/helpers/movies.html | 12 ++++++------ iiify/templates/helpers/texts.html | 8 ++++---- iiify/templates/helpers/unknown.html | 2 +- tests/test_helper.py | 4 ++-- 11 files changed, 48 insertions(+), 48 deletions(-) diff --git a/iiify/templates/docs/collections.html b/iiify/templates/docs/collections.html index 9cef01f..dac1ea8 100644 --- a/iiify/templates/docs/collections.html +++ b/iiify/templates/docs/collections.html @@ -14,10 +14,10 @@

Example

leedsuniversitylibrary

To then get the IIIF collection manifest, plug in the ID to the following template:

-
https://iiif.archive.org/iiif/3/:id/collection.json
+
https://iiif.archive.org/iiif/:id/collection.json

For the Leeds example above, the final IIIF collection manifest URL would be:

-
https://iiif.archive.org/iiif/3/leedsuniversitylibrary/collection.json
+
https://iiif.archive.org/iiif/leedsuniversitylibrary/collection.json

Note about nested collections

Please note that Internet Archive collections can be arbitrarily nested within other collections. In these cases, the IIIF collection manifest will return a link to one or more IIIF collection manifest(s) in addition to the items nested individually within that Internet Archive collection.

@@ -34,10 +34,10 @@

Pagination for large collections

- - - - + + + +
Collection manifest URLItems retrieved
https://iiif.archive.org/iiif/3/leedsuniversitylibrary/collection.json0-999
https://iiif.archive.org/iiif/3/leedsuniversitylibrary/2/collection.json1000-1999
https://iiif.archive.org/iiif/3/leedsuniversitylibrary/3/collection.json2000-2999
https://iiif.archive.org/iiif/3/leedsuniversitylibrary/4/collection.json3000-3775
https://iiif.archive.org/iiif/leedsuniversitylibrary/collection.json0-999
https://iiif.archive.org/iiif/leedsuniversitylibrary/2/collection.json1000-1999
https://iiif.archive.org/iiif/leedsuniversitylibrary/3/collection.json2000-2999
https://iiif.archive.org/iiif/leedsuniversitylibrary/4/collection.json3000-3775
diff --git a/iiify/templates/docs/items.html b/iiify/templates/docs/items.html index 05622ec..fc872ad 100644 --- a/iiify/templates/docs/items.html +++ b/iiify/templates/docs/items.html @@ -39,10 +39,10 @@

Example

So, from our example just above, the Internet Archive identifier for that item is:

img-8664_202009

To then get the IIIF manifest, plug in the ID to the following template:

-
https://iiif.archive.org/iiif/3/:id/manifest.json
+
https://iiif.archive.org/iiif/:id/manifest.json

For the example above, the final IIIF manifest URL would be:

-
https://iiif.archive.org/iiif/3/img-8664_202009/manifest.json
+
https://iiif.archive.org/iiif/img-8664_202009/manifest.json

Note about IIIF Presentation API versions

diff --git a/iiify/templates/docs/overview.html b/iiify/templates/docs/overview.html index 595fac0..676b77b 100644 --- a/iiify/templates/docs/overview.html +++ b/iiify/templates/docs/overview.html @@ -15,7 +15,7 @@

Convention: IDs

emphasis:

-
https://iiif.archive.org/iiif/3/:id/manifest.json
+
https://iiif.archive.org/iiif/:id/manifest.json

Getting started

@@ -45,7 +45,7 @@

Presentation API

The Presentation API can also faciliate the portability and playback of time-based media like audio and video files. In the A/V context, IIIF manifests often present multiple playback options based on the media formats and quality types available.

A manifest for an Internet Archive item looks like this:

-
https://iiif.archive.org/iiif/3/:id/manifest.json
+
https://iiif.archive.org/iiif/:id/manifest.json

See the sections below for all the possible ways to retrieve manifests for items and collections.

@@ -66,10 +66,10 @@

Image API

The Image API creates images using the following template:

{scheme}://{server}/{prefix}/{identifier}/{region}/{size}/{rotation}/{quality}.{format}

In the context of the Internet Archive items, that will look like this for a full image:

-
https://iiif.archive.org/image/iiif/3/:id+filename/full/max/0/default.jpg
+
https://iiif.archive.org/image/iiif/:id+filename/full/max/0/default.jpg

Making use of the various parameters, a request for a bitonal center-cropped square image 375 pixels on each side, rotated 45 degrees will look like this:

-
https://iiif.archive.org/image/iiif/3/:id+filename/square/375,/45/bitonal.jpg
+
https://iiif.archive.org/image/iiif/:id+filename/square/375,/45/bitonal.jpg

See the Image API section on "Image Requests" for more details on how images can be manipulated and specific sizes or sections retrieved.

@@ -90,11 +90,11 @@

Example

In order to get the :id+filename the way you need it for the IIIF Image API info.json, you can combine the ID and filename with a URL encoded slash, i.e. %2f.

So for this image, the info.json would be:

-
https://iiif.archive.org/image/iiif/3/img-8664_202009%2fIMG_8664.jpg/info.json
+
https://iiif.archive.org/image/iiif/img-8664_202009%2fIMG_8664.jpg/info.json

And the full URL for the image would be:

-
https://iiif.archive.org/image/iiif/3/img-8664_202009%2fIMG_8664.jpg/full/max/0/default.jpg
+
https://iiif.archive.org/image/iiif/img-8664_202009%2fIMG_8664.jpg/full/max/0/default.jpg

A cropped portion at the full resolution can be requested like this:

-
https://iiif.archive.org/image/iiif/3/img-8664_202009%2fIMG_8664.jpg/1100,904,704,664/max/0/default.jpg
+
https://iiif.archive.org/image/iiif/img-8664_202009%2fIMG_8664.jpg/1100,904,704,664/max/0/default.jpg

Where "1100,904,704,664" in that URL stands for 1100 pixels from the left edge, 904 pixels from the bottom edge, 704 pixels is the width of the desired section, and 664 pixels is the height.

diff --git a/iiify/templates/helper.html b/iiify/templates/helper.html index 1bdf133..0df6701 100644 --- a/iiify/templates/helper.html +++ b/iiify/templates/helper.html @@ -17,9 +17,9 @@

The manifest URL is: {{ uri }}/manifest.json

-

The Image API URL for the full image is: https://iiif.archive.org/image/iiif/3/{{ cantaloupe_id }}/full/max/0/default.jpg

+

The Image API URL for the full image is: https://iiif.archive.org/image/iiif/{{ cantaloupe_id }}/full/max/0/default.jpg

-

The Image API info.json for the image is: https://iiif.archive.org/image/iiif/3/{{ cantaloupe_id }}/info.json

+

The Image API info.json for the image is: https://iiif.archive.org/image/iiif/{{ cantaloupe_id }}/info.json

diff --git a/iiify/templates/helpers/audio.html b/iiify/templates/helpers/audio.html index 7e579f0..164815a 100644 --- a/iiify/templates/helpers/audio.html +++ b/iiify/templates/helpers/audio.html @@ -25,15 +25,15 @@

IIIF Presentation API Audio Helper

The IA identifier is: {{ identifier }}

-

The IIIF manifest URL is: https://iiif.archive.org/iiif/3/{{ identifier }}/manifest.json

+

The IIIF manifest URL is: https://iiif.archive.org/iiif/3/{{ identifier }}/manifest.json

IIIF player options for this mediatype:

diff --git a/iiify/templates/helpers/collection.html b/iiify/templates/helpers/collection.html index 3311349..bfd3b83 100644 --- a/iiify/templates/helpers/collection.html +++ b/iiify/templates/helpers/collection.html @@ -24,13 +24,13 @@

IIIF Collection Helper

The IA identifier is: {{ identifier }}

-

The IIIF collection URL is: https://iiif.archive.org/iiif/3/{{ identifier }}/collection.json

+

The IIIF collection URL is: https://iiif.archive.org/iiif/{{ identifier }}/collection.json

IIIF viewer options

diff --git a/iiify/templates/helpers/image.html b/iiify/templates/helpers/image.html index 1598e43..efda9e3 100644 --- a/iiify/templates/helpers/image.html +++ b/iiify/templates/helpers/image.html @@ -24,25 +24,25 @@

IIIF Image Helper

The IA identifier is: {{ identifier }}

-

The IIIF manifest URL is: https://iiif.archive.org/iiif/3/{{ identifier }}/manifest.json

+

The IIIF manifest URL is: https://iiif.archive.org/iiif/{{ identifier }}/manifest.json

-

The Image API URL for the full image is: https://iiif.archive.org/image/iiif/3/{{ cantaloupe_id }}/full/max/0/default.jpg

+

The Image API URL for the full image is: https://iiif.archive.org/image/iiif/{{ cantaloupe_id }}/full/max/0/default.jpg

-

The Image API info.json for the image is: https://iiif.archive.org/image/iiif/3/{{ cantaloupe_id }}/info.json

+

The Image API info.json for the image is: https://iiif.archive.org/image/iiif/{{ cantaloupe_id }}/info.json

IIIF viewer options

IIIF image tool options

diff --git a/iiify/templates/helpers/movies.html b/iiify/templates/helpers/movies.html index e7cfa68..626879e 100644 --- a/iiify/templates/helpers/movies.html +++ b/iiify/templates/helpers/movies.html @@ -24,15 +24,15 @@

IIIF Presentation API Movies Helper

The IA identifier is: {{ identifier }}

-

The IIIF manifest URL is: https://iiif.archive.org/iiif/3/{{ identifier }}/manifest.json

+

The IIIF manifest URL is: https://iiif.archive.org/iiif/{{ identifier }}/manifest.json

IIIF viewer options for this mediatype:

diff --git a/iiify/templates/helpers/texts.html b/iiify/templates/helpers/texts.html index cfef3b9..2dac7a8 100644 --- a/iiify/templates/helpers/texts.html +++ b/iiify/templates/helpers/texts.html @@ -24,13 +24,13 @@

IIIF Presentation API Texts Helper

The IA identifier is: {{ identifier }}

-

The IIIF manifest URL is: https://iiif.archive.org/iiif/3/{{ identifier }}/manifest.json

+

The IIIF manifest URL is: https://iiif.archive.org/iiif/{{ identifier }}/manifest.json

IIIF Viewer options for this mediatype:

diff --git a/iiify/templates/helpers/unknown.html b/iiify/templates/helpers/unknown.html index bbcc678..c43994a 100644 --- a/iiify/templates/helpers/unknown.html +++ b/iiify/templates/helpers/unknown.html @@ -24,7 +24,7 @@

IIIF Presentation API Helper

The IA identifier is: {{ identifier }}

-

The IIIF manifest URL is: https://iiif.archive.org/iiif/3/{{ identifier }}/manifest.json

+

The IIIF manifest URL is: https://iiif.archive.org/iiif/{{ identifier }}/manifest.json

The material type of the item you're requested is not a recognized material type for IIIF viewers.

diff --git a/tests/test_helper.py b/tests/test_helper.py index 0208411..7a8a35e 100644 --- a/tests/test_helper.py +++ b/tests/test_helper.py @@ -14,10 +14,10 @@ def test_single_image(self): resp = self.test_app.get("/iiif/helper/img-8664_202009/") self.assertEqual(resp.status_code, 200) - self.assertIn('Mirador', resp.text, "Couldn't find Mirador link in helper page.") + self.assertIn('Mirador', resp.text, "Couldn't find Mirador link in helper page.") def test_collection(self): resp = self.test_app.get("/iiif/helper/frankbford/") self.assertEqual(resp.status_code, 200) - self.assertIn('Mirador', resp.text, "Couldn't find Mirador link in helper page.") \ No newline at end of file + self.assertIn('Mirador', resp.text, "Couldn't find Mirador link in helper page.") \ No newline at end of file From 992c8f4ce430ca8254acdb6183b0b1fe36d763ba Mon Sep 17 00:00:00 2001 From: Mark Baggett Date: Thu, 20 Feb 2025 10:24:47 -0600 Subject: [PATCH 2/5] Add version number to v2 manifest requests. --- iiify/app.py | 2 +- iiify/resolver.py | 4 ++-- tests/test_manifests_v2.py | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/iiify/app.py b/iiify/app.py index d28956f..c0b1397 100755 --- a/iiify/app.py +++ b/iiify/app.py @@ -230,7 +230,7 @@ def manifest2(identifier): identifier, page = identifier.split('$') page = int(page) try: - return ldjsonify(create_manifest(identifier, domain=domain, page=page)) + return ldjsonify(create_manifest(identifier, domain=domain, page=page, version='2/')) except Exception as excpt: print("Exception occurred in manifest2:") print(excpt) diff --git a/iiify/resolver.py b/iiify/resolver.py index 298f164..5955949 100644 --- a/iiify/resolver.py +++ b/iiify/resolver.py @@ -236,14 +236,14 @@ def manifest_page(identifier, label='', page='', width='', height='', metadata=N } -def create_manifest(identifier, domain=None, page=None): +def create_manifest(identifier, domain=None, page=None, version=""): path = os.path.join(media_root, identifier) resp = requests.get('%s/metadata/%s' % (ARCHIVE, identifier)).json() metadata = resp.get("metadata", {}) manifest = { '@context': PRZ_CTX, - '@id': '%s%s/manifest.json' % (domain, identifier), + '@id': '%s%s%s/manifest.json' % (domain, version, identifier), '@type': 'sc:Manifest', 'description': metadata.get('description', ''), 'logo': 'https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcReMN4l9cgu_qb1OwflFeyfHcjp8aUfVNSJ9ynk2IfuHwW1I4mDSw', diff --git a/tests/test_manifests_v2.py b/tests/test_manifests_v2.py index a799100..24a957b 100644 --- a/tests/test_manifests_v2.py +++ b/tests/test_manifests_v2.py @@ -15,7 +15,7 @@ def test_v2_image_manifest(self): self.assertEqual(resp.status_code, 200) manifest = resp.json - self.assertEqual(manifest['@id'], 'https://localhost/iiif/rashodgson68/manifest.json', 'V2 Manifest ID is using new infrastructure changed') + self.assertEqual(manifest['@id'], 'https://localhost/iiif/2/rashodgson68/manifest.json', 'V2 Manifest ID is using new infrastructure changed') self.assertEqual(manifest['@type'], "sc:Manifest", f"Unexpected type. Expected Manifest got {manifest['@type']}") self.assertEqual(len(manifest['sequences'][0]['canvases']),32,f"Expected 32 canvases but got: {len(manifest['sequences'][0]['canvases'])}") self.assertEqual(manifest['sequences'][0]['canvases'][0]['@id'],"https://iiif.archivelab.org/iiif/rashodgson68$0/canvas",f"v2 canvas id has changed") @@ -26,7 +26,7 @@ def test_v2_image_api(self): self.assertEqual(resp.status_code, 200) manifest = resp.json - self.assertEqual(manifest['@id'], 'https://localhost/iiif/1991-12-compute-magazine/manifest.json', 'V2 Manifest ID is using new infrastructure changed') + self.assertEqual(manifest['@id'], 'https://localhost/iiif/2/1991-12-compute-magazine/manifest.json', 'V2 Manifest ID is using new infrastructure changed') image = manifest['sequences'][0]['canvases'][0]['images'][0]['resource'] self.assertEqual(image['@id'], "https://localhost/iiif/1991-12-compute-magazine$0/full/full/0/default.jpg", "Resource not using new image server") self.assertEqual(image['service']['@id'], 'https://localhost/iiif/1991-12-compute-magazine$0', "V2 service not using the new image server") @@ -36,7 +36,7 @@ def test_v2_single_image(self): self.assertEqual(resp.status_code, 200) manifest = resp.json - self.assertEqual(manifest['@id'], 'https://localhost/iiif/img-8664_202009/manifest.json', 'V2 Manifest ID is using new infrastructure changed') + self.assertEqual(manifest['@id'], 'https://localhost/iiif/2/img-8664_202009/manifest.json', 'V2 Manifest ID is using new infrastructure changed') canvas = manifest['sequences'][0]['canvases'][0] self.assertEqual(canvas['@id'], 'https://iiif.archivelab.org/iiif/img-8664_202009/canvas', 'Expected canvas id to be the same') image = canvas['images'][0]['resource'] @@ -48,7 +48,7 @@ def test_v2_single_text_manifest(self): self.assertEqual(resp.status_code, 200) manifest = resp.json - self.assertEqual(manifest['@id'], 'https://localhost/iiif/fbf_3chords_1_/manifest.json', 'V2 Manifest ID is using new infrastructure changed') + self.assertEqual(manifest['@id'], 'https://localhost/iiif/2/fbf_3chords_1_/manifest.json', 'V2 Manifest ID is using new infrastructure changed') canvas = manifest['sequences'][0]['canvases'][0] self.assertEqual(canvas['@id'], 'https://iiif.archivelab.org/iiif/fbf_3chords_1_$0/canvas', 'Expected canvas id to be the same') image = canvas['images'][0]['resource'] From 38f9beb2dc12e1a0ae4341769f91cb0560ec5bd6 Mon Sep 17 00:00:00 2001 From: Mark Baggett Date: Thu, 20 Feb 2025 13:43:26 -0600 Subject: [PATCH 3/5] Proxy instead of redirect. --- iiify/app.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iiify/app.py b/iiify/app.py index c0b1397..67796d1 100755 --- a/iiify/app.py +++ b/iiify/app.py @@ -171,14 +171,14 @@ def collection3page(identifier, page): @cache.cached(timeout=cache_timeouts["long"], forced_update=cache_bust) def collectionJSON(identifier): validate_ia_identifier(identifier, page_suffix=False) - return redirect(f'/iiif/3/{identifier}/collection.json', code=302) + return collection3JSON(identifier) @app.route('/iiif///collection.json') @cache.cached(timeout=cache_timeouts["long"], forced_update=cache_bust) def collectionPage(identifier, page): validate_ia_identifier(identifier, page_suffix=False) - return redirect(f'/iiif/3/{identifier}/{page}/collection.json', code=302) + return collection3page(identifier, page) @app.route('/iiif/3//manifest.json') @@ -219,7 +219,7 @@ def vtt_stream(identifier): @cache.cached(timeout=cache_timeouts["long"], forced_update=cache_bust) def manifest(identifier): validate_ia_identifier(identifier, page_suffix=False) - return redirect(f'/iiif/3/{identifier}/manifest.json', code=302) + return manifest3(identifier) @app.route('/iiif/2//manifest.json') def manifest2(identifier): From 5d6e6c1b46a2a8d202b8fdfe83654fa21658e982 Mon Sep 17 00:00:00 2001 From: Mark Baggett Date: Thu, 20 Feb 2025 14:51:05 -0600 Subject: [PATCH 4/5] Update tests for proxying rather than redirects. --- tests/test_collections.py | 11 ++++++----- tests/test_manifests.py | 3 +-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/test_collections.py b/tests/test_collections.py index 518bccb..692d5f3 100644 --- a/tests/test_collections.py +++ b/tests/test_collections.py @@ -22,13 +22,14 @@ def test_v3_collection_pages(self): resp = self.test_app.get("/iiif/3/frankbford/2/collection.json") self.assertEqual(resp.status_code, 200) - def test_collections_redirect(self): + def test_collections_proxy(self): resp = self.test_app.get("/iiif/frankbford/collection.json") - self.assertEqual(resp.status_code, 302) + print(resp.status_code) + self.assertEqual(resp.status_code, 200) - def test_v3_collection_pages_redirect(self): - resp = self.test_app.get("/iiif/frankbford/2/collection.json") - self.assertEqual(resp.status_code, 302) + def test_v3_collection_pages_proxy(self): + resp = self.test_app.get("/iiif/frankbford/2/collection.json") + self.assertEqual(resp.status_code, 200) def test_v3_collection_detection(self): resp = self.test_app.get("/iiif/frankbford/manifest.json") diff --git a/tests/test_manifests.py b/tests/test_manifests.py index 3a2387b..d9e7367 100644 --- a/tests/test_manifests.py +++ b/tests/test_manifests.py @@ -12,8 +12,7 @@ def setUp(self) -> None: def test_no_version(self): resp = self.test_app.get("/iiif/rashodgson68/manifest.json") - self.assertEqual(resp.status_code, 302) - self.assertEqual(resp.location, '/iiif/3/rashodgson68/manifest.json') + self.assertEqual(resp.status_code, 200) def test_ident(self): resp = self.test_app.get("/iiif/3/img-8664_202009/manifest.json") From 0e01aee8365ad9c3d397c561bc632bf03643bb3d Mon Sep 17 00:00:00 2001 From: Mark Baggett Date: Thu, 20 Feb 2025 18:13:39 -0600 Subject: [PATCH 5/5] Clean up and clear caches for tests. --- iiify/app.py | 2 +- iiify/resolver.py | 4 ++-- tests/test_collections.py | 3 +-- tests/test_images.py | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/iiify/app.py b/iiify/app.py index 67796d1..85dc308 100755 --- a/iiify/app.py +++ b/iiify/app.py @@ -230,7 +230,7 @@ def manifest2(identifier): identifier, page = identifier.split('$') page = int(page) try: - return ldjsonify(create_manifest(identifier, domain=domain, page=page, version='2/')) + return ldjsonify(create_manifest(identifier, domain=domain, page=page)) except Exception as excpt: print("Exception occurred in manifest2:") print(excpt) diff --git a/iiify/resolver.py b/iiify/resolver.py index 5955949..2e5e529 100644 --- a/iiify/resolver.py +++ b/iiify/resolver.py @@ -236,14 +236,14 @@ def manifest_page(identifier, label='', page='', width='', height='', metadata=N } -def create_manifest(identifier, domain=None, page=None, version=""): +def create_manifest(identifier, domain=None, page=None): path = os.path.join(media_root, identifier) resp = requests.get('%s/metadata/%s' % (ARCHIVE, identifier)).json() metadata = resp.get("metadata", {}) manifest = { '@context': PRZ_CTX, - '@id': '%s%s%s/manifest.json' % (domain, version, identifier), + '@id': '%s2/%s/manifest.json' % (domain,identifier), '@type': 'sc:Manifest', 'description': metadata.get('description', ''), 'logo': 'https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcReMN4l9cgu_qb1OwflFeyfHcjp8aUfVNSJ9ynk2IfuHwW1I4mDSw', diff --git a/tests/test_collections.py b/tests/test_collections.py index 692d5f3..d5a54b8 100644 --- a/tests/test_collections.py +++ b/tests/test_collections.py @@ -6,7 +6,7 @@ class TestCollections(unittest.TestCase): def setUp(self) -> None: - os.environ["FLASK_ENV"] = "testing" + os.environ["FLASK_CACHE_DISABLE"] = "true" self.test_app = FlaskClient(app) def test_v3_collection(self): @@ -24,7 +24,6 @@ def test_v3_collection_pages(self): def test_collections_proxy(self): resp = self.test_app.get("/iiif/frankbford/collection.json") - print(resp.status_code) self.assertEqual(resp.status_code, 200) def test_v3_collection_pages_proxy(self): diff --git a/tests/test_images.py b/tests/test_images.py index 3a6f3c3..8c7b620 100644 --- a/tests/test_images.py +++ b/tests/test_images.py @@ -7,7 +7,7 @@ class TestImages(unittest.TestCase): def setUp(self) -> None: - os.environ["FLASK_ENV"] = "testing" + os.environ["FLASK_CACHE_DISABLE"] = "true" self.test_app = FlaskClient(app) def test_v3_resolving(self):