adds activity indicators in header (ugly af)

This commit is contained in:
2025-02-11 01:58:06 +01:00
parent 0340dea4f8
commit 57e969a647
7 changed files with 234 additions and 92 deletions

View File

@@ -1,64 +1,22 @@
import { ScraperUtils } from './scraper_utils.js';
class Common {
constructor() {
this.activityIndicator = document.getElementById('activity_indicator');
this.endTimeElement = document.getElementById('end_time');
this.serverTimeElement = document.getElementById('server_time');
this.init();
this.utils = new ScraperUtils();
this.addEventListeners();
this.scheduleUpdates();
}
init() {
this.updateServerTime();
setInterval(() => this.updateServerTime(), 60000); // Update every minute
this.checkScrapingStatus();
scheduleUpdates() {
// Ensure server time updates every minute but only after initial fetch
setTimeout(() => {
setInterval(() => this.utils.updateServerTime(), 60000);
}, 5000); // Delay first scheduled update to prevent duplicate initial request
}
async fetchEndTime() {
try {
const response = await fetch('/scraping_get_end_time');
const data = await response.json();
if (data.end_time) {
const endTime = new Date(data.end_time);
const localEndTime = endTime.toLocaleString();
this.endTimeElement.textContent = `End Time: ${endTime} TCT`;
}
} catch (error) {
this.endTimeElement.textContent = 'Error fetching end time';
console.error('Error fetching end time:', error);
}
}
async updateServerTime() {
try {
const response = await fetch('/server_time');
const data = await response.json();
this.serverTimeElement.textContent = `Server Time (UTC): ${data.server_time}`;
} catch (error) {
console.error('Error fetching server time:', error);
}
}
async checkScrapingStatus() {
try {
const response = await fetch('/scraping_status');
const data = await response.json();
if (data.scraping_active) {
this.activityIndicator.classList.remove('text-bg-danger');
this.activityIndicator.classList.add('text-bg-success');
this.activityIndicator.textContent = 'Active';
this.endTimeElement.classList.remove('d-none');
this.endTimeElement.textContent = data.end_time;
await this.fetchEndTime();
} else {
this.activityIndicator.classList.remove('text-bg-success');
this.activityIndicator.classList.add('text-bg-danger');
this.activityIndicator.textContent = 'Inactive';
this.endTimeElement.textContent = '';
this.endTimeElement.classList.add('d-none');
}
} catch (error) {
console.error('Error checking scraping status:', error);
addEventListeners() {
if (this.utils.stopButton) {
this.utils.stopButton.addEventListener('click', () => this.utils.checkScrapingStatus());
}
}
}
@@ -67,10 +25,14 @@ document.addEventListener('DOMContentLoaded', () => {
new Common();
});
function checkAllCheckboxes(tableId, checkAllCheckboxId) {
const table = document.getElementById(tableId);
const checkboxes = table.querySelectorAll('input[type="checkbox"]:not(:disabled)');
const checkAllCheckbox = document.getElementById(checkAllCheckboxId);
window.checkAllCheckboxes = function(tableId, checkAllId) {
var table = document.getElementById(tableId);
var checkAll = document.getElementById(checkAllId);
var checkboxes = table.querySelectorAll('input[type="checkbox"]');
checkboxes.forEach(checkbox => checkbox.checked = checkAllCheckbox.checked);
}
checkboxes.forEach(function(checkbox) {
if (!checkbox.disabled) {
checkbox.checked = checkAll.checked;
}
});
};

View File

@@ -1,36 +1,21 @@
import { ScraperUtils } from './scraper_utils.js';
class ScraperApp {
constructor() {
this.utils = new ScraperUtils();
this.form = document.getElementById('scrapingForm');
this.stopButton = document.getElementById('stopButton');
this.startButton = document.getElementById('startButton');
this.activityIndicator = document.getElementById('activity_indicator');
this.endTimeElement = document.getElementById('end_time');
this.init();
}
init() {
this.checkScrapingStatusIndex();
this.utils.checkScrapingStatus();
this.addEventListeners();
}
async checkScrapingStatusIndex() {
try {
const response = await fetch('/scraping_status');
const data = await response.json();
if (data.scraping_active) {
this.startButton.disabled = true;
this.stopButton.disabled = false;
} else {
this.startButton.disabled = false;
this.stopButton.disabled = true;
}
} catch (error) {
console.error('Error checking scraping status:', error);
}
}
async startScraping(event) {
event.preventDefault(); // Prevent the default form submission
event.preventDefault(); // Prevent default form submission
const formData = new FormData(this.form);
try {
const response = await fetch('/start_scraping', {
@@ -39,7 +24,7 @@ class ScraperApp {
});
const data = await response.json();
if (data.status === "Scraping started") {
this.checkScrapingStatusIndex();
this.utils.checkScrapingStatus(); // Update UI
}
} catch (error) {
console.error('Error starting scraping:', error);
@@ -53,7 +38,7 @@ class ScraperApp {
});
const data = await response.json();
if (data.status === "Scraping stopped") {
this.checkScrapingStatusIndex();
this.utils.checkScrapingStatus(); // Update UI
}
} catch (error) {
console.error('Error stopping scraping:', error);
@@ -66,7 +51,6 @@ class ScraperApp {
}
}
// Initialize the application when DOM is fully loaded
document.addEventListener('DOMContentLoaded', () => {
new ScraperApp();
});
});

180
app/static/scraper_utils.js Normal file
View File

@@ -0,0 +1,180 @@
export class ScraperUtils {
constructor() {
this.activityIndicator = document.getElementById('activity_indicator');
this.endTimeElement = document.getElementById('end_time');
this.serverTimeElement = document.getElementById('server_time');
this.timeLeftElement = document.getElementById('time-left'); // New element for countdown
this.stopButton = document.getElementById('stopButton');
this.startButton = document.getElementById('startButton');
this.statusContainer = document.getElementById('status_container');
this.loadingIndicator = document.getElementById('loading_indicator');
this.statusContent = document.querySelectorAll('#status_content');
this.serverTime = null;
this.endTime = null;
this.init();
}
async init() {
this.showLoadingIndicator();
try {
// Ensure each function runs only once
await Promise.all([
this.updateServerTime(),
this.checkScrapingStatus()
]);
} catch (error) {
console.error("Error during initialization:", error);
}
// Ensure end time is fetched only if scraping is active
if (this.endTime === null) {
try {
await this.fetchEndTime();
} catch (error) {
console.error("Error fetching end time:", error);
}
}
// Ensure UI is only updated once everything is ready
if (this.serverTime && this.endTime) {
this.startClock();
this.hideLoadingIndicator();
} else {
console.warn("Delaying hiding the loading indicator due to missing data...");
const checkDataInterval = setInterval(() => {
if (this.serverTime && this.endTime) {
clearInterval(checkDataInterval);
this.startClock();
this.hideLoadingIndicator();
}
}, 500);
}
}
showLoadingIndicator() {
this.statusContainer.classList.remove('d-none');
this.loadingIndicator.classList.remove('d-none');
this.statusContent.forEach(element => element.classList.add('d-none'));
}
hideLoadingIndicator() {
this.loadingIndicator.classList.add('d-none');
this.statusContent.forEach(element => element.classList.remove('d-none'));
}
async checkScrapingStatus() {
try {
const response = await fetch('/scraping_status');
const data = await response.json();
if (data.scraping_active) {
if (this.startButton) this.startButton.disabled = true;
if (this.stopButton) this.stopButton.disabled = false;
this.activityIndicator.classList.remove('text-bg-danger');
this.activityIndicator.classList.add('text-bg-success');
this.activityIndicator.textContent = 'Active';
console.log(`Scraping is active until ${data.end_time} TCT`);
// Only call fetchEndTime() if endTime is not already set
if (!this.endTime) {
await this.fetchEndTime();
}
this.endTimeElement.classList.remove('d-none');
this.timeLeftElement.classList.remove('d-none');
} else {
if (this.startButton) this.startButton.disabled = false;
if (this.stopButton) this.stopButton.disabled = true;
this.activityIndicator.classList.remove('text-bg-success');
this.activityIndicator.classList.add('text-bg-danger');
this.activityIndicator.textContent = 'Inactive';
this.endTimeElement.classList.add('d-none');
this.timeLeftElement.classList.add('d-none');
}
} catch (error) {
console.error('Error checking scraping status:', error);
}
}
async updateServerTime() {
try {
const response = await fetch('/server_time');
const data = await response.json();
this.serverTime = new Date(data.server_time.replace(' ', 'T'));
this.serverTimeElement.textContent = `Server Time (TCT): ${this.formatDateToHHMMSS(this.serverTime)}`;
} catch (error) {
console.error('Error fetching server time:', error);
}
}
async fetchEndTime() {
if (this.endTime) return;
try {
const response = await fetch('/scraping_get_end_time');
const data = await response.json();
if (data.end_time) {
this.endTime = new Date(data.end_time);
this.endTimeElement.textContent = `Running until ${this.formatDateToYYYYMMDDHHMMSS(this.endTime)} TCT`;
}
} catch (error) {
this.endTimeElement.textContent = 'Error fetching end time';
console.error('Error fetching end time:', error);
}
}
startClock() {
const updateClock = () => {
if (this.serverTime) {
this.serverTime.setSeconds(this.serverTime.getSeconds() + 1);
this.serverTimeElement.textContent = `Server Time (TCT): ${this.formatDateToHHMMSS(this.serverTime)}`;
}
if (this.endTime && this.serverTime) {
const timeLeft = this.endTime - this.serverTime;
this.timeLeftElement.textContent = `Time Left: ${timeLeft > 0 ? this.formatMillisecondsToHHMMSS(timeLeft) : '00:00:00'}`;
}
};
// Immediately update the clock
updateClock();
// Continue updating every second
setInterval(updateClock, 1000);
}
formatDateToYYYYMMDDHHMMSS(date) {
if (!(date instanceof Date) || isNaN(date)) {
console.error('Invalid date:', date);
return '';
}
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')} ` +
`${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}:${String(date.getSeconds()).padStart(2, '0')}`;
}
formatDateToHHMMSS(date) {
if (!(date instanceof Date) || isNaN(date)) {
console.error('Invalid date:', date);
return '';
}
return `${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}:${String(date.getSeconds()).padStart(2, '0')}`;
}
formatMillisecondsToHHMMSS(ms) {
const totalSeconds = Math.floor(ms / 1000);
const hours = Math.floor(totalSeconds / 3600);
const minutes = Math.floor((totalSeconds % 3600) / 60);
const seconds = totalSeconds % 60;
return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
}
}