Files
mue/src/features/background/api/backgroundLoader.js
2025-10-28 21:17:33 +00:00

212 lines
6.0 KiB
JavaScript

import variables from 'config/variables';
import { supportsAVIF } from './avifSupport';
import { getOfflineImage } from './offlineImage';
import { randomColourStyleBuilder } from './randomColour';
import videoCheck from './videoCheck';
const parseJSON = (key, fallback = null) => {
try {
return JSON.parse(localStorage.getItem(key)) || fallback;
} catch {
return fallback;
}
};
/**
* Fetches image data from the configured API
*/
export async function fetchAPIImageData(excludedPun = null) {
const api = localStorage.getItem('backgroundAPI') || 'mue';
const quality = localStorage.getItem('apiQuality') || 'high';
const categories = parseJSON('apiCategories', localStorage.getItem('apiCategories'));
const excludes = [...parseJSON('backgroundExclude', []), ...(excludedPun ? [excludedPun] : [])];
const baseURL = `${variables.constants.API_URL}/images`;
const collection = localStorage.getItem('unsplashCollections');
const url = (api === 'unsplash' || api === 'pexels')
? `${baseURL}/unsplash?${collection ? `collections=${collection}` : `categories=${categories || ''}`}&quality=${quality}`
: `${baseURL}/random?categories=${categories || ''}&quality=${quality}&excludes=${excludes}`;
try {
const accept = `application/json, ${await supportsAVIF() ? 'image/avif' : 'image/webp'}`;
const data = await (await fetch(url, { headers: { accept } })).json();
return {
url: data.file,
type: 'api',
currentAPI: api,
photoInfo: {
hidden: false,
category: data.category,
credit: data.photographer,
location: data.location.name,
camera: data.camera,
url: data.file,
photographerURL: api === 'unsplash' ? data.photographer_page : undefined,
photoURL: api === 'unsplash' ? data.photo_page : undefined,
latitude: data.location.latitude,
longitude: data.location.longitude,
views: data.views,
downloads: data.downloads,
likes: data.likes,
description: data.description,
colour: data.colour,
blur_hash: data.blur_hash,
pun: data.pun,
},
};
} catch (error) {
console.error('Failed to fetch API image:', error);
return null;
}
}
/**
* Gets background data based on current configuration
*/
export async function getBackgroundData() {
const isOffline = localStorage.getItem('offlineMode') === 'true' || localStorage.getItem('showWelcome') === 'true';
// Handle favourited background
const fav = parseJSON('favourite');
if (fav) {
if (fav.type === 'random_colour' || fav.type === 'random_gradient') {
return { type: 'colour', style: `background:${fav.url}` };
}
return { url: fav.url, photoInfo: { ...fav, url: fav.url } };
}
const type = localStorage.getItem('backgroundType');
switch (type) {
case 'api':
return getAPIBackground(isOffline);
case 'colour':
return getColourBackground();
case 'random_colour':
case 'random_gradient':
return randomColourStyleBuilder(type);
case 'custom':
return getCustomBackground(isOffline);
case 'photo_pack':
return getPhotoPackBackground(isOffline);
default:
return null;
}
}
/**
* Gets solid colour background
*/
function getColourBackground() {
let colour = localStorage.getItem('customBackgroundColour');
// Migrate legacy format
if (colour?.startsWith('{')) {
try {
colour = JSON.parse(colour).gradient[0].colour;
localStorage.setItem('customBackgroundColour', colour);
} catch {
colour = 'rgb(0,0,0)';
}
}
return { type: 'colour', style: `background: ${colour || 'rgb(0,0,0)'}` };
}
/**
* Gets API background with caching
*/
async function getAPIBackground(isOffline) {
if (isOffline) return getOfflineImage('api');
// Use cached next image if available
const cached = parseJSON('nextImage');
const data = cached || await fetchAPIImageData();
if (!data) return getOfflineImage('api');
localStorage.setItem('currentBackground', JSON.stringify(data));
localStorage.setItem('nextImage', null);
// Pre-fetch next image
fetchAPIImageData(data.photoInfo.pun).then((next) => {
if (next) localStorage.setItem('nextImage', JSON.stringify(next));
});
return data;
}
/**
* Gets custom background
*/
function getCustomBackground(isOffline) {
let backgrounds = parseJSON('customBackground');
// Migrate legacy format
if (!Array.isArray(backgrounds)) {
const saved = localStorage.getItem('customBackground');
backgrounds = saved ? [saved] : [];
localStorage.setItem('customBackground', JSON.stringify(backgrounds));
}
if (backgrounds.length === 0) return null;
const selected = backgrounds[Math.floor(Math.random() * backgrounds.length)];
if (isOffline && !selected.startsWith('data:')) return getOfflineImage('custom');
const data = {
url: selected,
type: 'custom',
video: videoCheck(selected),
photoInfo: { hidden: true },
};
localStorage.setItem('currentBackground', JSON.stringify(data));
return data;
}
/**
* Gets photo pack background
*/
function getPhotoPackBackground(isOffline) {
if (isOffline) return getOfflineImage('photo_pack');
const photos = parseJSON('installed', []).flatMap((item) =>
item.type === 'photos' && item.photos ? item.photos : []
);
if (photos.length === 0) return null;
const interval = localStorage.getItem('backgroundchange');
const startTime = Number(localStorage.getItem('backgroundStartTime'));
const shouldRefresh = !interval || interval === 'refresh' || startTime + Number(interval) < Date.now();
let index;
if (shouldRefresh) {
index = Math.floor(Math.random() * photos.length);
localStorage.setItem('marketplaceNumber', index);
} else {
index = Number(localStorage.getItem('marketplaceNumber')) || 0;
}
const photo = photos[index];
return photo ? {
url: photo.url.default,
type: 'photo_pack',
photoInfo: {
hidden: false,
credit: photo.photographer,
location: photo.location,
},
} : null;
}