added icon

This commit is contained in:
Radek Davidek 2025-11-01 13:37:05 +01:00
parent dd14b7ba96
commit 2f3eeebe72
3 changed files with 243 additions and 205 deletions

View File

@ -13,219 +13,257 @@ import java.util.List;
public class HttpServerApp {
// Statický API klíč
private static final String API_KEY = "6666-1234";
// Statický API klíč
private static final String API_KEY = "6666-1234";
public static void main(String[] args) throws Exception {
TransmissionService service = new TransmissionService();
public static void main(String[] args) throws Exception {
TransmissionService service = new TransmissionService();
HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0);
ObjectMapper mapper = new ObjectMapper();
HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0);
ObjectMapper mapper = new ObjectMapper();
// /transmissions -> all data nebo jen pro konkrétní datum
server.createContext("/transmissions", exchange -> {
try {
setCors(exchange);
if (!checkApiKey(exchange)) return;
// /transmissions -> all data nebo jen pro konkrétní datum
server.createContext("/transmissions", exchange -> {
try {
setCors(exchange);
if (!checkApiKey(exchange))
return;
URI uri = exchange.getRequestURI();
String query = uri.getQuery();
String date = null;
URI uri = exchange.getRequestURI();
String query = uri.getQuery();
String date = null;
if (query != null) {
for (String part : query.split("&")) {
if (part.startsWith("date=")) {
date = java.net.URLDecoder.decode(part.substring(5), StandardCharsets.UTF_8);
}
}
}
if (query != null) {
for (String part : query.split("&")) {
if (part.startsWith("date=")) {
date = java.net.URLDecoder.decode(part.substring(5), StandardCharsets.UTF_8);
}
}
}
List<Transmission> result;
if (date != null && !date.isBlank()) {
result = service.getByDateLazy(date);
} else {
result = service.getAll();
}
List<Transmission> result;
if (date != null && !date.isBlank()) {
result = service.getByDateLazy(date);
} else {
result = service.getAll();
}
respondJson(exchange, mapper.writeValueAsString(result));
} catch (Exception e) {
e.printStackTrace();
sendError(exchange, 500, e.getMessage());
}
});
respondJson(exchange, mapper.writeValueAsString(result));
} catch (Exception e) {
e.printStackTrace();
sendError(exchange, 500, e.getMessage());
}
});
// /search?q=...
server.createContext("/search", exchange -> {
try {
setCors(exchange);
if (!checkApiKey(exchange)) return;
// /search?q=...
server.createContext("/search", exchange -> {
try {
setCors(exchange);
if (!checkApiKey(exchange))
return;
URI uri = exchange.getRequestURI();
String query = null;
if (uri.getQuery() != null) {
String fullq = uri.getQuery();
for (String part : fullq.split("&")) {
if (part.startsWith("q=")) {
query = java.net.URLDecoder.decode(part.substring(2), StandardCharsets.UTF_8.name());
}
}
}
List<Transmission> results = service.search(query);
respondJson(exchange, mapper.writeValueAsString(results));
} catch (Exception e) {
e.printStackTrace();
sendError(exchange, 500, e.getMessage());
}
});
URI uri = exchange.getRequestURI();
String query = null;
if (uri.getQuery() != null) {
String fullq = uri.getQuery();
for (String part : fullq.split("&")) {
if (part.startsWith("q=")) {
query = java.net.URLDecoder.decode(part.substring(2), StandardCharsets.UTF_8.name());
}
}
}
List<Transmission> results = service.search(query);
respondJson(exchange, mapper.writeValueAsString(results));
} catch (Exception e) {
e.printStackTrace();
sendError(exchange, 500, e.getMessage());
}
});
// /refresh endpoint
server.createContext("/refresh", exchange -> {
try {
setCors(exchange);
if (!checkApiKey(exchange)) return;
// /refresh endpoint
server.createContext("/refresh", exchange -> {
try {
setCors(exchange);
if (!checkApiKey(exchange))
return;
if ("GET".equalsIgnoreCase(exchange.getRequestMethod())) {
// přečti volitelné datum z query stringu
String dateParam = null;
String query = exchange.getRequestURI().getQuery();
if (query != null) {
for (String part : query.split("&")) {
if (part.startsWith("date=")) {
dateParam = java.net.URLDecoder.decode(part.substring(5), StandardCharsets.UTF_8);
break;
}
}
}
if ("GET".equalsIgnoreCase(exchange.getRequestMethod())) {
// přečti volitelné datum z query stringu
String dateParam = null;
String query = exchange.getRequestURI().getQuery();
if (query != null) {
for (String part : query.split("&")) {
if (part.startsWith("date=")) {
dateParam = java.net.URLDecoder.decode(part.substring(5), StandardCharsets.UTF_8);
break;
}
}
}
// pokud není zadané, použij dnešní den
String dateStr = (dateParam != null && !dateParam.isBlank())
? dateParam
: java.time.LocalDate.now().toString();
// pokud není zadané, použij dnešní den
String dateStr = (dateParam != null && !dateParam.isBlank()) ? dateParam
: java.time.LocalDate.now().toString();
// načti data pro konkrétní den
System.out.println("🔄 Obnovuji data pro den: " + dateStr);
service.reloadDayAsync(dateStr);
// načti data pro konkrétní den
System.out.println("🔄 Obnovuji data pro den: " + dateStr);
service.reloadDayAsync(dateStr);
respondJson(exchange, "{\"status\":\"ok\",\"message\":\"Data pro den " + dateStr + " se obnovují.\"}");
} else {
exchange.sendResponseHeaders(405, -1);
}
} catch (Exception e) {
sendError(exchange, 500, e.getMessage());
}
});
respondJson(exchange,
"{\"status\":\"ok\",\"message\":\"Data pro den " + dateStr + " se obnovují.\"}");
} else {
exchange.sendResponseHeaders(405, -1);
}
} catch (Exception e) {
sendError(exchange, 500, e.getMessage());
}
});
// serve /index.html
server.createContext("/", exchange -> {
try {
setCors(exchange);
if (!checkApiKey(exchange)) return;
String path = exchange.getRequestURI().getPath();
if ("/".equals(path) || path.isEmpty() || path.equals("/index.html")) {
String html = readResource("/index.html");
if (html == null) {
sendError(exchange, 404, "index.html not found in resources");
return;
}
exchange.getResponseHeaders().set("Content-Type", "text/html; charset=utf-8");
byte[] bytes = html.getBytes(StandardCharsets.UTF_8);
exchange.sendResponseHeaders(200, bytes.length);
try (OutputStream os = exchange.getResponseBody()) {
os.write(bytes);
}
} else {
sendError(exchange, 404, "Not found");
}
} catch (Exception e) {
e.printStackTrace();
sendError(exchange, 500, e.getMessage());
}
});
// serve /index.html
server.createContext("/", exchange -> {
try {
setCors(exchange);
String path = exchange.getRequestURI().getPath();
if (path.equals("/icon.png")) {
byte[] data = readResourceAsBytes("/icon.png");
if (data == null) {
sendError(exchange, 404, "index.html not found in resources");
return;
}
exchange.getResponseHeaders().set("Content-Type", "image/png");
exchange.sendResponseHeaders(200, data.length);
try (OutputStream os = exchange.getResponseBody()) {
os.write(data);
os.flush();
}
return;
}
server.start();
System.out.println("🚀 HTTP server běží na http://localhost:8080");
System.out.println(" ➜ /transmissions (všechny přenosy JSON, vyžaduje X-API-KEY)");
System.out.println(" ➜ /search?q=Brno (vyhledávání JSON, vyžaduje X-API-KEY)");
System.out.println(" ➜ /refresh (spustí opětovné načtení dat, vyžaduje X-API-KEY)");
System.out.println(" ➜ / (web UI)");
}
if (!checkApiKey(exchange))
return;
if ("/".equals(path) || path.isEmpty() || path.equals("/index.html")) {
String html = readResource("/index.html");
if (html == null) {
sendError(exchange, 404, "index.html not found in resources");
return;
}
exchange.getResponseHeaders().set("Content-Type", "text/html; charset=utf-8");
byte[] bytes = html.getBytes(StandardCharsets.UTF_8);
exchange.sendResponseHeaders(200, bytes.length);
try (OutputStream os = exchange.getResponseBody()) {
os.write(bytes);
os.flush();
}
} else {
sendError(exchange, 404, "Not found");
}
} catch (Exception e) {
e.printStackTrace();
sendError(exchange, 500, e.getMessage());
}
});
// ======= API Key ochrana =======
private static boolean checkApiKey(HttpExchange exchange) throws IOException {
String query = exchange.getRequestURI().getQuery(); // např. apiKey=xxxx
String key = null;
server.start();
System.out.println("🚀 HTTP server běží na http://localhost:8080");
System.out.println(" ➜ /transmissions (všechny přenosy JSON, vyžaduje X-API-KEY)");
System.out.println(" ➜ /search?q=Brno (vyhledávání JSON, vyžaduje X-API-KEY)");
System.out.println(" ➜ /refresh (spustí opětovné načtení dat, vyžaduje X-API-KEY)");
System.out.println(" ➜ / (web UI)");
}
if (query != null) {
for (String part : query.split("&")) {
if (part.startsWith("apiKey=")) {
key = java.net.URLDecoder.decode(part.substring(7), StandardCharsets.UTF_8);
break;
}
}
}
private static byte[] readResourceAsBytes(String string) {
try (InputStream is = HttpServerApp.class.getResourceAsStream(string)) {
if (is == null)
return null;
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
byte[] data = new byte[16384];
int nRead;
while ((nRead = is.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
return buffer.toByteArray();
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
if (!API_KEY.equals(key)) {
exchange.getResponseHeaders().set("Content-Type", "application/json; charset=utf-8");
byte[] bytes = "{\"error\":\"Unauthorized\"}".getBytes(StandardCharsets.UTF_8);
exchange.sendResponseHeaders(401, bytes.length);
try (OutputStream os = exchange.getResponseBody()) {
os.write(bytes);
}
return false;
}
return true;
}
// ======= API Key ochrana =======
private static boolean checkApiKey(HttpExchange exchange) throws IOException {
String query = exchange.getRequestURI().getQuery(); // např. apiKey=xxxx
String key = null;
// ======= CORS =======
private static void setCors(HttpExchange exchange) {
Headers h = exchange.getResponseHeaders();
h.set("Access-Control-Allow-Origin", "*");
h.set("Access-Control-Allow-Methods", "GET, OPTIONS");
h.set("Access-Control-Allow-Headers", "Content-Type, X-API-KEY");
if ("OPTIONS".equalsIgnoreCase(exchange.getRequestMethod())) {
try {
exchange.sendResponseHeaders(204, -1);
} catch (IOException e) {
e.printStackTrace();
}
}
}
if (query != null) {
for (String part : query.split("&")) {
if (part.startsWith("apiKey=")) {
key = java.net.URLDecoder.decode(part.substring(7), StandardCharsets.UTF_8);
break;
}
}
}
// ======= JSON odpověď =======
private static void respondJson(HttpExchange exchange, String json) throws IOException {
exchange.getResponseHeaders().set("Content-Type", "application/json; charset=utf-8");
byte[] bytes = json.getBytes(StandardCharsets.UTF_8);
exchange.sendResponseHeaders(200, bytes.length);
try (OutputStream os = exchange.getResponseBody()) {
os.write(bytes);
}
}
if (!API_KEY.equals(key)) {
exchange.getResponseHeaders().set("Content-Type", "application/json; charset=utf-8");
byte[] bytes = "{\"error\":\"Unauthorized\"}".getBytes(StandardCharsets.UTF_8);
exchange.sendResponseHeaders(401, bytes.length);
try (OutputStream os = exchange.getResponseBody()) {
os.write(bytes);
}
return false;
}
return true;
}
// ======= Chyba =======
private static void sendError(HttpExchange exchange, int code, String message) throws IOException {
exchange.getResponseHeaders().set("Content-Type", "text/plain; charset=utf-8");
byte[] bytes = message.getBytes(StandardCharsets.UTF_8);
exchange.sendResponseHeaders(code, bytes.length);
try (OutputStream os = exchange.getResponseBody()) {
os.write(bytes);
}
}
// ======= CORS =======
private static void setCors(HttpExchange exchange) {
Headers h = exchange.getResponseHeaders();
h.set("Access-Control-Allow-Origin", "*");
h.set("Access-Control-Allow-Methods", "GET, OPTIONS");
h.set("Access-Control-Allow-Headers", "Content-Type, X-API-KEY");
if ("OPTIONS".equalsIgnoreCase(exchange.getRequestMethod())) {
try {
exchange.sendResponseHeaders(204, -1);
} catch (IOException e) {
e.printStackTrace();
}
}
}
// ======= Načtení resource =======
private static String readResource(String resourcePath) {
try (InputStream is = HttpServerApp.class.getResourceAsStream(resourcePath)) {
if (is == null) return null;
try (BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line).append("\n");
}
return sb.toString();
}
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
// ======= JSON odpověď =======
private static void respondJson(HttpExchange exchange, String json) throws IOException {
exchange.getResponseHeaders().set("Content-Type", "application/json; charset=utf-8");
byte[] bytes = json.getBytes(StandardCharsets.UTF_8);
exchange.sendResponseHeaders(200, bytes.length);
try (OutputStream os = exchange.getResponseBody()) {
os.write(bytes);
}
}
// ======= Chyba =======
private static void sendError(HttpExchange exchange, int code, String message) throws IOException {
exchange.getResponseHeaders().set("Content-Type", "text/plain; charset=utf-8");
byte[] bytes = message.getBytes(StandardCharsets.UTF_8);
exchange.sendResponseHeaders(code, bytes.length);
try (OutputStream os = exchange.getResponseBody()) {
os.write(bytes);
}
}
// ======= Načtení resource =======
private static String readResource(String resourcePath) {
try (InputStream is = HttpServerApp.class.getResourceAsStream(resourcePath)) {
if (is == null)
return null;
try (BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line).append("\n");
}
return sb.toString();
}
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}

BIN
src/main/resources/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -2,6 +2,7 @@
<html lang="cs">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="icon.png">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>TVCOM Přenosy</title>
<style>
@ -74,7 +75,7 @@ input, select, button {
margin-top: 30px;
}
@media (max-width: 500px) {
@media ( max-width : 500px) {
.card img {
height: 120px;
}
@ -82,21 +83,20 @@ input, select, button {
</style>
</head>
<body>
<h1>📺 TVCOM Přenosy</h1>
<h1>📺 TVCOM Přenosy</h1>
<div class="filters">
<input id="search" type="text" placeholder="Hledat přenos..." />
<input id="datePicker" type="date" />
<select id="sportFilter">
<option value="">Všechny sporty</option>
</select>
<button id="refreshBtn">♻️ Obnovit data</button>
</div>
<div class="filters">
<input id="search" type="text" placeholder="Hledat přenos..." /> <input
id="datePicker" type="date" /> <select id="sportFilter">
<option value="">Všechny sporty</option>
</select>
<button id="refreshBtn">♻️ Obnovit data</button>
</div>
<div id="loading">Načítám data...</div>
<div id="list" class="grid" style="display: none"></div>
<div id="loading">Načítám data...</div>
<div id="list" class="grid" style="display: none"></div>
<script>
<script>
const API_BASE = "";
const urlParams = new URLSearchParams(window.location.search);
const apiKey = urlParams.get('apiKey');