Skip to content

Commit a356c53

Browse files
Use DOMjudge API to fetch images and team names for domlogo
1 parent 313916e commit a356c53

File tree

3 files changed

+120
-24
lines changed

3 files changed

+120
-24
lines changed

domlogo/domlogo.py

+103-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
#!/usr/bin/python3
1+
#!/usr/bin/env python3
2+
import subprocess
23

34
import PySimpleGUI as sg
45
import glob
@@ -9,6 +10,29 @@
910
import platform
1011
import yaml
1112

13+
14+
def download_image(image_type: str, entity_id: str, file: dict):
15+
href = file['href']
16+
filename = file['filename']
17+
photo_head = requests.head(f'{api_url}/{href}', auth=(user, passwd))
18+
etag = photo_head.headers['ETag']
19+
etag_file = f'domlogo-files/{image_type}s/{entity_id}.etag.txt'
20+
temp_file = f'domlogo-files/{image_type}s/temp-{entity_id}-{filename}'
21+
existing_etag = None
22+
if os.path.isfile(etag_file):
23+
with open(etag_file) as f:
24+
existing_etag = f.readline().strip()
25+
26+
if existing_etag != etag:
27+
print(f'Downloading and converting {image_type} for entity with ID {entity_id}...')
28+
with open(temp_file, 'wb') as f:
29+
f.write(requests.get(f'{api_url}/{href}', auth=(user, passwd)).content)
30+
31+
return True, temp_file, etag_file, etag
32+
33+
return False, None, None, None
34+
35+
1236
font = ('Roboto', 14)
1337
mono_font = ('Liberation Mono', 32)
1438
host = platform.node()
@@ -50,6 +74,73 @@
5074
break
5175
print(f'Using {api_url} as endpoint.')
5276

77+
print('Loading teams and organizations from API')
78+
teams = {team['id']: team for team in requests.get(f'{api_url}/teams', auth=(user, passwd)).json()}
79+
for team_id in teams:
80+
if 'display_name' not in teams[team_id]:
81+
teams[team_id]['display_name'] = teams[team_id]['name']
82+
organizations = {org['id']: org for org in requests.get(f'{api_url}/organizations', auth=(user, passwd)).json()}
83+
84+
85+
print('Downloading any new or changed logos and photos...')
86+
for organization in organizations.values():
87+
if 'logo' in organization:
88+
organization_id = organization['id']
89+
logo = organization['logo'][0]
90+
downloaded, downloaded_to, etag_file, etag = download_image('logo', organization_id, logo)
91+
if downloaded_to:
92+
# Convert to both 64x64 (for sidebar) and 160x160 (for overlay over photo)
93+
target = f'domlogo-files/logos/{organization_id}.png'
94+
command = f'convert {downloaded_to} -resize 64x64 -background none -gravity center -extent 64x64 {target}'
95+
os.system(command)
96+
97+
target = f'domlogo-files/logos/{organization_id}.160.png'
98+
command = f'convert {downloaded_to} -resize 160x160 -background none -gravity center -extent 160x160 {target}'
99+
os.system(command)
100+
101+
with open(etag_file, 'w') as f:
102+
f.write(etag)
103+
104+
os.unlink(downloaded_to)
105+
106+
for team in teams.values():
107+
if 'photo' in team and team['display_name'] != 'DOMjudge':
108+
team_id = team['id']
109+
photo = team['photo'][0]
110+
downloaded, downloaded_to, etag_file, etag = download_image('photo', team_id, photo)
111+
if downloaded_to:
112+
# First convert to a good known size because adding the annotation and logo assumes this
113+
intermediate_target = f'domlogo-files/photos/{team_id}-intermediate.png'
114+
command = f'convert {downloaded_to} -resize 1024x1024 -gravity center {intermediate_target}'
115+
os.system(command)
116+
117+
# Now add logo and team name. We use subprocess.run here to escape the team name
118+
target = f'domlogo-files/photos/{team_id}.png'
119+
organization_id = team['organization_id']
120+
logo_file = f'domlogo-files/logos/{organization_id}.png'
121+
command = [
122+
'convert',
123+
intermediate_target,
124+
'-fill', 'white',
125+
'-undercolor', '#00000080',
126+
'-gravity', 'south',
127+
'-font', 'Ubuntu',
128+
'-pointsize', '30',
129+
'-annotate', '+5+5', f' {team["display_name"]} ',
130+
logo_file,
131+
'-gravity', 'northeast',
132+
'-composite',
133+
target
134+
]
135+
136+
subprocess.run(command)
137+
138+
with open(etag_file, 'w') as f:
139+
f.write(etag)
140+
141+
os.unlink(downloaded_to)
142+
os.unlink(intermediate_target)
143+
53144
latest_logfile = max(glob.glob('output/log/judge.*-2.log'), key=os.path.getctime)
54145
print(f'Checking logfile {latest_logfile}')
55146
with open(latest_logfile, 'r') as logfile:
@@ -79,7 +170,7 @@
79170
team_id = submission_data['team_id']
80171
last_seen = (submission_id, judging_id, team_id)
81172
new_filename = f'domlogo-files/photos/{team_id}.png'
82-
if not team_id.isdigit():
173+
if not os.path.isfile(new_filename):
83174
new_filename = f'domlogo-files/photos/crew.png'
84175
team_image.update(filename=new_filename)
85176
metadata_text.update(f's{submission_id} / {submission_data["problem_id"]} / {submission_data["language_id"]}')
@@ -108,9 +199,16 @@
108199
color = 'DeepSkyBlue'
109200
for i in range(len(cache)-1):
110201
cache[i] = cache[i+1]
111-
if not tid.isdigit():
112-
tid = 'DOMjudge'
113-
cache[-1] = (f'domlogo-files/logos/{tid}.png', f's{sid}/j{jid}\n{verdict}', color, jid)
202+
organization_id = None
203+
if tid in teams:
204+
organization_id = teams[tid]['organization_id']
205+
organization_logo = 'domlogo-files/logos/DOMjudge.png'
206+
# Organization ID is null for internal teams so explicitly check for it
207+
if organization_id:
208+
potential_organization_logo = f'domlogo-files/logos/{organization_id}.png'
209+
if os.path.isfile(potential_organization_logo):
210+
organization_logo = potential_organization_logo
211+
cache[-1] = (organization_logo, f's{sid}/j{jid}\n{verdict}', color, jid)
114212
for i in range(len(cache)):
115213
previous_column[i][0].update(filename=cache[i][0])
116214
previous_column[i][1].update(cache[i][1])
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
1-
# Generating logos from a Contest Package
1+
# Preparing DOMlogo
22

3-
```bash
4-
for team in $(cat ~/wf2021/contests/finals/teams.json | jq -r '.[].id'); do
5-
echo $team
6-
ORG_ID=$(cat ~/wf2021/contests/finals/teams.json | jq -r ".[] | select(.id == \"$team\") | .organization_id")
7-
convert ~/wf2021/contests/finals/organizations/$ORG_ID/logo.png -resize 64x64 -background none -gravity center -extent 64x64 $team.png
8-
done
9-
```
3+
First, create the following files:
4+
- `images/logos/DOMjudge.png`, a 64x64 DOMjudge logo with transparent background.
5+
- `images/photos/crew.png`, an image with a width of 1024 (and any height) to show for teams without a photo.
6+
- `images/photos/idle.png`, an image with a width of 1024 (and any height) to show when the judgedaemon is idle.
7+
8+
Next, add the needed Python dependencies to the `lib` folder, within a folder called `python3.8`. You can copy this
9+
folder from a local machine and it should contain the `PySimpleGUI` and `requests` Python packages.
1010

11-
# Generating photos from a Contest package
11+
Optionally you can create a file `images/config.yaml` with something like:
12+
13+
```yaml
14+
host-bg-color: '#013370'
15+
```
1216
13-
```bash
14-
for team in $(cat ~/wf2021/contests/finals/teams.json | jq -r '.[].id'); do
15-
echo $team
16-
ORG_ID=$(cat ~/wf2021/contests/finals/teams.json | jq -r ".[] | select(.id == \"$team\") | .organization_id")
17-
TEAM_NAME=$(cat ~/wf2021/contests/finals/teams.json | jq -r ".[] | select(.id == \"$team\") | .display_name")
18-
convert ~/wf2021/contests/finals/teams/$team/photo.jpg -fill white -undercolor '#00000080' -gravity south -font 'Ubuntu' -pointsize 30 -annotate +5+5 " $TEAM_NAME " ~/wf2021/contests/finals/organizations/$ORG_ID/logo.160x160.png -gravity northeast -composite -resize 1024x1024 $team.png
19-
done
20-
```
17+
DOMlogo will use the DOMjudge API to download logos and photos for all teams, so no further configuration should be needed.

provision-contest/ansible/roles/domlogo/tasks/main.yml

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
---
22
# These tasks install domlogo
33

4-
- name: Install python3 modules for domlogo
4+
- name: Install python3 modules and imagemagick for domlogo
55
apt:
66
state: present
77
pkg:
88
- python3-tk
9+
- imagemagick
910

1011
- name: Install domlogo
1112
copy:
@@ -17,7 +18,7 @@
1718
loop:
1819
- domlogo
1920

20-
- name: Install domlogo
21+
- name: Install domlogo Python libraries
2122
synchronize:
2223
src: lib
2324
dest: /home/domjudge/.local/

0 commit comments

Comments
 (0)