Add publisher artwork to GitHub APK source entries

Include curated app images and summaries, owner avatars and social banners for topic discovery, and fixture coverage for artwork preservation.

Co-Authored-By: GPT-6 Astra <noreply@openai.com>
This commit is contained in:
saphidandGPT-6 Astra committed 2026-09-28 21:24:55 +10:00
1 parent 113216cc0e
commit 41684e2d90
9 files changed
+225 -17

No files matched your search

+25
View File
@@ -42,3 +42,28 @@ Final verification:
- Final artifact: docs/apk-sources.md plus two source modules, a private HTTPS
helper, curated JSON, recorded fixtures and tests. Evidence scripts/logs stay
in .claude; research HTML and APK cache are explicitly ignored there.
## Artwork follow-up
Added curated icon/images metadata and plain-language summaries. Icons use
publisher repository assets pinned to inspected commits. Open Brush's banner
is its README image; three screenshots are from its README-linked Steam page.
SuperTux's banner/screenshot is the upstream gameplay preview in the port's
README, not a Quest capture. hello_xr has its actual Vulkan launcher icon and
repository social banner; no real screenshot was found in its repository or
README, so screenshots stays empty rather than mislabeling branding.
Topic search uses owner.avatar_url and the requested GitHub social-preview
pattern, retaining curated artwork when a curated app is discovered by topic.
Unknown repository details use GitHub's owner.png avatar endpoint and the same
social banner without an extra API request. Existing itch cover behavior is
unchanged; tests now assert icon/banner equality and empty screenshots because
the recorded RSS provides no separate screenshots.
Validation: all nine distinct curated artwork URLs returned HTTP 200, image
Content-Type and image magic. Of six topic artwork URLs, five returned images
and LWJGL's social preview returned HTTP 429. Recorded in
`tests/fixtures/more_sources/artwork-check.json`; no repeated retry.
`python3 -m unittest discover -s tests`: 176 passed in 5.879s, real exit 0.
`git diff --check`: exit 0. No UI rendering/headset testing or independent
review; parent retains integration/review, and delegation remains prohibited.
+2 -2
View File
@@ -1,5 +1,5 @@
..............................................................................................................................................................................
................................................................................................................................................................................
----------------------------------------------------------------------
Ran 174 tests in 5.569s
Ran 176 tests in 5.879s
OK
+9 -2
View File
@@ -60,8 +60,15 @@ does not suppress the other at the aggregator level. Queries filter the current
feed window locally: this is not an exhaustive historical itch search. Only
explicit zero-price Android entries are returned. Covers are exposed in
`images`; absent screenshots, APK version, ABI and minimum SDK stay unknown.
GitHub's release metadata has no standard app artwork field, so artwork stays
empty rather than presenting a repository-owner avatar as an app icon. VR is
Curated GitHub entries include publisher artwork and plain-language summaries.
Repository image URLs are pinned to inspected commits. Open Brush screenshots
come from its README-linked Steam listing; SuperTux uses the upstream gameplay
preview embedded in the port's README (not a headset capture). The hello_xr
sample has a launcher icon and GitHub social banner; no published screenshot
was found in the inspected repository/README, so its screenshot list is empty.
Uncurated topic results use the owner's avatar and GitHub's repository social
preview. These are repository placeholders, not app screenshots. Itch's recorded
RSS includes only covers, so screenshot lists remain empty without page scraping. VR is
based on curated evidence or a VR-specific feed/topic, not a compatibility claim.
Downloads stream to unique temporary files, require an APK manifest entry,
+8
View File
@@ -13,3 +13,11 @@ values are unchanged. No token, cookies or signed download URL is included.
The synthetic ZIP in tests is only a transport/integrity fixture, not an
installable APK. Actual APK parsing was verified separately on the downloaded
Khronos Vulkan sample; see docs/apk-sources.md.
Artwork follow-up: `topic.json` now retains `owner.avatar_url` from authenticated
repository API reads. `artwork-check.json` records HTTPS response status,
Content-Type and image magic checks for all curated URLs and three topic
results. All curated URLs returned real images; LWJGL's social preview returned
HTTP 429. This fixture is evidence of a point-in-time check, not an uptime test.
Open Brush screenshots came from the Steam appdetails response for app 1634870,
linked by its README. SuperTux's README links the recorded upstream screenshot.
+90
View File
@@ -0,0 +1,90 @@
[
{
"url": "https://avatars.githubusercontent.com/u/2757344?v=4",
"status": 200,
"content_type": "image/png",
"image": true
},
{
"url": "https://avatars.githubusercontent.com/u/784805?v=4",
"status": 200,
"content_type": "image/png",
"image": true
},
{
"url": "https://avatars.githubusercontent.com/u/94376830?v=4",
"status": 200,
"content_type": "image/png",
"image": true
},
{
"url": "https://opengraph.githubassets.com/1/KhronosGroup/OpenXR-SDK-Source",
"status": 200,
"content_type": "image/png",
"image": true
},
{
"url": "https://opengraph.githubassets.com/1/LWJGL/lwjgl3",
"error": "HTTP Error 429: Too Many Requests"
},
{
"url": "https://opengraph.githubassets.com/1/bjornbytes/lovr",
"status": 200,
"content_type": "image/png",
"image": true
},
{
"url": "https://opengraph.githubassets.com/1/sahibzada-allahyar/YC-Killer",
"status": 200,
"content_type": "image/png",
"image": true
},
{
"url": "https://raw.githubusercontent.com/KhronosGroup/OpenXR-SDK-Source/3ed64d0f9bb680f24b80a085091e5c8fab38f7b7/src/tests/hello_xr/android_resources/vulkan/mipmap-xxxhdpi/ic_helloxr_launcher.png",
"status": 200,
"content_type": "image/png",
"image": true
},
{
"url": "https://raw.githubusercontent.com/SgtBilko76/SuperTux-3D/1955493ee6f1000e048c58db40d4904df827210e/data/images/engine/icons/supertux-256x256.png",
"status": 200,
"content_type": "image/png",
"image": true
},
{
"url": "https://raw.githubusercontent.com/icosa-foundation/open-brush/56acbce831c7e9f257bfee9e21853da99773787b/Assets/Resources/DefaultImages/OpenBrushLogo.png",
"status": 200,
"content_type": "image/png",
"image": true
},
{
"url": "https://raw.githubusercontent.com/icosa-foundation/open-brush/56acbce831c7e9f257bfee9e21853da99773787b/open-brush.png",
"status": 200,
"content_type": "image/png",
"image": true
},
{
"url": "https://shared.akamai.steamstatic.com/store_item_assets/steam/apps/1634870/ss_0a9c208e26a43cf34879c2ca361d4c8f18af8cba.1920x1080.jpg",
"status": 200,
"content_type": "image/jpeg",
"image": true
},
{
"url": "https://shared.akamai.steamstatic.com/store_item_assets/steam/apps/1634870/ss_19b25b86ef55c0d8769a65135d60eaae8fa40553.1920x1080.jpg",
"status": 200,
"content_type": "image/jpeg",
"image": true
},
{
"url": "https://shared.akamai.steamstatic.com/store_item_assets/steam/apps/1634870/ss_785ea37d63378146dfe0f0ffa3f1d5c155ca978f.1920x1080.jpg",
"status": 200,
"content_type": "image/jpeg",
"image": true
},
{
"url": "https://www.supertux.org/images/0_7_0/github_preview.png",
"status": 200,
"content_type": "image/png",
"image": true
}
]
+12 -3
View File
@@ -3,17 +3,26 @@
{
"full_name": "LWJGL/lwjgl3",
"name": "lwjgl3",
"description": "LWJGL is a Java library that enables cross-platform access to popular native APIs useful in the development of graphics (OpenGL, Vulkan, bgfx), audio (OpenAL, Opus), parallel computing (OpenCL, CUDA) and XR (OpenVR, LibOVR, OpenXR) applications."
"description": "LWJGL is a Java library that enables cross-platform access to popular native APIs useful in the development of graphics (OpenGL, Vulkan, bgfx), audio (OpenAL, Opus), parallel computing (OpenCL, CUDA) and XR (OpenVR, LibOVR, OpenXR) applications.",
"owner": {
"avatar_url": "https://avatars.githubusercontent.com/u/2757344?v=4"
}
},
{
"full_name": "sahibzada-allahyar/YC-Killer",
"name": "YC-Killer",
"description": "A library of enterprise-grade AI agents designed to democratize artificial intelligence and provide free, open-source alternatives to overvalued Y Combinator startups."
"description": "A library of enterprise-grade AI agents designed to democratize artificial intelligence and provide free, open-source alternatives to overvalued Y Combinator startups.",
"owner": {
"avatar_url": "https://avatars.githubusercontent.com/u/94376830?v=4"
}
},
{
"full_name": "bjornbytes/lovr",
"name": "lovr",
"description": "Lua Virtual Reality Framework"
"description": "Lua Virtual Reality Framework",
"owner": {
"avatar_url": "https://avatars.githubusercontent.com/u/784805?v=4"
}
}
]
}
+40
View File
@@ -23,6 +23,33 @@ class PublisherSources(unittest.TestCase):
self.assertEqual(github.search(github.sources()[0], 'hello')[0]['id'], 'KhronosGroup/OpenXR-SDK-Source')
self.assertEqual(github.search(github.sources()[0], '', 0), [])
def test_curated_artwork_has_recorded_image_evidence(self):
evidence = {r['url']: r for r in json.loads((FIX / 'artwork-check.json').read_text())}
entries = github.search(github.sources()[0], '')
self.assertEqual(len(entries), 3)
for entry in entries:
self.assertTrue(entry['summary'])
images = entry['images']
self.assertEqual(entry['icon'], images['icon'])
for url in [images['icon'], images['banner']] + images['screenshots']:
self.assertTrue(url.startswith('https://'))
self.assertEqual(evidence[url]['status'], 200)
self.assertTrue(evidence[url]['image'])
self.assertTrue(entries[1]['images']['screenshots'])
self.assertTrue(entries[2]['images']['screenshots'])
def test_topic_keeps_curated_artwork(self):
curated = github._curated()[1]
repo = {'full_name': curated['repo'], 'name': 'open-brush',
'owner': {'avatar_url': 'https://avatars.githubusercontent.com/u/1'}}
with patch.object(github, '_api', return_value={'items': [repo]}):
entry = github.search(github.sources()[0], 'topic:openxr')[0]
self.assertEqual(entry['images'], curated['images'])
unknown = github.details(github.sources()[0], 'unknown/project')
self.assertEqual(unknown['icon'], 'https://github.com/unknown.png')
self.assertEqual(unknown['images']['banner'],
'https://opengraph.githubassets.com/1/unknown/project')
def test_real_releases(self):
for key, repo in [('khronos', 'KhronosGroup/OpenXR-SDK-Source'),
('brush', 'icosa-foundation/open-brush'), ('tux', 'SgtBilko76/SuperTux-3D')]:
@@ -31,6 +58,9 @@ class PublisherSources(unittest.TestCase):
self.assertTrue(e['downloadable'])
self.assertTrue(e['versions'][0]['name'].endswith('.apk'))
self.assertIsNone(e['version_code'])
search_entry = github.search(github.sources()[0], repo)[0]
self.assertEqual(e['images'], search_entry['images'])
self.assertEqual(e['icon'], e['images']['icon'])
with self.assertRaises(SourceError):
github.download(github.sources()[0], repo, 123)
@@ -40,6 +70,12 @@ class PublisherSources(unittest.TestCase):
entries = github.search(github.sources()[0], 'topic:openxr')
self.assertTrue(entries)
self.assertTrue(any(not e['downloadable'] for e in entries))
for entry, repo in zip(entries, data['items']):
self.assertEqual(entry['icon'], repo['owner']['avatar_url'])
self.assertEqual(entry['images']['icon'], entry['icon'])
self.assertEqual(entry['images']['banner'],
'https://opengraph.githubassets.com/1/' + repo['full_name'])
self.assertEqual(entry['images']['screenshots'], [])
self.assertFalse(github.details(github.sources()[0], 'unknown/project')['downloadable'])
with self.assertRaises(SourceError):
github.search(github.sources()[0], 'topic:piracy')
@@ -51,6 +87,10 @@ class PublisherSources(unittest.TestCase):
e = itch.details(itch.sources()[0], entries[0]['id'])
self.assertTrue(e['vr'])
self.assertTrue(e['images']['banner'])
for item in entries:
self.assertEqual(item['icon'], item['images']['icon'])
self.assertEqual(item['icon'], item['images']['banner'])
self.assertEqual(item['images']['screenshots'], [])
self.assertFalse(e['downloadable'])
self.assertEqual(itch.search(itch.sources()[0], 'off nominal')[0]['name'], 'Off Nominal')
with self.assertRaises(SourceError):
+9 -4
View File
@@ -31,9 +31,14 @@ def _api(path):
def _entry(source, c, approved=True):
artwork = c.get('images') or {}
icon = artwork.get('icon') or c.get('icon') or 'https://github.com/' + c['repo'].split('/')[0] + '.png'
images = {'icon': icon,
'banner': artwork.get('banner') or 'https://opengraph.githubassets.com/1/' + c['repo'],
'screenshots': list(artwork.get('screenshots') or [])}
return {'source': source['id'], 'id': c['repo'], 'package': None,
'name': c['name'], 'summary': c.get('summary') or '', 'icon': None,
'images': {'icon': None, 'banner': None, 'screenshots': []},
'name': c['name'], 'summary': c.get('summary') or '', 'icon': icon,
'images': images,
'page': 'https://github.com/' + c['repo'], 'version': None, 'version_code': None,
'min_sdk': None, 'abis': None, 'vr': c.get('vr'), 'size': None,
'free': True if approved else None, 'license': c.get('license'), 'updated': None,
@@ -55,8 +60,8 @@ def search(source, query, limit=50):
for repo in data.get('items', []):
c = curated.get(repo['full_name'].lower())
entry = _entry(source, c or {'repo': repo['full_name'], 'name': repo['name'],
'summary': repo.get('description'), 'vr': True}, bool(c))
# Repository owners' avatars are not app artwork.
'summary': repo.get('description'), 'vr': True,
'icon': (repo.get('owner') or {}).get('avatar_url')}, bool(c))
out.append(entry)
return out
words = query.lower().split()
+30 -6
View File
@@ -2,28 +2,52 @@
{
"repo": "KhronosGroup/OpenXR-SDK-Source",
"name": "hello_xr",
"summary": "Khronos OpenXR sample (Vulkan and OpenGL ES)",
"summary": "A simple VR scene for checking that OpenXR graphics and controllers work.",
"license": "Apache-2.0",
"vr": true,
"asset_pattern": "hello_xr-Vulkan-*.apk",
"allow_prerelease": false
"allow_prerelease": false,
"images": {
"icon": "https://raw.githubusercontent.com/KhronosGroup/OpenXR-SDK-Source/3ed64d0f9bb680f24b80a085091e5c8fab38f7b7/src/tests/hello_xr/android_resources/vulkan/mipmap-xxxhdpi/ic_helloxr_launcher.png",
"banner": "https://opengraph.githubassets.com/1/KhronosGroup/OpenXR-SDK-Source",
"screenshots": []
},
"icon": "https://raw.githubusercontent.com/KhronosGroup/OpenXR-SDK-Source/3ed64d0f9bb680f24b80a085091e5c8fab38f7b7/src/tests/hello_xr/android_resources/vulkan/mipmap-xxxhdpi/ic_helloxr_launcher.png"
},
{
"repo": "icosa-foundation/open-brush",
"name": "Open Brush",
"summary": "Open source spatial painting",
"summary": "Paint in the air and create colorful 3D artwork in VR.",
"license": "Apache-2.0",
"vr": true,
"asset_pattern": "*Quest*.apk",
"allow_prerelease": true
"allow_prerelease": true,
"images": {
"icon": "https://raw.githubusercontent.com/icosa-foundation/open-brush/56acbce831c7e9f257bfee9e21853da99773787b/Assets/Resources/DefaultImages/OpenBrushLogo.png",
"banner": "https://raw.githubusercontent.com/icosa-foundation/open-brush/56acbce831c7e9f257bfee9e21853da99773787b/open-brush.png",
"screenshots": [
"https://shared.akamai.steamstatic.com/store_item_assets/steam/apps/1634870/ss_785ea37d63378146dfe0f0ffa3f1d5c155ca978f.1920x1080.jpg",
"https://shared.akamai.steamstatic.com/store_item_assets/steam/apps/1634870/ss_0a9c208e26a43cf34879c2ca361d4c8f18af8cba.1920x1080.jpg",
"https://shared.akamai.steamstatic.com/store_item_assets/steam/apps/1634870/ss_19b25b86ef55c0d8769a65135d60eaae8fa40553.1920x1080.jpg"
]
},
"icon": "https://raw.githubusercontent.com/icosa-foundation/open-brush/56acbce831c7e9f257bfee9e21853da99773787b/Assets/Resources/DefaultImages/OpenBrushLogo.png"
},
{
"repo": "SgtBilko76/SuperTux-3D",
"name": "SuperTux 3D",
"summary": "OpenXR stereoscopic platform game for Quest and PICO",
"summary": "Run and jump through Tux’s platform adventure on a layered 3D screen in VR.",
"license": "GPL-3.0",
"vr": true,
"asset_pattern": "*Quest*.apk",
"allow_prerelease": true
"allow_prerelease": true,
"images": {
"icon": "https://raw.githubusercontent.com/SgtBilko76/SuperTux-3D/1955493ee6f1000e048c58db40d4904df827210e/data/images/engine/icons/supertux-256x256.png",
"banner": "https://www.supertux.org/images/0_7_0/github_preview.png",
"screenshots": [
"https://www.supertux.org/images/0_7_0/github_preview.png"
]
},
"icon": "https://raw.githubusercontent.com/SgtBilko76/SuperTux-3D/1955493ee6f1000e048c58db40d4904df827210e/data/images/engine/icons/supertux-256x256.png"
}
]