Add production deployment, photorealistic movement walls, and fix duplicate influence links.
Configure hosting for gallery.mysuperlab.netcraze.pro and LAN access, enhance movement gallery textures with period-appropriate painted materials, dedupe influenced-by API responses via painting_influence_sources, and refresh several painting image files. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
df29848d89
commit
4eead54062
+37
-41
@@ -9,7 +9,13 @@ const { ensurePaintingImages, preloadArtistImagesLocal, replacePaintingImageFrom
|
||||
const { searchGoogleImagesFirst, searchArtistPortraitFirst, searchPaintingImagesMany, searchArtistPortraitMany, fetchImageBuffer, friendlyImageFetchError, pickExt } = require('../scripts/image-fetcher');
|
||||
|
||||
const app = express();
|
||||
const PORT = process.env.PORT || 3001;
|
||||
const HOST = process.env.HOST || '0.0.0.0';
|
||||
const PORT = Number(process.env.PORT) || 3001;
|
||||
const PUBLIC_URL = process.env.PUBLIC_URL || '';
|
||||
|
||||
if (process.env.TRUST_PROXY === '1' || process.env.TRUST_PROXY === 'true') {
|
||||
app.set('trust proxy', 1);
|
||||
}
|
||||
|
||||
app.use(cors());
|
||||
app.use(express.json({ limit: '20mb' }));
|
||||
@@ -19,9 +25,6 @@ const INFLUENCE_LINKS_EXISTS = `
|
||||
EXISTS (
|
||||
SELECT 1 FROM painting_influence_sources pis
|
||||
WHERE pis.painting_id = p.id OR pis.source_painting_id = p.id
|
||||
) OR EXISTS (
|
||||
SELECT 1 FROM painting_influences pi
|
||||
WHERE pi.painting_id = p.id OR pi.influenced_by_painting_id = p.id
|
||||
)`;
|
||||
|
||||
const INFLUENCED_BY_SQL = `
|
||||
@@ -59,6 +62,28 @@ const INFLUENCED_BY_SQL = `
|
||||
ORDER BY
|
||||
CASE pis.source_type WHEN 'painting' THEN 1 WHEN 'artist' THEN 2 ELSE 3 END,
|
||||
COALESCE(p.year, pis.period_start_year) NULLS LAST`;
|
||||
|
||||
const INFLUENCED_SQL = `
|
||||
SELECT
|
||||
pis.notes,
|
||||
pis.source,
|
||||
pis.aspects,
|
||||
pis.quote,
|
||||
pis.source_author,
|
||||
pis.source_url,
|
||||
'painting' AS source_type,
|
||||
p.id,
|
||||
p.title,
|
||||
p.year,
|
||||
p.image_path,
|
||||
a.name AS artist_name,
|
||||
a.id AS artist_id
|
||||
FROM painting_influence_sources pis
|
||||
JOIN paintings p ON pis.painting_id = p.id
|
||||
JOIN artists a ON p.artist_id = a.id
|
||||
WHERE pis.source_painting_id = $1 AND pis.source_type = 'painting'
|
||||
ORDER BY p.year NULLS LAST, p.title`;
|
||||
|
||||
app.get('/api/timeline', async (req, res) => {
|
||||
try {
|
||||
const { start, end } = req.query;
|
||||
@@ -221,16 +246,7 @@ app.get('/api/artists/:id/navigation', async (req, res) => {
|
||||
LEFT JOIN paintings p_pred ON pis.source_painting_id = p_pred.id
|
||||
LEFT JOIN artists a ON a.id = COALESCE(p_pred.artist_id, pis.source_artist_id)
|
||||
LEFT JOIN art_movements m ON a.movement_id = m.id
|
||||
WHERE p_work.artist_id = $1 AND a.id IS NOT NULL AND a.id <> $1
|
||||
UNION
|
||||
SELECT DISTINCT a.id, a.name, a.birth_year, a.death_year, a.portrait_path,
|
||||
m.id AS movement_id, m.name AS movement_name, m.color AS movement_color
|
||||
FROM painting_influences pi
|
||||
JOIN paintings p_work ON pi.painting_id = p_work.id
|
||||
JOIN paintings p_pred ON pi.influenced_by_painting_id = p_pred.id
|
||||
JOIN artists a ON p_pred.artist_id = a.id
|
||||
LEFT JOIN art_movements m ON a.movement_id = m.id
|
||||
WHERE p_work.artist_id = $1 AND a.id <> $1`;
|
||||
WHERE p_work.artist_id = $1 AND a.id IS NOT NULL AND a.id <> $1`;
|
||||
|
||||
const successorSql = `
|
||||
SELECT DISTINCT a.id, a.name, a.birth_year, a.death_year, a.portrait_path,
|
||||
@@ -244,12 +260,11 @@ app.get('/api/artists/:id/navigation', async (req, res) => {
|
||||
UNION
|
||||
SELECT DISTINCT a.id, a.name, a.birth_year, a.death_year, a.portrait_path,
|
||||
m.id AS movement_id, m.name AS movement_name, m.color AS movement_color
|
||||
FROM painting_influences pi
|
||||
JOIN paintings p_src ON pi.influenced_by_painting_id = p_src.id
|
||||
JOIN paintings p_work ON pi.painting_id = p_work.id
|
||||
FROM painting_influence_sources pis
|
||||
JOIN paintings p_work ON pis.painting_id = p_work.id
|
||||
JOIN artists a ON p_work.artist_id = a.id
|
||||
LEFT JOIN art_movements m ON a.movement_id = m.id
|
||||
WHERE p_src.artist_id = $1 AND a.id <> $1`;
|
||||
WHERE pis.source_artist_id = $1 AND a.id <> $1`;
|
||||
|
||||
const [predecessors, successors] = await Promise.all([
|
||||
pool.query(
|
||||
@@ -610,27 +625,7 @@ app.get('/api/paintings/:id', async (req, res) => {
|
||||
|
||||
const [influencedBy, influenced, annotations] = await Promise.all([
|
||||
pool.query(INFLUENCED_BY_SQL, [id]),
|
||||
pool.query(
|
||||
`SELECT * FROM (
|
||||
SELECT pi.notes, pi.source, pi.aspects, pi.quote, pi.source_author, pi.source_url,
|
||||
'painting' AS source_type,
|
||||
p.id, p.title, p.year, p.image_path, a.name as artist_name, a.id as artist_id
|
||||
FROM painting_influences pi
|
||||
JOIN paintings p ON pi.painting_id = p.id
|
||||
JOIN artists a ON p.artist_id = a.id
|
||||
WHERE pi.influenced_by_painting_id = $1
|
||||
UNION ALL
|
||||
SELECT pis.notes, pis.source, pis.aspects, pis.quote, pis.source_author, pis.source_url,
|
||||
'painting' AS source_type,
|
||||
p.id, p.title, p.year, p.image_path, a.name as artist_name, a.id as artist_id
|
||||
FROM painting_influence_sources pis
|
||||
JOIN paintings p ON pis.painting_id = p.id
|
||||
JOIN artists a ON p.artist_id = a.id
|
||||
WHERE pis.source_painting_id = $1 AND pis.source_type = 'painting'
|
||||
) influenced_works
|
||||
ORDER BY year NULLS LAST`,
|
||||
[id]
|
||||
),
|
||||
pool.query(INFLUENCED_SQL, [id]),
|
||||
pool.query(
|
||||
`SELECT id, label, body, category, pos_x, pos_y, source_author, source, source_url, sort_order, confidence
|
||||
FROM painting_annotations
|
||||
@@ -861,6 +856,7 @@ if (fs.existsSync(CLIENT_DIST)) {
|
||||
});
|
||||
}
|
||||
|
||||
app.listen(PORT, () => {
|
||||
console.log(`Gallery running on http://localhost:${PORT}`);
|
||||
app.listen(PORT, HOST, () => {
|
||||
console.log(`Gallery listening on http://${HOST}:${PORT}`);
|
||||
if (PUBLIC_URL) console.log(`Public URL: ${PUBLIC_URL}`);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user