Skip to content

Commit

Permalink
Add support for fetching slugs from atlasobscura daily
Browse files Browse the repository at this point in the history
- Refactored constants and types into their own files
  • Loading branch information
jesusoterogomez committed Apr 19, 2020
1 parent 7296f1a commit 7ae3e73
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 22 deletions.
3 changes: 3 additions & 0 deletions src/Constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const BASE_URL = "http://www.atlasobscura.com";
export const PLACES_LIST_URL = BASE_URL + "/extension_image_pool/v2/pool.json";
export const FETCH_INTERVAL = 24; // Fetch json content every n hours.
21 changes: 21 additions & 0 deletions src/Types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
export type Place = {
id: number;
title: string;
subtitle: string;
city: string;
state: string;
country: string;
location: string;
url: string;
destination_url: string;
image_url_v2: string;
image_attribution: string;
background_image_url: string;
};

export type PlacesJSONContent = {
slugs: {
slug: string;
upvotes?: number;
}[];
};
85 changes: 63 additions & 22 deletions src/utils/atlas.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import slugsFile from "../files/place_slugs_v3.json";
import { getStorage, setStorage, KEYS } from "./storage";

export const BASE_URL = "http://www.atlasobscura.com";
import { BASE_URL, FETCH_INTERVAL, PLACES_LIST_URL } from "Constants";
import { Place, PlacesJSONContent } from "Types";
import { getStorage, setStorage, KEYS } from "utils/storage";
import { differenceInHours } from "date-fns";
import localSlugsFile from "files/slugs.json";

// Sets initial image index in chrome storage.
const initIndex = async () => {
Expand All @@ -25,10 +26,37 @@ const incrementIndex = async () => {
await setStorage(KEYS.CURRENT_INDEX, index + 1);
};

const getSlugs = () => {
return slugsFile.slugs;
const getSlugs = async () => {
const timestamp = (await getStorage(KEYS.PLACES_LIST_FETCH_TIMESTAMP)) as
| number
| undefined;

// If there hasn't been any fetched JSON content, fetch it and store the timestamp
if (!timestamp) {
return await fetchSlugs();
}

// If the time since last fetch has been longer than the fetch interval.
// fetch slugs json again.
const hoursSinceLastFetch = differenceInHours(
new Date(timestamp),
new Date()
);

if (hoursSinceLastFetch >= FETCH_INTERVAL) {
return await fetchSlugs();
}

// If the cached slugs are still valid, fetch from chrome storage.
return await getCachedSlugs();
};

/**
* Depending on the URL returned from atlas obscura's API
* the image either has the full URL or needs to be prepended with the Base URL
* This function ensures we return a valid URL every time.
* @param url
*/
const getImageUrl = (url: string): string => {
if (url.match(/^\/browser_tab/)) {
return BASE_URL + url;
Expand All @@ -37,28 +65,41 @@ const getImageUrl = (url: string): string => {
return url;
};

export type Place = {
id: number;
title: string;
subtitle: string;
city: string;
state: string;
country: string;
location: string;
url: string;
destination_url: string;
image_url_v2: string;
image_attribution: string;
background_image_url: string;
const fetchSlugs = async () => {
const response = await fetch(PLACES_LIST_URL);
const places: PlacesJSONContent = await response.json();

// Store time when the list was fetched.
await setStorage(KEYS.PLACES_LIST_FETCH_TIMESTAMP, Date.now());

// Store list of places
await setStorage(KEYS.PLACES_LIST, places.slugs);

// @todo: Reenable if it's proven that every new day, the array order completely changes. Otherwise resetting the index might make the users see the same images at the start of every day.
// await initIndex(); // Reset index when fetching new slugs

return places.slugs;
};

const getCachedSlugs = async (): Promise<PlacesJSONContent["slugs"]> => {
const places = (await getStorage(KEYS.PLACES_LIST)) as
| PlacesJSONContent["slugs"]
| undefined;

// Default to local slugs if places list is empty.
if (!places) {
return localSlugsFile.slugs;
}

return places;
};

export const getPlaceData = async () => {
const slugs = getSlugs();
const slugs = await getSlugs();
const index = await getCurrentIndex();
const { slug } = slugs[index % slugs.length];

const slug = slugs[index % slugs.length];
const response = await fetch(BASE_URL + slug);

const body: Place = await response.json();

await incrementIndex();
Expand Down

0 comments on commit 7ae3e73

Please sign in to comment.