diff --git a/documentation/meta/media_properties/frontend.md b/documentation/meta/media_properties/frontend.md
index e3b28413f16..2d2017ad4ca 100644
--- a/documentation/meta/media_properties/frontend.md
+++ b/documentation/meta/media_properties/frontend.md
@@ -42,11 +42,11 @@ clarity.
| `license_version` | `LicenseVersion` (custom) | |
| [`originalTitle`](#Media-originalTitle-notes) | `string` | |
| `provider` | `string` | |
-| `providerName` | `string` | ✓ |
+| `providerName` | `string` | |
| `related_url` | `string` | |
| `sensitivity` | `Sensitivity[]` (custom) | |
-| `source` | `string` | ✓ |
-| `sourceName` | `string` | ✓ |
+| `source` | `string` | |
+| `sourceName` | `string` | |
| `tags` | `Tag[]` (custom) | |
| `thumbnail` | `string` | ✓ |
| [`title`](#Media-title-notes) | `string` | |
diff --git a/frontend/nuxt.config.ts b/frontend/nuxt.config.ts
index c03f6a16507..900ea1cdff9 100644
--- a/frontend/nuxt.config.ts
+++ b/frontend/nuxt.config.ts
@@ -135,7 +135,7 @@ const config: NuxtConfig = {
: undefined,
},
router: {
- middleware: "middleware",
+ middleware: "feature-flags",
},
components: [
{ path: "~/components", extensions: ["vue"], pathPrefix: false },
@@ -148,6 +148,7 @@ const config: NuxtConfig = {
"~/plugins/sentry.ts",
"~/plugins/analytics.ts",
"~/plugins/errors.ts",
+ "~/plugins/init-stores.ts",
],
css: ["~/assets/fonts.css", "~/styles/tailwind.css", "~/styles/accent.css"],
head,
@@ -314,6 +315,7 @@ const config: NuxtConfig = {
trackLocalhost: !isProdNotPlaywright,
},
publicRuntimeConfig: {
+ deploymentEnv: process.env.DEPLOYMENT_ENV ?? "local",
plausible: {
// This is the current domain of the site.
domain:
@@ -346,7 +348,6 @@ const config: NuxtConfig = {
environment: process.env.SENTRY_ENVIRONMENT,
},
},
- deploymentEnv: process.env.DEPLOYMENT_ENV ?? "local",
},
}
diff --git a/frontend/src/components/VContentSwitcher/VSearchTypeButton.vue b/frontend/src/components/VContentSwitcher/VSearchTypeButton.vue
index b4f9e810ac9..e19d7420d17 100644
--- a/frontend/src/components/VContentSwitcher/VSearchTypeButton.vue
+++ b/frontend/src/components/VContentSwitcher/VSearchTypeButton.vue
@@ -9,7 +9,7 @@
v-bind="$attrs"
@click="$emit('click')"
>
-
+
{{ label }}
diff --git a/frontend/src/components/VMediaInfo/VByLine/VByLine.vue b/frontend/src/components/VMediaInfo/VByLine/VByLine.vue
index ff07a1bca23..016d68a7f25 100644
--- a/frontend/src/components/VMediaInfo/VByLine/VByLine.vue
+++ b/frontend/src/components/VMediaInfo/VByLine/VByLine.vue
@@ -1,15 +1,15 @@
@@ -18,7 +18,7 @@
import { computed, defineComponent, type PropType } from "vue"
import { useSearchStore } from "~/stores/search"
-import type { SupportedMediaType } from "~/constants/media"
+import type { AudioDetail, ImageDetail } from "~/types/media"
import VSourceCreatorButton from "~/components/VMediaInfo/VByLine/VSourceCreatorButton.vue"
import VScrollableLine from "~/components/VScrollableLine.vue"
@@ -33,58 +33,41 @@ export default defineComponent({
VSourceCreatorButton,
},
props: {
- creator: {
- type: String,
- },
- sourceName: {
- type: String,
- required: true,
- },
- sourceSlug: {
- type: String,
- required: true,
- },
- mediaType: {
- type: String as PropType,
+ media: {
+ type: Object as PropType,
required: true,
},
},
setup(props) {
- const showCreator = computed(() => {
- return Boolean(
- props.creator && props.creator.toLowerCase() !== "unidentified"
- )
- })
-
const searchStore = useSearchStore()
- const creatorHref = computed(() => {
- if (!props.creator) {
- return undefined
+ const creator = computed(() => {
+ if (props.media.creator && props.media.creator !== "unidentified") {
+ const href = searchStore.getCollectionPath({
+ type: props.media.frontendMediaType,
+ collectionParams: {
+ collection: "creator",
+ source: props.media.source,
+ creator: props.media.creator,
+ },
+ })
+ return { name: props.media.creator, href }
}
- return searchStore.getCollectionPath({
- type: props.mediaType,
- collectionParams: {
- collection: "creator",
- source: props.sourceSlug,
- creator: props.creator,
- },
- })
+ return null
})
const sourceHref = computed(() => {
return searchStore.getCollectionPath({
- type: props.mediaType,
+ type: props.media.frontendMediaType,
collectionParams: {
collection: "source",
- source: props.sourceSlug,
+ source: props.media.source,
},
})
})
return {
- showCreator,
- creatorHref,
+ creator,
sourceHref,
}
},
diff --git a/frontend/src/components/VMediaInfo/VByLine/meta/VByLine.stories.mdx b/frontend/src/components/VMediaInfo/VByLine/meta/VByLine.stories.mdx
index 58ffa5f7613..494b6a7b55f 100644
--- a/frontend/src/components/VMediaInfo/VByLine/meta/VByLine.stories.mdx
+++ b/frontend/src/components/VMediaInfo/VByLine/meta/VByLine.stories.mdx
@@ -6,7 +6,6 @@ import {
Story,
} from "@storybook/addon-docs"
import { supportedMediaTypes } from "~/constants/media"
-import { useProviderStore } from "~/stores/provider"
import VByLine from "~/components/VMediaInfo/VByLine/VByLine.vue"
@@ -14,8 +13,6 @@ export const Template = (args) => ({
template: `
`,
components: { VByLine },
setup() {
- const providerStore = useProviderStore()
- providerStore.getProviders().then(/** */)
return { args }
},
})
diff --git a/frontend/src/components/VMediaInfo/VMediaInfo.vue b/frontend/src/components/VMediaInfo/VMediaInfo.vue
index 3d7eec74a02..b2c88779ff7 100644
--- a/frontend/src/components/VMediaInfo/VMediaInfo.vue
+++ b/frontend/src/components/VMediaInfo/VMediaInfo.vue
@@ -1,19 +1,13 @@
{{ media.title }}
-
+
diff --git a/frontend/src/middleware/feature-flags.ts b/frontend/src/middleware/feature-flags.ts
new file mode 100644
index 00000000000..097a3c24173
--- /dev/null
+++ b/frontend/src/middleware/feature-flags.ts
@@ -0,0 +1,11 @@
+import { defineNuxtMiddleware } from "@nuxtjs/composition-api"
+
+import { useFeatureFlagStore } from "~/stores/feature-flag"
+
+/**
+ * On every page navigation, update the feature flags from query.
+ */
+export default defineNuxtMiddleware(async ({ $pinia, query }) => {
+ const featureFlagStore = useFeatureFlagStore($pinia)
+ featureFlagStore.initFromQuery(query)
+})
diff --git a/frontend/src/middleware/middleware.ts b/frontend/src/middleware/middleware.ts
deleted file mode 100644
index 45077fcc461..00000000000
--- a/frontend/src/middleware/middleware.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-import { useProviderStore } from "~/stores/provider"
-import { useFeatureFlagStore } from "~/stores/feature-flag"
-import { useUiStore } from "~/stores/ui"
-
-import type { Context, Middleware } from "@nuxt/types"
-
-/**
- * In embedded mode, the app sends its url
- * to the outer window to improve the user experience.
- *
- * The app is in embedded mode by default. To set it to
- * standalone mode with larger header and a footer,
- * add `?embedded=false` to the end of the URL.
- *
- * Messages sent to the outer window have the following format:
- * `{type: , value: }`.
- * Currently, one event type is used:
- * - `urlChange` sends the relative path of the URL on every URL change.
- */
-const middleware: Middleware = async ({ $cookies, query, $pinia }: Context) => {
- /* Provider store */
- const providerStore = useProviderStore($pinia)
- await providerStore.fetchMediaProviders()
-
- /* Feature flag store */
-
- const featureFlagStore = useFeatureFlagStore($pinia)
- featureFlagStore.initFromCookies($cookies.get("features") ?? {})
- featureFlagStore.initFromCookies($cookies.get("sessionFeatures") ?? {})
- featureFlagStore.initFromQuery(query)
-
- /* UI store */
-
- const uiStore = useUiStore($pinia)
-
- uiStore.initFromCookies($cookies.get("ui") ?? {})
-}
-export default middleware
diff --git a/frontend/src/plugins/init-stores.ts b/frontend/src/plugins/init-stores.ts
new file mode 100644
index 00000000000..c5ec285b403
--- /dev/null
+++ b/frontend/src/plugins/init-stores.ts
@@ -0,0 +1,23 @@
+import { defineNuxtPlugin } from "@nuxtjs/composition-api"
+
+import { useFeatureFlagStore } from "~/stores/feature-flag"
+import { useUiStore } from "~/stores/ui"
+import { useProviderStore } from "~/stores/provider"
+
+/**
+ * Initialize the feature flag and UI stores from cookies and query parameters on every request.
+ */
+export default defineNuxtPlugin(async ({ $cookies, $pinia }) => {
+ /* Provider store */
+ const providerStore = useProviderStore($pinia)
+ await providerStore.fetchProviders()
+
+ /* Feature flag store */
+ const featureFlagStore = useFeatureFlagStore($pinia)
+ featureFlagStore.initFromCookies($cookies.get("features") ?? {})
+ featureFlagStore.initFromCookies($cookies.get("sessionFeatures") ?? {})
+
+ /* UI store */
+ const uiStore = useUiStore($pinia)
+ uiStore.initFromCookies($cookies.get("ui") ?? {})
+})
diff --git a/frontend/src/stores/media/single-result.ts b/frontend/src/stores/media/single-result.ts
index 67aa181a989..9f173cca743 100644
--- a/frontend/src/stores/media/single-result.ts
+++ b/frontend/src/stores/media/single-result.ts
@@ -11,7 +11,6 @@ import type { SupportedMediaType } from "~/constants/media"
import { initServices } from "~/stores/media/services"
import { useMediaStore } from "~/stores/media/index"
-import { useProviderStore } from "~/stores/provider"
import type { FetchingError, FetchState } from "~/types/fetch-state"
@@ -59,23 +58,6 @@ export const useSingleResultStore = defineStore("single-result", {
action === "start" ? this._startFetching() : this._endFetching(option)
},
- _addProviderName(
- mediaItem: DetailFromMediaType
- ): DetailFromMediaType {
- const providerStore = useProviderStore()
-
- mediaItem.providerName = providerStore.getProviderName(
- mediaItem.provider,
- mediaItem.frontendMediaType
- )
- if (mediaItem.source) {
- mediaItem.sourceName = providerStore.getProviderName(
- mediaItem.source,
- mediaItem.frontendMediaType
- )
- }
- return mediaItem
- },
reset() {
this.mediaItem = null
this.mediaType = null
@@ -91,7 +73,7 @@ export const useSingleResultStore = defineStore("single-result", {
*/
setMediaItem(mediaItem: AudioDetail | ImageDetail | null) {
if (mediaItem) {
- this.mediaItem = this._addProviderName(mediaItem)
+ this.mediaItem = mediaItem
this.mediaType = mediaItem.frontendMediaType
this.mediaId = mediaItem.id
} else {
@@ -160,7 +142,7 @@ export const useSingleResultStore = defineStore("single-result", {
this._updateFetchState("start")
const accessToken = this.$nuxt.$openverseApiToken
const service = initServices[type](accessToken)
- const item = this._addProviderName(await service.getMediaDetail(id))
+ const item = await service.getMediaDetail(id)
this.setMediaItem(item)
this._updateFetchState("end")
diff --git a/frontend/src/stores/provider.ts b/frontend/src/stores/provider.ts
index fad0221f39b..7dd4c270376 100644
--- a/frontend/src/stores/provider.ts
+++ b/frontend/src/stores/provider.ts
@@ -1,8 +1,6 @@
import { defineStore } from "pinia"
-import { ssrRef } from "@nuxtjs/composition-api"
import { capitalCase } from "~/utils/case"
-import { env } from "~/utils/env"
import {
AUDIO,
IMAGE,
@@ -14,8 +12,6 @@ import { initProviderServices } from "~/data/media-provider-service"
import type { MediaProvider } from "~/types/media-provider"
import type { FetchingError, FetchState } from "~/types/fetch-state"
-import type { Ref } from "vue"
-
export interface ProviderState {
providers: {
audio: MediaProvider[]
@@ -42,12 +38,6 @@ const sortProviders = (data: MediaProvider[]): MediaProvider[] => {
return nameA.localeCompare(nameB)
})
}
-/**
- * Timestamp is used to limit the update frequency to one every 60 minutes per request.
- */
-const lastUpdated: Ref = ssrRef(null)
-
-const updateFrequency = parseInt(env.providerUpdateFrequency, 10)
export const useProviderStore = defineStore("provider", {
state: (): ProviderState => ({
@@ -90,10 +80,6 @@ export const useProviderStore = defineStore("provider", {
? this._startFetching(mediaType)
: this._endFetching(mediaType, option)
},
- async getProviders() {
- await this.fetchMediaProviders()
- return this.providers
- },
_getProvider(providerCode: string, mediaType: SupportedMediaType) {
return this.providers[mediaType].find(
@@ -108,31 +94,25 @@ export const useProviderStore = defineStore("provider", {
* @param mediaType - mediaType of the provider
*/
getProviderName(providerCode: string, mediaType: SupportedMediaType) {
- const provider = this._getProvider(providerCode, mediaType)
- return provider?.display_name || capitalCase(providerCode)
+ return (
+ this._getProvider(providerCode, mediaType)?.display_name ||
+ capitalCase(providerCode)
+ )
},
/**
* Returns the source URL given the source code and media type.
*/
getSourceUrl(providerCode: string, mediaType: SupportedMediaType) {
- const provider = this._getProvider(providerCode, mediaType)
- return provider?.source_url
+ return this._getProvider(providerCode, mediaType)?.source_url
},
- /**
- * Fetches provider data if no data is available, or if the data is too old.
- * On successful fetch updates lastUpdated value.
- */
- async fetchMediaProviders() {
- if (this.needsUpdate) {
- await Promise.allSettled(
- supportedMediaTypes.map((mediaType) =>
- this.fetchMediaTypeProviders(mediaType)
- )
+ async fetchProviders() {
+ await Promise.allSettled(
+ supportedMediaTypes.map((mediaType) =>
+ this.fetchMediaTypeProviders(mediaType)
)
- lastUpdated.value = new Date()
- }
+ )
},
/**
@@ -177,23 +157,4 @@ export const useProviderStore = defineStore("provider", {
return this.sourceNames[mediaType].includes(sourceName)
},
},
-
- getters: {
- /**
- * Fetch providers only if there is no data, or if the last update for current request
- * was more than 1 hour ago.
- */
- needsUpdate(state) {
- const noData = supportedMediaTypes.some(
- (mediaType) => !state.providers[mediaType].length
- )
- if (noData || !lastUpdated.value) {
- return true
- }
-
- const timeSinceLastUpdate =
- new Date().getTime() - new Date(lastUpdated.value).getTime()
- return timeSinceLastUpdate > updateFrequency
- },
- },
})
diff --git a/frontend/src/stores/search.ts b/frontend/src/stores/search.ts
index 9e8834ac333..31b8533ef5b 100644
--- a/frontend/src/stores/search.ts
+++ b/frontend/src/stores/search.ts
@@ -432,12 +432,11 @@ export const useSearchStore = defineStore("search", {
async initProviderFilters() {
const providerStore = useProviderStore()
- const providers = await providerStore.getProviders()
for (const mediaType of supportedMediaTypes) {
this.updateProviderFilters({
mediaType,
- providers: providers[mediaType],
+ providers: providerStore.providers[mediaType],
})
}
},
diff --git a/frontend/src/types/media.ts b/frontend/src/types/media.ts
index 9fd7b8491f2..e23e97b9823 100644
--- a/frontend/src/types/media.ts
+++ b/frontend/src/types/media.ts
@@ -55,9 +55,9 @@ export interface Media {
category: string | null
provider: string
- source?: string
- providerName?: string
- sourceName?: string
+ source: string
+ providerName: string
+ sourceName: string
thumbnail?: string
filesize?: string
@@ -137,6 +137,8 @@ export interface ApiMedia
| "originalTitle"
| "isSensitive"
| "sensitivity"
+ | "sourceName"
+ | "providerName"
> {
title?: string
originalTitle?: string
diff --git a/frontend/src/utils/decode-media-data.ts b/frontend/src/utils/decode-media-data.ts
index a1ebf4e663d..7619792b76e 100644
--- a/frontend/src/utils/decode-media-data.ts
+++ b/frontend/src/utils/decode-media-data.ts
@@ -1,9 +1,10 @@
import { decodeData as decodeString } from "~/utils/decode-data"
-import type { ApiMedia, Media, Tag } from "~/types/media"
import { SENSITIVITY_RESPONSE_PARAM } from "~/constants/content-safety"
-import type { MediaType } from "~/constants/media"
import { AUDIO, IMAGE, MODEL_3D, VIDEO } from "~/constants/media"
+import type { ApiMedia, Media, Tag } from "~/types/media"
+import type { MediaType } from "~/constants/media"
import { useFeatureFlagStore } from "~/stores/feature-flag"
+import { useProviderStore } from "~/stores/provider"
import { capitalCase } from "~/utils/case"
import { getFakeSensitivities } from "~/utils/content-safety"
@@ -112,12 +113,18 @@ export const decodeMediaData = (
sensitivity.sort()
const isSensitive = sensitivity.length > 0
+ const providerStore = useProviderStore()
+ const sourceName = providerStore.getProviderName(media.source, mediaType)
+ const providerName = providerStore.getProviderName(media.provider, mediaType)
+
return {
...media,
...mediaTitle(media, mediaType),
frontendMediaType: mediaType,
creator: decodeString(media.creator),
tags: media.tags ? parseTags(media.tags) : ([] as Tag[]),
+ sourceName,
+ providerName,
sensitivity,
isSensitive,
} as T
diff --git a/frontend/src/utils/env.ts b/frontend/src/utils/env.ts
index 962f10ba21e..0386d9d1d0d 100644
--- a/frontend/src/utils/env.ts
+++ b/frontend/src/utils/env.ts
@@ -9,5 +9,4 @@ export const env = {
apiUrl: apiUrl.endsWith("/") ? apiUrl : `${apiUrl}/`,
filterStorageKey: "openverse-filter-visibility",
savedSearchCount: "4",
- providerUpdateFrequency: `${60 * 60 * 1000}`, // 1 hour
} as const
diff --git a/frontend/test/playwright/utils/navigation.ts b/frontend/test/playwright/utils/navigation.ts
index d6d9b748f1f..e6565db33cb 100644
--- a/frontend/test/playwright/utils/navigation.ts
+++ b/frontend/test/playwright/utils/navigation.ts
@@ -2,6 +2,8 @@ import { expect } from "@playwright/test"
import { LanguageDirection, t } from "~~/test/playwright/utils/i18n"
+import featureData from "~~/feat/feature-flags.json"
+
import type { MediaType, SupportedSearchType } from "~/constants/media"
import {
ALL_MEDIA,
@@ -226,6 +228,17 @@ export const preparePageForTests = async (
} else {
cookiesToSet.features = { fetch_sensitive: "off" }
}
+
+ // Split sessionFeatures from cookie features when setting the cookies
+ for (const [name, value] of Object.entries(cookiesToSet.features)) {
+ if (
+ featureData.features[name as keyof typeof featureData.features]
+ .storage === "session"
+ ) {
+ cookiesToSet.sessionFeatures = { [name]: value }
+ delete cookiesToSet.features[name]
+ }
+ }
await setCookies(page.context(), cookiesToSet)
}
diff --git a/frontend/test/playwright/visual-regression/components/content-report-form.spec.ts b/frontend/test/playwright/visual-regression/components/content-report-form.spec.ts
index 5cd3f463907..1728cf4d56a 100644
--- a/frontend/test/playwright/visual-regression/components/content-report-form.spec.ts
+++ b/frontend/test/playwright/visual-regression/components/content-report-form.spec.ts
@@ -13,7 +13,7 @@ const getReportButton = (page: Page) => {
}
/**
- * This test was previoiusly known to be flaky:
+ * This test was previously known to be flaky:
* https://github.com/WordPress/openverse/issues/2020
*
* The flake involved an offset of 1-2 pixels in both
@@ -34,6 +34,8 @@ test.describe("content report form", () => {
breakpoints.describeMd(({ expectSnapshot }) => {
test("unfocused close button", async ({ page }) => {
+ await page.route("**flickr**", (r) => r.abort())
+
await preparePageForTests(page, "md")
await page.goto(imageUrl)
diff --git a/frontend/test/tapes/stats-images-keep-alive.json5 b/frontend/test/tapes/stats-images-keep-alive.json5
index b0966e3a585..d2285bf4355 100644
--- a/frontend/test/tapes/stats-images-keep-alive.json5
+++ b/frontend/test/tapes/stats-images-keep-alive.json5
@@ -1,428 +1,431 @@
{
- meta: {
- createdAt: '2024-03-03T11:50:51.008Z',
- host: 'https://api.openverse.org',
- resHumanReadable: true,
- resUncompressed: true,
+ meta: {
+ createdAt: '2024-03-03T11:50:51.008Z',
+ host: 'https://api.openverse.org',
+ resHumanReadable: true,
+ resUncompressed: true,
+ },
+ req: {
+ headers: {
+ connection: 'keep-alive',
},
- req: {
- headers: {
- connection: 'keep-alive',
- },
- url: '/v1/images/stats/',
- method: 'GET',
- body: '',
- },
- res: {
- status: 200,
- headers: {
- date: [
- 'Sun, 03 Mar 2024 11:50:51 GMT',
- ],
- 'content-type': [
- 'application/json',
- ],
- 'transfer-encoding': [
- 'chunked',
- ],
- connection: [
- 'keep-alive',
- ],
- vary: [
- 'Accept-Encoding, Accept, Authorization, origin',
- ],
- allow: [
- 'GET, HEAD, OPTIONS',
- ],
- 'x-ratelimit-limit-anon_burst': [
- '20/min',
- ],
- 'x-ratelimit-available-anon_burst': [
- '19',
- ],
- 'x-ratelimit-limit-anon_sustained': [
- '200/day',
- ],
- 'x-ratelimit-available-anon_sustained': [
- '199',
- ],
- 'x-frame-options': [
- 'DENY',
- ],
- 'x-content-type-options': [
- 'nosniff',
- ],
- 'referrer-policy': [
- 'same-origin',
- ],
- 'cross-origin-opener-policy': [
- 'same-origin',
- ],
- 'x-request-id': [
- '23171f49a4a742629bb968bd6c1f022b',
- ],
- 'cache-control': [
- 'max-age=259200',
- ],
- 'cf-cache-status': [
- 'MISS',
- ],
- 'last-modified': [
- 'Sun, 03 Mar 2024 11:50:51 GMT',
- ],
- 'strict-transport-security': [
- 'max-age=15552000; includeSubDomains; preload',
- ],
- server: [
- 'cloudflare',
- ],
- 'cf-ray': [
- '85e9694b7aee6ae9-FRA',
- ],
- 'content-encoding': [
- 'br',
- ],
- 'alt-svc': [
- 'h3=":443"; ma=86400',
- ],
- },
- body: [
- {
- source_name: 'flickr',
- display_name: 'Flickr',
- source_url: 'https://www.flickr.com',
- logo_url: null,
- media_count: 468372073,
- },
- {
- source_name: 'wikimedia',
- display_name: 'Wikimedia Commons',
- source_url: 'https://commons.wikimedia.org',
- logo_url: null,
- media_count: 47823833,
- },
- {
- source_name: 'animaldiversity',
- display_name: 'Animal Diversity Web',
- source_url: 'https://animaldiversity.org',
- logo_url: null,
- media_count: 15554,
- },
- {
- source_name: 'bio_diversity',
- display_name: 'Biodiversity Heritage Library',
- source_url: 'https://www.biodiversitylibrary.org/',
- logo_url: null,
- media_count: 243596,
- },
- {
- source_name: 'brooklynmuseum',
- display_name: 'Brooklyn Museum',
- source_url: 'https://www.brooklynmuseum.org',
- logo_url: null,
- media_count: 63340,
- },
- {
- source_name: 'clevelandmuseum',
- display_name: 'Cleveland Museum of Art',
- source_url: 'http://www.clevelandart.org',
- logo_url: null,
- media_count: 34828,
- },
- {
- source_name: 'CAPL',
- display_name: 'Culturally Authentic Pictorial Lexicon',
- source_url: 'http://capl.washjeff.edu',
- logo_url: null,
- media_count: 15143,
- },
- {
- source_name: 'spacex',
- display_name: 'SpaceX',
- source_url: 'https://spacex.com',
- logo_url: null,
- media_count: 924,
- },
- {
- source_name: 'deviantart',
- display_name: 'DeviantArt',
- source_url: 'https://www.deviantart.com',
- logo_url: null,
- media_count: 238982,
- },
- {
- source_name: 'svgsilh',
- display_name: 'SVG Silh',
- source_url: 'https://svgsilh.com',
- logo_url: null,
- media_count: 358942,
- },
- {
- source_name: 'digitaltmuseum',
- display_name: 'Digitalt Museum',
- source_url: 'https://digitaltmuseum.no',
- logo_url: null,
- media_count: 289769,
- },
- {
- source_name: 'thingiverse',
- display_name: 'Thingiverse',
- source_url: 'https://www.thingiverse.com',
- logo_url: null,
- media_count: 32395,
- },
- {
- source_name: 'thorvaldsensmuseum',
- display_name: 'Thorvaldsens Museum',
- source_url: 'http://www.thorvaldsensmuseum.dk',
- logo_url: null,
- media_count: 5356,
- },
- {
- source_name: 'WoRMS',
- display_name: 'World Register of Marine Species',
- source_url: 'http://www.marinespecies.org',
- logo_url: null,
- media_count: 19783,
- },
- {
- source_name: 'smithsonian_air_and_space_museum',
- display_name: 'Smithsonian Institution: National Air and Space Museum',
- source_url: 'https://airandspace.si.edu',
- logo_url: null,
- media_count: 5109,
- },
- {
- source_name: 'smithsonian_american_art_museum',
- display_name: 'Smithsonian Institution: Smithsonian American Art Museum',
- source_url: 'https://americanart.si.edu/',
- logo_url: null,
- media_count: 11887,
- },
- {
- source_name: 'smithsonian_american_history_museum',
- display_name: 'Smithsonian Institution: National Museum of American History',
- source_url: 'https://americanhistory.si.edu/',
- logo_url: null,
- media_count: 2824,
- },
- {
- source_name: 'smithsonian_american_indian_museum',
- display_name: 'Smithsonian Institution: National Museum of the American Indian',
- source_url: 'https://americanindian.si.edu/',
- logo_url: null,
- media_count: 246,
- },
- {
- source_name: 'smithsonian_gardens',
- display_name: 'Smithsonian Institution: Smithsonian Gardens',
- source_url: 'https://gardens.si.edu/',
- logo_url: null,
- media_count: 689,
- },
- {
- source_name: 'smithsonian_anacostia_museum',
- display_name: 'Smithsonian Institution: Anacostia Community Museum',
- source_url: 'https://anacostia.si.edu/',
- logo_url: null,
- media_count: 571,
- },
- {
- source_name: 'nypl',
- display_name: 'New York Public Library',
- source_url: 'https://www.nypl.org',
- logo_url: null,
- media_count: 1275,
- },
- {
- source_name: 'floraon',
- display_name: 'Flora-On',
- source_url: 'https://flora-on.pt',
- logo_url: null,
- media_count: 55010,
- },
- {
- source_name: 'geographorguk',
- display_name: 'Geograph Britain and Ireland',
- source_url: 'https://www.geograph.org.uk',
- logo_url: null,
- media_count: 1090119,
- },
- {
- source_name: 'met',
- display_name: 'Metropolitan Museum of Art',
- source_url: 'https://www.metmuseum.org',
- logo_url: null,
- media_count: 243515,
- },
- {
- source_name: 'mccordmuseum',
- display_name: 'McCord Museum',
- source_url: 'http://www.musee-mccord.qc.ca/en',
- logo_url: null,
- media_count: 108815,
- },
- {
- source_name: 'museumsvictoria',
- display_name: 'Museums Victoria',
- source_url: 'https://museumsvictoria.com.au',
- logo_url: null,
- media_count: 149880,
- },
- {
- source_name: 'nasa',
- display_name: 'NASA',
- source_url: 'https://www.nasa.gov/',
- logo_url: null,
- media_count: 115600,
- },
- {
- source_name: 'phylopic',
- display_name: 'PhyloPic',
- source_url: 'http://phylopic.org',
- logo_url: null,
- media_count: 3892,
- },
- {
- source_name: 'rawpixel',
- display_name: 'Rawpixel',
- source_url: 'https://www.rawpixel.com',
- logo_url: null,
- media_count: 25831,
- },
- {
- source_name: 'rijksmuseum',
- display_name: 'Rijksmuseum',
- source_url: 'https://www.rijksmuseum.nl/en',
- logo_url: null,
- media_count: 29999,
- },
- {
- source_name: 'sciencemuseum',
- display_name: 'Science Museum – UK',
- source_url: 'https://www.sciencemuseum.org.uk',
- logo_url: null,
- media_count: 64542,
- },
- {
- source_name: 'sketchfab',
- display_name: 'Sketchfab',
- source_url: 'https://sketchfab.com',
- logo_url: null,
- media_count: 37872,
- },
- {
- source_name: 'smithsonian_libraries',
- display_name: 'Smithsonian Institution: Smithsonian Libraries',
- source_url: 'https://library.si.edu/',
- logo_url: null,
- media_count: 55,
- },
- {
- source_name: 'smithsonian_african_american_history_museum',
- display_name: 'Smithsonian Institution: National Museum of African American History and Culture',
- source_url: 'https://nmaahc.si.edu',
- logo_url: null,
- media_count: 7488,
- },
- {
- source_name: 'smithsonian_african_art_museum',
- display_name: 'Smithsonian Institution: National Museum of African Art',
- source_url: 'https://africa.si.edu/',
- logo_url: null,
- media_count: 135,
- },
- {
- source_name: 'smithsonian_national_museum_of_natural_history',
- display_name: 'Smithsonian Institution: National Museum of Natural History',
- source_url: 'https://naturalhistory.si.edu/',
- logo_url: null,
- media_count: 2796396,
- },
- {
- source_name: 'smithsonian_cooper_hewitt_museum',
- display_name: 'Smithsonian Institution: Cooper Hewitt, Smithsonian Design Museum',
- source_url: 'https://www.cooperhewitt.org',
- logo_url: null,
- media_count: 65694,
- },
- {
- source_name: 'smithsonian_freer_gallery_of_art',
- display_name: 'Smithsonian Institution: Freer Gallery of Art',
- source_url: 'https://asia.si.edu/',
- logo_url: null,
- media_count: 3878,
- },
- {
- source_name: 'smithsonian_hirshhorn_museum',
- display_name: 'Smithsonian Institution: Hirshhorn Museum and Sculpture Garden',
- source_url: 'https://hirshhorn.si.edu/',
- logo_url: null,
- media_count: 423,
- },
- {
- source_name: 'smithsonian_portrait_gallery',
- display_name: 'Smithsonian Institution: National Portrait Gallery',
- source_url: 'https://npg.si.edu/',
- logo_url: null,
- media_count: 13176,
- },
- {
- source_name: 'smithsonian_postal_museum',
- display_name: 'Smithsonian Institution: National Postal Museum',
- source_url: 'http://postalmuseum.si.edu/',
- logo_url: null,
- media_count: 2945,
- },
- {
- source_name: 'smithsonian_zoo_and_conservation',
- display_name: 'Smithsonian Institution: National Zoo',
- source_url: 'https://nationalzoo.si.edu/',
- logo_url: null,
- media_count: 462,
- },
- {
- source_name: 'smithsonian_institution_archives',
- display_name: 'Smithsonian Institution Archives',
- source_url: 'https://siarchives.si.edu/',
- logo_url: null,
- media_count: 6853,
- },
- {
- source_name: 'woc_tech',
- display_name: 'WOCinTech Chat',
- source_url: 'https://www.wocintechchat.com/',
- logo_url: null,
- media_count: 267,
- },
- {
- source_name: 'stocksnap',
- display_name: 'StockSnap.io',
- source_url: 'https://stocksnap.io',
- logo_url: null,
- media_count: 34321,
- },
- {
- source_name: 'wordpress',
- display_name: 'WP Photo Directory',
- source_url: 'https://wordpress.org/photos',
- logo_url: null,
- media_count: 154,
- },
- {
- source_name: 'inaturalist',
- display_name: 'iNaturalist',
- source_url: 'https://inaturalist.org',
- logo_url: null,
- media_count: 158267579,
- },
- {
- source_name: 'nappy',
- display_name: 'Nappy',
- source_url: 'https://nappy.co',
- logo_url: null,
- media_count: 2211,
- },
- ],
+ url: '/v1/images/stats/',
+ method: 'GET',
+ body: '',
+ },
+ res: {
+ status: 200,
+ headers: {
+ date: [
+ 'Sun, 03 Mar 2024 11:50:51 GMT',
+ ],
+ 'content-type': [
+ 'application/json',
+ ],
+ 'transfer-encoding': [
+ 'chunked',
+ ],
+ connection: [
+ 'keep-alive',
+ ],
+ vary: [
+ 'Accept-Encoding, Accept, Authorization, origin',
+ ],
+ allow: [
+ 'GET, HEAD, OPTIONS',
+ ],
+ 'x-ratelimit-limit-anon_burst': [
+ '20/min',
+ ],
+ 'x-ratelimit-available-anon_burst': [
+ '19',
+ ],
+ 'x-ratelimit-limit-anon_sustained': [
+ '200/day',
+ ],
+ 'x-ratelimit-available-anon_sustained': [
+ '199',
+ ],
+ 'x-frame-options': [
+ 'DENY',
+ ],
+ 'x-content-type-options': [
+ 'nosniff',
+ ],
+ 'referrer-policy': [
+ 'same-origin',
+ ],
+ 'cross-origin-opener-policy': [
+ 'same-origin',
+ ],
+ 'x-request-id': [
+ '23171f49a4a742629bb968bd6c1f022b',
+ ],
+ 'cache-control': [
+ 'max-age=259200',
+ ],
+ 'cf-cache-status': [
+ 'MISS',
+ ],
+ 'last-modified': [
+ 'Sun, 03 Mar 2024 11:50:51 GMT',
+ ],
+ 'strict-transport-security': [
+ 'max-age=15552000; includeSubDomains; preload',
+ ],
+ server: [
+ 'cloudflare',
+ ],
+ 'cf-ray': [
+ '85e9694b7aee6ae9-FRA',
+ ],
+ 'content-encoding': [
+ 'br',
+ ],
+ 'alt-svc': [
+ 'h3=":443"; ma=86400',
+ ],
+ 'access-control-allow-origin': [
+ '*',
+ ]
},
+ body: [
+ {
+ source_name: 'flickr',
+ display_name: 'Flickr',
+ source_url: 'https://www.flickr.com',
+ logo_url: null,
+ media_count: 468372073,
+ },
+ {
+ source_name: 'wikimedia',
+ display_name: 'Wikimedia Commons',
+ source_url: 'https://commons.wikimedia.org',
+ logo_url: null,
+ media_count: 47823833,
+ },
+ {
+ source_name: 'animaldiversity',
+ display_name: 'Animal Diversity Web',
+ source_url: 'https://animaldiversity.org',
+ logo_url: null,
+ media_count: 15554,
+ },
+ {
+ source_name: 'bio_diversity',
+ display_name: 'Biodiversity Heritage Library',
+ source_url: 'https://www.biodiversitylibrary.org/',
+ logo_url: null,
+ media_count: 243596,
+ },
+ {
+ source_name: 'brooklynmuseum',
+ display_name: 'Brooklyn Museum',
+ source_url: 'https://www.brooklynmuseum.org',
+ logo_url: null,
+ media_count: 63340,
+ },
+ {
+ source_name: 'clevelandmuseum',
+ display_name: 'Cleveland Museum of Art',
+ source_url: 'http://www.clevelandart.org',
+ logo_url: null,
+ media_count: 34828,
+ },
+ {
+ source_name: 'CAPL',
+ display_name: 'Culturally Authentic Pictorial Lexicon',
+ source_url: 'http://capl.washjeff.edu',
+ logo_url: null,
+ media_count: 15143,
+ },
+ {
+ source_name: 'spacex',
+ display_name: 'SpaceX',
+ source_url: 'https://spacex.com',
+ logo_url: null,
+ media_count: 924,
+ },
+ {
+ source_name: 'deviantart',
+ display_name: 'DeviantArt',
+ source_url: 'https://www.deviantart.com',
+ logo_url: null,
+ media_count: 238982,
+ },
+ {
+ source_name: 'svgsilh',
+ display_name: 'SVG Silh',
+ source_url: 'https://svgsilh.com',
+ logo_url: null,
+ media_count: 358942,
+ },
+ {
+ source_name: 'digitaltmuseum',
+ display_name: 'Digitalt Museum',
+ source_url: 'https://digitaltmuseum.no',
+ logo_url: null,
+ media_count: 289769,
+ },
+ {
+ source_name: 'thingiverse',
+ display_name: 'Thingiverse',
+ source_url: 'https://www.thingiverse.com',
+ logo_url: null,
+ media_count: 32395,
+ },
+ {
+ source_name: 'thorvaldsensmuseum',
+ display_name: 'Thorvaldsens Museum',
+ source_url: 'http://www.thorvaldsensmuseum.dk',
+ logo_url: null,
+ media_count: 5356,
+ },
+ {
+ source_name: 'WoRMS',
+ display_name: 'World Register of Marine Species',
+ source_url: 'http://www.marinespecies.org',
+ logo_url: null,
+ media_count: 19783,
+ },
+ {
+ source_name: 'smithsonian_air_and_space_museum',
+ display_name: 'Smithsonian Institution: National Air and Space Museum',
+ source_url: 'https://airandspace.si.edu',
+ logo_url: null,
+ media_count: 5109,
+ },
+ {
+ source_name: 'smithsonian_american_art_museum',
+ display_name: 'Smithsonian Institution: Smithsonian American Art Museum',
+ source_url: 'https://americanart.si.edu/',
+ logo_url: null,
+ media_count: 11887,
+ },
+ {
+ source_name: 'smithsonian_american_history_museum',
+ display_name: 'Smithsonian Institution: National Museum of American History',
+ source_url: 'https://americanhistory.si.edu/',
+ logo_url: null,
+ media_count: 2824,
+ },
+ {
+ source_name: 'smithsonian_american_indian_museum',
+ display_name: 'Smithsonian Institution: National Museum of the American Indian',
+ source_url: 'https://americanindian.si.edu/',
+ logo_url: null,
+ media_count: 246,
+ },
+ {
+ source_name: 'smithsonian_gardens',
+ display_name: 'Smithsonian Institution: Smithsonian Gardens',
+ source_url: 'https://gardens.si.edu/',
+ logo_url: null,
+ media_count: 689,
+ },
+ {
+ source_name: 'smithsonian_anacostia_museum',
+ display_name: 'Smithsonian Institution: Anacostia Community Museum',
+ source_url: 'https://anacostia.si.edu/',
+ logo_url: null,
+ media_count: 571,
+ },
+ {
+ source_name: 'nypl',
+ display_name: 'New York Public Library',
+ source_url: 'https://www.nypl.org',
+ logo_url: null,
+ media_count: 1275,
+ },
+ {
+ source_name: 'floraon',
+ display_name: 'Flora-On',
+ source_url: 'https://flora-on.pt',
+ logo_url: null,
+ media_count: 55010,
+ },
+ {
+ source_name: 'geographorguk',
+ display_name: 'Geograph Britain and Ireland',
+ source_url: 'https://www.geograph.org.uk',
+ logo_url: null,
+ media_count: 1090119,
+ },
+ {
+ source_name: 'met',
+ display_name: 'Metropolitan Museum of Art',
+ source_url: 'https://www.metmuseum.org',
+ logo_url: null,
+ media_count: 243515,
+ },
+ {
+ source_name: 'mccordmuseum',
+ display_name: 'McCord Museum',
+ source_url: 'http://www.musee-mccord.qc.ca/en',
+ logo_url: null,
+ media_count: 108815,
+ },
+ {
+ source_name: 'museumsvictoria',
+ display_name: 'Museums Victoria',
+ source_url: 'https://museumsvictoria.com.au',
+ logo_url: null,
+ media_count: 149880,
+ },
+ {
+ source_name: 'nasa',
+ display_name: 'NASA',
+ source_url: 'https://www.nasa.gov/',
+ logo_url: null,
+ media_count: 115600,
+ },
+ {
+ source_name: 'phylopic',
+ display_name: 'PhyloPic',
+ source_url: 'http://phylopic.org',
+ logo_url: null,
+ media_count: 3892,
+ },
+ {
+ source_name: 'rawpixel',
+ display_name: 'Rawpixel',
+ source_url: 'https://www.rawpixel.com',
+ logo_url: null,
+ media_count: 25831,
+ },
+ {
+ source_name: 'rijksmuseum',
+ display_name: 'Rijksmuseum',
+ source_url: 'https://www.rijksmuseum.nl/en',
+ logo_url: null,
+ media_count: 29999,
+ },
+ {
+ source_name: 'sciencemuseum',
+ display_name: 'Science Museum – UK',
+ source_url: 'https://www.sciencemuseum.org.uk',
+ logo_url: null,
+ media_count: 64542,
+ },
+ {
+ source_name: 'sketchfab',
+ display_name: 'Sketchfab',
+ source_url: 'https://sketchfab.com',
+ logo_url: null,
+ media_count: 37872,
+ },
+ {
+ source_name: 'smithsonian_libraries',
+ display_name: 'Smithsonian Institution: Smithsonian Libraries',
+ source_url: 'https://library.si.edu/',
+ logo_url: null,
+ media_count: 55,
+ },
+ {
+ source_name: 'smithsonian_african_american_history_museum',
+ display_name: 'Smithsonian Institution: National Museum of African American History and Culture',
+ source_url: 'https://nmaahc.si.edu',
+ logo_url: null,
+ media_count: 7488,
+ },
+ {
+ source_name: 'smithsonian_african_art_museum',
+ display_name: 'Smithsonian Institution: National Museum of African Art',
+ source_url: 'https://africa.si.edu/',
+ logo_url: null,
+ media_count: 135,
+ },
+ {
+ source_name: 'smithsonian_national_museum_of_natural_history',
+ display_name: 'Smithsonian Institution: National Museum of Natural History',
+ source_url: 'https://naturalhistory.si.edu/',
+ logo_url: null,
+ media_count: 2796396,
+ },
+ {
+ source_name: 'smithsonian_cooper_hewitt_museum',
+ display_name: 'Smithsonian Institution: Cooper Hewitt, Smithsonian Design Museum',
+ source_url: 'https://www.cooperhewitt.org',
+ logo_url: null,
+ media_count: 65694,
+ },
+ {
+ source_name: 'smithsonian_freer_gallery_of_art',
+ display_name: 'Smithsonian Institution: Freer Gallery of Art',
+ source_url: 'https://asia.si.edu/',
+ logo_url: null,
+ media_count: 3878,
+ },
+ {
+ source_name: 'smithsonian_hirshhorn_museum',
+ display_name: 'Smithsonian Institution: Hirshhorn Museum and Sculpture Garden',
+ source_url: 'https://hirshhorn.si.edu/',
+ logo_url: null,
+ media_count: 423,
+ },
+ {
+ source_name: 'smithsonian_portrait_gallery',
+ display_name: 'Smithsonian Institution: National Portrait Gallery',
+ source_url: 'https://npg.si.edu/',
+ logo_url: null,
+ media_count: 13176,
+ },
+ {
+ source_name: 'smithsonian_postal_museum',
+ display_name: 'Smithsonian Institution: National Postal Museum',
+ source_url: 'http://postalmuseum.si.edu/',
+ logo_url: null,
+ media_count: 2945,
+ },
+ {
+ source_name: 'smithsonian_zoo_and_conservation',
+ display_name: 'Smithsonian Institution: National Zoo',
+ source_url: 'https://nationalzoo.si.edu/',
+ logo_url: null,
+ media_count: 462,
+ },
+ {
+ source_name: 'smithsonian_institution_archives',
+ display_name: 'Smithsonian Institution Archives',
+ source_url: 'https://siarchives.si.edu/',
+ logo_url: null,
+ media_count: 6853,
+ },
+ {
+ source_name: 'woc_tech',
+ display_name: 'WOCinTech Chat',
+ source_url: 'https://www.wocintechchat.com/',
+ logo_url: null,
+ media_count: 267,
+ },
+ {
+ source_name: 'stocksnap',
+ display_name: 'StockSnap.io',
+ source_url: 'https://stocksnap.io',
+ logo_url: null,
+ media_count: 34321,
+ },
+ {
+ source_name: 'wordpress',
+ display_name: 'WP Photo Directory',
+ source_url: 'https://wordpress.org/photos',
+ logo_url: null,
+ media_count: 154,
+ },
+ {
+ source_name: 'inaturalist',
+ display_name: 'iNaturalist',
+ source_url: 'https://inaturalist.org',
+ logo_url: null,
+ media_count: 158267579,
+ },
+ {
+ source_name: 'nappy',
+ display_name: 'Nappy',
+ source_url: 'https://nappy.co',
+ logo_url: null,
+ media_count: 2211,
+ },
+ ],
+ },
}
diff --git a/frontend/test/tapes/thumb/images/feb91b13-422d-46fa-8ef4-cbf1e6ddee9b_keep-alive.json5 b/frontend/test/tapes/thumb/images/feb91b13-422d-46fa-8ef4-cbf1e6ddee9b_keep-alive.json5
new file mode 100644
index 00000000000..aae34bd365e
--- /dev/null
+++ b/frontend/test/tapes/thumb/images/feb91b13-422d-46fa-8ef4-cbf1e6ddee9b_keep-alive.json5
@@ -0,0 +1,74 @@
+{
+ meta: {
+ createdAt: '2024-05-03T03:38:53.028Z',
+ host: 'https://api.openverse.org',
+ },
+ req: {
+ headers: {
+ connection: 'keep-alive',
+ },
+ url: '/v1/images/feb91b13-422d-46fa-8ef4-cbf1e6ddee9b/thumb/',
+ method: 'GET',
+ body: '',
+ },
+ res: {
+ status: 200,
+ headers: {
+ date: [
+ 'Fri, 03 May 2024 03:38:53 GMT',
+ ],
+ 'content-type': [
+ 'image/webp',
+ ],
+ 'content-length': [
+ '15208',
+ ],
+ connection: [
+ 'keep-alive',
+ ],
+ vary: [
+ 'Accept, Authorization, origin, Accept-Encoding',
+ ],
+ allow: [
+ 'GET, HEAD, OPTIONS',
+ ],
+ 'x-ratelimit-limit-anon_thumbnail': [
+ '1000/day',
+ ],
+ 'x-ratelimit-available-anon_thumbnail': [
+ '999',
+ ],
+ 'x-frame-options': [
+ 'DENY',
+ ],
+ 'x-content-type-options': [
+ 'nosniff',
+ ],
+ 'referrer-policy': [
+ 'same-origin',
+ ],
+ 'cross-origin-opener-policy': [
+ 'same-origin',
+ ],
+ 'x-request-id': [
+ 'db17975e97c2434b80737d31b97e0ba6',
+ ],
+ 'cf-cache-status': [
+ 'MISS',
+ ],
+ 'last-modified': [
+ 'Fri, 03 May 2024 03:38:53 GMT',
+ ],
+ 'accept-ranges': [
+ 'bytes',
+ ],
+ server: [
+ 'cloudflare',
+ ],
+ 'cf-ray': [
+ '87dd38845dd571c5-FRA',
+ ],
+ },
+ body: 'UklGRmA7AABXRUJQVlA4IFQ7AADQlQGdASpYApABPm00lUikIqSwI/Kq2gANiWduSQM6wVsBOd+ZM+KdWNOdInR/2nhCHf8LsPrarckvtUaNdv+F7HmgD2thQSf8KW04umi/c/oC9SMitcjXI5H3m/lR430I7QXoj0CvsFliPD+BDUR6ZfpGk87ve/vVn31pV4Gyg4SRcK56oYaqqRJDymNhBcTVVxfsOBOta/puFcPhYiF8FzwoEX3T3ODWbAo2unTJ5mwRLPzyZjoa4uH/1/reago94UvlKFN2OQG0ClDxnNvfVABYVVZ7KhPMQ1wx94JWdRRFCVHPC71naSCXfJwc+2DSGpV3uOkQGHt6v0GrWHXDy0CorVcfvNhu9YpcG91l5830R0fY3CojEeUeu2DxokVHiA2sDFIAHwF545BElFcZwb5/ixwt7ehaz9T9JoaIbM+qqHrqXfbilVRoQTtxHLn5qQOOYNHtTiTvCdl8WfizTcprDUEaGcIVBxaf0TXpyau/jW7/ZTsoM2vhKWifaYj1AT+bZ/yRzmKgw8Pr8JEs/uYQZ8FOygDVB/vtrdKB//zd3nVvH53pAbkwWrqsi9tDZhb4D63lOv7jxVOZs6qjtEpxh8hBTv87su1NvMJaT1cVFgCTgUgcWnkj4S9NxdM2TdZo1aeR33DzBrXhe4LMiud8LadyrxgUBk7LiJyij/agkk4g7OnnEDB4VQ6U9f3mS+4DPZJIUerJubtkKKX4y1DMofLvrb0NfzfODBY+e9I/vAidwdou46H1/GHFV2ygZfp5nBKtR50cTGVFhGGzCJ7ns/UPJgTOloyfAjduKjMeSwgoWAvnJBlTOETQqMSY78Jz0cKM28sSj+Pg1hxLPCOaXtnthbsXmzXnDJ6eTBDlg69mfVchd+mTulvXcCqxc5FcOwR3LH7NXzov0oyKX7YDGpKRslZZfWIPL1GxP8hfGuJi1EuK9or5WbwQ2X6sQNy5RgNe9/cwRSrKbJ34GDb5fWPopJ24XjmYXkFepSsHRK3ieytp+O37wRVPSPj4cRqqHqSX5z1AJNDHRXm6/vqkLxB61H60eXxPSxeqopHd9OLqHXHtk+VW8zvIa+CPGsegjzE5WpkccMy77L/OoLFsXRLRrOPparhkfpfgogvfi7pu447GkTUWrhuJk9kl0vgTMgAiSXrYZr9t+Ed2zh36cIwtP3F8C0OmXTRBDHkU/uPLMBkj8y+o2AIw9wzToLmSJnf7977c1jmMGBu398z5OGUbWfCkLTEEq53in/g+XEjT3yGKezKcujO4SeJ712PLUQtNaKt+uusXHKw8WEweV5/zebrGg36eCsCXbKjcxiqAKqoVOBvXf72zVyPXomjePcJelNoA4vYycznV8pKZZVgdsX+RjF25fAISHVjsQPQsIZMQJUzsnhJvJTDB67hWqpOly4pXWCxuWT+Jb0g+KQK7Fn6OU4ou4WeLuEfA5+UQD5nsur49hEnba/7IbzeCOvIwvpjuAWUvrXj0GJEzgwd+vvmD6FkK2x2sWB7qEXFLiJDpi0yfUi1oY3YDf56A9w2gym2tv++EpFwI7+EDMjowzwKdAqCSaDPFLMkvOdCP4EFLywRzDfPKEFobZGV6qh5m2ykEeuSY7CsMTBZK+qyZ4NJ+RbIK7NsRDgJrfJDg2E0RGhx42Ykt0JNGuK0tGbX34l1xBMbIGxPb8d7Y9Zwf2dKMOGDUBKM+S05gxuzEXna9yok3CyECeMUc7ynRn9PBrwvrDzyywcc/D2/61laQEMvnmnAmbP9bJ9aVBmf1+SdZ2sKwabPGtwitmnz3zhHc+MGBhAzY62cYYiAKp7LYwTS8qrPmMFnHlXSgO376+cB17OGmJLJQY8Vjy5nBMOhhBgduNMAxIhevSLcR6us3DqzGFwelEIf/78yYypvvzZ9xXRauMUWi+AIKKwoEQDAHBb2eYfsg99IzxzfgpPxUKgT4LZvyy6iKw3x7ja3VGck3kdPfIOhhEeITy6Arx5mTlPCVahJQS2P11RawsoXC6ScTixPza7m3NJ0lKhuqlKbP0qQ+rvxQ0d0GT2Ppp5MdTXMCdQVOV05oRK+/ALzASBcM63vUm7+bQhbwfbE3d5famgkJ/Tv814Y9PMlpUgN88YsvwXmb884FA0Fb+0MMhMDcThtJSikv9JR5ZPYvaSu/rEsByEIbNd6bn/dvIM5VzZRgB2trYn8ScCp2kG+6TMZdQGnun+NzzlLM9PBFFJMmYrT6mUWo1+m8IaGxOJHENiFCgybeqTYmBP7bGJeJNxdZRqAB32tB9jDIhIqaqNSnbv/2EhgBzxbcCTB5dBwpdGV3YF+SuG+JaGCkwvBPa2bIHxPYakkT3KXYeJNDvBAWb5wZK9njG96nyHx/fOSyV3vje35oPqL6Rin1xXc07VuDs/Y5b2VrbqTIy7iscnPGd3+lBOvz46y6bmOYui6l/kSn3YMGkHcSCo/29uYti69tel8GbEOloSo+6op9hBRsz5da6f/sH6//6/iIhRbzaqR7zBP6SD42im5PByRJNmcJf9lMeiXypvu4GZTZ1bH9dsIdxlcLf3UaMwA0SZhj96qp3+Y7O2osIdFu/XO30i00yhUNE/d/qnP/FaGq9U+ozf1yDaJRxLMS0uJIMYOefZhiGAIbeS8fKvVht8/w0j9CmiEMkMiCW/m+3hY7Zd++eoyqi15j9y96Oj5qIqI+wHxwvdopR9Wpd8y//1qgiSv+TLErAc62BXIxCI4L3jg+K7A3duv2LCVL6bbYnEqX66cdJMUlARLvkDtlXzxsBYUg9p7OM8q3YFwmobyMGDypJ1zEaT2+GFoGDnYsgRmF5Ug+L2jcjY1ZJiuqaIfyPSHeGcseJiPG6xdeuLO7fnm8LAp9Kq/E/KDm2ShJbErCTlr2clT6JZORfwXRcG6K2GLatY1aBl9LYw/60n+o2VdZtGOwx+TrvYJbW6ddi6gfsYiTrg3V3fVYvDXk7+J7U7w07qw1V+NU6EcN41SNA/Xd3HU9AA3D6AlNXNZXX1EIn55iwPaqDS8TF2JuFAd09ZICD+Yw2xacjalMNBhpXeniw/8u+ke1I5MjgRgH0T76Bjc61Bfa0x0V/ZzKRy08KtVqZxX68TmJr/lCzKtBd+OLW3L1G5gTeU8zq6TDy7di/nB9Mj1Pu3n/DrimRNScUbmW/wVtiEERc69WecrFfNoJAkAEJ/QflMIvpiq9VjPCVsTprE9LwotW1zLaz9QnWfJqm5SiPVJjocdeuRebYPGyjcQv/FwQJxlC1XI5SivUt3Xdv5MU3jMtCfiHUNAwVNiUu9b8zQwJcFYUJpEP6b2O5sQUzevgjpKpBJzNSlKNxYc2ihG7DUBoqLeIxRmkJRJnJ2l7lH5/aaoz8JmDpeWrBBAYaf3wHfcALqtilKP9esOyJsC/y71qLvVBOMhA622f6lsyPOBD6779cJW/8jR1ibLC4XyiRapPmt5cV6N+4xdMudvBPxtM5z1H7ZXXdoBQNdheBIRrELMtCXwuXe6ZCWe+SNqbEZdHGVwFPGUHXvZBqTKEcCDu0BUh8lXlADMowWQiCLae77rtAJeGNs7LSYFvvKtaaCOzeuTyLSS+JlKT7l6LJXxumovnNuGMdjGoAtMg6paXMv+qxRhrnJaF9pmO0N5MHr0CVjaBHpo5vYLJbasWXNpEW1tX6zud9SvjVcxi43GSzdqwslUobrBpLxgO6AIhFBaM8to3fl43v9vdscbOzZLNk27mphzUEnA/CRwSfSjpymjJRIrq6r23NOTV0N5288ZFkZfIfHQSL/xlYtIA22xEXhc8Xsz4+JlFbEno7/BVroiaI73xpV8oe6Uf2MxkHgY1bMZmSmotwZQkBSmaW/owWlLT9C0EWMR9KCuUejAZ5Fy8BWpsYPL37sqwkBotiAePR9UoGP2Ke/F4R74+38YJubA/m60JypZc2ocahhZKR4KuwaxXmv/tQJEOR2WcqQ6kYMKyftvAtM0D28DpbI/oMsFlrYIpVALYCr2oc1Oaa0Zk2UskvLfRRslGILKqegB5brQ90A0pKBGtJkwsTb7ObOtc8GymhF0HXo9mMC8JfKXYOEimaacCHa7RgbngBJjefzCase+xZBoQnm2JIMLxnUyXD1kBjmwEwlkI8QUl3yPju+T9k/Hqm0fs2fxynk0xkaEYlAc/EU5EC0qwaS3qTuB4ueBAjeYfCS5dNtEtp/JSxBKojW1DUqSD/re6HNL59AdMZOhX4Pfv4jFX4iqa4mGBNlVzw1/lqGfx+5ZcRtxMAJYoO9gIJr0u9lIW+Lv1RvNYlhpqbSDD8q7YppheJao8cJ7no3U7JBWoRHGM33a26eCO+oAA/uufLT+cOUOJ/L+bdLa+cCcyhcSuWinhcc+PNGdbJrX/XXT6yHj+dYDLzm5YI0Su4/dYQ7VsWWH0PomiR4TlpjpKL4xpxjEPxFBU4IUJtXS+ggA8QwJAAMDBhNpnbEfRVTAvLkgUHu66Czek7RO78q9eF4J29/V4QIbC2f1TTMcKKn3DIv8MCnSe2GUEQXWSsxnrGsFJEz5YE/AIGvcTuM+OQCWRMg5RgX/jwTQ8bxC/hYeOB+be3jXS5h9oAEqwcrcuKnSKP8hoilbIIiwQ2XXI9qNb9TwD1jbOH0CVr2GztKOslX/ZwwWMq+XeVWL+6h40gCaolNXwPtIWfwDdiQJNbp5W0GQnpkg6Q2jeUd84HwZ+I4XTQhximfSJwBcCHvCO2c+yRGIJubfdCzoaoDBiMZ5uuLB+iwhNgfswxg0WT/pBRiuH25+PIZU4UKJDNbSbg6TK81WkozNYIrbvA0xK+QBGfODhgX+66ZfEQuPZkvuflNU8Wp2+YSjB+RyS1oYCasCHXslYpq1rPkbTPBvAZgnVRUkYHyBM62gtUlTZXtVs4hrK1I4DnuVldjIyjAT+61r+orx0zs9N9OVs+zNiJGafmGnAxkqjX44Tzuq1M6i1cePHJdKz2SmE4iAgouE/WKYuIRs5SEPThwnSu90vmEEn9A82HA3rIJ13L4ZKy4GWmK7RmbtXtRCqodONIY562L6hJx/bP0UVYRk4agwO4JYfmv1xYxEe02NB+yTPDPSAgQkS4WqXx9tY6kfMrkp5NkRDRA/xB71lb3wB2An/Bm3JxcCP9p9GsGkruJemfLs6i35gUHXhPEq6TYr3lNCx3NRgEsd0awujsTH3/+B5YMN6GL9CJ+IuSehmq+NusQSnHDCqnlVFSGF/t1Lx5e3ik/xuoajU30BoROYnzSrv1uPN2TYVVA752bx5qhPRSBrB4tQX+mGC3E2ID/z/o9FlnPweyr6kp+S50X14kwVs4vN9yCqVAgBvAv2Nuekkt9iyIlIXLcexXHWYJU75K+RZYbnnS9rwe+/dChrcZaKjC/ScHqnZpH+2rap0r8ZNWXZd2DWCbMAaAR5gu4+vsqYh+Fte4MrSLd+Ip6KKvTriaJ9yARCAWvhRi1HSFObZ3OKjrMm4jWgaFg8gMdLIetT2IKrXgYKaeC9ucoic8arJXAsiAX6OjVi/f1S+UBHGCv3oBTJAWmq5ae0Ac3werfjP2JMStO0SD6p1egCMcErpAn1EEAMrpm8ELNsbkuDP7rhPUw6DK71YFPFugfp3FqPfL3JRCxl+RK1GlmgiJgBAZjW/WVJGndjNjYIjBlm264T4hpYQm2tfYVJggsS3XFT2CqriTpSTIJoFlqhzfSaF3SXS9zlt64nsZgM26R9hvmURpGsCWd91NtkLqFSvlvq4CPMVLroojXKG6v7kWu15Y590xKcowFHvfOXi2eVMpVqoNinFQrcn0wCTIHldhV1m+RjI0fuQoOglpUKywIJ1J0CmYyUhvXizkezHSMRswwl8pm5j4TJMF2WD8YR5KTpW2fwTcZhQW6PAA/W0es6tkIcz7R4195s51uwcJhRZHC6ZwBQ567yYP0RJ+5urQ5L1ngjDRhad6E9EBtpvE46i0iAH8eXoZ+uiRZzy91kGgwlv6cRF8EI9yIfSTRlk6usBJYt2tEGKC5AifiUaEK3TGPwlmRxWKZ09ifIKLTdg2lIMgsFSsLcMnBNTZDUFfOUamYfeRCHfUTRwxCn9i92rNy3jpqiitONVW74IiC2he6VB7NYqj8zNIpcss9crCuDspOjU221S8AxYOMJwsJk/ZCGBiyj1bN7QUd2Z8PAMtscLRlRJLQGk6BIOgA+v5WHbOiT3crHqv6WuncZL32yl6OoxC34/EZKnWzCR/aOc2YXmL+sBC/m1nH+aCoosoaebqG+7stRBiG2YcG9Gu2uaDPEe3S1P3qpFiWCeROmF+JmtYC+YG+m8xcJN9+8DgsYu5PWXPG8DBhioggNHydj479FJZwosTvIW87+GjD8g9cEtEakHR+//w8gijysq1zu66ZmgJCK2imhAy6banbNM6ms93FDTX+iHsa9RnpPsfw4pH9sWe2VYGIIb56n+PX5Cw582kCgkl3Zh7QXLtWpzOMNGj8PIJ64kCSZle+BZS614VZ1ratco+IbthnNvrbb3xAoLXA+qth/+WoISSU92oz2zH9LsHqkjmNOBFr9S1+32S11YpddyycTCrlNREdOwrRruNLlRgptKv+mYDtmh0Mt7jOsLzuftlXzh8X+n1o/KXaAVTeXIAMvlIR8VnbEIRfzp0ZH5LJVSLB3yX4wIO/SAetv4bH8255XtZ3Wqtji+GxWpvVr31k0m44VuEpH+3bhesuSK7zwQA6ndhwOBf8aVTKHFwbhBBpMS8zqPcsTtqM7eRwT874UjlIPMFNYfuA9lMAaWp72lccBtdHqOP422/bd+N9IT5jGuq8BQOO7WAYs3RXhtHZ5SDG4smJqO7/ikc8l4LhGEesOiu7gFjBSyO4C10Ys9KWPK8Bxj2glJQkGhWdelxzVM9wgAbDmJqUcPh37pVHKRsmxPklDClAUy9FUZPGH1RFfZCP9WalrODvb7s49Hy0slaqbCjHP9iFBnEyh0swpsU1mhEb/1oPYmA9xpyIOgnlGWKxjfY5uc1AFqHP3gBvyHQ9Hh5mZ2MUm6w95bn77d9hXoo5mhErFZbAwo/uLMe6GK4zLtoDISlLjp1ouSrWPFx/XWULg3ZMwTXbOPM/FY944UlKfMpe/u73bNea1Gs+wR8z067U41ClfcMp1Fz3/xoMqX9D0y5TpvFtpq5YKQpvqiuM0O6AmAI3d6tyArlpFwkGlsge+KSpdAm3AghBZ+jmEgno1QmMvoxT5uzMaqX4VzeH92dVROXxbDKIdKeHIC87jauOUeVdGh6Vrrm7+d56MZron5IE+ypWTDfgwEozaTMkPf5vD4Fx0Qc7EaqchnJ8lN57wEYHHHVx27+JIZcI4qz+3g6/u0w6keSYvI+oO2hNZ7lEAXGFvxzLNaPEDpOf9siuhn8SlCXN/c/OfUPeGNpTXYkBQqov87kP1zRqqXBlADFMEWLs/sij/peQmIRLpZydpv4BZVQfC2nc54fgVqgKAxZfR95ZMLCtM8klVFs+lKO6Q7DzAmU+NJzJn0x5+NN9bEmPTU6j2oerTDyO/zZC+EPoOeJycY1N+x2O9YR7xJpB4o2WBYjRdVu06fRrxSFYBkqD/HfuKSUvElXdanlz0paTtTCBess2Zd8IHqMSiflXg42fHtPawICpRqB/hou7kffdq2XWBP+KGGX8/C4Czmp5spSyu0n/Q8HiMyelYZ506lcqi54dQPo1HWuQrQQC6pM3h9tQ2/mN+HbdnVwl4u+iZabjCJ1BsFE5LN+OUFlZqV9XCp7LnFXwi9c4xjZKL9/tCJ0t3MxdTxuSFDFnCM0UwMk882GzwyhOPrqFuLnRZgpGjKqKENouqpi5zKQOLBd+5D/MVYaXkL92LywVQkPJPtOdd0sISOFJIhhO35vOPTe5Wml1dFwU2LJ4A0QMYJ5mewdM+JzXi9ui6PU0CHRMOYeAY189Y6pzdAEWlInL6wfNfyKJM2HxeMQZN7QG0jM8U6hAqjet0+xI0hwQaBLhHAxiVfdcm9OOamThXAoCJurzMjNhX/8Va9RIcw8B4A/9/hvkgEV8WPaF46dfEijQ2IoP6l/wysP9zqjT2WzPklAGyNF8p68aptwWusVc/87FWQDEp6jXvLkGq3EV7EcIP/bB3u5TLwO1xj/jtvsAardpxNQHG43LbUAuNxuE5DtJZF8J8MRZXmFjQ2PZOBNkVzpt1x09II4tIPYMt3UIO+bXqYJ3muMVBFcKW4Lzeunr4yxq7NSlXR63FRpJFOInBjXRSGURArFEp1sEZwIyX37G/TSXuKIryhC+cB+xEs6xPzRzuZ4rBpcKlV4rTTdceoZBnuk3RY0tTnSxDTSQuloco1hAIWvmkJqa/BtpAevzkjBp3ONk5ZMDOulmux+kOaS6iizJNImK8cFRqyg3WXWKbQff7IHIRyPi0Trg8OTXc/VjMVXD2koZ/L5Mx/f10PKeKY1P5UBZaqvTjNobCPV5VvtTfuyAuJIJzVPWzzqjUNrFCn7xKXvbfL/8Pyk9BVeyptnBRG8HLiphByMHduO+AjeJNgUI0BtIbsHQJPTaKPEVd/AKfxWAH1R4y7cfIsGAb+AF7cWIxeSVsrskZNANosbH7AwOvhNp89phlZXIvqOGdU/OBwob7/jBm8w1my82F4Qbbw/OVtz/OHIuELg2GpT/zWXFxy2lVEXcWqdXrD4BanJgGJBv7b2hzkTOVmiUj9IPwofBVYiqbyl+vttVBroJNxU3ih67CAe9YbjF2py9s3BBRvCEKlVxq0esrFGWj6bdL87AKqINSOZtDWnrEVlrmXSx6oRXVr+0/+zJZ2Ok9ajuyqJoPkZKl0gZSN/FstEoOywM6lLynL+/hL7pkrNYxVK2TumOtM61mMI68NFOe4yvsFZ2yqogflZP/C1Pd9aiHjLNpO4hNmADIkvT2s8cgJNjV2vPCYEYKAA5f0ClcXQ/SjS8bm6/KMsenXdWXKuFHbvozLLUuKCJPNE160zUhBXhCPBZe8KE2t8vWN/7C4rb6oa/qzfevBvdVV2W/nkn/7P6rn4On9+WrrqdHoqPWoaP5XdObqQn7WnEeYm6d9PNfVvoMiiM86zChvUGVqRKZqeSih2UPpE06wYgn4EETt0et18hp7xq9pfLTLE2pydAM+6A0fn1jZcclGlX1T9E0Lef7q06Q40Mk6+oqOs3aa9MbGlCc0PuwHbt6CYgBsYLR6XTY6btsCtL3FkCqPhJqU9OdvJ4iGTw2CSK2nCvxzHtzXvOH0T8dvpa0kz+VoHiw4MGLXbBr7kzCowAescU5t+8/izjdG2oBbTwbs2Zxy4vmIE8dmpba4sqvXfkJ5iV0cah+p/PunM9fRcFZ9O6XGt2+OiwmLgjiD2Wfxb3nzfqpz8xr06/bnYbUYu86itbHg9hcWZPXrAZ8YAVZ/ydkYbtq8Swvhr5elZIsh+9SHlF9gMhQW4+N0bCQBilTG5RHcqHq61/F+yiUkN93e2UDHCQvUFPhyMOvBe6YeiQzA4dJsHBQ4mLXoJ/6pt+Zywy1j/vEIlYJP22Oiy1I9AulSv+JvyNfckgh5iZagOUxtCBfu6vLR7wucsmd38czoVlNxtCE2WSsbHQ61wH56nudxNYxQmooIvM7wsb+85qqZkGfNnaKPU44S9DQSyrPuP87UU0PXjViVxlPNpqDxo+gJrh15N/7rAwBpDFJyoBdoP1dzb0+oq4XHMX57ljRLhC0/W4zuIzWUnMyfpHif0s2jFKRJ8fqzbOBSCgRK4fv0DK9W7MyuLF6rQ3TIMToVcnMQ099m6eh+jyDfjjyzV7XOxZJ5PVWAOfYW6vhPxdy9FTC3qTnkbD3L/Jy+mzz3N5A/bxYGjKIBoXEr3KeA+3HM7Qyfc8U7+xSAKSsoktvmgUqJNmrfxXtN4If8YZzuJuagJNubrSB+yJUoXbL8iGLYm1qrG2b66ZkloUPi6Pp+YC7oTpHEhOWVfJJ0+LprrKU05/FECKpRUOvXcoojJNS2v27Vg7jU6jepkWleBi5GnbC6nyYs8TjvNQ7v3KiAqVto8sbr13/0C/V5oy7FhsWsdMigMdGr7DNFprKJlz6p4elR1EkqenDW3HDOakJJ85dgjpH5CS2ns7ZTEIlaiCjl9xpnKcZ495LicNCusNC0O1xUvL1vFvPVMGOVe5Jt8gdBU1nTPtVw9tG4BnlrD9pI8gNZ4KUmMzgj+bFbmZ3c5xG9zQS4jLVWK+ZNXKyiVPm/ykCp0TlkE/QJQCFUh4OvAbEA21TVqFj8THOEa9zWMCKBNChy9vWuHNezsr2jCoVGeMv6p+haT4g9T+YlN8Ttsx8LQ5LC6uj6LMbQNWiGb7LPjovygyPIVqxAKFK54RsLEdK9b++VtjYzcXUyOlys4qq/eAAnYmeIbvl8XMA+xw3lJaKYKYMlFNMMh/NrMR7eTHMjUUJA9iMc4FmImDiW4to5QqmWCFMrlskfcvMGN8xjOgKdWoodgoGFOmH/sCRBrB/sNepLFk718on1oEbyFg+c8S0GgCNs9hNGpiwqm5Ta5llm09eanz5qRwl1JpKd+o78CwxZZLZj8MRMAiOVH1Xzrbh6fBx3pavC+C39H5O+IRanFu9ZabE5R6PyvpvajjKgMdm7OgSXTitnIKfQhh5GeskjxvU2V78I7YO+f5mtlgLlYE6j4Hj9P38ASlKdGZNHybVguALtPuP89jUMbpiWnu7p9zCKNVIUUmp7xOuZsV70CmrwnZI4oURgsHomB7+tlqvrTIshuklKVbtDW9SdRr163vrhGpkeKiHtSha3SlDz0wGNTiSti+IUejHimZPGR0ZcNW0Nk+Xfw75G6ScE3oNRzBtto7FXC85p8R7E7zusAP1ZJPcTC3puq5nIJV+GTJUhssrmBVY/+jIidz9QB0HdODSRCnDJ9iXHwGFxyTlYF6J+3w+x9F//+0Jbuh35TfTPcvdmfKcsbhzDT2v1CDxp3VydnhCd2RTPg2QpKpDC4anuzKukoN5Nd2KCGNMGpTlYizOfzrNWlBzuELJP+ysrPdb0ypKw3uYD74680sdJKq5zGnn6bT3AyxKIFUKDYhOHuzWezDnOBjP3yGaMMcf2Xgw9FvNrM9UIIkuSREeS0JS8orkOOBDg0pr/OK2cMG+liqaVLbeqpeV44Huv65R7wCHcvdpa0aSG3jvodNkEHykMUnBvgZTU1305n7Yp+LdQx16X0D+bFzbU1V/mC8R3ZZQfkyKq0zVONl10dZkE+7W/aeX09TXqS6tdfpe5x3WK6JqUUyUlbcvIsHE+JjJR0wy7Npbdg+g0y1GONTzKhMuV3wsjGRsQPVYCwtQQhSt12HCL1ZyXUAgwn1deoS9OwJKhEvaLVYo4DWjvXcvTy57Iiivsx1I9OzOjBniCB4HHpjXZeSqux501bGjZgRnOJ3W/HYEaUMM3Ob+0MXeqcamfT2gIkY06cPvFE7YUGXemijGrw7IfB6tAREEJdmbdYwNYhTr8FeummTU4lIPFo6pWyuGWZG9pjdPCjwgUHR/+CYNn7+yxqUXBxXVuNsXwqTJnodG7V4dX2XTFPhl64XmNeu6rIyDvBxow1ejlFOwQB0uoMGwifcrPkTTtew5pjGTiFwUAt3rV9ChspUnEmfZw/h/qxc0DuNL77bQai5OBth36RoMGn1hB6+F5ZtTd0YroH+ZDyBTv32W8VHwAS2B9yrEF3Jry8mT3/SPt975bLyyEY3G7hptGyDnFhcVKmwvPoKku9V+WzNlZnpJ9lsBes9NafMhSs6c3WzRRST+/BlIWTeFZiFz03cZA6e1u90DVHDClzBBgcOAebqxNjMKHyUyXFN1zUo3Sji74vlMRbq9XKkPFZ+KYXW+HItf+jJgsQ6j7SQ1wXxouxQmOZE7Cex7QnabHAQUSGmT92KnpgYrXQqy2Exmf7EEXuaXUMQgCW21Wfxvzjh8sj1NeN4g8Xa/ac09rz//kl6a/hghquAbrI2yzOm1/3zKUD1D68NOnfTprxNU0JXDedUXlHRFLVU2Ypnpbh4rDK+HFR4sDzGW3cRlzN0sEv46G9mPpxKZAPJmyBXN7IOdnMNX75uvxQQKZRozRT38K3eRxn/SMxMQkqRWD0GA5dgguXwgaUEHgk9k5hTttSX75VoCn/DInhFGwoGQBf7yMtCHXhO7JVkPqafxLkClGZJBkxxTmteqAHvylsV9cpzBIpj+D6yARxV2X7sFPnaJsVA5z+0h+qHd4nmFVw7GLE7SmJQUDn2NmEHSnXoWPQNA6VckYKe4qBUrKcbqneRy2ZzWwKgCNraLSKoFXp1nIGnazqr8jO6PqbYFg5E5zkNfYAGqS6kULqDAgORnP035jKaNiTymoeNiPnuA/5/rG61El2BeU/0iQw060dZpQU6RWUyTQxsylQL4SZPCKTlQ/bDyZvxZ2uIP4XmVnShGcNmkASE1yKhpwXC4TkqgcqBjhLRvXLnNMOA0fcSPBFiZjKSvjGbOxdmGqRvUDQK2t9syV4tePpNQvmFcBcuJskQQvXaiE8tUj6+z52fAgAq03xUxnWSz2OJexKYMOMLGa89ldRCQOGbQzMGnrKvMx8IOLWiiX0Wtp+dwQx9PVRdd9d3GpqpGVRlxI6okc4eu7vuoqRu9qaEDrohPw/F/Kzol09SORAtggxpI7CBuRcrUn0N1x0lP1AGQnUnFhFxsTiX57Ae1LDu5gh3QnFs19e+ksFkH9MduN3mPhyqWZH5OWBYQETImMS4F/FcJOaeN+9uaa10EaADzFikmZdkvbjMiW3sleDpocP2uBfK1Ju0uLL8cMVG4+dKcr7ObQoNoxsjA7+L3+/We1repjjZssVjJWZorhF/1TJMEc6ofuN4fgX/ZUD39EwoRZ+cC71kdX8rp/YgYTn8RBjTMO34zkEOy6I0Gbae0j4ptLNOp7FawCZqsOEZ43Sy0xjff7i+qzvtmFBxJn63lvq6LmJFYiNDC6SiSqSY0WpSzHugSvnM/tXimJoyyx4ycy70v657S5SoNDv3ocDcQYidxjwSbBVyBgCBHrkdYdBE2HRfIZRtgRdBlf7uIINArYYhecsvbyKhqX5dgF7TcKhHll0eNzbkkyNy37esXM8Op05XWhiMtGv7WfnYpMylC4KdcPFYDg++IenwlB2Jzo4vyLmZ2kRmUkcc0PyS/HnA113i1LorIhyB3KRVyoOuEuyp99iVh01WqF3tB932V4o+7anfatAX7ulmYlr/NAu7oCwBsMwmZ2Vn2Brnpk9KvgNNeQkmuY+mY6pxymetGmkYvb5WhinTPl4QGQ8E9A9eYWS2NiAY0E+109VR3UEAcsIzPzQjLtWDqV99J9rvlZo8gAk73gscrg05C6Zst2Y2ZKca2K4457Gty17EylF1rT5n8ozfcmNKQl5BoQ1qYdXEXoaXjKPimih9oTqNCuKq4Zxy2LL7l1Hox4aL2ojddr9SBVUK3n+vj2cfuIaVtGU7pdzPBpoLtBqsh36R57Sq3yzvTsQfxICuOqLlgZqaQ0j/OmfCmJv7Cfb2QozCk1E4nNt10OZ5PwOyo9MOzMIFQazUfkmJ5QZEWihlRtpuvFVPJq5y6o8a3KDPBzEHyVatHkPtFlU9qaECHGRPSVbytibUmHYyhDsYg2IVukPJvQ0w0hRYx+HHn+oeXRp4AoTjtzSs5NevwR+WcK3gCHoleXBVm+ZegHo8FKtYKq64BVLPHI4gGNv1QSH6N1ttc+/owYQDvAV+SgV86hMH5CU2LGMWYuaMyyyN0PQZcGn8pM3rtrW5WVR3K+7G16/UyJxgcaHlpJBlFGUFns3JoBsfpJYPT6gDlHm4mIqTicBsirk+C6IbvUStYxfWrtF7rGqL66DmW2h/Ay7pdRd/Cnf1/2kXkY3RqgUqKQO8wvutBzCagrjs0xmN6UetAm7qidLRIwnh4cBxDzv6y6pOIy38tXcEqWT6s+PEuIT33E+GpvQfP5HLC0XAF2d1sQVheNL5MFvUj7r3NlkDphdz+XnGlgDqos+01lkAll0+TGMaw1v7bbqPa6ieBZhoYIM3E83gSl47p1yD/oq5xorP+Zug5CITyGmwjDacb3s//M2NYLfwfSIyjcUv3/FFiDPo+WdASdwKzqZ5HG7wkj7cc+M1f1w2iMoLJKDvd8H0LI5BCgPCNx3iepNxvpv5SI4jOG7Mmh8MKt3vPjW89G5Kepf8nXGPkPgcZqVEug9nPQh1nSIrPCwb0OlXqvpIsmCj43adq9qMGrKwFBNRB9h+Gt3pINdRwEtwRkklDr1UQ7bqG44WgtAk/J5kgpbGhSPFLPeMXQAl7MAxgoJuvadCgbnEJmzabMkWmoq+cg2VpOJ5hEF1+c3h2eS43EfessTIQ0Gc57qQisLqf07LzPqiJJmKmJOIqEyroyplELcBA7qQfE5Z9VZquoMy+VJ5CFft1Lgn2V+exv0TJEDNMYtZoqQoF+WiAi/O0AMMmUTznhURnrXfjhXRodMAZlpgpNF+RMq+oQNPCBcvSs5W3wBxz9vRGNb6lQ6W5hzwlWrAAdnBGEQTr0Uv/R6H8agvtmQvS89nyp5jEXdSWsO9cQ5kpkXPpVlGLvNlvxe0QFngkdir3k3ZFA108Z62xhtDUrvJWVpn+QNd1V1CJKAchn45kRvnxgWNWZNIdUjATar6ThUcIAc/QtG5QnTwf0shoN4kfCYq4KkZTJ9V8Jfe5Cqd22HRf5DNf1WvCwihbR2jtc8F6VzTgzlTJUISES7RygrWDXCay48f9A+8dGpa6UTRAhVhBmbR2MjU1VdTFJOpoVkQ2JVPRglch+kXI5JKfcIsCJNbF8yvjeFH+FZ0Arwx4eDQaJ95Slq+05rWd9779iBSdS+7VQ0jvGs6xFFzwdfdOJjyaavrBko0dnNVAUr4Ct3WoKFSLLf36qwnFTMEUb+F6rIkD/tJcO9CkTiZr/iG38CsWvxU4S712rNVoknKT9oYZC5iF6ExJtFyGO/Pa+8CgTfbjzvpyTuslR36Vz4PcAUdj0IyYNdkAcMOMu3gGYzArWTt+H2P1MvEnfwb2pGhZK6FNRnhd5b3lmzZcsocpZQSEn+iDHKOsRb63ksP24sTjmsV0v9hKBm1FKLLT9BCeWrdLqI96qu41cCp8blSYzSjPDeSe23+z2OQnZqkxS1Olgs1UjWPX9JtPCJtpRnDECKWKSsYGwpNIEv1PMsVwGJDZeJt800K6jlZgcdCrHPn7nVCeFduvZJVjsUR48bMHDyuBjXQM+UxHPapzajTV8V0TW7WWBSQSD45By0GDdirL9oLtvqshFxM7EO772r8EtaCUxSCZktqOkfgpnT0wakgdw7bGagPWTYRcJ26euclQYcIeOJVR6o4zmqmbK1AQlQeFfbjHCrUNsMsGkXttwMSodptM+laVYEEtIWNuTSLBNZEToiiWjjdvUc/0RCaB3QxfwM2ALYbc/cs0aLNK6Gj647n9WxTtktUpri/tKCEHRBDtO0Rc/85zkz8UcwitEl7LX3Ju8D8MmQDP7wMw2nNAQjCI3PmlryL2u/CpiYWBN0f1oDDrz4+N2B2HusF8cLiXNckZpOyN3Nen1RwcW8p1bpEFSGfYRrGHGClQ10UJwxuhTkU970wFYaKa9PFgy+OfgdRbBvGKMWICzxOk1VaL6KGJ2BZwlgbnH4SSRvTKn3eH2PJ6lnO04PO5OqKLGi3OFih0/kry4ts2v7kdHAnXUf8RnBC3avZjL0TMbsVp/MfdPX+xAmg+v9Lf7K0FEwmADQXeml19viMKyLlHf+hpWMkMUmNKBPldldbKogKusilvbSMZmwdkRjrQsQ2qQUtLc6Bbz0fKhiSPXfpZTdHs/4CE3GaWZjotbygLjVzUb7qml5aQUM9YxV2jyWbNN7BCo4AR9DabSR8NA9vzm++M/Qedu+ynK+NhMbWspyJa6395qYVswN83JFtaO6VTlBTGh8IV1nMtD/XhEdIhaEuhODYM36H0Mz/h/SpXRmNsNyvTLcS3ABKIS+KIsd/xeXChAYhNe+FpKCPDqhcJbxS6TBczst5X89SCVBHx0uBP7Il2l7BcMPOJdPfV5N+UR8oOOY+p0GAfKZ+82Rehk7AtiFCQeyhmZ5zm228xmdcEKW+BNiubKR/ZnMqhUlz+71XFU7pM44p9XPWKP+L4+8w7q7j5uOLuGOpxBbt8au8FPe8lhTS/DL4m+cLxbM0MpfMtyd3XeGY24ZAMZL5MNWUOjjftu0ZYGkW/M6ldXe2I4M9BN48r9Ya8osLtFv0sA3/pUR8kaI/iZo5cypNgTc18FiaQEHsZj7EI9wi0+jWdNZ3DMg6GOkVor9YXggg7LVujslQY+g6IsJmXCw6dVnq7veg0fD4349h92aUOqXIos77XYKLyRix/80LLgX132fw8cmAcDp3QSe104cKbGY4RK1Ywsil8MsWLj1Ab+EysFktHfVmFlOwRuM+X+1kjy+MH4QFDHFcwDtLt395DQB5yrj1YCpZN47Fz1zNLEHv2Zgyd/VhQmf6t3pT/maqGDDl/rc5DJi/pKUPo96ZLzsIKvbjtYxg1YBGMlcNz5AvYYp41tazwmpxlFcRd2ZmtDMXmRlKxhN0LppdVzYl0kJB+u06BbS28ozN70vbWinV4r1XH+Pg+8o3mvtFlZaci0WAJ5fqxHhCig7pb93bV7Yls5smZbk2TZr4glkHb/jx23dy1HVMd7BtEhqevDAtTtOipLJs9F028PViQ/JpRAQHtIMRup/QWNV4C32jaW/E5kBJG0KAK4ClNSm+wdGgzkyisGmZUiRy121FVX7wFVbaZ3Gurn8EDqnb7YNauGfx1gifdD9DjTsFyaA1jaztf0l4dDVOWPKNYbLrcdEoIYM1Y/WH7PBz8ztEacpM9sOMWSrp7GLI4EDRhlOXEmiR8LpR94OCJou1JYrhSqLbW4t6+5iQ8faAyS6sAEC3jLlkXZvGslPqt6tSTZYmmwUzh/qpEk1zP/t+Af3qHt/RV98AX0jlZWcMNOs0sMKEUMxImKVQl1lkJ6LBKoxHVLyBQW4MKSKBWNU7uzM9UC3ZRHjVCVx6tBpoLGPkh3dsIwJGRm/6mSB7NDcJ7L9kV96gGngSKRNzZBji13Y7o/d8ZB3nV1w8tc+G+X6pCH7Pp1Twkwt6bnDNdH5LWaQqm9zFiRaA1uqaq12B+PUhcoRB5ffb0Ci5ZkzzLFO0bOEDSr0YiMLoGTXfnGuSot3NXF83v6UV55NaAwCY8rfa7Ra1fU09APV283bl/VYysrVpzUO18Zvus9uUF5f99ikL4wT0KKiidpuf4RSn6KW6Gum5vhDIhxvszJl2B1asCXo/VrGwqj3nQO9NB6lbJGaSrUwEHyGX72VdBKqRDmhDZSR+iHLOrWIyDVmx2EBtuj/eOHF384ewK9sriFrfwp8soHaHn+PBBBZoP9LWGpWkPLsZt3Hk085jE9pUJuaaSjmMJkkT5jy3rZJNBFJp1ikd7uLJeP8LC/rjzz4TRi4oadLALMhqV3J+YEcTdXViZtY+Q2a6HgMTeiXg8WZCyRPFjRuoOrds2pSHrKm8QFPVr/RinihYTPrN2U3cKiFlXWLqAPvF37kEvgGKsckJ4Hh9B2W0EhzOkKQImRBKdkfE0GgInWRg9VO8BcGMlZ2u8fWtv8hnHMWVRjO0XcMRnHVv9HTWWxkE0q/gVFzUBKn7pJ9kobk2RASOOt/AEnx/iAoMS84cJhH2Wd2Ap7FkRucThMNxF+L9Pu7NUXfAMOGkKBwqMjKYVcadyI5TblB+IJd8wY8AdmioOD+/jLlODHCVoM2zhxGDIShkG05nOFRxjUn+EM69rTfu1GnQ3J24Y6mhwjcyjH7Eeb4YpNV8/l7XL6+KJbsNIZ4jodoO0SF4hY4Rr/H1g5H8bTEjFhY1G/BsvPm26Q79dmQ3w8N5SjXB+f+24fGRe07kznqQvqsfbIw+UL0BIxx8RB3kJ5dMeHUBfUd0TSBpKO6xLPr8E8waNU+QjVcyQTwW4V/hZmeLXZQjKM/f1alC8CZ4YahglRQMJh2XtyRJEKu0vi1a+jzpfIpR1vSgSPNrbXJC1QtxfJalRQA516hUHZzNXiNG2I36AHrADVdRxkRRsv1YoaaL6Jw4p84QbiIU5AMK5jrN7tet8cNrWTrUL6x2ywkJU8Bc2Z4oWe5JyM443r/Aq9tO5+tdNxxE1SI87GJCp36W21tkFWOJIsd47XLm3bVK0CLzPo5zffFNjKBi1sjVZBZWN4EPXNyNUimVFiKc1HZLmq1EDbnlUeMNyvESlLx0zFw5b2WvWy79Wc4+hP9y/Oj4QRtO4w2dlC+2cgv0q9dAOEC7KjLpWT4+6DsLaspD9zoIQqHfY2YV91qnDxp1dHe0hQUADbqImxkZ3M/+2/lmGbQAUxSYFOWRbc3QyPvYba7HMxIAeSY+/TjJSBMOAE43HxsWHQBgyq++JOkHSkE3SC+nFmiYkZNGueL3lqQvQY9eNkqJ3TrAaKx2b/6L6EsKhhHk7qDK/HlOLN91Fz/n5LrsYayjvovpfa1HBMI7lOAKfurMFrgHi9ouf4TXu27CsprVugHJ8iGS9KRai3BiGxIj4UBFWULy5btNk1bgkR1ECuwNKGRSz2AMM2eOeE9CehMF0vBc9WQO01mYDDVod4fqkQFgtr4mQmQMIQNWWPlB3Mc5+vzc3knYx8JlOWgRbJ2Yah2Hb9b44eEBc60OaHwhRmiWd4JDYhcr1bmXSWSPnc3jXF0O+fr23ePk+dgJ+ztvb9C/t09cIBCW2UuPWTN8+4p7ZkXuuAUKCSROWuctvrW8EX+fC6o9VJ5HQXGGAcRk3lbaXgGo3I1N/TnabQcxQbUKMXbXFZZDlMZ3dlTPL9++7L9QBQwWhKFVUlaqU0p2At7SM+sAVnIqREDOlKd2tR8xhPW/Or71PRvKJavDl8SseoS3n1YeqVl0eee0+np2RiuA7fTTnbdgAxZgSpJUndJIFW5YHKNQCm4jq1VuLLJdRX3L6m+u+QjI5jRs21h73s2TcmuRCDyIUChKb4BXSi4kjZIGJUhVtviAFXsW/sdNKuU26M+u92RlWBtmXL5z9FyG9c0/poygX0diYpn8sg+SvD8WRCI1x9X2GhRhT7+hdKUK2YiXfg3P01zdR8wWMD719CmD1+jDkzFSz1YAmTmG+h9LweDRFXQ+Cecewgq1zdb3mCylETkz4itbKvZN3HXmjHsWRSIcgE8BDaTF4dQXJuhfpLYy7sApJZ8ppMv1MBUI0/dclZ0j7JGWmHQ/81XV5x0Rw0AQTW5/P3gXuTusmRIACbd+rErpfuUrdi0eUnme7bgXpv2GZ9SZPm7fiCygGcyE4PqCm5FfO9imFKDM3O8MQdcBvnQP2gPyPnBs3GzKCf1UoES76vrMCHWfGSH1JA5mLMukOt/BXrACI94TB6r3IGJ5zCPd/io1eyLevOJU4etWnnquCTzYyn/bfpqyfbLNrPbqoGbCT6p3MT6e+8ayLKt6LlGU2uYYQgwf6ErgaBx16nVfJIyC0uWPrMEmhzeuR8j9U3VWE37mBunz7xzwBmV8DCo+MgQTeRkAE97L/ppv9O2V26+p5xW+mYfYqVWvPYlCN0hjF2W163Yb1/HswMXKq1/zRGlqvlJeRRfYhVWdajryUbJ3m6pyu3O8sWf8jVxhnW5lMbdKoZ/GPz3/hVf5mpwREJy/Wl956KnCQbchL3d2inX8dQm4TsGtew+EBR94j+OZFhw3srg6GVTGF7gNrWzJL44IP/J3/1UDsPxJqbit/jBrm76XLJ0C2+Z7R0DUEoB3IkuKWy3xscokXn2uVskbcAh1UW6j/epG7d4qwX+8dYfoUV3jU/sdthYtCGxwH2CRStwoTdzy+zobk87OoRlnPwOduDe08XNh9Vlg5UH2oqq0mwxA98wvTC5yCvSCthgirbUZXwxWKyM3U4+Ab5+HcTPCJ8uDX1U/4Ge4AZ9ukPu2UdWETUeZp3U1keojZPsxfpZr9mglJRnJhuP/tuEVpb8P7tm5KVQmkUdkcJSY9FSpdgaQYNgsLAswZUapNTvM2dcQN5vLHUHpLNA6VTWtQyfIkjlxHhEnwn2IykbAXcSQkuA6egx4AN+EH4++yQDU3maF/qtiiONn61iGhdzqfXhOqxziYQ9/M46Yy+45fsVt+yVDQOAae8UO2fNZA8s/OyPkptyE3KasCQYoj2aMrJIK24qQxNIBr7/0mIzd3nyICzLmRY66EtG3MyaGBMYFNvS2j2eDuGLBiAAA==',
+ },
+}
\ No newline at end of file
diff --git a/frontend/test/tapes/thumb/images/feb91b13-422d-46fa-8ef4-cbf1e6ddee9b_keep-alive_HEAD.json5 b/frontend/test/tapes/thumb/images/feb91b13-422d-46fa-8ef4-cbf1e6ddee9b_keep-alive_HEAD.json5
new file mode 100644
index 00000000000..9a3af870e50
--- /dev/null
+++ b/frontend/test/tapes/thumb/images/feb91b13-422d-46fa-8ef4-cbf1e6ddee9b_keep-alive_HEAD.json5
@@ -0,0 +1,80 @@
+{
+ meta: {
+ createdAt: '2024-05-03T03:38:54.005Z',
+ host: 'https://api.openverse.org',
+ },
+ req: {
+ headers: {
+ connection: 'keep-alive',
+ },
+ url: '/v1/images/feb91b13-422d-46fa-8ef4-cbf1e6ddee9b/thumb/',
+ method: 'HEAD',
+ body: '',
+ },
+ res: {
+ status: 200,
+ headers: {
+ date: [
+ 'Fri, 03 May 2024 03:38:54 GMT',
+ ],
+ 'content-type': [
+ 'image/jpeg',
+ ],
+ 'content-length': [
+ '25794',
+ ],
+ connection: [
+ 'keep-alive',
+ ],
+ vary: [
+ 'Accept, Authorization, origin, Accept-Encoding',
+ ],
+ allow: [
+ 'GET, HEAD, OPTIONS',
+ ],
+ 'x-ratelimit-limit-anon_thumbnail': [
+ '1000/day',
+ ],
+ 'x-ratelimit-available-anon_thumbnail': [
+ '998',
+ ],
+ 'x-frame-options': [
+ 'DENY',
+ ],
+ 'x-content-type-options': [
+ 'nosniff',
+ ],
+ 'referrer-policy': [
+ 'same-origin',
+ ],
+ 'cross-origin-opener-policy': [
+ 'same-origin',
+ ],
+ 'access-control-allow-origin': [
+ '*',
+ ],
+ 'access-control-expose-headers': [
+ 'cf-cache-status, cf-ray, date',
+ ],
+ 'x-request-id': [
+ '9783a2b22fe94971816f362632c017ea',
+ ],
+ 'cf-cache-status': [
+ 'MISS',
+ ],
+ 'last-modified': [
+ 'Fri, 03 May 2024 03:38:54 GMT',
+ ],
+ 'accept-ranges': [
+ 'bytes',
+ ],
+ server: [
+ 'cloudflare',
+ ],
+ 'cf-ray': [
+ '87dd38880feb71c5-FRA',
+ ],
+ },
+ body: '',
+ },
+}
\ No newline at end of file
diff --git a/frontend/test/unit/fixtures/audio.js b/frontend/test/unit/fixtures/audio.js
index ff8db994659..ee0422e793e 100644
--- a/frontend/test/unit/fixtures/audio.js
+++ b/frontend/test/unit/fixtures/audio.js
@@ -14,7 +14,9 @@ export const getAudioObj = (overrides = {}) =>
license_version: "2.5",
license_url: "https://creativecommons.org/licenses/by-nc-sa/2.5/",
provider: "jamendo",
+ providerName: "Jamendo",
source: "jamendo",
+ sourceName: "Jamendo",
filetype: "mp32",
tags: [
{
diff --git a/frontend/test/unit/specs/stores/provider.spec.js b/frontend/test/unit/specs/stores/provider.spec.js
index 4af16b838b2..43d91680d36 100644
--- a/frontend/test/unit/specs/stores/provider.spec.js
+++ b/frontend/test/unit/specs/stores/provider.spec.js
@@ -80,21 +80,19 @@ describe("Provider Store", () => {
it.each`
providerCode | displayName
- ${"wikimedia"} | ${"Wikimedia Commons"}
- ${"wordpress"} | ${"WP Photo Directory"}
${"test_source"} | ${"Test Source"}
`(
"getProviderName returns provider name or capitalizes providerCode",
async ({ providerCode, displayName }) => {
- await providerStore.fetchMediaProviders()
+ await providerStore.fetchProviders()
expect(providerStore.getProviderName(providerCode, IMAGE)).toEqual(
displayName
)
}
)
- it("fetchMediaProviders on success", async () => {
- await providerStore.fetchMediaProviders()
+ it("fetchProviders on success", async () => {
+ await providerStore.fetchProviders()
expect(providerStore.fetchState[IMAGE]).toEqual({
fetchingError: null,
hasStarted: true,
@@ -103,7 +101,7 @@ describe("Provider Store", () => {
expect(providerStore.providers[IMAGE]).toEqual(mockData)
})
- it("fetchMediaProviders on error", async () => {
+ it("fetchProviders on error", async () => {
for (const mediaType of supportedMediaTypes) {
initProviderServices[mediaType] = () => ({
getProviderStats: jest.fn().mockImplementation(() =>
@@ -126,7 +124,7 @@ describe("Provider Store", () => {
})
}
const searchStore = useSearchStore()
- await providerStore.fetchMediaProviders()
+ await providerStore.fetchProviders()
for (const mediaType of supportedMediaTypes) {
expect(providerStore.fetchState[mediaType].fetchingError).toEqual({
code: AxiosError.ERR_BAD_REQUEST,
diff --git a/frontend/test/unit/specs/utils/decode-image-data.spec.js b/frontend/test/unit/specs/utils/decode-image-data.spec.js
index 5bdfe6e203c..cf7e36b7d20 100644
--- a/frontend/test/unit/specs/utils/decode-image-data.spec.js
+++ b/frontend/test/unit/specs/utils/decode-image-data.spec.js
@@ -12,6 +12,7 @@ const requiredFields = {
attribution: "Attribution",
category: null,
+ source: "source",
provider: "provider",
detail_url: "url",
@@ -22,6 +23,11 @@ const requiredFields = {
tags: [],
}
+const expectedFields = {
+ ...requiredFields,
+ sourceName: "Source",
+ providerName: "Provider",
+}
describe("decodeImageData", () => {
beforeEach(() => {
@@ -30,14 +36,14 @@ describe("decodeImageData", () => {
it("decodes symbols correctly", () => {
const data = {
- ...requiredFields,
+ ...expectedFields,
creator: "S\\xe3",
title: "S\\xe9",
tags: [{ name: "ma\\xdf" }],
}
const expected = {
- ...requiredFields,
+ ...expectedFields,
title: "Sé",
originalTitle: "Sé",
creator: "Sã",
@@ -50,14 +56,14 @@ describe("decodeImageData", () => {
it("strips the extension if the same as media filetype", () => {
const data = {
- ...requiredFields,
+ ...expectedFields,
creator: "Creator",
title: "Image.JPEG",
filetype: "jpg",
}
const expected = {
- ...requiredFields,
+ ...expectedFields,
title: "Image",
originalTitle: "Image.JPEG",
creator: "Creator",
@@ -77,7 +83,7 @@ describe("decodeImageData", () => {
}
const expected = {
- ...requiredFields,
+ ...expectedFields,
title: "Image",
originalTitle: "Image.JPG",
creator: "Creator",
@@ -96,7 +102,7 @@ describe("decodeImageData", () => {
}
const expected = {
- ...requiredFields,
+ ...expectedFields,
url: "https://example.com/image.png",
title: "Image.JPG",
originalTitle: "Image.JPG",