Compare commits
2 Commits
76ba0213c6
...
6363a6b332
| Author | SHA1 | Date |
|---|---|---|
|
|
6363a6b332 | |
|
|
87f0786a0a |
|
|
@ -17,6 +17,7 @@ temp_restore_*/
|
|||
# Logs
|
||||
error_log
|
||||
access_log
|
||||
*.log
|
||||
|
||||
# Debug and utility scripts
|
||||
debug_db.php
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
# Disable Directory Listing
|
||||
Options -Indexes
|
||||
|
||||
# Protect sensitive files
|
||||
<FilesMatch "^\.">
|
||||
Order allow,deny
|
||||
Deny from all
|
||||
</FilesMatch>
|
||||
|
||||
# Protect config files
|
||||
<FilesMatch "(db|config)\.php">
|
||||
Order allow,deny
|
||||
Deny from all
|
||||
</FilesMatch>
|
||||
|
||||
# Protect SQL files
|
||||
<FilesMatch "\.sql$">
|
||||
Order allow,deny
|
||||
Deny from all
|
||||
</FilesMatch>
|
||||
|
|
@ -83,8 +83,3 @@ Feel free to fork this project and submit pull requests to the [Linology Git](ht
|
|||
|
||||
## 📄 License
|
||||
This project is licensed under the MIT License.
|
||||
=======
|
||||
# Podcast-server
|
||||
|
||||
A lightweight, professional-grade podcast hosting and management platform designed for churches and small organizations. Built with PHP 8 and MySQL, this system provides a seamless way to host audio content, track analytics, and engage listeners via push notifications.
|
||||
|
||||
|
|
|
|||
|
|
@ -2,11 +2,6 @@
|
|||
require_once '../includes/db.php';
|
||||
require_once '../includes/functions.php';
|
||||
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
ini_set('log_errors', 1);
|
||||
ini_set('error_log', 'backup_debug.log');
|
||||
|
||||
set_time_limit(300); // 5 minutes
|
||||
ini_set('memory_limit', '512M');
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
<?php header('Location: ../../index.php'); exit;
|
||||
|
|
@ -11,6 +11,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||
updateSetting($pdo, 'site_title', $_POST['site_title']);
|
||||
updateSetting($pdo, 'footer_copyright', $_POST['footer_copyright']);
|
||||
updateSetting($pdo, 'footer_powered_by', $_POST['footer_powered_by']);
|
||||
updateSetting($pdo, 'theme_primary_color', $_POST['theme_primary_color']);
|
||||
updateSetting($pdo, 'theme_bg_color', $_POST['theme_bg_color']);
|
||||
updateSetting($pdo, 'theme_text_color', $_POST['theme_text_color']);
|
||||
$success = "Site settings updated!";
|
||||
}
|
||||
|
||||
|
|
@ -67,9 +70,25 @@ $site_title = getSetting($pdo, 'site_title');
|
|||
<input type="text" id="footer_copyright" name="footer_copyright" value="<?php echo htmlspecialchars(getSetting($pdo, 'footer_copyright')); ?>" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="footer_powered_by">"Powered By" Text</label>
|
||||
<label for="footer_powered_by">Other</label>
|
||||
<input type="text" id="footer_powered_by" name="footer_powered_by" value="<?php echo htmlspecialchars(getSetting($pdo, 'footer_powered_by')); ?>" required>
|
||||
</div>
|
||||
|
||||
<h3 style="margin: 2rem 0 1rem; border-bottom: 1px solid var(--glass-border); padding-bottom: 0.5rem;">Theme Colors</h3>
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 1rem; margin-bottom: 1.5rem;">
|
||||
<div class="form-group">
|
||||
<label for="theme_primary_color">Primary Color</label>
|
||||
<input type="color" id="theme_primary_color" name="theme_primary_color" value="<?php echo htmlspecialchars(getSetting($pdo, 'theme_primary_color') ?: '#6366f1'); ?>" style="height: 45px; cursor: pointer;">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="theme_bg_color">Background Color</label>
|
||||
<input type="color" id="theme_bg_color" name="theme_bg_color" value="<?php echo htmlspecialchars(getSetting($pdo, 'theme_bg_color') ?: '#0f172a'); ?>" style="height: 45px; cursor: pointer;">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="theme_text_color">Text Color</label>
|
||||
<input type="color" id="theme_text_color" name="theme_text_color" value="<?php echo htmlspecialchars(getSetting($pdo, 'theme_text_color') ?: '#f8fafc'); ?>" style="height: 45px; cursor: pointer;">
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" name="update_site" class="btn btn-primary" style="width: 100%;">Update Settings</button>
|
||||
</form>
|
||||
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ nav {
|
|||
.hero {
|
||||
height: 400px;
|
||||
background-size: cover;
|
||||
background-position: center 20%; /* Adjusted to show more of the top/center */
|
||||
background-position: top center; /* Anchored to top to prevent cutting off */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
|
@ -136,6 +136,7 @@ nav {
|
|||
border-radius: 0 0 40px 40px;
|
||||
margin-bottom: 3rem;
|
||||
background-repeat: no-repeat;
|
||||
overflow: hidden; /* Prevent image bleeding */
|
||||
}
|
||||
|
||||
.hero::after {
|
||||
|
|
@ -145,7 +146,7 @@ nav {
|
|||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(to bottom, rgba(15, 23, 42, 0.4), var(--bg-dark));
|
||||
background: linear-gradient(to bottom, rgba(15, 23, 42, 0.05), rgba(15, 23, 42, 0.3));
|
||||
}
|
||||
|
||||
.hero-content {
|
||||
|
|
@ -265,6 +266,12 @@ input:focus, textarea:focus {
|
|||
.hero h1 {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
.hero {
|
||||
height: auto;
|
||||
min-height: 180px;
|
||||
padding: 2.5rem 1.5rem;
|
||||
border-radius: 0 0 24px 24px;
|
||||
}
|
||||
.nav-links {
|
||||
display: none;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<footer style="text-align: center; padding: 3rem; color: var(--text-muted); border-top: 1px solid var(--glass-border); margin-top: 3rem;">
|
||||
<p>© <?php echo date('Y'); ?> <?php echo htmlspecialchars(getSetting($pdo, 'footer_copyright')); ?>. Powered by <?php echo htmlspecialchars(getSetting($pdo, 'footer_powered_by')); ?>.</p>
|
||||
<p>© <?php echo date('Y'); ?> <?php echo parseFooterText(getSetting($pdo, 'footer_copyright')); ?>. <?php echo parseFooterText(getSetting($pdo, 'footer_powered_by')); ?></p>
|
||||
</footer>
|
||||
<script src="<?php echo PROJECT_ROOT_URL; ?>/assets/js/main.js"></script>
|
||||
</body>
|
||||
|
|
|
|||
|
|
@ -43,7 +43,14 @@ function requireRole($role) {
|
|||
function logActivity($user_id, $action, $details = null) {
|
||||
global $pdo;
|
||||
$username = $_SESSION['admin_username'] ?? 'GUEST';
|
||||
$ip = $_SERVER['REMOTE_ADDR'] ?? 'UNKNOWN';
|
||||
$ip = 'UNKNOWN';
|
||||
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
|
||||
$ip = $_SERVER['HTTP_CLIENT_IP'];
|
||||
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
|
||||
$ip = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])[0];
|
||||
} elseif (!empty($_SERVER['REMOTE_ADDR'])) {
|
||||
$ip = $_SERVER['REMOTE_ADDR'];
|
||||
}
|
||||
|
||||
$stmt = $pdo->prepare("INSERT INTO activity_log (user_id, username, action, details, ip_address) VALUES (?, ?, ?, ?, ?)");
|
||||
$stmt->execute([$user_id, $username, $action, $details, $ip]);
|
||||
|
|
@ -121,4 +128,15 @@ function uploadImage($file) {
|
|||
function formatDate($date) {
|
||||
return date("F j, Y", strtotime($date));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse text for URLs and convert to clickable links
|
||||
*/
|
||||
function parseFooterText($text) {
|
||||
$escaped = htmlspecialchars($text);
|
||||
// Regex for URLs
|
||||
$pattern = '/(https?:\/\/[^\s]+)/';
|
||||
$replacement = '<a href="$1" target="_blank" style="color: var(--primary-color); text-decoration: none; font-weight: 600;">$1</a>';
|
||||
return preg_replace($pattern, $replacement, $escaped);
|
||||
}
|
||||
?>
|
||||
|
|
|
|||
|
|
@ -12,13 +12,25 @@ $banner_image = getSetting($pdo, 'banner_image');
|
|||
<title><?php echo htmlspecialchars($site_title); ?></title>
|
||||
<link rel="stylesheet" href="<?php echo PROJECT_ROOT_URL; ?>/assets/css/style.css">
|
||||
<link rel="icon" type="image/png" href="<?php echo PROJECT_ROOT_URL; ?>/assets/uploads/images/icon.png">
|
||||
<style>
|
||||
:root {
|
||||
<?php
|
||||
$pColor = getSetting($pdo, 'theme_primary_color') ?: '#6366f1';
|
||||
$bgColor = getSetting($pdo, 'theme_bg_color') ?: '#0f172a';
|
||||
$tColor = getSetting($pdo, 'theme_text_color') ?: '#f8fafc';
|
||||
?>
|
||||
--primary-color: <?php echo $pColor; ?>;
|
||||
--bg-dark: <?php echo $bgColor; ?>;
|
||||
--text-main: <?php echo $tColor; ?>;
|
||||
--primary-hover: <?php echo $pColor; ?>dd; /* Slightly lighter/transparent for hover */
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<nav>
|
||||
<a href="<?php echo PROJECT_ROOT_URL; ?>/" class="logo"><?php echo htmlspecialchars($site_title); ?></a>
|
||||
<div class="nav-links">
|
||||
<a href="<?php echo PROJECT_ROOT_URL; ?>/">Home</a>
|
||||
<a href="<?php echo PROJECT_ROOT_URL; ?>/subscribe.php">How to Subscribe</a>
|
||||
<button id="notify-btn" class="notify-btn">🔔 Notify Me</button>
|
||||
<?php if (isAdmin()): ?>
|
||||
<a href="<?php echo PROJECT_ROOT_URL; ?>/admin/dashboard.php">Dashboard</a>
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
<?php header('Location: ../index.php'); exit;
|
||||
|
|
@ -26,14 +26,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||
logActivity(null, 'LISTENER_STARTED', "Episode: $title (Session: $session_id)");
|
||||
}
|
||||
|
||||
file_put_contents('debug.log', date('[Y-m-d H:i:s] ') . "SUCCESS: Logged play for episode $episode_id ($duration s, session: $session_id)" . PHP_EOL, FILE_APPEND);
|
||||
echo json_encode(['status' => 'success']);
|
||||
} catch (PDOException $e) {
|
||||
file_put_contents('debug.log', date('[Y-m-d H:i:s] ') . "DB ERROR: " . $e->getMessage() . PHP_EOL, FILE_APPEND);
|
||||
echo json_encode(['status' => 'error', 'message' => 'Database error']);
|
||||
}
|
||||
} else {
|
||||
file_put_contents('debug.log', date('[Y-m-d H:i:s] ') . "INVALID DATA: ID=$episode_id, DUR=$duration" . PHP_EOL, FILE_APPEND);
|
||||
echo json_encode(['status' => 'error', 'message' => 'Invalid episode ID']);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
12
index.php
12
index.php
|
|
@ -18,17 +18,7 @@ if ($banner_image === 'default-banner.jpg') {
|
|||
?>
|
||||
|
||||
<div class="hero" style="background-image: url('<?php echo $banner_url; ?>');">
|
||||
<div class="hero-content">
|
||||
<h1><?php echo htmlspecialchars($site_title); ?></h1>
|
||||
<p>Listen to our latest messages and sermons.</p>
|
||||
<div style="margin-top: 2rem; display: flex; gap: 1rem; justify-content: center;">
|
||||
<a href="subscribe.php" class="btn btn-primary">How to Subscribe</a>
|
||||
<a href="feed.php" class="btn" style="background: rgba(255,255,255,0.1); backdrop-filter: blur(10px); border: 1px solid var(--glass-border);">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align: middle; margin-right: 0.5rem;"><path d="M4 11a9 9 0 0 1 9 9"></path><path d="M4 4a16 16 0 0 1 16 16"></path><circle cx="5" cy="19" r="1"></circle></svg>
|
||||
RSS Feed
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
<?php header('Location: ../index.php'); exit;
|
||||
|
|
@ -44,7 +44,10 @@ INSERT IGNORE INTO settings (`key`, `value`) VALUES
|
|||
('site_title', 'Our Church Podcast'),
|
||||
('banner_image', 'default-banner.jpg'),
|
||||
('footer_copyright', 'Our Church'),
|
||||
('footer_powered_by', 'Antigravity Podcast Server');
|
||||
('footer_powered_by', 'Antigravity Podcast Server'),
|
||||
('theme_primary_color', '#6366f1'),
|
||||
('theme_bg_color', '#0f172a'),
|
||||
('theme_text_color', '#f8fafc');
|
||||
|
||||
-- Subscriptions table (Push Notifications)
|
||||
CREATE TABLE IF NOT EXISTS subscriptions (
|
||||
|
|
|
|||
Loading…
Reference in New Issue