Skip to content

Commit 1a02122

Browse files
authored
Merge pull request #1123 from EngineeringKiosk/games
Add data sync + page content for `awesome-software-engineering-games`
2 parents a6f5fc5 + ae3faf1 commit 1a02122

File tree

18 files changed

+895
-0
lines changed

18 files changed

+895
-0
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: Sync awesome-software-engineering-games
2+
3+
on:
4+
workflow_dispatch:
5+
repository_dispatch:
6+
types: [game-list-update]
7+
8+
jobs:
9+
publishing:
10+
name: Sync awesome-software-engineering-games from external repository
11+
runs-on: ubuntu-24.04
12+
13+
steps:
14+
- uses: actions/checkout@v5.0.0
15+
- uses: actions/setup-python@v6.0.0
16+
with:
17+
python-version-file: 'scripts/.python-version'
18+
cache: 'pip'
19+
20+
- name: Install python dependencies
21+
run: make init-python
22+
23+
- name: Run make update-awesome-software-engineering-games
24+
run: make update-awesome-software-engineering-games
25+
26+
# Commit results back to repository
27+
- uses: stefanzweifel/git-auto-commit-action@v6
28+
env:
29+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
30+
with:
31+
commit_message: Update the latest data from awesome-software-engineering-games
32+
branch: main
33+
commit_user_name: Sync awesome-software-engineering-games workflow bot
34+
commit_user_email: stehtisch@engineeringkiosk.dev
35+
commit_author: Sync awesome-software-engineering-games workflow bot <stehtisch@engineeringkiosk.dev>

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ update-episode-redirects: ## Writes all short url redirects for Podcast episodes
7272
update-german-tech-podcasts: ## Updates the German Tech Podcasts data from https://github.com/EngineeringKiosk/GermanTechPodcasts
7373
. $(VENV_ACTIVATE); python ./scripts/sync_german_tech_podcasts.py
7474

75+
.PHONY: update-awesome-software-engineering-games
76+
update-awesome-software-engineering-games: ## Updates the Awesome Software Engineering Games data from https://github.com/EngineeringKiosk/awesome-software-engineering-games
77+
. $(VENV_ACTIVATE); python ./scripts/sync_awesome_software_engineering_games.py
78+
7579
.PHONY: find-missing-tag-descriptions-content-files
7680
find-missing-tag-descriptions-content-files: ## Finds all used tags in content files that need SEO descriptions and output them on stdout
7781
. $(VENV_ACTIVATE); python ./scripts/find_tags_that_need_descriptions.py website-content

public/images/brands/apple-os.svg

Lines changed: 11 additions & 0 deletions
Loading

public/images/brands/linux.svg

Lines changed: 438 additions & 0 deletions
Loading

public/images/brands/steam.svg

Lines changed: 1 addition & 0 deletions
Loading

public/images/brands/windows.svg

Lines changed: 1 addition & 0 deletions
Loading

scripts/constants.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,14 @@
2828
GERMAN_TECH_PODCAST_IMAGE_STORAGE = "src/content/germantechpodcasts/"
2929
GERMAN_TECH_PODCAST_OPML_STORAGE = "public/deutsche-tech-podcasts/podcasts.opml"
3030

31+
# awesome-software-engineering-games
32+
AWESOME_SOFTWARE_ENGINEERING_GAMES_GIT_REPO = "https://github.com/EngineeringKiosk/awesome-software-engineering-games.git"
33+
AWESOME_SOFTWARE_ENGINEERING_GAMES_GIT_REPO_NAME = "awesome-software-engineering-games"
34+
AWESOME_SOFTWARE_ENGINEERING_GAMES_JSON_PATH_IN_GIT_REPO = "generated"
35+
AWESOME_SOFTWARE_ENGINEERING_GAMES_IMAGES_PATH_IN_GIT_REPO = "generated/images"
36+
AWESOME_SOFTWARE_ENGINEERING_GAMES_JSON_STORAGE = "src/content/awesome-software-engineering-games/"
37+
AWESOME_SOFTWARE_ENGINEERING_GAMES_IMAGE_STORAGE = "src/content/awesome-software-engineering-games/"
38+
3139
# Website redirects
3240
TOML_FILE = 'netlify.toml'
3341
REDIRECT_PREFIX = '/episodes/'
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import os
2+
import json
3+
import logging
4+
import tempfile
5+
import shutil
6+
7+
from functions import (
8+
build_correct_file_path,
9+
configure_global_logger
10+
)
11+
12+
from constants import (
13+
AWESOME_SOFTWARE_ENGINEERING_GAMES_GIT_REPO,
14+
AWESOME_SOFTWARE_ENGINEERING_GAMES_GIT_REPO_NAME,
15+
AWESOME_SOFTWARE_ENGINEERING_GAMES_JSON_PATH_IN_GIT_REPO,
16+
AWESOME_SOFTWARE_ENGINEERING_GAMES_IMAGES_PATH_IN_GIT_REPO,
17+
AWESOME_SOFTWARE_ENGINEERING_GAMES_JSON_STORAGE,
18+
AWESOME_SOFTWARE_ENGINEERING_GAMES_IMAGE_STORAGE
19+
)
20+
21+
from git import Repo
22+
from PIL import Image
23+
24+
def sync_awesome_software_engineering_games(json_storage_path, image_storage_path):
25+
tmp_dir = tempfile.gettempdir()
26+
tmp_clone_dir = os.path.join(tmp_dir, AWESOME_SOFTWARE_ENGINEERING_GAMES_GIT_REPO_NAME)
27+
28+
# Cloning git repository
29+
logging.info(f"Cloning {AWESOME_SOFTWARE_ENGINEERING_GAMES_GIT_REPO} into {tmp_clone_dir}...")
30+
Repo.clone_from(AWESOME_SOFTWARE_ENGINEERING_GAMES_GIT_REPO, tmp_clone_dir)
31+
logging.info(f"Cloning {AWESOME_SOFTWARE_ENGINEERING_GAMES_GIT_REPO} into {tmp_clone_dir}... successful")
32+
33+
# Reading JSON files
34+
json_file_dir = os.path.join(tmp_clone_dir, AWESOME_SOFTWARE_ENGINEERING_GAMES_JSON_PATH_IN_GIT_REPO)
35+
json_files = [json_file for json_file in os.listdir(json_file_dir) if json_file.endswith('.json')]
36+
logging.info(f"Found {len(json_files)} JSON files in {json_file_dir}")
37+
38+
# Copy JSON files over
39+
for json_file in json_files:
40+
# Copy files over
41+
src = os.path.join(tmp_clone_dir, AWESOME_SOFTWARE_ENGINEERING_GAMES_JSON_PATH_IN_GIT_REPO, json_file)
42+
dst = os.path.join(json_storage_path, json_file)
43+
logging.info(f"Copying {json_file} from {src} to {dst}...")
44+
shutil.copy2(src, dst)
45+
46+
# Modify file content
47+
with open(dst) as f:
48+
data = json.load(f)
49+
# Modify image key to only contain the filename
50+
data["image"] = f"./{os.path.basename(data['image'])}"
51+
52+
# Write new file content
53+
with open(dst, 'w') as fp:
54+
json.dump(data, fp, indent=4)
55+
56+
# Copy images over
57+
# Right now we only do it oneway.
58+
# If a game updates its image, we don't delete the old one.
59+
# Dirty? Maybe. However, fast for now and the assumption is, that this
60+
# will not happen very often. If this assumption is wrong, we will update the
61+
# piece of code below.
62+
images_file_dir = os.path.join(tmp_clone_dir, AWESOME_SOFTWARE_ENGINEERING_GAMES_IMAGES_PATH_IN_GIT_REPO)
63+
image_files = [image_file for image_file in os.listdir(images_file_dir) if not image_file.startswith(".")]
64+
logging.info(f"Found {len(image_files)} image files in {images_file_dir}")
65+
66+
for image_file in image_files:
67+
# Copy files over
68+
src = os.path.join(tmp_clone_dir, AWESOME_SOFTWARE_ENGINEERING_GAMES_IMAGES_PATH_IN_GIT_REPO, image_file)
69+
dst = os.path.join(image_storage_path, image_file)
70+
logging.info(f"Copying {image_file} from {src} to {dst}...")
71+
shutil.copy2(src, dst)
72+
73+
# Resize images
74+
image_to_resize = Image.open(dst)
75+
if image_to_resize.width > 700 and image_to_resize.height > 700:
76+
logging.info(f"Resizing {image_file} from {image_to_resize.width}x{image_to_resize.height} to 700x700...")
77+
resized_image = image_to_resize.resize((700, 700))
78+
resized_image.save(dst)
79+
80+
# Removing git clone
81+
logging.info(f"Removing cloned repository from merged JSON file {tmp_clone_dir}...")
82+
shutil.rmtree(tmp_clone_dir)
83+
84+
logging.info("Aaaaand we are done")
85+
86+
87+
if __name__ == "__main__":
88+
# Setup logger
89+
configure_global_logger()
90+
91+
image_storage_path = build_correct_file_path(AWESOME_SOFTWARE_ENGINEERING_GAMES_IMAGE_STORAGE)
92+
json_storage_path = build_correct_file_path(AWESOME_SOFTWARE_ENGINEERING_GAMES_JSON_STORAGE)
93+
94+
sync_awesome_software_engineering_games(json_storage_path, image_storage_path)

src/components/Nav.astro

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,9 @@ let latestEpisode = episodesToShow[0];
132132
<li>
133133
<a class="block py-3 px-4 text-coolGray-500 hover:text-coolGray-900 font-medium hover:bg-coolGray-50 rounded-md" href="/deutsche-tech-podcasts/" title="Deutschsprachige Tech Podcasts"> 🎧 Deutschsprachige Tech Podcasts</a>
134134
</li>
135+
<li>
136+
<a class="block py-3 px-4 text-coolGray-500 hover:text-coolGray-900 font-medium hover:bg-coolGray-50 rounded-md" href="/spiele-fuer-softwareentwickler/" title="Spiele für Softwareentwickler:innen"> 👾 Spiele für Softwareentwickler:innen</a>
137+
</li>
135138
</ul>
136139
<div class="flex flex-wrap">
137140
<div class="w-full mb-2">
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
---
2+
import type { CollectionEntry } from 'astro:content';
3+
import { Image } from "astro:assets";
4+
import { URLify } from '../scripts/urlify.js';
5+
6+
export interface Props {
7+
game: CollectionEntry<'awesomeSoftwareEngineeringGames'>;
8+
}
9+
10+
const { game } = Astro.props;
11+
12+
let genres = [];
13+
if (game.data.german_content.genres) {
14+
genres = game.data.german_content.genres.map((element) => URLify(element));
15+
}
16+
17+
// Generate id based on the name
18+
const nameId = URLify(game.data.name);
19+
---
20+
21+
<section
22+
id={nameId.url}
23+
class="game py-8 md:py-12 bg-white overflow-hidden"
24+
style="background-image: url('/images/elements/pattern-white.svg'); background-position: center;"
25+
>
26+
<div class="container px-4 mx-auto">
27+
<div class="flex flex-wrap lg:items-center -mx-4">
28+
<div class="w-full md:w-8/12 px-4 mb-16 md:mb-0">
29+
{
30+
genres.map((element) => (
31+
<a class="inline-block py-px mr-2 px-2 mb-4 text-xs leading-5 text-yellow-500 bg-yellow-100 font-medium uppercase rounded-full shadow-sm" href={`/spiele-fuer-softwareentwickler/${element.url}-spiele/`}>
32+
{element.name}
33+
</a>
34+
))
35+
}
36+
37+
<h2 class="mb-8 text-4xl md:text-5xl leading-tight text-coolGray-900 font-bold tracking-tighter">
38+
<a href={game.data.website} class="hover:underline hover:text-yellow-500" title={`Website von ${game.data.name}`}>
39+
{game.data.name}
40+
</a>
41+
</h2>
42+
<p class="mb-6 text-lg md:text-xl text-coolGray-500 font-medium">
43+
{game.data.german_content.short_description}
44+
</p>
45+
<ul class="mb-4 text-lg md:text-xl text-coolGray-500 font-medium list-disc list-inside">
46+
<li class="flex flex-wrap items-center">Verfügbar auf: {game.data.platforms.windows && (<img class="w-8 ml-3" src="/images/brands/windows.svg" alt={`${game.data.name} auf Windows`} title={`${game.data.name} auf Windows`} />)} {game.data.platforms.mac && (<img class="w-8 ml-3" src="/images/brands/apple-os.svg" alt={`${game.data.name} auf Mac`} title={`${game.data.name} auf Mac`} />)} {game.data.platforms.linux && (<img class="w-8 ml-3" src="/images/brands/linux.svg" alt={`${game.data.name} auf Linux`} title={`${game.data.name} auf Linux`} />)}</li>
47+
</ul>
48+
49+
<div class="flex flex-wrap">
50+
{
51+
game.data.steamID > 0 && (
52+
<div class="mb-4 mt-4 mr-4">
53+
<a class="flex items-center" href={`https://store.steampowered.com/app/${game.data.steamID}`} title={`${game.data.name} auf Steam`}>
54+
<img class="w-8" src="/images/brands/steam.svg" alt={`${game.data.name} auf Steam`} title={`${game.data.name} auf Steam`} />
55+
<span class="text-coolGray-500 text-lg m-2">Steam</span>
56+
</a>
57+
</div>
58+
)
59+
}
60+
</div>
61+
</div>
62+
<div class="w-full md:w-4/12 px-4">
63+
<div class="relative mx-auto md:mr-0 max-w-max">
64+
<a href={game.data.website} title={`Website von ${game.data.name}`}>
65+
<Image class="rounded-3xl" src={game.data.image} alt={`Spiel ${game.data.name}`} title={`Spiel ${game.data.name}`} />
66+
</a>
67+
</div>
68+
</div>
69+
</div>
70+
</div>
71+
</section>

0 commit comments

Comments
 (0)