diff --git a/Dockerfile b/Dockerfile index 1944932..04e1b6a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -30,7 +30,8 @@ FROM pb_base AS production # Skopiuj statyczny build frontendu prosto z vite do pb_public (serwowania przez Pocketbase) COPY --from=build_frontend /app/dist /pb_public -# Skopiuj ewentualne migracje na produkcję +# Skopiuj ewentualne migracje i hooki na produkcję COPY backend/pb_migrations /pb_migrations +COPY backend/pb_hooks /pb_hooks -CMD ["/pocketbase", "serve", "--http=0.0.0.0:8090"] +CMD ["/pocketbase", "serve", "--http=0.0.0.0:8090", "--hooksDir=/pb_hooks"] diff --git a/backend/pb_hooks/fetch_covers.pb.js b/backend/pb_hooks/fetch_covers.pb.js new file mode 100644 index 0000000..74dfc80 --- /dev/null +++ b/backend/pb_hooks/fetch_covers.pb.js @@ -0,0 +1,111 @@ +// Pocketbase Hook fetch_covers +console.log("POCKETBASE HOOK: loaded fetch_covers.pb.js"); + +onRecordAfterCreateRequest((e) => { + try { + console.log("Wyzwolono onRecordAfterCreateRequest dla " + e.record.get("title")); + const title = e.record.get("title"); + if (!title) return; + + // Jeśli ma już okładkę, ignorujemy + const existingFile = e.record.get("cover_image"); + if (existingFile) return; + + const urlArgs = encodeURIComponent(title); + let thumbUrl = null; + + console.log("Szukam w Steam API: " + title); + try { + const steamRes = $http.send({ + url: `https://store.steampowered.com/api/storesearch/?term=${urlArgs}&l=english&cc=US`, + method: "GET" + }); + if (steamRes.json && steamRes.json.total > 0 && steamRes.json.items.length > 0) { + const appId = steamRes.json.items[0].id; + // Steam serwuje kapitalne pionowe okladki library_600x900_2x (2x to wysoka rozdzielczosc) + const steamThumb = `https://shared.akamai.steamstatic.com/store_item_assets/steam/apps/${appId}/library_600x900_2x.jpg`; + + try { + const checkRes = $http.send({ url: steamThumb, method: "HEAD" }); + if (checkRes.statusCode === 200) { + thumbUrl = steamThumb; + console.log("Znaleziono okładke Steam dla: " + title); + } + } catch(err) { + // Brak okładki 600x900, probujemy standardowej capsule + const fallbackSteam = `https://shared.akamai.steamstatic.com/store_item_assets/steam/apps/${appId}/capsule_616x353.jpg`; + const checkRes2 = $http.send({ url: fallbackSteam, method: "HEAD" }); + if (checkRes2.statusCode === 200) { + thumbUrl = fallbackSteam; + } + } + } + } catch (e) { + console.log("Steam API error, pomijam:", e); + } + + if (!thumbUrl) { + console.log("Szukam w Wikipedia API (fallback): " + title); + try { + const wikiRes = $http.send({ + url: `https://en.wikipedia.org/w/api.php?action=query&prop=pageimages&titles=${urlArgs}&pithumbsize=600&format=json`, + method: "GET", + headers: { "User-Agent": "Nene-Game-App/1.0" } + }); + const pages = wikiRes.json && wikiRes.json.query && wikiRes.json.query.pages; + if (pages) { + const keys = Object.keys(pages); + if (keys.length > 0 && pages[keys[0]].thumbnail) { + thumbUrl = pages[keys[0]].thumbnail.source; + console.log("Znaleziono okładke na Wikipedii dla: " + title); + } + } + } catch(e) { + console.log("Wikipedia API error, pomijam:", e); + } + } + + if (!thumbUrl) { + console.log("Szukam w CheapShark API (druga deska ratunku): " + title); + try { + const searchRes = $http.send({ + url: `https://www.cheapshark.com/api/1.0/games?title=${urlArgs}`, + method: "GET" + }); + if (searchRes.json && searchRes.json.length > 0) { + thumbUrl = searchRes.json[0].thumb; + console.log("Znaleziono miniaturę w CheapShark dla: " + title); + } + } catch(e) {} + } + + if (thumbUrl) { + console.log("Ostatecznie pobieram wybraną okladke z sieci..."); + const imgRes = $http.send({ + url: thumbUrl, + method: "GET" + }); + + const safeTitle = title.replace(/[^a-z0-9]/gi, '_').toLowerCase(); + let ext = ".jpg"; + const lowerThumbUrl = thumbUrl.toLowerCase(); + if (lowerThumbUrl.includes(".png")) ext = ".png"; + else if (lowerThumbUrl.includes(".webp")) ext = ".webp"; + else if (lowerThumbUrl.includes(".gif")) ext = ".gif"; + + const file = $filesystem.fileFromBytes(imgRes.raw, `${safeTitle}_cover${ext}`); + + // Używamy formularza (RecordUpsertForm) aby wgrać do serwera i zlinkować + const form = new RecordUpsertForm($app, e.record); + form.addFiles("cover_image", file); + form.submit(); + + console.log("Pomyslnie dodano okładkę dla: " + title); + } else { + console.log("Niestety w żadnym źródle (Steam, Wikipedia, CheapShark) nie znaleziono danych dla: " + title); + } + + } catch (err) { + console.error("Generalny błąd podczas pobierania okladki: ", err); + } +}, "games"); diff --git a/backend/pb_migrations/1710000000_create_games.js b/backend/pb_migrations/1710000000_create_games.js index 70b6f3b..c556fa3 100644 --- a/backend/pb_migrations/1710000000_create_games.js +++ b/backend/pb_migrations/1710000000_create_games.js @@ -55,25 +55,6 @@ migrate((db) => { const dao = new Dao(db); dao.saveCollection(collection); - // Add examples: - - const examples = [ - "Wiedźmin 3: Dziki Gon", - "Cyberpunk 2077", - "Red Dead Redemption 2", - "Baldur's Gate 3", - "GTA V", - "Minecraft", - "Hades", - "Elden Ring" - ]; - - for (const title of examples) { - const record = new Record(collection); - record.set("title", title); - dao.saveRecord(record); - } - }, (db) => { const dao = new Dao(db); const collection = dao.findCollectionByNameOrId("games1234567890"); diff --git a/compose.dev.yaml b/compose.dev.yaml index c53bc51..1d8b0f3 100644 --- a/compose.dev.yaml +++ b/compose.dev.yaml @@ -6,11 +6,13 @@ services: context: . dockerfile: Dockerfile target: pb_base + command: ["/pocketbase", "serve", "--http=0.0.0.0:8090", "--hooksDir=/pb_hooks"] ports: - "8090:8090" volumes: - ./pb_data:/pb_data - ./backend/pb_migrations:/pb_migrations + - ./backend/pb_hooks:/pb_hooks restart: unless-stopped frontend: diff --git a/frontend/main.js b/frontend/main.js index 5373064..8cc6dc5 100644 --- a/frontend/main.js +++ b/frontend/main.js @@ -84,8 +84,11 @@ async function handleDraw() { : null; card.innerHTML = ` -