Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions .github/workflows/ci-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
---
name: CI Tests
permissions: {}

on:
pull_request:
push:
branches:
- master
workflow_dispatch:

concurrency:
group: "${{ github.workflow }}-${{ github.ref }}"
cancel-in-progress: true

jobs:
tests:
permissions:
contents: write # write is required for release_setup
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: '3.12'

- name: Set up Node
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version: latest

- name: Install Python Dependencies
shell: bash
run: |
python -m pip install --upgrade pip setuptools wheel
python -m pip install -e .[dev]

- name: Install Node Dependencies
shell: bash
run: npm install --ignore-scripts

- name: Test with pytest
id: pytest
shell: bash
run: python -m pytest

- name: Test with Jest
id: jest
if: always()
env:
FORCE_COLOR: true
shell: bash
run: npm test

- name: Upload coverage
# any except canceled or skipped
if: >-
always() &&
(
steps.pytest.outcome == 'success' ||
steps.pytest.outcome == 'failure' ||
steps.jest.outcome == 'success' ||
steps.jest.outcome == 'failure'
) &&
startsWith(github.repository, 'LizardByte/')
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
with:
fail_ci_if_error: true
files: ./coverage/python-coverage.xml,./coverage/coverage-final.json
flags: ${{ runner.os }}
report_type: coverage
token: ${{ secrets.CODECOV_TOKEN }}
verbose: true

- name: Upload test results
# any except canceled or skipped
if: >-
always() &&
(
steps.pytest.outcome == 'success' ||
steps.pytest.outcome == 'failure' ||
steps.jest.outcome == 'success' ||
steps.jest.outcome == 'failure'
) &&
startsWith(github.repository, 'LizardByte/')
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
with:
fail_ci_if_error: true
files: ./junit-python.xml,./junit.xml
flags: ${{ runner.os }}
report_type: test_results
token: ${{ secrets.CODECOV_TOKEN }}
verbose: true
4 changes: 2 additions & 2 deletions .github/workflows/update-db.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@ jobs:
- name: Install Python dependencies
run: |
python -m pip install --upgrade pip
python -m pip install -r requirements.txt
python -m pip install -e .

- name: Update
env:
TWITCH_CLIENT_ID: ${{ secrets.TWITCH_CLIENT_ID }}
TWITCH_CLIENT_SECRET: ${{ secrets.TWITCH_CLIENT_SECRET }}
YOUTUBE_API_KEY: ${{ secrets.YOUTUBE_API_KEY }}
run: python -u src/update_db.py ${{ github.event_name == 'pull_request' && '-t' || '' }}
run: python -u ./src/update_db.py ${{ github.event_name == 'pull_request' && '-t' || '' }}

- name: Prepare Artifacts # uploading artifacts will fail if not zipped due to very large quantity of files
shell: bash
Expand Down
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,18 @@ cython_debug/
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
.idea/

# Node.js
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
package-lock.json

# Jest
.jest-cache/
coverage/
junit*.xml

# Project specific
gh-pages/
cache/
Expand Down
9 changes: 1 addition & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,8 @@
# GameDB

[![GitHub Workflow Status (DB)](https://img.shields.io/github/actions/workflow/status/lizardbyte/gamedb/update-db.yml.svg?branch=master&label=update%20db&logo=github&style=for-the-badge)](https://github.com/LizardByte/GameDB/actions/workflows/update-db.yml?query=branch%3Amaster)
[![Codecov](https://img.shields.io/codecov/c/gh/LizardByte/GameDB.svg?token=AG91ICECDX&style=for-the-badge&logo=codecov&label=codecov)](https://app.codecov.io/gh/LizardByte/GameDB)

This repository clones IGDB to gh-pages to be consumed by LizardByte projects, such as LizardByte/Sunshine.

Information from YouTube API is also added to the database for videos.

## Plans

- [x] Build with Jekyll
- [ ] Revamp index page
- [x] Provide an item page for each API item
- [ ] Add unit tests
- [ ] Add code coverage
2 changes: 2 additions & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// this allows jest to use ES6 module imports
module.exports = {presets: ['@babel/preset-env']}
15 changes: 15 additions & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
codecov:
branch: master

coverage:
status:
project:
default:
target: auto
threshold: 10%

comment:
layout: "header, reach, diff, flags, files, footer"
behavior: default
require_changes: false
32 changes: 32 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import globals from "globals";
import pluginJs from "@eslint/js";

export default [
pluginJs.configs.recommended,
{
ignores: [
"coverage/**",
"node_modules/**",
"gh-pages/**",
],
},
{
languageOptions: {
globals: {
...globals.browser,
...globals.node,
...globals.jquery,
// cross-file globals injected by item_detail.js into the browser scope
"base_url": "readonly",
"base_path": "readonly",
"igdbImageUrl": "readonly",
"makeBadge": "readonly",
"addDlRow": "readonly",
"loadItemDetail": "readonly",
"renderGameList": "readonly",
"splitString": "readonly",
"require": "readonly",
},
},
},
];
7 changes: 7 additions & 0 deletions gh-pages-template/assets/js/character_detail.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,10 @@ function renderCharacter(data) {
document.addEventListener("DOMContentLoaded", () => {
loadItemDetail("characters", renderCharacter);
});

/* istanbul ignore next */
if (typeof module !== "undefined") {
module.exports = {
renderCharacter,
};
}
7 changes: 7 additions & 0 deletions gh-pages-template/assets/js/collection_detail.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,10 @@ function renderCollection(data) {
document.addEventListener("DOMContentLoaded", () => {
loadItemDetail("collections", renderCollection);
});

/* istanbul ignore next */
if (typeof module !== "undefined") {
module.exports = {
renderCollection,
};
}
7 changes: 7 additions & 0 deletions gh-pages-template/assets/js/franchise_detail.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,10 @@ function renderFranchise(data) {
document.addEventListener("DOMContentLoaded", () => {
loadItemDetail("franchises", renderFranchise);
});

/* istanbul ignore next */
if (typeof module !== "undefined") {
module.exports = {
renderFranchise,
};
}
29 changes: 26 additions & 3 deletions gh-pages-template/assets/js/game_detail.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ function setupGameBanner(data) {
bigImgsEl.dataset.numImg = data.artworks.length;
data.artworks.forEach((artwork, index) => {
const imgNum = index + 1;
bigImgsEl.setAttribute(`data-img-src-${imgNum}`, igdbImageUrl(artwork.url, "t_screenshot_huge_2x"));
bigImgsEl.dataset[`imgSrc${imgNum}`] = igdbImageUrl(artwork.url, "t_screenshot_huge_2x");
});

// Add big-img class and img-desc span to existing header
Expand Down Expand Up @@ -169,6 +169,7 @@ function renderCompanies(data, metaDl) {
if (data.involved_companies && data.involved_companies.length > 0) {
const devs = data.involved_companies.filter(c => c.developer).map(c => c.company?.name).filter(Boolean);
const pubs = data.involved_companies.filter(c => !c.developer).map(c => c.company?.name).filter(Boolean);
/* istanbul ignore else */
if (devs.length > 0) {
addDlRow(metaDl, "Developer(s)", devs.join(", "));
}
Expand Down Expand Up @@ -469,8 +470,8 @@ function initGameBanner() {

// Set initial image
const getImgInfo = function(imgNum) {
const src = bigImgsEl.getAttribute(`data-img-src-${imgNum}`);
const desc = bigImgsEl.getAttribute(`data-img-desc-${imgNum}`);
const src = bigImgsEl.dataset[`imgSrc${imgNum}`];
const desc = bigImgsEl.dataset[`imgDesc${imgNum}`];
return { src, desc };
};

Expand Down Expand Up @@ -532,3 +533,25 @@ function initGameBanner() {
document.addEventListener("DOMContentLoaded", () => {
loadItemDetail("games", renderGame);
});

/* istanbul ignore next */
if (typeof module !== "undefined") {
module.exports = {
setupGameBanner,
renderGameCover,
renderGameBadges,
renderGameRatings,
renderGamePlatforms,
renderReleaseDates,
renderCompanies,
renderCollectionsAndFranchises,
renderMultiplayer,
renderGame,
renderScreenshots,
renderVideos,
renderExternalLinks,
renderCharacters,
getRegionFlag,
initGameBanner,
};
}
15 changes: 15 additions & 0 deletions gh-pages-template/assets/js/item_detail.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ function renderGameList(container, games) {

// Render games that already have full data
gamesWithData.forEach(game => {
/* istanbul ignore next */
renderGameCard(row, game.id, game.name, game.cover ? igdbImageUrl(game.cover.url, "t_cover_small_2x") : null);
});

Expand Down Expand Up @@ -228,3 +229,17 @@ function renderGameCard(row, gameId, gameName, coverUrl) {
cardBody.appendChild(nameEl);
}
}

/* istanbul ignore next */
if (typeof module !== "undefined") {
module.exports = {
getQueryParam,
igdbImageUrl,
makeBadge,
addDlRow,
showError,
loadItemDetail,
renderGameList,
renderGameCard,
};
}
27 changes: 26 additions & 1 deletion gh-pages-template/assets/js/item_loader.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// setup defaults — base_path is injected by Jekyll via globalThis.GAMEDB_CONFIG
/* istanbul ignore next */
const _cfg = globalThis.GAMEDB_CONFIG || {};
/* istanbul ignore next */
let base_path = _cfg.base_path
? ("/" + _cfg.base_path).replaceAll(/\/+/g, "/").replace(/\/$/, "")
: "/GameDB";
Expand All @@ -23,6 +25,7 @@ function splitString(string) {
const regex = /(.{0,200})\b/;
const match = regex.exec(string);

/* istanbul ignore next */
if (match) {
// Split the string at the end of the last full word
const splitIndex = match[1].length;
Expand Down Expand Up @@ -111,7 +114,9 @@ function createGameCard(id, game, allPlatforms = null) {
const platformYears = {}
if (game.release_dates && game.release_dates.length > 0) {
game.release_dates.forEach(rd => {
/* istanbul ignore else */
if (rd.platform && rd.y) {
/* istanbul ignore else */
if (!platformYears[rd.platform] || rd.y < platformYears[rd.platform]) {
platformYears[rd.platform] = rd.y
}
Expand Down Expand Up @@ -532,7 +537,7 @@ function run_search() {

// Filter results by name (case-insensitive)
const term_lower = search_term.toLowerCase()
const matches = Object.entries(bucket_data).filter(([_id, game]) =>
const matches = Object.entries(bucket_data).filter(([, game]) =>
game.name.toLowerCase().includes(term_lower)
)

Expand Down Expand Up @@ -587,3 +592,23 @@ function run_search() {
search_container.appendChild(errEl)
})
}

/* istanbul ignore next */
if (typeof module !== "undefined") {
module.exports = {
splitString,
fetchGameData,
createGameCard,
renderSearchResults,
addMoreResultsNote,
createPlatformBanner,
createPlatformCardBody,
getPlatformVersion,
addVersionMetadataToFooter,
addReleaseDatesToFooter,
addMetadataItemToFooter,
processPlatformsData,
createPlatformCardElement,
run_search,
};
}
13 changes: 13 additions & 0 deletions gh-pages-template/assets/js/platform_detail.js
Original file line number Diff line number Diff line change
Expand Up @@ -253,3 +253,16 @@ function renderPlatform(data) {
document.addEventListener("DOMContentLoaded", () => {
loadItemDetail("platforms", renderPlatform);
});

/* istanbul ignore next */
if (typeof module !== "undefined") {
module.exports = {
getRegionFlag,
renderPlatformLogo,
renderPlatformBadges,
renderPlatformMetadata,
createVersionAccordionItem,
populateVersionBody,
renderPlatform,
};
}
Loading