Track timestamps server-side
This commit is contained in:
@@ -75,4 +75,4 @@ Build and push this container to ghcr
|
|||||||
- [x] header on playlist page
|
- [x] header on playlist page
|
||||||
- [x] Choose database directory
|
- [x] Choose database directory
|
||||||
- [x] add extension to download
|
- [x] add extension to download
|
||||||
- [ ] server-side watch progress
|
- [x] server-side watch progress
|
||||||
|
@@ -20,24 +20,20 @@ func SetTimestamp(c echo.Context) error {
|
|||||||
|
|
||||||
// Define a struct to receive the timestamp from JSON
|
// Define a struct to receive the timestamp from JSON
|
||||||
type TimestampRequest struct {
|
type TimestampRequest struct {
|
||||||
Timestamp string `json:"timestamp"`
|
Timestamp float64 `json:"timestamp"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the request body
|
// Parse the request body
|
||||||
var req TimestampRequest
|
var req TimestampRequest
|
||||||
if err := c.Bind(&req); err != nil {
|
if err := c.Bind(&req); err != nil {
|
||||||
|
log.Errorln(err)
|
||||||
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid request body"})
|
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid request body"})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate that timestamp was provided
|
log.Debugln("set video", id, "timestamp:", req.Timestamp)
|
||||||
if req.Timestamp == "" {
|
|
||||||
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Timestamp is required"})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get database connection
|
|
||||||
db := database.Get()
|
|
||||||
|
|
||||||
// Update the timestamp field with the value from the request
|
// Update the timestamp field with the value from the request
|
||||||
|
db := database.Get()
|
||||||
result := db.Model(&originals.Original{}).
|
result := db.Model(&originals.Original{}).
|
||||||
Where("id = ?", id).
|
Where("id = ?", id).
|
||||||
Update("timestamp", req.Timestamp)
|
Update("timestamp", req.Timestamp)
|
||||||
|
@@ -1,42 +1,60 @@
|
|||||||
|
|
||||||
// Get all video and audio elements
|
// Get all video and audio elements
|
||||||
const mediaElements = document.querySelectorAll('video, audio');
|
const mediaElements = document.querySelectorAll('video, audio');
|
||||||
|
|
||||||
// Generate a unique key for this page
|
// Get the video ID from the hidden input
|
||||||
const pageKey = `mediaProgress_${window.location.pathname}`;
|
const videoId = document.getElementById('video-id').value;
|
||||||
|
|
||||||
// Function to save the current time of the most recently played media
|
// Get the initial timestamp from the hidden input
|
||||||
function saveMediaProgress(media) {
|
const initialTimestamp = parseFloat(document.getElementById('video-timestamp').value || 0);
|
||||||
localStorage.setItem(pageKey, media.currentTime);
|
|
||||||
|
// Track the last time we sent an update to avoid excessive requests
|
||||||
|
let lastUpdateTime = 0;
|
||||||
|
const UPDATE_INTERVAL = 5000; // 5 seconds in milliseconds
|
||||||
|
|
||||||
|
// Function to send the current time to the server
|
||||||
|
function sendTimestampToServer(timestamp) {
|
||||||
|
console.log(timestamp)
|
||||||
|
fetch(`/video/${videoId}/set_timestamp`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ "timestamp": timestamp })
|
||||||
|
}).catch(error => {
|
||||||
|
console.error('Error sending timestamp to server:', error);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to load and set the saved time for all media elements
|
// Function to handle periodic updates while playing
|
||||||
function loadMediaProgress() {
|
function handleTimeUpdate(media) {
|
||||||
const savedTime = localStorage.getItem(pageKey);
|
// Only send updates every 5 seconds while playing
|
||||||
if (savedTime) {
|
const now = Date.now();
|
||||||
mediaElements.forEach(media => {
|
if (!media.paused && now - lastUpdateTime >= UPDATE_INTERVAL) {
|
||||||
media.currentTime = Math.min(parseFloat(savedTime), media.duration || Infinity);
|
sendTimestampToServer(media.currentTime);
|
||||||
});
|
lastUpdateTime = now;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up event listeners for each media element
|
// Set up event listeners for each media element
|
||||||
mediaElements.forEach(media => {
|
mediaElements.forEach(media => {
|
||||||
// Save progress when the media is playing
|
// Set initial timestamp when media is ready
|
||||||
media.addEventListener('timeupdate', () => {
|
media.addEventListener('loadedmetadata', () => {
|
||||||
if (!media.paused) {
|
// Only set if the initial timestamp is within the media duration
|
||||||
saveMediaProgress(media);
|
if (initialTimestamp > 0 && initialTimestamp < media.duration) {
|
||||||
|
media.currentTime = initialTimestamp;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Also save when the media is paused
|
// Send updates periodically while playing
|
||||||
media.addEventListener('pause', () => saveMediaProgress(media));
|
media.addEventListener('timeupdate', () => handleTimeUpdate(media));
|
||||||
|
|
||||||
// Load the saved progress when the media is ready
|
// Send update when media is paused
|
||||||
media.addEventListener('loadedmetadata', loadMediaProgress);
|
media.addEventListener('pause', () => {
|
||||||
|
sendTimestampToServer(media.currentTime);
|
||||||
|
});
|
||||||
|
|
||||||
// Clear progress when any media ends
|
// Reset timestamp when media ends
|
||||||
media.addEventListener('ended', () => {
|
media.addEventListener('ended', () => {
|
||||||
localStorage.removeItem(pageKey);
|
sendTimestampToServer(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
Reference in New Issue
Block a user