additional screenshots

This commit is contained in:
Trilarion
2021-10-26 21:49:07 +02:00
parent df80f70125
commit 364f8c8c46
205 changed files with 13650 additions and 13274 deletions

View File

@ -1,104 +1,81 @@
"""
Generates the static website
Generates the static website.
Uses Jinja2 (see https://jinja.palletsprojects.com/en/2.11.x/)
Uses
Sitemaps is not needed, only for large projects with lots of JavaScript und many undiscoverable pages.
- Jinja2 (https://jinja.palletsprojects.com/en/2.11.x/)
- Simple-DataTables (https://github.com/fiduswriter/Simple-DataTables)
Sitemap is not needed, only for large projects with lots of JavaScript und many pages that aren't discoverable.
"""
# TODO simple data table with columns: name (homepage as link), keywords (at least essential ones), inspiration, language, code license
# TODO table: state, os, license smaller
# TODO table: search window width larger
# TODO languages: ? at the end sort
# TODO categories: index and (number) no space in between, maybe span around index
# TODO categories: put more explanations on the category pages and the categories (number and short sentences)
# TODO categories: missing categories icons
# TODO categories: use icon-text as in https://bulma.io/documentation/elements/icon/ instead of is-large
# TODO too many spans, especially for text (maybe just plain text), also text with URLs inside is difficult (but why)
# TODO top level tab (search tab) goes to table
# TODO keywords: content, multiplayer replace by icons (open, commercial (dollar signs))
# TODO keywords: explain most common ones
# TODO most people only come to the main page, put more information there (direct links to genres, ...)
# TODO put more explanations on the category pages and the categories (number and short sentences)
# TODO general: most people only come to the main page, put more information there (direct links to genres, ...)
# TODO general: if the only change is a change in last updated, do not change it (we can probably check with git diff for it) or checksums
# TODO general: minimize tag usage: jinja template optimization for line breaks and indention and minimal amount of spaces (and size of files) and minimal amount of repetition of tags
# TODO general: too many spans, especially for text (maybe just plain text), also text with URLs inside is difficult (but why)
# TODO general: replace or remove @notices in entries
# TODO general: check singular, plural (game, entries, items) although support is already quite good for that
# TODO general: better link replacements
# TODO general: update Bulma (already at latest version)
# TODO general: meta/title+description tag
# TODO general: meta description of the pages, fill them
# TODO general: style URLs (Github, Wikipedia, Internet archive, SourceForge, ...)
# TODO general: optimize layout for mobile view (quite good already)
# TODO general: meta titles for all pages, make them nice because they appear in search results! (https://www.contentpowered.com/blog/good-ctr-search-console/)
# TODO general: <a> rel attribute https://www.w3schools.com/TAGS/att_a_rel.asp
# TODO text description automaticall generated from keywords, state, and technical informations for example: First-person action shooter written in C++, inspired by ... but inactive for 7 years.
# TODO statistics should have disclaimer (warning or info box) about accuracy with link to contribute guidelines
# TODO game move developer to technical information and maybe rename technical information to details
# TODO game engines should be sorted with frameworks/tools, not with games (they aren't games or are they?)
# TODO if the only change is a change in last updated, do not change it (we can probably check with git diff for it) or checksums
# TODO minimize tag usage: jinja template optimization for line breaks and indention and minimal amount of spaces (and size of files) and minimal amount of repetition of tags
# TODO contribute.html add content
# TODO more icons - missing categories
# TODO replace or remove @notices in entries (maybe different entries format)
# TODO everywhere: singular, plural (game, entries, items)
# TODO games: platform icons and mature, state larger (but maybe not on mobile)
# TODO games: platform information larger printed, keyword tags underlined to indicate links
# TODO devs: icons mark as links (how? ask on ux.stackexchange.com?)
# TODO everywhere: better link replacements
# TODO game: first homepage link bold
# TODO idea: text description automatically generate from keywords, state, and technical informations for example: First-person action shooter written in C++, inspired by ... but inactive for 7 years.
# TODO statistics: should have disclaimer (warning or info box) about accuracy with link to contribute guidelines
# TODO statistics: better and more statistics with links where possible
# TODO statistics: with nice graphics (pie charts in SVG) with matplotlib
# TODO statistics: get it from common statistics generator
# TODO frameworks: icons for frameworks/libraries/tools
# TODO filter by category: icons too large (overlapping)
# TODO games: developer details is too small to click on some devices, maybe details is-size6 instead
# TODO games: platform icons and mature, state make them all larger (but maybe not on mobile)
# TODO games: keyword tags underlined to indicate links
# TODO games: first homepage link bold
# TODO games: @see-home/@see-download/@add (ignore or replace?)
# TODO games: top 50 list from Github via their stars with download links (add to entries) and with screenshot
# TODO games: add screenshot ability (add screenshot to database, at least for top 50)
# TODO games: screenshot render directly with make_img
# TODO games: order: homepage, inspiration, download, developer
# TODO update Bulma
# TODO everywhere: meta/title tag
# TODO everywhere: style URLs (Github, Wikipedia, Internet archive, SourceForge, ...)
# TODO inspirations: icon full lamp (not contained in icomoon.io)
# TODO games: developers if more than a single line (collapse, expand?) without JS? (https://stackoverflow.com/questions/41220717/collapse-without-javascript, https://codeconvey.com/html-expand-collapse-text-without-javascript/)
# TODO games: technical info (collapse on click)
# TODO games: link to dependencies (either if existing or if url)
# TODO games: javascript table
# TODO games: repositories comments have too much space after( and before )
# TODO games: show or not show info?? show only first line of info (which should be a short description or make it a field (only for popular ones), otherwise rely on keywords)
# TODO games: cross-references for code dependencies if included
# TODO mobile view: optimize layout for mobile view
# TODO languages: C# redirects to C
# TODO keywords: explain most common ones
# TODO categories: use icon-text as in https://bulma.io/documentation/elements/icon/ instead of is-large
# TODO meta description of the pages, fill them
# TODO info: show only first line of info (which should be a short description or make it a field (only for popular ones), otherwise rely on keywords)
# TODO contribute: contribute.html add content
# TODO devs: icons mark as links (how? ask on ux.stackexchange.com?)
# TODO developers: anchors to non-latin written developers do not work (chinese names have simply xxxxx)
# TODO SEO optimizations, google search ...
# TODO sitemap
# TODO Google search console
# TODO <a> rel attribute https://www.w3schools.com/TAGS/att_a_rel.asp
# TODO frameworks: icons for frameworks/libraries/tools
# TODO filter by category: icons too large (overlapping)
# TODO top50: only those that are active (and mature? and remove python of the week maybe ignore list)
# TODO inspirations: icon full lamp (not contained in icomoon.io)
# TODO inspirations: if included in the database, link instead to game (cross-reference)
# TODO cross-references for code dependencies if included
# TODO add dynamic table (what to include)
# TODO meta titles for all pages, make them nice because they appear in search results! (https://www.contentpowered.com/blog/good-ctr-search-console/)
import os
import shutil
import math
@ -180,8 +157,8 @@ genre_icon_map = {
'Library': 'library'
}
# cross-references to the langue pages
code_language_references = {l: games_by_language_path[:-1] + ['{}#{}'.format(games_by_language_path[-1], osg.canonical_name(l))] for l in c.known_languages}
# cross-references to the language pages
code_language_references = {language: games_by_language_path[:-1] + ['{}#{}'.format(games_by_language_path[-1], language.lower())] for language in c.known_languages}
# map of internal non game names to display names (which are in plural)
non_game_category_names = {
@ -194,6 +171,9 @@ non_game_category_names = {
# we check the output html structure every time
html5parser = html5lib.HTMLParser(strict=True)
# file hashes for detecting changes
previous_files = {}
# pluralization (mostly with s, but there are a few exceptions)
plurals = {k: k+'s' for k in ('Assets license', 'Contact', 'Code language', 'Code license', 'Developer', 'Download', 'Inspiration', 'Game', 'Keyword', 'Home', 'Homepage', 'Organization', 'Platform', 'Tag')}
for k in ('Media', 'Play', 'Play online', 'State'):
@ -204,7 +184,7 @@ for k in ('Code repository', 'Code dependency'):
def get_plural_or_singular(name, amount):
"""
Gets the pluarization of a known word for a known amount. Helper function.
Gets the pluralization of a known word for a known amount. Helper function.
"""
if not name in plurals.keys():
raise RuntimeError('"{}" not a known singular!'.format(name))
@ -213,6 +193,18 @@ def get_plural_or_singular(name, amount):
return plurals[name]
def file_hash(text):
"""
Removes the last updated ... line from html file and the data line from svg and then computes a hash.
:param text:
:return:
"""
text = text.split('\n')
text = [t for t in text if not any(t.startswith(prefix) for prefix in (' This website is built ', ' <dc:date>'))]
text = ''.join(text)
return hash(text)
def raise_helper(msg):
"""
Helper, because raise in lambda expression is a bit cumbersome.
@ -227,21 +219,29 @@ def write(text, file):
:param text:
:param file:
"""
# validate text
# output file
if isinstance(file, str):
file = [file]
try:
html5parser.parse(text)
except Exception as e:
utils.write_text(os.path.join(c.web_path, 'invalid.html'), text) # for further checking with https://validator.w3.org/
print('problem with file {}, see invalid.html'.format(file))
raise RuntimeError(e)
# output file
file = os.path.join(c.web_path, *file)
# check file hash and use previous version
if file in previous_files and previous_files[file]['hash'] == file_hash(text):
# no significant change, use previous version instead
text = previous_files[file]['text']
else:
# validate text
try:
html5parser.parse(text)
except Exception as e:
utils.write_text(os.path.join(c.web_path, 'invalid.html'), text) # for further checking with https://validator.w3.org/
print('problem with file {}, see invalid.html'.format(file))
raise RuntimeError(e)
# create output directory if necessary
containing_dir = os.path.dirname(file)
if not os.path.isdir(containing_dir):
os.mkdir(containing_dir)
# write text
utils.write_text(file, text)
@ -844,7 +844,7 @@ def add_screenshot_information(entries):
:param entries:
:return:
"""
d """
# read screenshot information
overview = osg.read_screenshots_overview()
@ -853,8 +853,8 @@ def add_screenshot_information(entries):
# get screenshots entry
name = osg.canonical_name(entry['Title']) # TODO should be stored upon loading I guess
screenshots = overview.get(name, {})
screenshots = [{'width': s[0], 'height': s[1], 'url': s[2], 'file': ['screenshots', '{}_{:02d}.jpg'.format(name, id)]} for id, s in screenshots.items()]
if screenshots: # TODO url None should be treated here or in the jinja template
screenshots = [{'width': s[0], 'height': s[1], 'url': s[2] if s[2] and not s[2].startswith('!') else None, 'file': ['screenshots', '{}_{:02d}.jpg'.format(name, id)]} for id, s in screenshots.items()]
if screenshots: # TODO inline from the template to just have an element that is rendered for screenshot (make_image missing for that still)
entry['screenshots'] = screenshots
@ -869,15 +869,15 @@ def create_table_json_data(entries):
db = {'headings': ['Title', 'State', 'Tags', 'Platform', 'Language', 'License']}
data = []
for entry in entries:
title = '<a href="{}">{}</a> (<a href="{}">Entry</a>)'.format(entry['Home'][0], entry['Title'], url_to([], entry['href']))
title = '<a href="{}" class="has-text-weight-semibold">{}</a> <a href="{}"><i class="icon-new-tab"></i></a>'.format(url_to([], entry['href']), entry['Title'], entry['Home'][0])
state = ', '.join(entry['State'])
tags = entry['Keyword']
tags = [tag for tag in tags if tag in c.recommended_keywords]
tags = [tag for tag in tags if tag in c.interesting_keywords]
tags = ', '.join(tags)
platform = entry.get('Platform', ['-'])
platform = ', '.join(platform)
language = ', '.join(entry['Code language'])
license = [x[-1] for x in entry['Code license']]
license = [x[-1] for x in entry['Code license']] # undo license links again
license = ', '.join(license)
data.append([title, state, tags, platform, language, license])
data.sort(key=lambda x: str.casefold(x[0]))
@ -919,7 +919,7 @@ def generate(entries, inspirations, developers):
convert_entries(non_games, inspirations, developers)
# set external links up
add_license_links_to_entries(games)
add_license_links_to_entries(entries)
# create entries.json for the table
create_table_json_data(entries)
@ -1002,7 +1002,14 @@ def generate(entries, inspirations, developers):
# build-systems
build_systems_stat = stat.get_build_systems(entries)
build_systems_stat = stat.truncate_stats(build_systems_stat, 10)
stat.export_pie_chart([stat for stat in build_systems_stat if stat[0] != 'N/A'], os.path.join(c.web_path, 'statistics', 'build_systems.svg'))
file = os.path.join(c.web_path, 'statistics', 'build_systems.svg')
stat.export_pie_chart([statistic for statistic in build_systems_stat if statistic[0] != 'N/A'], file)
# read back and check if identical with old version (up to date)
text = utils.read_text(file)
if file in previous_files and previous_files[file]['hash'] == file_hash(text):
# use old version instead
text = previous_files[file]['text']
utils.write_text(file, text)
section = {
'title': 'Build system',
'items': ['{} ({})'.format(*item) for item in build_systems_stat],
@ -1188,6 +1195,15 @@ if __name__ == "__main__":
start_time = time.process_time()
# create dictionary of file hashes
print('estimate file hashes')
for dirpath, dirnames, filenames in os.walk(c.web_path):
for file in filenames:
if any(file.endswith(ext) for ext in ('.html', '.svg')):
file = os.path.join(dirpath, file)
text = utils.read_text(file)
previous_files[file] = {'hash': file_hash(text), 'text': text}
# clean the output directory
print('clean current static website')
utils.recreate_directory(c.web_path)

View File

@ -30,7 +30,7 @@
{#- screenshots if available -#}
{%- if 'screenshots' in item%}<nav class="level">
{%- for screenshot in item['screenshots'] -%}
<div class="level-item"><a href="{{ screenshot['url'] }}"><img src="{{ base['url_to'](screenshot['file']) }}" width="{{ screenshot['width'] }}" height="{{ screenshot['height'] }}" alt=""></a></div>
<div class="level-item">{% if screenshot['url'] %}<a href="{{ screenshot['url'] }}">{% endif %}<img src="{{ base['url_to'](screenshot['file']) }}" width="{{ screenshot['width'] }}" height="{{ screenshot['height'] }}" alt="">{% if screenshot['url'] %}</a>{% endif %}</div>
{%- endfor -%}
</nav>{% endif -%}
{#- technical fields -#}

View File

@ -7,13 +7,13 @@
<p class="subtitle is-6">Sortable and searchable.</p>
</div>
</div>
<table class="table is-narrow is-hoverable"></table>
<table class="table is-narrow is-hoverable is-size-6"></table>
</div>
<script>
fetch("data/entries.json").then(response => response.json()).then(data => {
let table = new simpleDatatables.DataTable(".table", {
perPage: 50,
perPageSelect: [30, 50, 100],
perPage: 30,
perPageSelect: [10, 30, 50],
footer: true,
data: {
headings: data["headings"],
@ -22,7 +22,12 @@
});
table.on('datatable.init', function(args) {
// sort by first column
table.columns().sort(0);
// use the urls search part for the search input field of the table
if (window.location.search) {
document.getElementsByClassName("dataTable-input").item(0).value = window.location.search.substring(1).replace("+", " ");
}
});
})
</script>