3 Angajamente 09c1c44b82 ... 673eb3a50a

Autor SHA1 Permisiunea de a trimite mesaje. Dacă este dezactivată, utilizatorul nu va putea trimite nici un fel de mesaj Data
  raylu 673eb3a50a cf-worker: kit availability 2 săptămâni în urmă
  raylu 6cc8f0d4f1 plan: estimate STL travel time 2 săptămâni în urmă
  raylu 09c1c44b82 plan: estimate STL travel time 2 săptămâni în urmă
7 a modificat fișierele cu 122 adăugiri și 25 ștergeri
  1. 1 0
      cf-worker/.gitignore
  2. 106 22
      cf-worker/src/entry.py
  3. 1 0
      cf-worker/src/kit.html
  4. 5 1
      cf-worker/wrangler.toml
  5. 1 1
      ts/plan.ts
  6. 1 1
      www/shipbuilding.html
  7. 7 0
      www/style.css

+ 1 - 0
cf-worker/.gitignore

@@ -1,4 +1,5 @@
 .dev.vars
 .venv-workers/
+.wrangler/
 node_modules/
 python_modules/

+ 106 - 22
cf-worker/src/entry.py

@@ -1,9 +1,13 @@
 from __future__ import annotations
 
+import collections
 import datetime
+import pathlib
+import traceback
 import typing
 import urllib.parse
 
+from js import console # pyright: ignore[reportMissingImports]
 from workers import Response, WorkerEntrypoint, fetch
 
 if typing.TYPE_CHECKING:
@@ -14,28 +18,108 @@ class Default(WorkerEntrypoint):
 		url = urllib.parse.urlparse(request.url)
 		match url.path:
 			case '/gy-694c':
-				return await gy_694c(self.env.punoted_api_key)
+				return await self.gy_694c()
+			case '/kit':
+				return await self.kit()
 			case _:
 				return Response('404', status=404)
 
-async def gy_694c(punoted_api_key: str) -> Response:
-	headers = {'X-Data-Token': punoted_api_key}
-	response = await fetch('https://api.punoted.net/v1/storages/user', headers=headers)
-	storages = await response.json() # pyright: ignore[reportGeneralTypeIssues]
-	(storage,) = (s for s in storages if s['Location'] == 'GY-694c')
-	tio = 0
-	for item in storage['StorageItems']:
-		if item['MaterialTicker'] == 'TIO':
-			tio = item['MaterialAmount']
-	last_update = datetime.datetime.fromtimestamp(storage['LastUpdatedEpochMs'] / 1000)
-	delta = datetime.datetime.now() - last_update
-
-	response = await fetch('https://api.punoted.net/v1/production/user/burn?location=gy-694c', headers=headers)
-	production = await response.json() # pyright: ignore[reportGeneralTypeIssues]
-	(tio_production,) = (p for p in production['GY-694c'] if p['MaterialTicker'] == 'TIO')
-	daily_production = tio_production['Production']
-
-	estimated = int(tio + daily_production * (delta.total_seconds() / 60 / 60 / 24))
-	return Response(f'raylu had {tio} TIO in storage as of {last_update} UTC ({delta.total_seconds() / 60 / 60:.1f} hours ago)\n'
-			f'raylu is producing {daily_production}/day\n'
-			f'estimated TIO in inventory: {estimated}\n')
+	async def gy_694c(self) -> Response:
+		headers = {'X-Data-Token': self.env.punoted_api_key}
+		response = await fetch('https://api.punoted.net/v1/storages/user', headers=headers)
+		storages = await response.json() # pyright: ignore[reportGeneralTypeIssues]
+		(storage,) = (s for s in storages if s['Location'] == 'GY-694c')
+		tio = 0
+		for item in storage['StorageItems']:
+			if item['MaterialTicker'] == 'TIO':
+				tio = item['MaterialAmount']
+		last_update = datetime.datetime.fromtimestamp(storage['LastUpdatedEpochMs'] / 1000)
+		delta = datetime.datetime.now() - last_update
+
+		response = await fetch('https://api.punoted.net/v1/production/user/burn?location=gy-694c', headers=headers)
+		production = await response.json() # pyright: ignore[reportGeneralTypeIssues]
+		(tio_production,) = (p for p in production['GY-694c'] if p['MaterialTicker'] == 'TIO')
+		daily_production = tio_production['Production']
+
+		estimated = int(tio + daily_production * (delta.total_seconds() / 60 / 60 / 24))
+		return Response(f'raylu had {tio} TIO in storage as of {last_update} UTC ({delta.total_seconds() / 60 / 60:.1f} hours ago)\n'
+				f'raylu is producing {daily_production}/day\n'
+				f'estimated TIO in inventory: {estimated}\n')
+
+	async def kit(self) -> Response:
+		html = (pathlib.Path(__file__).parent / 'kit.html').read_text()
+		try:
+			headers = {'X-Data-Token': self.env.punoted_api_key}
+			response = await fetch('https://api.punoted.net/v1/storages/user', headers=headers)
+			storages = await response.json() # pyright: ignore[reportGeneralTypeIssues]
+
+			lcb = {
+				'FFC': 1,
+				'RCT': 1,
+				'FSE': 1,
+				'LFE': 2,
+				'MFE': 2,
+				'SFE': 1,
+				'LCB': 1,
+				'MFL': 1,
+				'MSL': 1,
+				'LHP': 94,
+				'SSC': 128,
+				'BR1': 1,
+				'CQM': 1,
+			}
+			wcb_upgrade = {
+				'LFE': 1,
+				'WCB': 1,
+				'MFL': 1,
+				'LHP': 64,
+				'SSC': 26,
+			}
+			ship_parts = list(lcb.keys())
+			ship_parts.extend(mat for mat in wcb_upgrade.keys() if mat not in ship_parts)
+			items = collections.defaultdict(int)
+			items_beanironia = collections.defaultdict(int)
+			last_update = None
+			for storage in storages:
+				for item in storage['StorageItems']:
+					if item['MaterialTicker'] in ship_parts:
+						items[item['MaterialTicker']] += item['MaterialAmount']
+						if storage['Location'] == 'Beanironia':
+							items_beanironia[item['MaterialTicker']] += item['MaterialAmount']
+				if storage['Location'] == 'Beanironia':
+					last_update = datetime.datetime.fromtimestamp(storage['LastUpdatedEpochMs'] / 1000)
+			assert last_update is not None
+			delta = datetime.datetime.now() - last_update
+
+			availability = '''
+			<table>
+				<tr>
+					<th></th>
+					<th>LCB</th>
+					<th>LCB<br>(at beanironia)</th>
+					<th>WCB upgrade</th>
+					<th>WCB upgrade<br>(at beanironia)</th>
+				</tr>
+			'''
+			for part in ship_parts:
+				availability += f'<tr><td>{part}</td>'
+				if part in lcb:
+					percent = min(items[part] / lcb[part], 1) * 100
+					availability += f'<td><span style="color: color-mix(in xyz, #0aa {percent}%, #f80)">{items[part]}</span>/{lcb[part]}</td>'
+					percent = min(items_beanironia[part] / lcb[part], 1) * 100
+					availability += f'<td><span style="color: color-mix(in xyz, #0aa {percent}%, #f80)">{items_beanironia[part]}</span>/{lcb[part]}</td>'
+				else:
+					availability += '<td></td><td></td>'
+				if part in wcb_upgrade:
+					percent = min(items[part] / wcb_upgrade[part], 1) * 100
+					availability += f'<td><span style="color: color-mix(in xyz, #0aa {percent}%, #f80)">{items[part]}</span>/{wcb_upgrade[part]}</td>'
+					percent = min(items_beanironia[part] / wcb_upgrade[part], 1) * 100
+					availability += f'<td><span style="color: color-mix(in xyz, #0aa {percent}%, #f80)">{items_beanironia[part]}</span>/{wcb_upgrade[part]}</td>'
+				else:
+					availability += '<td></td><td></td>'
+				availability += '</tr>'
+			availability += f'</table>as of {last_update.strftime("%Y-%m-%d %H:%M:%S")} UTC ({delta.total_seconds() / 60 / 60:.1f} hours ago)'
+			html = html.replace('{{availability}}', availability, 1)
+		except Exception:
+			console.error('Error fetching kit data:', traceback.format_exc())
+		return Response(html, headers={'Content-Type': 'text/html'})

+ 1 - 0
www/kit.html → cf-worker/src/kit.html

@@ -13,6 +13,7 @@
 	<main class="kit">
 		<h1>forevermore ship kits</h1>
 		order on the <a href="https://discord.gg/WJGwna8Kzs">ICR discord</a>
+		{{availability}}
 
 		<h2>RCT FSE LCB</h2>
 		this kit is 7 million ICA

+ 5 - 1
cf-worker/wrangler.toml

@@ -4,11 +4,15 @@ main = 'src/entry.py'
 compatibility_date = '2026-07-12'
 compatibility_flags = ['python_workers']
 routes = [
-	{zone_name = 'raylu.net', pattern = 'prun.raylu.net/gy-694c'}
+	{zone_name = 'raylu.net', pattern = 'prun.raylu.net/gy-694c'},
+	{zone_name = 'raylu.net', pattern = 'prun.raylu.net/kit'},
 ]
 
 [secrets]
 required = ['punoted_api_key']
 
+[env.dev.assets]
+directory = '../www'
+
 [observability]
 enabled = true

+ 1 - 1
ts/plan.ts

@@ -136,7 +136,7 @@ async function travel(edges: Edge[], system: string, planet_name: string, cx: st
 	const {parsecs, jumps} = ftlDistance(edges, system, cx);
 	if (jumps === 0) { // STL
 		const planet: FIOPlanet = await cachedFetchJSON('https://api.fnar.net/planet/' + planet_name);
-		const km =  planet.SemiMajorAxis / 1000;
+		const km = planet.SemiMajorAxis / 1000;
 		// ENG at 750 SF usage (50% of an SSL) TRAs at ~300,000,000 km/h
 		return Math.ceil(km / 300_000_000);
 	} else // FTL

+ 1 - 1
www/shipbuilding.html

@@ -23,10 +23,10 @@
 		import {setupProduction} from './production.js';
 		const blueprint = {
 			'FFC': 1,
+			'RCT': 1,
 			'FSE': 1,
 			'LFE': 2,
 			'MFE': 2,
-			'RCT': 1,
 			'SFE': 1,
 			'LCB': 1,
 			'MFL': 1,

+ 7 - 0
www/style.css

@@ -162,6 +162,13 @@ main.junk {
 main.kit {
 	width: 1200px;
 
+	table {
+		width: auto;
+		th, td {
+			padding: 0 8px;
+		}
+	}
+
 	img {
 		display: block;
 		max-width: 100%;