Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6df59e4eae | |||
| 38291f7866 | |||
| 570f0adc0f | |||
| bddac4360a |
@@ -110,10 +110,8 @@
|
||||
}
|
||||
```
|
||||
|
||||
## Lizenz
|
||||
---
|
||||
|
||||
Dieses Plugin hat keine Lizenz. Es darf nicht verändert oder weiterverbreitet werden.
|
||||
**Copyright © 2026 - M_Viper - Alle Rechte vorbehalten**
|
||||
|
||||
## Autor
|
||||
|
||||
M_Viper
|
||||
Die unbefugte Vervielfältigung, Verbreitung oder Weitergabe dieses Plugins ist strafbar und wird rechtlich verfolgt.
|
||||
|
||||
154
pulsecast.php
154
pulsecast.php
@@ -1,12 +1,21 @@
|
||||
<?php
|
||||
/**
|
||||
* Plugin Name: PulseCast
|
||||
* Plugin URI: https://git.viper.ipv64.net/M_Viper/PulseCast/
|
||||
* Description: Sende Broadcasts (sofort oder geplant) an deine StatusAPI direkt aus dem WordPress-Backend. Flexibel für Homenetzwerk, externe Server und gemischte Setups.
|
||||
* Version: 1.0.2
|
||||
* Author: M_Viper
|
||||
* Author URI: https://m-viper.de
|
||||
*/
|
||||
/*
|
||||
Plugin Name: PulseCast
|
||||
Plugin URI: https://git.viper.ipv64.net/M_Viper/PulseCast/
|
||||
Description: Sende Broadcasts (sofort oder geplant) an deine StatusAPI direkt aus dem WordPress-Backend. Flexibel für Homenetzwerk, externe Server und gemischte Setups.
|
||||
Version: 1.0.3
|
||||
Author: M_Viper
|
||||
Author URI: https://m-viper.de
|
||||
Requires at least: 6.8
|
||||
Tested up to: 6.8
|
||||
PHP Version: 7.4
|
||||
License: GPL2
|
||||
License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
||||
Text Domain: pulsecast
|
||||
Tags: broadcast, statusapi, wordpress, backend, scheduling, network, server, flexible
|
||||
Support: [Discord Support](https://discord.com/invite/FdRs4BRd8D)
|
||||
Support: [Telegram Support](https://t.me/M_Viper04)
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
@@ -158,11 +167,71 @@ class PulseCast {
|
||||
add_menu_page('PulseCast', 'PulseCast', 'manage_options', 'pulsecast', [$this, 'page_main'], 'dashicons-megaphone', 55);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formatiert die Nachricht für die Ausgabe im WordPress-Backend.
|
||||
* - Wandelt &-Farbcodes in HTML-Span um.
|
||||
* - Macht URLs anklickbar.
|
||||
*/
|
||||
private function format_message_output($text) {
|
||||
if (empty($text)) return '';
|
||||
|
||||
// Zuerst HTML escapen für Sicherheit
|
||||
$text = esc_html($text);
|
||||
|
||||
// Farben Map (Minecraft Classic)
|
||||
$colors = [
|
||||
'0' => '#000000', '1' => '#0000AA', '2' => '#00AA00', '3' => '#00AAAA',
|
||||
'4' => '#AA0000', '5' => '#AA00AA', '6' => '#FFAA00', '7' => '#AAAAAA',
|
||||
'8' => '#555555', '9' => '#5555FF', 'a' => '#55FF55', 'b' => '#55FFFF',
|
||||
'c' => '#FF5555', 'd' => '#FF55FF', 'e' => '#FFFF55', 'f' => '#FFFFFF',
|
||||
];
|
||||
|
||||
// Formate Map
|
||||
$formats = [
|
||||
'l' => 'font-weight:bold;', // Bold
|
||||
'o' => 'font-style:italic;', // Italic
|
||||
'n' => 'text-decoration:underline;', // Underline
|
||||
'm' => 'text-decoration:line-through;', // Strikethrough
|
||||
'r' => '', // Reset
|
||||
];
|
||||
|
||||
// Regex findet &code (wegen des vorherigen esc_html)
|
||||
$pattern = '/&([0-9a-fk-or])/i';
|
||||
|
||||
$formatted = preg_replace_callback($pattern, function($matches) use ($colors, $formats) {
|
||||
$code = strtolower($matches[1]);
|
||||
|
||||
// Reset (schließt alle offenen Tags)
|
||||
if ($code === 'r') {
|
||||
return '</span>';
|
||||
}
|
||||
|
||||
// Farben öffnen einen neuen Span
|
||||
if (isset($colors[$code])) {
|
||||
return '<span style="color:' . $colors[$code] . ';">';
|
||||
}
|
||||
|
||||
// Formate (fett, kursiv) - Wir öffnen ebenfalls einen Span
|
||||
if (isset($formats[$code])) {
|
||||
return '<span style="' . $formats[$code] . ';">';
|
||||
}
|
||||
|
||||
// Unbekannter Code (z.B. &k für obfuscated) - ignorieren oder Text lassen
|
||||
return $matches[0];
|
||||
}, $text);
|
||||
|
||||
// Links anklickbar machen (WordPress Funktion)
|
||||
return make_clickable($formatted);
|
||||
}
|
||||
|
||||
public function page_main() {
|
||||
if (!current_user_can('manage_options')) wp_die('Keine Berechtigung.');
|
||||
|
||||
$settings = get_option(self::OPTION_KEY, []);
|
||||
$schedules = get_option(self::SCHEDULES_KEY, []);
|
||||
$wp_tz = wp_timezone();
|
||||
$tz_name = $wp_tz->getName();
|
||||
$tz_offset = $wp_tz->getOffset(new DateTime('now')) / 3600;
|
||||
|
||||
// Automatische Status-Aktualisierung beim Seitenladen
|
||||
$this->auto_refresh_status();
|
||||
@@ -192,6 +261,16 @@ class PulseCast {
|
||||
echo '<div class="notice notice-error is-dismissible pulsecast-auto-dismiss"><p>' . esc_html(urldecode($_GET['pulsecast_error'])) . '</p></div>';
|
||||
}
|
||||
|
||||
// Warnung wenn Zeitzone auf UTC steht
|
||||
if ($tz_offset == 0) {
|
||||
?>
|
||||
<div class="notice notice-warning">
|
||||
<p><strong>⚠️ PulseCast Zeitzone:</strong> Deine WordPress-Zeitzone ist aktuell auf <strong><?php echo esc_html($tz_name); ?></strong> eingestellt.</p>
|
||||
<p>Dadurch werden "Lokale Zeit" und "UTC" als gleich angezeigt. Bitte gehe zu <a href="<?php echo admin_url('options-general.php'); ?>">Einstellungen > Allgemein</a> und wähle deine Stadt (z.B. Berlin), damit die Umrechnung korrekt funktioniert.</p>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
$current_server_time = current_time('Y-m-d H:i:s');
|
||||
$current_utc_time = gmdate('Y-m-d H:i:s');
|
||||
|
||||
@@ -202,12 +281,12 @@ class PulseCast {
|
||||
<h1>PulseCast — Broadcasts</h1>
|
||||
|
||||
<div class="notice notice-info">
|
||||
<p><strong>Aktuelle Zeit (Server-Zeitzone):</strong> <?php echo esc_html($current_server_time); ?></p>
|
||||
<p><strong>Aktuelle Zeit (WordPress-Zeitzone: <?php echo esc_html($tz_name); ?>):</strong> <?php echo esc_html($current_server_time); ?></p>
|
||||
<p><strong>Aktuelle Zeit (UTC):</strong> <?php echo esc_html($current_utc_time); ?></p>
|
||||
<?php if (!empty($current_api_url)): ?>
|
||||
<p><strong>API Endpoint:</strong> <code><?php echo esc_html($current_api_url); ?></code></p>
|
||||
<?php endif; ?>
|
||||
<p class="description">Zeitgeplante Broadcasts werden in UTC an die StatusAPI gesendet.</p>
|
||||
<p class="description">Zeitgeplante Broadcasts werden in UTC an die StatusAPI gesendet, aber hier in deiner Lokalzeit angezeigt.</p>
|
||||
</div>
|
||||
|
||||
<h2>Einstellungen</h2>
|
||||
@@ -459,7 +538,7 @@ class PulseCast {
|
||||
<td><textarea name="sched_message" id="sched_message" rows="3" class="large-text" required></textarea></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><label for="sched_time">Zeit (YYYY-MM-DD HH:MM, Server-Zeitzone)</label></th>
|
||||
<th><label for="sched_time">Zeit (YYYY-MM-DD HH:MM, <?php echo esc_html($tz_name); ?>)</label></th>
|
||||
<td>
|
||||
<input name="sched_time" id="sched_time" type="datetime-local" class="regular-text" required>
|
||||
<p class="description">Beispiel: <?php echo esc_html(date('Y-m-d\TH:i', strtotime('+1 hour'))); ?> (in einer Stunde)</p>
|
||||
@@ -507,11 +586,29 @@ class PulseCast {
|
||||
</div>
|
||||
|
||||
<table class="widefat">
|
||||
<thead><tr><th>ID</th><th>Nachricht</th><th>Sendezeit (Lokal)</th><th>Sendezeit (UTC)</th><th>Status</th><th>Wiederholung</th><th>Aktionen</th></tr></thead>
|
||||
<thead><tr><th>ID</th><th>Nachricht</th><th>Endzeit (Lokal)</th><th>Sendezeit (UTC)</th><th>Status</th><th>Wiederholung</th><th>Aktionen</th></tr></thead>
|
||||
<tbody>
|
||||
<?php foreach ($schedules as $id => $s):
|
||||
$local_time = get_date_from_gmt(gmdate('Y-m-d H:i:s', $s['time']), 'Y-m-d H:i:s');
|
||||
$utc_time = gmdate('Y-m-d H:i:s', $s['time']);
|
||||
// --- FIX: EXPLIZITE DATUMSKONVERTIERUNG ---
|
||||
// Wir nehmen an, dass $s['time'] ein UTC Timestamp ist
|
||||
|
||||
// 1. Lokale Zeit berechnen (UTC Timestamp -> WP Timezone)
|
||||
try {
|
||||
$date_local = new DateTime('@' . $s['time']);
|
||||
$date_local->setTimezone($wp_tz);
|
||||
$local_time = $date_local->format('Y-m-d H:i:s');
|
||||
} catch (Exception $e) {
|
||||
$local_time = 'Fehler';
|
||||
}
|
||||
|
||||
// 2. UTC Zeit berechnen (UTC Timestamp -> UTC)
|
||||
try {
|
||||
$date_utc = new DateTime('@' . $s['time']);
|
||||
$utc_time = $date_utc->format('Y-m-d H:i:s');
|
||||
} catch (Exception $e) {
|
||||
$utc_time = 'Fehler';
|
||||
}
|
||||
|
||||
$now = time();
|
||||
$scheduled_time = $s['time'];
|
||||
$time_diff = $now - $scheduled_time;
|
||||
@@ -583,7 +680,7 @@ class PulseCast {
|
||||
?>
|
||||
<tr style="<?php echo $row_style; ?>">
|
||||
<td><?php echo esc_html($id); ?></td>
|
||||
<td><?php echo esc_html($s['message']); ?></td>
|
||||
<td><?php echo $this->format_message_output($s['message']); ?></td>
|
||||
<td><?php echo esc_html($local_time); ?></td>
|
||||
<td><?php echo esc_html($utc_time); ?></td>
|
||||
<td style="<?php echo $status_color; ?> font-weight: bold;">
|
||||
@@ -943,6 +1040,7 @@ class PulseCast {
|
||||
public function handle_schedule_post() {
|
||||
if (!current_user_can('manage_options')) wp_die('Forbidden');
|
||||
|
||||
// 1. Einstellungen speichern
|
||||
if (isset($_POST['_wpnonce']) && wp_verify_nonce($_POST['_wpnonce'], 'pulsecast_save_settings')) {
|
||||
check_admin_referer('pulsecast_save_settings');
|
||||
$settings = get_option(self::OPTION_KEY, []);
|
||||
@@ -962,15 +1060,16 @@ class PulseCast {
|
||||
exit;
|
||||
}
|
||||
|
||||
// 2. Neuen Schedule planen
|
||||
check_admin_referer('pulsecast_schedule_new');
|
||||
$message = sanitize_textarea_field($_POST['sched_message'] ?? '');
|
||||
$timeRaw = sanitize_text_field($_POST['sched_time'] ?? '');
|
||||
$recur = sanitize_text_field($_POST['sched_recur'] ?? 'none');
|
||||
|
||||
$type = 'global';
|
||||
|
||||
$settings = get_option(self::OPTION_KEY, []);
|
||||
|
||||
// Farben aus den Formularwerten oder Standard
|
||||
$prefix = sanitize_text_field($_POST['sched_prefix'] ?? '');
|
||||
$prefix_color = sanitize_text_field($_POST['sched_prefix_color'] ?? '');
|
||||
$bracket_color = sanitize_text_field($_POST['sched_bracket_color'] ?? '');
|
||||
@@ -986,15 +1085,30 @@ class PulseCast {
|
||||
exit;
|
||||
}
|
||||
|
||||
// --- FIX: UTC KONVERTIERUNG ---
|
||||
// Wir nutzen DateTime mit der WordPress-Zeitzoneneinstellung
|
||||
$timeRaw = str_replace('T', ' ', $timeRaw);
|
||||
$local_timestamp = strtotime($timeRaw);
|
||||
if ($local_timestamp === false || $local_timestamp <= 0) {
|
||||
|
||||
try {
|
||||
// Zeitzone aus WordPress Einstellungen holen
|
||||
$wp_timezone = wp_timezone();
|
||||
|
||||
// Datum Objekt erstellen (interpretiert Input als WP Zeit)
|
||||
$date = DateTime::createFromFormat('Y-m-d H:i', $timeRaw, $wp_timezone);
|
||||
|
||||
if ($date === false) {
|
||||
wp_redirect(add_query_arg('pulsecast_error', urlencode('Ungültiges Zeitformat'), wp_get_referer()));
|
||||
exit;
|
||||
}
|
||||
|
||||
$utc_datetime = get_gmt_from_date(date('Y-m-d H:i:s', $local_timestamp), 'Y-m-d H:i:s');
|
||||
$timestamp_utc = strtotime($utc_datetime . ' UTC');
|
||||
// Zeitzone auf UTC setzen und den Timestamp holen
|
||||
$date->setTimezone(new DateTimeZone('UTC'));
|
||||
$timestamp_utc = $date->getTimestamp();
|
||||
|
||||
} catch (Exception $e) {
|
||||
wp_redirect(add_query_arg('pulsecast_error', urlencode('Zeitkonvertierungsfehler: ' . $e->getMessage()), wp_get_referer()));
|
||||
exit;
|
||||
}
|
||||
|
||||
$schedules = get_option(self::SCHEDULES_KEY, []);
|
||||
$id = (string) time() . rand(1000,9999);
|
||||
|
||||
Reference in New Issue
Block a user