diff --git a/app/static/common.js b/app/static/common.js index e6d41cb..92cc934 100644 --- a/app/static/common.js +++ b/app/static/common.js @@ -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); -} \ No newline at end of file + checkboxes.forEach(function(checkbox) { + if (!checkbox.disabled) { + checkbox.checked = checkAll.checked; + } + }); +}; \ No newline at end of file diff --git a/app/static/index.js b/app/static/index.js index 32ce09b..9c9aed1 100644 --- a/app/static/index.js +++ b/app/static/index.js @@ -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(); -}); \ No newline at end of file +}); diff --git a/app/static/scraper_utils.js b/app/static/scraper_utils.js new file mode 100644 index 0000000..9e0eb09 --- /dev/null +++ b/app/static/scraper_utils.js @@ -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')}`; + } +} diff --git a/app/templates/download_results.html b/app/templates/download_results.html index c8f1f3e..4eecbd5 100644 --- a/app/templates/download_results.html +++ b/app/templates/download_results.html @@ -67,7 +67,7 @@ - + diff --git a/app/templates/includes/navigation.html b/app/templates/includes/navigation.html index 4081cb0..5916d93 100644 --- a/app/templates/includes/navigation.html +++ b/app/templates/includes/navigation.html @@ -15,9 +15,25 @@
- \ No newline at end of file diff --git a/app/templates/includes/scripts.html b/app/templates/includes/scripts.html index 75476c2..f560c92 100644 --- a/app/templates/includes/scripts.html +++ b/app/templates/includes/scripts.html @@ -1,3 +1,3 @@ {{ bootstrap.load_js() }} - + \ No newline at end of file diff --git a/app/templates/index.html b/app/templates/index.html index 356bca2..b04c4d0 100644 --- a/app/templates/index.html +++ b/app/templates/index.html @@ -30,5 +30,5 @@
- + {% endblock content %} \ No newline at end of file
File Name Last Modified Created