|
1 |
| -#!/usr/bin/python3 |
| 1 | +#!/usr/bin/env python3 |
| 2 | +import subprocess |
2 | 3 |
|
3 | 4 | import PySimpleGUI as sg
|
4 | 5 | import glob
|
|
7 | 8 | import re
|
8 | 9 | import time
|
9 | 10 | import platform
|
| 11 | +import shlex |
10 | 12 | import yaml
|
11 | 13 |
|
| 14 | + |
| 15 | +def download_image(image_type: str, entity_id: str, file: dict): |
| 16 | + href = file['href'] |
| 17 | + filename = file['filename'] |
| 18 | + photo_head = requests.head(f'{api_url}/{href}', auth=(user, passwd)) |
| 19 | + etag = photo_head.headers['ETag'] |
| 20 | + etag_file = f'domlogo-files/{image_type}s/{entity_id}.etag.txt' |
| 21 | + temp_file = f'domlogo-files/{image_type}s/temp-{entity_id}-{filename}' |
| 22 | + existing_etag = None |
| 23 | + if os.path.isfile(etag_file): |
| 24 | + with open(etag_file) as f: |
| 25 | + existing_etag = f.readline().strip() |
| 26 | + |
| 27 | + if existing_etag != etag: |
| 28 | + print(f'Downloading and converting {image_type} for entity with ID {entity_id}...') |
| 29 | + with open(temp_file, 'wb') as f: |
| 30 | + f.write(requests.get(f'{api_url}/{href}', auth=(user, passwd)).content) |
| 31 | + |
| 32 | + return True, temp_file, etag_file, etag |
| 33 | + |
| 34 | + return False, None, None, None |
| 35 | + |
| 36 | + |
12 | 37 | font = ('Roboto', 14)
|
13 | 38 | mono_font = ('Liberation Mono', 32)
|
14 | 39 | host = platform.node()
|
|
50 | 75 | break
|
51 | 76 | print(f'Using {api_url} as endpoint.')
|
52 | 77 |
|
| 78 | +print('Loading teams and organizations from API') |
| 79 | +teams = {team['id']: team for team in requests.get(f'{api_url}/teams', auth=(user, passwd)).json()} |
| 80 | +for team_id in teams: |
| 81 | + if 'display_name' not in teams[team_id]: |
| 82 | + teams[team_id]['display_name'] = teams[team_id]['name'] |
| 83 | +organizations = {org['id']: org for org in requests.get(f'{api_url}/organizations', auth=(user, passwd)).json()} |
| 84 | + |
| 85 | + |
| 86 | +print('Downloading any new or changed logos and photos...') |
| 87 | +for organization in organizations.values(): |
| 88 | + if 'logo' in organization: |
| 89 | + organization_id = organization['id'] |
| 90 | + logo = organization['logo'][0] |
| 91 | + downloaded, downloaded_to, etag_file, etag = download_image('logo', organization_id, logo) |
| 92 | + if downloaded_to: |
| 93 | + # Convert to both 64x64 (for sidebar) and 160x160 (for overlay over photo) |
| 94 | + downloaded_to_escaped = shlex.quote(downloaded_to) |
| 95 | + target = shlex.quote(f'domlogo-files/logos/{organization_id}.png') |
| 96 | + command = f'convert {downloaded_to_escaped} -resize 64x64 -background none -gravity center -extent 64x64 {target}' |
| 97 | + os.system(command) |
| 98 | + |
| 99 | + target = shlex.quote(f'domlogo-files/logos/{organization_id}.160.png') |
| 100 | + command = f'convert {downloaded_to_escaped} -resize 160x160 -background none -gravity center -extent 160x160 {target}' |
| 101 | + os.system(command) |
| 102 | + |
| 103 | + with open(etag_file, 'w') as f: |
| 104 | + f.write(etag) |
| 105 | + |
| 106 | + os.unlink(downloaded_to) |
| 107 | + |
| 108 | +for team in teams.values(): |
| 109 | + if 'photo' in team and team['display_name'] != 'DOMjudge': |
| 110 | + team_id = team['id'] |
| 111 | + photo = team['photo'][0] |
| 112 | + downloaded, downloaded_to, etag_file, etag = download_image('photo', team_id, photo) |
| 113 | + if downloaded_to: |
| 114 | + # First convert to a good known size because adding the annotation and logo assumes this |
| 115 | + intermediate_target = f'domlogo-files/photos/{team_id}-intermediate.png' |
| 116 | + command = f'convert {downloaded_to} -resize 1024x1024 -gravity center {intermediate_target}' |
| 117 | + os.system(command) |
| 118 | + |
| 119 | + # Now add logo and team name. We use subprocess.run here to escape the team name |
| 120 | + target = f'domlogo-files/photos/{team_id}.png' |
| 121 | + organization_id = team['organization_id'] |
| 122 | + logo_file = f'domlogo-files/logos/{organization_id}.png' |
| 123 | + command = [ |
| 124 | + 'convert', |
| 125 | + intermediate_target, |
| 126 | + '-fill', 'white', |
| 127 | + '-undercolor', '#00000080', |
| 128 | + '-gravity', 'south', |
| 129 | + '-font', 'Ubuntu', |
| 130 | + '-pointsize', '30', |
| 131 | + '-annotate', '+5+5', f' {team["display_name"]} ', |
| 132 | + logo_file, |
| 133 | + '-gravity', 'northeast', |
| 134 | + '-composite', |
| 135 | + target |
| 136 | + ] |
| 137 | + |
| 138 | + subprocess.run(command) |
| 139 | + |
| 140 | + with open(etag_file, 'w') as f: |
| 141 | + f.write(etag) |
| 142 | + |
| 143 | + os.unlink(downloaded_to) |
| 144 | + os.unlink(intermediate_target) |
| 145 | + |
53 | 146 | latest_logfile = max(glob.glob('output/log/judge.*-2.log'), key=os.path.getctime)
|
54 | 147 | print(f'Checking logfile {latest_logfile}')
|
55 | 148 | with open(latest_logfile, 'r') as logfile:
|
|
79 | 172 | team_id = submission_data['team_id']
|
80 | 173 | last_seen = (submission_id, judging_id, team_id)
|
81 | 174 | new_filename = f'domlogo-files/photos/{team_id}.png'
|
82 |
| - if not team_id.isdigit(): |
| 175 | + if not os.path.isfile(new_filename): |
83 | 176 | new_filename = f'domlogo-files/photos/crew.png'
|
84 | 177 | team_image.update(filename=new_filename)
|
85 | 178 | metadata_text.update(f's{submission_id} / {submission_data["problem_id"]} / {submission_data["language_id"]}')
|
|
108 | 201 | color = 'DeepSkyBlue'
|
109 | 202 | for i in range(len(cache)-1):
|
110 | 203 | 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) |
| 204 | + organization_id = None |
| 205 | + if tid in teams: |
| 206 | + organization_id = teams[tid]['organization_id'] |
| 207 | + organization_logo = 'domlogo-files/logos/DOMjudge.png' |
| 208 | + # Organization ID is null for internal teams so explicitly check for it |
| 209 | + if organization_id: |
| 210 | + potential_organization_logo = f'domlogo-files/logos/{organization_id}.png' |
| 211 | + if os.path.isfile(potential_organization_logo): |
| 212 | + organization_logo = potential_organization_logo |
| 213 | + cache[-1] = (organization_logo, f's{sid}/j{jid}\n{verdict}', color, jid) |
114 | 214 | for i in range(len(cache)):
|
115 | 215 | previous_column[i][0].update(filename=cache[i][0])
|
116 | 216 | previous_column[i][1].update(cache[i][1])
|
|
0 commit comments