179 lines
7.3 KiB
JavaScript
179 lines
7.3 KiB
JavaScript
// Smooth transitions and audio player enhancements
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
const cards = document.querySelectorAll('.episode-card');
|
|
|
|
// Find project root from script src
|
|
const scripts = document.getElementsByTagName('script');
|
|
let projectRoot = '';
|
|
for(let s of scripts) {
|
|
if(s.src.includes('main.js')) {
|
|
projectRoot = s.src.split('/assets/js/main.js')[0];
|
|
}
|
|
}
|
|
if (!projectRoot) projectRoot = window.location.origin;
|
|
|
|
// Intersection Observer for fade-in effect
|
|
const observerOptions = {
|
|
threshold: 0.1
|
|
};
|
|
|
|
const observer = new IntersectionObserver((entries) => {
|
|
entries.forEach(entry => {
|
|
if (entry.isIntersecting) {
|
|
entry.target.style.opacity = '1';
|
|
entry.target.style.transform = 'translateY(0)';
|
|
}
|
|
});
|
|
}, observerOptions);
|
|
|
|
cards.forEach(card => {
|
|
card.style.opacity = '0';
|
|
card.style.transform = 'translateY(20px)';
|
|
card.style.transition = 'all 0.6s cubic-bezier(0.4, 0, 0.2, 1)';
|
|
observer.observe(card);
|
|
});
|
|
|
|
// Handle audio player play states and tracking
|
|
const audios = document.querySelectorAll('audio');
|
|
audios.forEach(audio => {
|
|
let startTime = 0;
|
|
let sessionId = null;
|
|
const episodeCard = audio.closest('.episode-card');
|
|
const episodeId = episodeCard ? episodeCard.id.replace('episode-', '') : null;
|
|
|
|
const generateSessionId = () => {
|
|
return Date.now() + '-' + Math.random().toString(36).substr(2, 9);
|
|
};
|
|
|
|
audio.addEventListener('play', () => {
|
|
if (!sessionId) sessionId = generateSessionId();
|
|
startTime = Date.now();
|
|
// Pause other players
|
|
audios.forEach(otherAudio => {
|
|
if (otherAudio !== audio) {
|
|
otherAudio.pause();
|
|
}
|
|
});
|
|
});
|
|
|
|
const logPlay = (isHeartbeat = false) => {
|
|
if (!episodeId || startTime === 0) return;
|
|
const duration = Math.round((Date.now() - startTime) / 1000);
|
|
if (duration < 1 && !isHeartbeat) {
|
|
console.log('Skipping log: duration too short', duration);
|
|
return;
|
|
}
|
|
|
|
console.log(`Tracking play for episode ${episodeId}: ${duration}s (Session: ${sessionId}, Heartbeat: ${isHeartbeat})`);
|
|
|
|
fetch(projectRoot + '/includes/track_play.php', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
body: `episode_id=${episodeId}&duration=${duration}&session_id=${sessionId}`
|
|
}).then(response => response.json())
|
|
.then(data => console.log('Tracking response:', data))
|
|
.catch(err => console.error('Tracking fetch error:', err));
|
|
|
|
|
|
if (!isHeartbeat) startTime = 0; // Reset after logging
|
|
else startTime = Date.now(); // Reset for next heartbeat
|
|
};
|
|
|
|
// Log when paused or finished
|
|
audio.addEventListener('pause', () => logPlay());
|
|
audio.addEventListener('ended', () => logPlay());
|
|
|
|
// Heartbeat every 30 seconds
|
|
setInterval(() => {
|
|
if (!audio.paused) logPlay(true);
|
|
}, 30000);
|
|
});
|
|
|
|
// --- Push Notifications Logic ---
|
|
const notifyBtn = document.getElementById('notify-btn');
|
|
if (notifyBtn) {
|
|
if (Notification.permission === 'granted') {
|
|
notifyBtn.classList.add('active');
|
|
notifyBtn.textContent = '🔔 Notifications On';
|
|
}
|
|
|
|
notifyBtn.addEventListener('click', async () => {
|
|
console.log('Notify button clicked');
|
|
|
|
if (!('Notification' in window)) {
|
|
alert('This browser does not support desktop notifications.');
|
|
return;
|
|
}
|
|
|
|
if (window.location.protocol !== 'https:' && window.location.hostname !== 'localhost') {
|
|
alert('Notifications require a secure connection (HTTPS). Please ensure your site has an SSL certificate.');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const permission = await Notification.requestPermission();
|
|
console.log('Permission status:', permission);
|
|
|
|
if (permission === 'granted') {
|
|
notifyBtn.classList.add('active');
|
|
notifyBtn.textContent = '🔔 Notifications On';
|
|
|
|
new Notification('Notifications Enabled!', {
|
|
body: 'You will now receive updates from our podcast.',
|
|
icon: projectRoot + '/favicon.ico'
|
|
});
|
|
|
|
if ('serviceWorker' in navigator) {
|
|
navigator.serviceWorker.register(projectRoot + '/sw.js')
|
|
.then(async reg => {
|
|
console.log('SW Registered');
|
|
try {
|
|
const subscription = await reg.pushManager.subscribe({
|
|
userVisibleOnly: true,
|
|
// Note: In a real app, you'd generate VAPID keys.
|
|
// For now, we use a placeholder or skip if browser allows.
|
|
applicationServerKey: 'BM-YOUR-PUBLIC-VAPID-KEY-HERE'
|
|
});
|
|
|
|
await fetch(projectRoot + '/includes/subscribe_push.php', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(subscription)
|
|
});
|
|
console.log('Subscription saved to server');
|
|
} catch (e) {
|
|
console.warn('Push subscription failed:', e);
|
|
}
|
|
})
|
|
.catch(err => console.error('SW Error:', err));
|
|
}
|
|
} else if (permission === 'denied') {
|
|
alert('Notifications were denied. Please enable them in your browser settings if you wish to receive updates.');
|
|
}
|
|
} catch (err) {
|
|
console.error('Error requesting notification permission:', err);
|
|
alert('An error occurred while requesting permission. Check the console for details.');
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Copy text to clipboard with UI feedback
|
|
*/
|
|
function copyToClipboard(text, btnId) {
|
|
const btn = document.getElementById(btnId);
|
|
navigator.clipboard.writeText(text).then(() => {
|
|
if (btn) {
|
|
btn.classList.add('copy-success');
|
|
const originalHtml = btn.innerHTML;
|
|
btn.innerHTML = '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg>';
|
|
|
|
setTimeout(() => {
|
|
btn.classList.remove('copy-success');
|
|
btn.innerHTML = originalHtml;
|
|
}, 2000);
|
|
}
|
|
});
|
|
}
|