added icon
This commit is contained in:
parent
dd14b7ba96
commit
2f3eeebe72
@ -13,219 +13,257 @@ import java.util.List;
|
|||||||
|
|
||||||
public class HttpServerApp {
|
public class HttpServerApp {
|
||||||
|
|
||||||
// ✅ Statický API klíč
|
// ✅ Statický API klíč
|
||||||
private static final String API_KEY = "6666-1234";
|
private static final String API_KEY = "6666-1234";
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
TransmissionService service = new TransmissionService();
|
TransmissionService service = new TransmissionService();
|
||||||
|
|
||||||
HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0);
|
HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0);
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
|
||||||
// /transmissions -> all data nebo jen pro konkrétní datum
|
// /transmissions -> all data nebo jen pro konkrétní datum
|
||||||
server.createContext("/transmissions", exchange -> {
|
server.createContext("/transmissions", exchange -> {
|
||||||
try {
|
try {
|
||||||
setCors(exchange);
|
setCors(exchange);
|
||||||
if (!checkApiKey(exchange)) return;
|
if (!checkApiKey(exchange))
|
||||||
|
return;
|
||||||
|
|
||||||
URI uri = exchange.getRequestURI();
|
URI uri = exchange.getRequestURI();
|
||||||
String query = uri.getQuery();
|
String query = uri.getQuery();
|
||||||
String date = null;
|
String date = null;
|
||||||
|
|
||||||
if (query != null) {
|
if (query != null) {
|
||||||
for (String part : query.split("&")) {
|
for (String part : query.split("&")) {
|
||||||
if (part.startsWith("date=")) {
|
if (part.startsWith("date=")) {
|
||||||
date = java.net.URLDecoder.decode(part.substring(5), StandardCharsets.UTF_8);
|
date = java.net.URLDecoder.decode(part.substring(5), StandardCharsets.UTF_8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Transmission> result;
|
List<Transmission> result;
|
||||||
if (date != null && !date.isBlank()) {
|
if (date != null && !date.isBlank()) {
|
||||||
result = service.getByDateLazy(date);
|
result = service.getByDateLazy(date);
|
||||||
} else {
|
} else {
|
||||||
result = service.getAll();
|
result = service.getAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
respondJson(exchange, mapper.writeValueAsString(result));
|
respondJson(exchange, mapper.writeValueAsString(result));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
sendError(exchange, 500, e.getMessage());
|
sendError(exchange, 500, e.getMessage());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// /search?q=...
|
// /search?q=...
|
||||||
server.createContext("/search", exchange -> {
|
server.createContext("/search", exchange -> {
|
||||||
try {
|
try {
|
||||||
setCors(exchange);
|
setCors(exchange);
|
||||||
if (!checkApiKey(exchange)) return;
|
if (!checkApiKey(exchange))
|
||||||
|
return;
|
||||||
|
|
||||||
URI uri = exchange.getRequestURI();
|
URI uri = exchange.getRequestURI();
|
||||||
String query = null;
|
String query = null;
|
||||||
if (uri.getQuery() != null) {
|
if (uri.getQuery() != null) {
|
||||||
String fullq = uri.getQuery();
|
String fullq = uri.getQuery();
|
||||||
for (String part : fullq.split("&")) {
|
for (String part : fullq.split("&")) {
|
||||||
if (part.startsWith("q=")) {
|
if (part.startsWith("q=")) {
|
||||||
query = java.net.URLDecoder.decode(part.substring(2), StandardCharsets.UTF_8.name());
|
query = java.net.URLDecoder.decode(part.substring(2), StandardCharsets.UTF_8.name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
List<Transmission> results = service.search(query);
|
List<Transmission> results = service.search(query);
|
||||||
respondJson(exchange, mapper.writeValueAsString(results));
|
respondJson(exchange, mapper.writeValueAsString(results));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
sendError(exchange, 500, e.getMessage());
|
sendError(exchange, 500, e.getMessage());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// /refresh endpoint
|
// /refresh endpoint
|
||||||
server.createContext("/refresh", exchange -> {
|
server.createContext("/refresh", exchange -> {
|
||||||
try {
|
try {
|
||||||
setCors(exchange);
|
setCors(exchange);
|
||||||
if (!checkApiKey(exchange)) return;
|
if (!checkApiKey(exchange))
|
||||||
|
return;
|
||||||
|
|
||||||
if ("GET".equalsIgnoreCase(exchange.getRequestMethod())) {
|
if ("GET".equalsIgnoreCase(exchange.getRequestMethod())) {
|
||||||
// přečti volitelné datum z query stringu
|
// přečti volitelné datum z query stringu
|
||||||
String dateParam = null;
|
String dateParam = null;
|
||||||
String query = exchange.getRequestURI().getQuery();
|
String query = exchange.getRequestURI().getQuery();
|
||||||
if (query != null) {
|
if (query != null) {
|
||||||
for (String part : query.split("&")) {
|
for (String part : query.split("&")) {
|
||||||
if (part.startsWith("date=")) {
|
if (part.startsWith("date=")) {
|
||||||
dateParam = java.net.URLDecoder.decode(part.substring(5), StandardCharsets.UTF_8);
|
dateParam = java.net.URLDecoder.decode(part.substring(5), StandardCharsets.UTF_8);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// pokud není zadané, použij dnešní den
|
// pokud není zadané, použij dnešní den
|
||||||
String dateStr = (dateParam != null && !dateParam.isBlank())
|
String dateStr = (dateParam != null && !dateParam.isBlank()) ? dateParam
|
||||||
? dateParam
|
: java.time.LocalDate.now().toString();
|
||||||
: java.time.LocalDate.now().toString();
|
|
||||||
|
|
||||||
// načti data pro konkrétní den
|
// načti data pro konkrétní den
|
||||||
System.out.println("🔄 Obnovuji data pro den: " + dateStr);
|
System.out.println("🔄 Obnovuji data pro den: " + dateStr);
|
||||||
service.reloadDayAsync(dateStr);
|
service.reloadDayAsync(dateStr);
|
||||||
|
|
||||||
respondJson(exchange, "{\"status\":\"ok\",\"message\":\"Data pro den " + dateStr + " se obnovují.\"}");
|
respondJson(exchange,
|
||||||
} else {
|
"{\"status\":\"ok\",\"message\":\"Data pro den " + dateStr + " se obnovují.\"}");
|
||||||
exchange.sendResponseHeaders(405, -1);
|
} else {
|
||||||
}
|
exchange.sendResponseHeaders(405, -1);
|
||||||
} catch (Exception e) {
|
}
|
||||||
sendError(exchange, 500, e.getMessage());
|
} catch (Exception e) {
|
||||||
}
|
sendError(exchange, 500, e.getMessage());
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// serve /index.html
|
// serve /index.html
|
||||||
server.createContext("/", exchange -> {
|
server.createContext("/", exchange -> {
|
||||||
try {
|
try {
|
||||||
setCors(exchange);
|
setCors(exchange);
|
||||||
if (!checkApiKey(exchange)) return;
|
String path = exchange.getRequestURI().getPath();
|
||||||
String path = exchange.getRequestURI().getPath();
|
if (path.equals("/icon.png")) {
|
||||||
if ("/".equals(path) || path.isEmpty() || path.equals("/index.html")) {
|
byte[] data = readResourceAsBytes("/icon.png");
|
||||||
String html = readResource("/index.html");
|
if (data == null) {
|
||||||
if (html == null) {
|
sendError(exchange, 404, "index.html not found in resources");
|
||||||
sendError(exchange, 404, "index.html not found in resources");
|
return;
|
||||||
return;
|
}
|
||||||
}
|
exchange.getResponseHeaders().set("Content-Type", "image/png");
|
||||||
exchange.getResponseHeaders().set("Content-Type", "text/html; charset=utf-8");
|
exchange.sendResponseHeaders(200, data.length);
|
||||||
byte[] bytes = html.getBytes(StandardCharsets.UTF_8);
|
try (OutputStream os = exchange.getResponseBody()) {
|
||||||
exchange.sendResponseHeaders(200, bytes.length);
|
os.write(data);
|
||||||
try (OutputStream os = exchange.getResponseBody()) {
|
os.flush();
|
||||||
os.write(bytes);
|
}
|
||||||
}
|
return;
|
||||||
} else {
|
}
|
||||||
sendError(exchange, 404, "Not found");
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
sendError(exchange, 500, e.getMessage());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
server.start();
|
if (!checkApiKey(exchange))
|
||||||
System.out.println("🚀 HTTP server běží na http://localhost:8080");
|
return;
|
||||||
System.out.println(" ➜ /transmissions (všechny přenosy JSON, vyžaduje X-API-KEY)");
|
if ("/".equals(path) || path.isEmpty() || path.equals("/index.html")) {
|
||||||
System.out.println(" ➜ /search?q=Brno (vyhledávání JSON, vyžaduje X-API-KEY)");
|
String html = readResource("/index.html");
|
||||||
System.out.println(" ➜ /refresh (spustí opětovné načtení dat, vyžaduje X-API-KEY)");
|
if (html == null) {
|
||||||
System.out.println(" ➜ / (web UI)");
|
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 =======
|
server.start();
|
||||||
private static boolean checkApiKey(HttpExchange exchange) throws IOException {
|
System.out.println("🚀 HTTP server běží na http://localhost:8080");
|
||||||
String query = exchange.getRequestURI().getQuery(); // např. apiKey=xxxx
|
System.out.println(" ➜ /transmissions (všechny přenosy JSON, vyžaduje X-API-KEY)");
|
||||||
String key = null;
|
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) {
|
private static byte[] readResourceAsBytes(String string) {
|
||||||
for (String part : query.split("&")) {
|
try (InputStream is = HttpServerApp.class.getResourceAsStream(string)) {
|
||||||
if (part.startsWith("apiKey=")) {
|
if (is == null)
|
||||||
key = java.net.URLDecoder.decode(part.substring(7), StandardCharsets.UTF_8);
|
return null;
|
||||||
break;
|
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)) {
|
// ======= API Key ochrana =======
|
||||||
exchange.getResponseHeaders().set("Content-Type", "application/json; charset=utf-8");
|
private static boolean checkApiKey(HttpExchange exchange) throws IOException {
|
||||||
byte[] bytes = "{\"error\":\"Unauthorized\"}".getBytes(StandardCharsets.UTF_8);
|
String query = exchange.getRequestURI().getQuery(); // např. apiKey=xxxx
|
||||||
exchange.sendResponseHeaders(401, bytes.length);
|
String key = null;
|
||||||
try (OutputStream os = exchange.getResponseBody()) {
|
|
||||||
os.write(bytes);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ======= CORS =======
|
if (query != null) {
|
||||||
private static void setCors(HttpExchange exchange) {
|
for (String part : query.split("&")) {
|
||||||
Headers h = exchange.getResponseHeaders();
|
if (part.startsWith("apiKey=")) {
|
||||||
h.set("Access-Control-Allow-Origin", "*");
|
key = java.net.URLDecoder.decode(part.substring(7), StandardCharsets.UTF_8);
|
||||||
h.set("Access-Control-Allow-Methods", "GET, OPTIONS");
|
break;
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ======= JSON odpověď =======
|
if (!API_KEY.equals(key)) {
|
||||||
private static void respondJson(HttpExchange exchange, String json) throws IOException {
|
exchange.getResponseHeaders().set("Content-Type", "application/json; charset=utf-8");
|
||||||
exchange.getResponseHeaders().set("Content-Type", "application/json; charset=utf-8");
|
byte[] bytes = "{\"error\":\"Unauthorized\"}".getBytes(StandardCharsets.UTF_8);
|
||||||
byte[] bytes = json.getBytes(StandardCharsets.UTF_8);
|
exchange.sendResponseHeaders(401, bytes.length);
|
||||||
exchange.sendResponseHeaders(200, bytes.length);
|
try (OutputStream os = exchange.getResponseBody()) {
|
||||||
try (OutputStream os = exchange.getResponseBody()) {
|
os.write(bytes);
|
||||||
os.write(bytes);
|
}
|
||||||
}
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// ======= Chyba =======
|
// ======= CORS =======
|
||||||
private static void sendError(HttpExchange exchange, int code, String message) throws IOException {
|
private static void setCors(HttpExchange exchange) {
|
||||||
exchange.getResponseHeaders().set("Content-Type", "text/plain; charset=utf-8");
|
Headers h = exchange.getResponseHeaders();
|
||||||
byte[] bytes = message.getBytes(StandardCharsets.UTF_8);
|
h.set("Access-Control-Allow-Origin", "*");
|
||||||
exchange.sendResponseHeaders(code, bytes.length);
|
h.set("Access-Control-Allow-Methods", "GET, OPTIONS");
|
||||||
try (OutputStream os = exchange.getResponseBody()) {
|
h.set("Access-Control-Allow-Headers", "Content-Type, X-API-KEY");
|
||||||
os.write(bytes);
|
if ("OPTIONS".equalsIgnoreCase(exchange.getRequestMethod())) {
|
||||||
}
|
try {
|
||||||
}
|
exchange.sendResponseHeaders(204, -1);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ======= Načtení resource =======
|
// ======= JSON odpověď =======
|
||||||
private static String readResource(String resourcePath) {
|
private static void respondJson(HttpExchange exchange, String json) throws IOException {
|
||||||
try (InputStream is = HttpServerApp.class.getResourceAsStream(resourcePath)) {
|
exchange.getResponseHeaders().set("Content-Type", "application/json; charset=utf-8");
|
||||||
if (is == null) return null;
|
byte[] bytes = json.getBytes(StandardCharsets.UTF_8);
|
||||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
|
exchange.sendResponseHeaders(200, bytes.length);
|
||||||
StringBuilder sb = new StringBuilder();
|
try (OutputStream os = exchange.getResponseBody()) {
|
||||||
String line;
|
os.write(bytes);
|
||||||
while ((line = br.readLine()) != null) {
|
}
|
||||||
sb.append(line).append("\n");
|
}
|
||||||
}
|
|
||||||
return sb.toString();
|
// ======= Chyba =======
|
||||||
}
|
private static void sendError(HttpExchange exchange, int code, String message) throws IOException {
|
||||||
} catch (IOException e) {
|
exchange.getResponseHeaders().set("Content-Type", "text/plain; charset=utf-8");
|
||||||
e.printStackTrace();
|
byte[] bytes = message.getBytes(StandardCharsets.UTF_8);
|
||||||
return null;
|
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
BIN
src/main/resources/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
@ -2,6 +2,7 @@
|
|||||||
<html lang="cs">
|
<html lang="cs">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" href="icon.png">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>TVCOM Přenosy</title>
|
<title>TVCOM Přenosy</title>
|
||||||
<style>
|
<style>
|
||||||
@ -74,7 +75,7 @@ input, select, button {
|
|||||||
margin-top: 30px;
|
margin-top: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 500px) {
|
@media ( max-width : 500px) {
|
||||||
.card img {
|
.card img {
|
||||||
height: 120px;
|
height: 120px;
|
||||||
}
|
}
|
||||||
@ -82,21 +83,20 @@ input, select, button {
|
|||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>📺 TVCOM Přenosy</h1>
|
<h1>📺 TVCOM Přenosy</h1>
|
||||||
|
|
||||||
<div class="filters">
|
<div class="filters">
|
||||||
<input id="search" type="text" placeholder="Hledat přenos..." />
|
<input id="search" type="text" placeholder="Hledat přenos..." /> <input
|
||||||
<input id="datePicker" type="date" />
|
id="datePicker" type="date" /> <select id="sportFilter">
|
||||||
<select id="sportFilter">
|
<option value="">Všechny sporty</option>
|
||||||
<option value="">Všechny sporty</option>
|
</select>
|
||||||
</select>
|
<button id="refreshBtn">♻️ Obnovit data</button>
|
||||||
<button id="refreshBtn">♻️ Obnovit data</button>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="loading">Načítám data...</div>
|
<div id="loading">Načítám data...</div>
|
||||||
<div id="list" class="grid" style="display: none"></div>
|
<div id="list" class="grid" style="display: none"></div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const API_BASE = "";
|
const API_BASE = "";
|
||||||
const urlParams = new URLSearchParams(window.location.search);
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
const apiKey = urlParams.get('apiKey');
|
const apiKey = urlParams.get('apiKey');
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user