clean
This commit is contained in:
854
news4.html
854
news4.html
@@ -1,854 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
|
||||
<script src="https://code.jquery.com/ui/1.13.1/jquery-ui.js" integrity="sha256-6XMVI0zB8cRzfZjqKcD01PBsAy3FlDASrlC8SxCpInY=" crossorigin="anonymous"></script>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>RLX News</title>
|
||||
<style>
|
||||
/* --- Flexbox Sticky Footer --- */
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
body {
|
||||
min-height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
html, body {
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: #f4f4f4;
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
#full-display-container, #sad-display-area {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.form-container {
|
||||
max-width: 800px;
|
||||
position: relative;
|
||||
padding: 15px;
|
||||
background: white;
|
||||
margin-bottom: 10px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.toggle-btn, button { font-size: 20px; padding: 8px 15px; cursor: pointer; }
|
||||
button { background-color: #4CAF50; color: white; border: none; border-radius: 4px; }
|
||||
button:hover { background-color: #45a049; }
|
||||
.form-group label { font-size: 20px; margin-bottom: 5px; display: block; }
|
||||
input, textarea { width: 100%; padding: 10px; font-size: 18px; box-sizing: border-box; }
|
||||
|
||||
#full-display-container {
|
||||
max-width: 100%;
|
||||
margin: 0 auto;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
#sad-display-area {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
#top-stories-container, #bottom-stories-container {
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
min-height: 0;
|
||||
}
|
||||
#top-stories-container { flex-basis: 50%; flex-shrink: 0; }
|
||||
#bottom-stories-container { background: #e9e9e9; padding: 5px; border-radius: 8px; }
|
||||
|
||||
.scroller-inner {
|
||||
animation-name: continuous-scroll;
|
||||
animation-timing-function: linear;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
|
||||
.content-block {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
@keyframes continuous-scroll {
|
||||
0% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
100% {
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
}
|
||||
|
||||
.news-item { background: white; padding: 5px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); display: flex; align-items: center; }
|
||||
.news-item img { width: 150px; height: 100px; object-fit: cover; border-radius: 6px; margin-right: 10px; }
|
||||
.news-content { flex: 2; }
|
||||
.headline { color: #333; font-size: 36px; margin: 0 0 5px 0; line-height: 1.0; font-weight: bold; }
|
||||
.summary { color: #666; font-size: 28px; margin: 0 0 5px 0; line-height: 1.0; display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; }
|
||||
.storylink { color: #007BFF; text-decoration: none; }
|
||||
.storylink:hover { text-decoration: underline; }
|
||||
|
||||
.relevance-high { background-color: lightblue; }
|
||||
.relevance-really-high { background-color: cyan; }
|
||||
.relevance-super-high { background-color: yellow; }
|
||||
.relevance-mazza-high { background-color: orange; }
|
||||
.relevance-cheech-high { background-color: #FF8790; }
|
||||
|
||||
@keyframes flashRedOutline {
|
||||
0% { outline: 7px solid red; }
|
||||
50% { outline: 7px solid transparent; }
|
||||
100% { outline: 10px solid red; }
|
||||
}
|
||||
.new-story-flash {
|
||||
animation: flashRedOutline 2s linear infinite;
|
||||
border-radius: 8px; /* Match the news-item border-radius */
|
||||
}
|
||||
|
||||
#ticker-container {
|
||||
width: 100%;
|
||||
background-color: black;
|
||||
overflow: hidden;
|
||||
padding: 5px 0;
|
||||
box-sizing: border-box;
|
||||
z-index: 1000;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
#ticker-content {
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
/* animation removed, now handled by JS */
|
||||
}
|
||||
|
||||
#ticker-content > span {
|
||||
margin: 0 20px;
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
.ticker-year { color: lightgray; }
|
||||
.ticker-event { color: white; }
|
||||
.ticker-report { color: lightblue; }
|
||||
.ticker-wikimedia { color: lightpink; } /* Style for Wikimedia events */
|
||||
.ticker-holiday { color: lightgreen; } /* Style for holiday events */
|
||||
.ticker-upcoming { color: cyan; } /* Style for upcoming events */
|
||||
|
||||
@media (max-width: 768px) {
|
||||
#full-display-container {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.content-block {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="form-container" id="form-container">
|
||||
<button class="toggle-btn" onclick="toggleForm();">Expand News Search Dialog</button>
|
||||
<div id="searchForm" style="display: none;">
|
||||
<div class="form-group"><label for="startTime">Start Time (Zulu/UTC):</label><input type="datetime-local" id="startTime" name="startTime" required></div>
|
||||
<div class="form-group"><label for="endTime">End Time (Zulu/UTC):</label><input type="datetime-local" id="endTime" name="endTime" required></div>
|
||||
<div class="form-group"><label for="keyTerms">Key Terms (comma-separated):</label><textarea id="keyTerms" name="keyTerms" rows="3" required>weather,flood,fire,fog,snow,emergency,wind,ice,rain,power,explosion,warmer,colder,drown,stream,river,air,wind,destroyed,rime,glaze,river,ice,creek,crash,thunder,spinup,black ice,fog,spill,pileup,pile-up,gust,frozen,funnel,rainfall,fatal,injury,sleet,injured,frost,dead,death,landslide,culvert,slippery,wildfire,tornado,blizzard,creek,hail,thunderstorm,downburst,microburst,crash,heatstroke,derecho,lightning,hypothermia,slide,flow,ski,water,innundation,victim,victims,flooding,flooded,snowing,freezing rain,clouds,cloud,storm,aircraft</textarea></div>
|
||||
<button onclick="updatenews();">Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="full-display-container"></div>
|
||||
|
||||
<div class="display-area" id="sad-display-area" style="display: none;">
|
||||
<div id="top-stories-container"></div>
|
||||
<div id="bottom-stories-container"></div>
|
||||
</div>
|
||||
|
||||
<div id="ticker-container">
|
||||
<div id="ticker-content"></div>
|
||||
</div>
|
||||
<script>
|
||||
let lastTickerData = null;
|
||||
let isSadMode = false;
|
||||
var refreshTimer;
|
||||
var tickerWatchdogTimer;
|
||||
const NUM_TOP_STORIES = 8;
|
||||
const BOTTOM_SCROLLER_SPEED_MULTIPLIER = 2;
|
||||
window.currentWikimediaEvents = []; // Initialize the global variable
|
||||
let tickerCycleCount = 0;
|
||||
let upcomingHolidays = [];
|
||||
let triviaQuestions = [];
|
||||
let lastTriviaFetchTime = 0;
|
||||
|
||||
// Always fetch fresh Wikimedia events
|
||||
// No need to cache them between cycles
|
||||
|
||||
const TARGET_BROADCAST_SECONDS = 150;
|
||||
const PIXELS_PER_SECOND_SPEED = 150; // Adjust this value to control scroll speed. Higher is faster.
|
||||
let lastTickerUpdateTime = Date.now();
|
||||
let lastNewsData = null;
|
||||
let currentNewsUrl = 'https://wx.stoat.org/lsr.php?news3=potato';
|
||||
|
||||
let nextTickerHtml = null;
|
||||
let animationId = null;
|
||||
let tickerPosition = 0;
|
||||
let lastTime = 0;
|
||||
let tickerContent = document.getElementById('ticker-content');
|
||||
let injectionHtml = null;
|
||||
|
||||
function animateTicker(currentTime) {
|
||||
if (!lastTime) lastTime = currentTime;
|
||||
const deltaTime = (currentTime - lastTime) / 1000;
|
||||
lastTime = currentTime;
|
||||
tickerPosition -= PIXELS_PER_SECOND_SPEED * deltaTime;
|
||||
const scrollWidth = tickerContent.scrollWidth;
|
||||
if (tickerPosition <= -scrollWidth) {
|
||||
updateTickerContent();
|
||||
tickerPosition = 0;
|
||||
}
|
||||
tickerContent.style.transform = `translateX(${tickerPosition}px)`;
|
||||
animationId = requestAnimationFrame(animateTicker);
|
||||
}
|
||||
|
||||
function updateTickerContent() {
|
||||
if (nextTickerHtml) {
|
||||
tickerContent.innerHTML = nextTickerHtml;
|
||||
const containerWidth = document.getElementById('ticker-container').clientWidth;
|
||||
tickerPosition = -containerWidth;
|
||||
nextTickerHtml = null;
|
||||
// Fetch new
|
||||
fetchAndDisplayTickerData(false);
|
||||
}
|
||||
}
|
||||
|
||||
function fetchAndDisplayNews(url = 'https://wx.stoat.org/lsr.php?news3=potato') {
|
||||
// Update the current URL if provided
|
||||
if (url) {
|
||||
currentNewsUrl = url;
|
||||
}
|
||||
|
||||
$.getJSON(currentNewsUrl, function(newsData) {
|
||||
// Sort the data
|
||||
newsData.sort((a, b) => {
|
||||
if (b.impact_score !== a.impact_score) return b.impact_score - a.impact_score;
|
||||
return new Date(b.timeutc) - new Date(a.timeutc);
|
||||
});
|
||||
|
||||
// Check if data has changed
|
||||
if (lastNewsData && JSON.stringify(newsData) === JSON.stringify(lastNewsData)) {
|
||||
console.log('News data unchanged, skipping update');
|
||||
return;
|
||||
}
|
||||
|
||||
// Update cache
|
||||
lastNewsData = newsData;
|
||||
|
||||
if (isSadMode) {
|
||||
const topContainer = document.getElementById('top-stories-container');
|
||||
const bottomContainer = document.getElementById('bottom-stories-container');
|
||||
topContainer.innerHTML = '';
|
||||
bottomContainer.innerHTML = '';
|
||||
|
||||
const topStories = newsData.slice(0, NUM_TOP_STORIES);
|
||||
const scrollingStories = newsData.slice(NUM_TOP_STORIES);
|
||||
|
||||
function createScroller(stories, durationMultiplier, isBottomScroller = false) {
|
||||
if (stories.length === 0) return null;
|
||||
const scrollerInner = document.createElement('div');
|
||||
scrollerInner.className = 'scroller-inner';
|
||||
const contentBlock1 = document.createElement('div');
|
||||
contentBlock1.className = 'content-block';
|
||||
stories.forEach(news => contentBlock1.appendChild(createNewsItem(news)));
|
||||
const contentBlock2 = contentBlock1.cloneNode(true);
|
||||
contentBlock2.setAttribute('aria-hidden', 'true');
|
||||
scrollerInner.appendChild(contentBlock1);
|
||||
scrollerInner.appendChild(contentBlock2);
|
||||
const duration = stories.length * durationMultiplier;
|
||||
scrollerInner.style.animationName = 'continuous-scroll';
|
||||
scrollerInner.style.animationDuration = `${duration}s`;
|
||||
// Ensure no delay is applied to any scroller
|
||||
scrollerInner.style.animationDelay = '0s';
|
||||
return scrollerInner;
|
||||
}
|
||||
|
||||
const topScroller = createScroller(topStories, 7, false);
|
||||
if (topScroller) topContainer.appendChild(topScroller);
|
||||
|
||||
const bottomScroller = createScroller(scrollingStories, BOTTOM_SCROLLER_SPEED_MULTIPLIER, true);
|
||||
if (bottomScroller) bottomContainer.appendChild(bottomScroller);
|
||||
|
||||
} else {
|
||||
const fullContainer = document.getElementById('full-display-container');
|
||||
fullContainer.innerHTML = '';
|
||||
newsData.forEach(news => fullContainer.appendChild(createNewsItem(news)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createNewsItem(news) {
|
||||
const newsItem = document.createElement('div');
|
||||
newsItem.className = 'news-item';
|
||||
let score = news.impact_score;
|
||||
const storyTime = new Date(news.timeutc);
|
||||
const currentTime = new Date();
|
||||
const oneHourInMs = 3600000;
|
||||
|
||||
// Add flashRedOutline class if the story is less than 1 hour old
|
||||
if (currentTime - storyTime < oneHourInMs) {
|
||||
newsItem.classList.add('new-story-flash');
|
||||
}
|
||||
|
||||
const relevanceClasses = {
|
||||
'relevance-high': score > 15,
|
||||
'relevance-really-high': score > 25,
|
||||
'relevance-super-high': score > 50,
|
||||
'relevance-mazza-high': score > 90,
|
||||
'relevance-cheech-high': score > 150
|
||||
};
|
||||
Object.entries(relevanceClasses).filter(([, c]) => c).forEach(([cN]) => newsItem.classList.add(cN));
|
||||
|
||||
newsItem.innerHTML = `<a href="${news.storylink}" target="_blank"><img src="${news.imageurl}"></a><div class="news-content"><h2 class="headline"><a href="${news.storylink}" target="_blank" class="storylink">(${extractTextBetweenHttpAndCom(news.storylink)}) ${news.headline}</a></h2><p class="summary">${news.summary} ${convertPostgresTimestamp(news.timeutc)}L</p></div>`;
|
||||
return newsItem;
|
||||
}
|
||||
|
||||
function extractTextBetweenHttpAndCom(url) {
|
||||
url = url.replace(/www\./, '');
|
||||
const match = url.match(/https?:\/\/(.*?)\.com/);
|
||||
return match && match[1] ? match[1].toUpperCase() : 'FAUXNEWS';
|
||||
}
|
||||
|
||||
function convertPostgresTimestamp(timestamp) {
|
||||
const d = new Date(timestamp.replace('Z', ''));
|
||||
return `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')} ${String(d.getHours()).padStart(2,'0')}:${String(d.getMinutes()).padStart(2,'0')}`;
|
||||
}
|
||||
|
||||
function toggleForm() {
|
||||
const formContent = document.getElementById("searchForm");
|
||||
const toggleBtn = document.querySelector(".toggle-btn");
|
||||
if (formContent.style.display === "none") {
|
||||
formContent.style.display = "block";
|
||||
toggleBtn.textContent = "Collapse News Search Dialog";
|
||||
if (refreshTimer) clearInterval(refreshTimer);
|
||||
} else {
|
||||
formContent.style.display = "none";
|
||||
toggleBtn.textContent = "Expand News Search Dialog";
|
||||
// Always use the current URL
|
||||
fetchAndDisplayNews(currentNewsUrl);
|
||||
refreshTimer = setInterval(() => {
|
||||
fetchAndDisplayNews(currentNewsUrl);
|
||||
}, 300000);
|
||||
}
|
||||
}
|
||||
|
||||
function completelyHide() { document.getElementById("form-container").style.display = "none"; }
|
||||
|
||||
function updatenews() {
|
||||
const start = document.getElementById("startTime").value;
|
||||
const end = document.getElementById("endTime").value;
|
||||
const keyTerms = document.getElementById("keyTerms").value;
|
||||
const terms = keyTerms.split(',');
|
||||
let arrayterms = terms.map(term => `key[]=${encodeURIComponent(term)}`).join('&');
|
||||
url = `lsr.php?newsarchive=true&start=${start}&end=${end}&${arrayterms}`;
|
||||
// Clear the cache to force an update
|
||||
lastNewsData = null;
|
||||
fetchAndDisplayNews(url);
|
||||
}
|
||||
|
||||
function sadCheck() {
|
||||
const params = new URLSearchParams(document.location.search);
|
||||
if (params.has("sad") || params.has("SAD")) {
|
||||
isSadMode = true;
|
||||
completelyHide();
|
||||
Object.assign(document.documentElement.style, {height: '100%'});
|
||||
Object.assign(document.body.style, {height: '100%', overflow: 'hidden', display: 'flex', flexDirection: 'column'});
|
||||
document.getElementById('sad-display-area').style.display = 'flex';
|
||||
document.getElementById('full-display-container').style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
function format_date_with_ordinal(date) {
|
||||
const day = date.getDate();
|
||||
const month = date.toLocaleString('default', { month: 'long' });
|
||||
const get_ordinal_suffix = (day) => {
|
||||
if (day > 3 && day < 21) return 'th';
|
||||
switch (day % 10) {
|
||||
case 1: return "st";
|
||||
case 2: return "nd";
|
||||
case 3: return "rd";
|
||||
default: return "th";
|
||||
}
|
||||
};
|
||||
const suffix = get_ordinal_suffix(day);
|
||||
return `${month} ${day}${suffix}`;
|
||||
}
|
||||
|
||||
function fetchWikimediaEvents() {
|
||||
const now = new Date();
|
||||
|
||||
// Get the individual components
|
||||
const year = now.getFullYear();
|
||||
const month = String(now.getMonth() + 1).padStart(2, '0'); // Months are 0-indexed, so add 1
|
||||
const day = String(now.getDate()).padStart(2, '0');
|
||||
const hours = String(now.getHours()).padStart(2, '0');
|
||||
|
||||
// Concatenate them into the final string
|
||||
const formattedDate = `${year}${month}${day}${hours}`;
|
||||
|
||||
|
||||
const url = 'https://wx.stoat.org/calendar/wikimedia_onthisday.json';
|
||||
const cacheBustingUrl = `${url}?v=${formattedDate}`;
|
||||
|
||||
return $.getJSON(cacheBustingUrl)
|
||||
.done(function(data) {
|
||||
if (data && data.events && Array.isArray(data.events) && data.events.length > 0) {
|
||||
// Always shuffle and use all events
|
||||
window.currentWikimediaEvents = [...data.events].sort(() => 0.5 - Math.random());
|
||||
} else {
|
||||
console.warn("Wikimedia JSON is empty, invalid, or does not contain an 'events' array.");
|
||||
window.currentWikimediaEvents = [];
|
||||
}
|
||||
})
|
||||
.fail(function(jqXHR, textStatus, errorThrown) {
|
||||
console.error(`Failed to load from ${cacheBustingUrl}. Status: ${textStatus}, Error: ${errorThrown}`);
|
||||
window.currentWikimediaEvents = [];
|
||||
});
|
||||
}
|
||||
|
||||
function fetchHolidays() {
|
||||
const now = new Date();
|
||||
|
||||
// Format today's date as YYYY-MM-DD to match the API response keys
|
||||
const year = now.getFullYear();
|
||||
const month = String(now.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(now.getDate()).padStart(2, '0');
|
||||
const todayFormatted = `${year}-${month}-${day}`;
|
||||
|
||||
// Get the individual components for cache busting
|
||||
const hours = String(now.getHours()).padStart(2, '0');
|
||||
const formattedDate = `${year}${month}${day}${hours}`;
|
||||
|
||||
const url = 'https://calendar.wx4rlx.org/get_holidays.py';
|
||||
const cacheBustingUrl = `${url}?time=${formattedDate}`;
|
||||
|
||||
return $.getJSON(cacheBustingUrl)
|
||||
.done(function(data) {
|
||||
if (data && data.holidays) {
|
||||
// Get holidays for today using the formatted date as the key
|
||||
window.currentHolidays = data.holidays[todayFormatted] || [];
|
||||
|
||||
// Store upcoming holidays for the next 9 days
|
||||
upcomingHolidays = [];
|
||||
for (let i = 1; i <= 9; i++) {
|
||||
const nextDate = new Date(now);
|
||||
nextDate.setDate(now.getDate() + i);
|
||||
const nextYear = nextDate.getFullYear();
|
||||
const nextMonth = String(nextDate.getMonth() + 1).padStart(2, '0');
|
||||
const nextDay = String(nextDate.getDate()).padStart(2, '0');
|
||||
const nextFormatted = `${nextYear}-${nextMonth}-${nextDay}`;
|
||||
|
||||
const nextHolidays = data.holidays[nextFormatted] || [];
|
||||
if (nextHolidays.length > 0) {
|
||||
upcomingHolidays.push({
|
||||
date: nextDate,
|
||||
holidays: nextHolidays
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.warn("Holidays JSON is empty, invalid, or does not contain 'holidays'.");
|
||||
window.currentHolidays = [];
|
||||
upcomingHolidays = [];
|
||||
}
|
||||
})
|
||||
.fail(function(jqXHR, textStatus, errorThrown) {
|
||||
console.error(`Failed to load holidays from ${cacheBustingUrl}. Status: ${textStatus}, Error: ${errorThrown}`);
|
||||
window.currentHolidays = [];
|
||||
upcomingHolidays = [];
|
||||
});
|
||||
}
|
||||
|
||||
function fetchTriviaQuestions() {
|
||||
const now = Date.now();
|
||||
// Check if we need to fetch new questions and respect the 5-second rate limit
|
||||
if (triviaQuestions.length > 10 || now - lastTriviaFetchTime < 5000) {
|
||||
return $.Deferred().resolve().promise();
|
||||
}
|
||||
|
||||
lastTriviaFetchTime = now;
|
||||
const url = 'https://opentdb.com/api.php?amount=50&type=multiple';
|
||||
return $.getJSON(url)
|
||||
.done(function(data) {
|
||||
if (data.response_code === 0 && data.results) {
|
||||
triviaQuestions = data.results;
|
||||
console.log(`Fetched ${triviaQuestions.length} trivia questions`);
|
||||
} else {
|
||||
console.warn('Trivia API returned non-zero response code or no results');
|
||||
triviaQuestions = [];
|
||||
}
|
||||
})
|
||||
.fail(function(jqXHR, textStatus, errorThrown) {
|
||||
console.error(`Failed to fetch trivia questions: ${textStatus}, ${errorThrown}`);
|
||||
triviaQuestions = [];
|
||||
});
|
||||
}
|
||||
|
||||
function fetchInjection() {
|
||||
const injectionApiUrl = 'https://calendar.wx4rlx.org/onetime.py?action=api';
|
||||
return $.ajax({
|
||||
url: injectionApiUrl,
|
||||
dataType: 'text' // Treat the response as plain text
|
||||
})
|
||||
.done(function(data) {
|
||||
if (data && data.trim().length > 0) {
|
||||
injectionHtml = data;
|
||||
console.log('Injection content fetched:', injectionHtml);
|
||||
} else {
|
||||
injectionHtml = null;
|
||||
}
|
||||
})
|
||||
.fail(function() {
|
||||
console.log('No injection content available or error fetching');
|
||||
injectionHtml = null;
|
||||
});
|
||||
}
|
||||
|
||||
function fetchAndDisplayTickerData(startImmediately = true) {
|
||||
// First, fetch the injection content
|
||||
fetchInjection().always(function() {
|
||||
// Then fetch other data
|
||||
$.when(fetchWikimediaEvents(), fetchHolidays(), fetchTriviaQuestions()).always(function() {
|
||||
const tickerApiUrl = 'https://calendar.wx4rlx.org/?action=api';
|
||||
$.getJSON(tickerApiUrl, function(data) {
|
||||
if (data.status !== 'success') return;
|
||||
updateTickerLastUpdateTime();
|
||||
|
||||
// Always update the ticker with fresh data
|
||||
const today = new Date();
|
||||
const currentYear = today.getFullYear();
|
||||
const formatted_date = format_date_with_ordinal(today);
|
||||
const tickerContent = $('#ticker-content');
|
||||
|
||||
let localItems = [];
|
||||
data.events.forEach(item => localItems.push({ date: item.date, text: item.event, type: 'event' }));
|
||||
data.weather_reports.forEach(item => localItems.push({ date: item.date, text: item.report, type: 'report' }));
|
||||
|
||||
// Increment cycle count
|
||||
tickerCycleCount++;
|
||||
|
||||
// Add upcoming events based on cycle count
|
||||
let upcomingEventItem = null;
|
||||
if (upcomingHolidays.length > 0) {
|
||||
// Every 10 cycles takes priority over every other cycle
|
||||
if (tickerCycleCount % 10 === 0) {
|
||||
const nextFiveDays = upcomingHolidays.slice(0, 5);
|
||||
let upcomingTexts = [];
|
||||
nextFiveDays.forEach(day => {
|
||||
const formattedDay = format_date_with_ordinal(day.date);
|
||||
upcomingTexts.push(`${formattedDay} - ${day.holidays.join(', ')}`);
|
||||
});
|
||||
if (upcomingTexts.length > 0) {
|
||||
upcomingEventItem = {
|
||||
date: today.toISOString().split('T')[0],
|
||||
text: 'Upcoming Special Days: ' + upcomingTexts.join('; '),
|
||||
type: 'upcoming',
|
||||
year: 'Upcoming'
|
||||
};
|
||||
}
|
||||
}
|
||||
// Only show tomorrow's events if it's an even cycle AND not a multiple of 10
|
||||
else if (tickerCycleCount % 2 === 0) {
|
||||
const tomorrow = upcomingHolidays[0];
|
||||
if (tomorrow) {
|
||||
upcomingEventItem = {
|
||||
date: tomorrow.date.toISOString().split('T')[0],
|
||||
text: 'Upcoming Special Days: Tomorrow - ' + tomorrow.holidays.join(', '),
|
||||
type: 'upcoming',
|
||||
year: 'Tomorrow'
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add today's holidays to local items
|
||||
if (window.currentHolidays && window.currentHolidays.length > 0) {
|
||||
localItems.push({
|
||||
date: today.toISOString().split('T')[0],
|
||||
text: 'Special Days: ' + window.currentHolidays.join(', '),
|
||||
type: 'holiday',
|
||||
year: 'Today'
|
||||
});
|
||||
}
|
||||
|
||||
// Add injection HTML at the beginning if available
|
||||
// Use the injectionHtml that was fetched at the start of this function
|
||||
if (injectionHtml) {
|
||||
localItems.unshift({
|
||||
date: today.toISOString().split('T')[0],
|
||||
text: injectionHtml,
|
||||
type: 'injection',
|
||||
year: 'INJECTION'
|
||||
});
|
||||
}
|
||||
|
||||
// Add upcoming event at the very end if it exists
|
||||
if (upcomingEventItem) {
|
||||
localItems.push(upcomingEventItem);
|
||||
}
|
||||
|
||||
// Sort items by year
|
||||
localItems.sort((a, b) => {
|
||||
const getYear = (item) => {
|
||||
if (item.year !== undefined) {
|
||||
// Handle 'INJECTION', 'Today', 'Tomorrow', 'Upcoming' etc.
|
||||
if (isNaN(Number(item.year))) return Infinity;
|
||||
return Number(item.year);
|
||||
}
|
||||
return Number(item.date.split('-')[0]);
|
||||
};
|
||||
|
||||
const yearA = getYear(a);
|
||||
const yearB = getYear(b);
|
||||
|
||||
if (isNaN(yearA) && isNaN(yearB)) return 0;
|
||||
if (isNaN(yearA)) return 1;
|
||||
if (isNaN(yearB)) return -1;
|
||||
|
||||
return yearA - yearB;
|
||||
});
|
||||
|
||||
// Calculate duration of local items
|
||||
const tempLocalHtml = buildTickerHtml(localItems, currentYear);
|
||||
tickerContent.html(tempLocalHtml);
|
||||
const localWidth = tickerContent[0].scrollWidth;
|
||||
const localDuration = localWidth / PIXELS_PER_SECOND_SPEED;
|
||||
|
||||
// Determine number of Wikimedia items to add
|
||||
let numToSprinkle = 0;
|
||||
if (window.currentWikimediaEvents && window.currentWikimediaEvents.length > 0) {
|
||||
// Always include at least one item
|
||||
numToSprinkle = 1;
|
||||
|
||||
// Calculate average width per Wikimedia item using the first few events
|
||||
const sampleEvents = window.currentWikimediaEvents.slice(0, Math.min(5, window.currentWikimediaEvents.length));
|
||||
let totalWidth = 0;
|
||||
sampleEvents.forEach(event => {
|
||||
const tempWikiItem = { date: `${event.year}-01-01`, text: event.text, type: 'wikimedia', year: event.year };
|
||||
tickerContent.html(buildTickerHtml([tempWikiItem], currentYear));
|
||||
totalWidth += tickerContent[0].scrollWidth;
|
||||
});
|
||||
|
||||
const avgWikiWidth = totalWidth / sampleEvents.length;
|
||||
const timePerWikiItem = avgWikiWidth / PIXELS_PER_SECOND_SPEED;
|
||||
|
||||
// Add more items if there's time
|
||||
const durationGap = TARGET_BROADCAST_SECONDS - localDuration;
|
||||
if (timePerWikiItem > 0 && durationGap > timePerWikiItem) {
|
||||
const additionalItems = Math.floor((durationGap - timePerWikiItem) / timePerWikiItem);
|
||||
numToSprinkle += Math.max(0, additionalItems);
|
||||
}
|
||||
numToSprinkle = Math.min(numToSprinkle, window.currentWikimediaEvents.length);
|
||||
}
|
||||
|
||||
// Add Wikimedia items to local items
|
||||
if (numToSprinkle > 0 && window.currentWikimediaEvents && window.currentWikimediaEvents.length > 0) {
|
||||
const eventsToAdd = window.currentWikimediaEvents.slice(0, numToSprinkle);
|
||||
eventsToAdd.forEach(event => {
|
||||
localItems.push({ date: `${event.year}-01-01`, text: event.text, type: 'wikimedia', year: event.year });
|
||||
});
|
||||
|
||||
// Re-sort with the new items
|
||||
localItems.sort((a, b) => {
|
||||
const getYear = (item) => {
|
||||
if (item.year !== undefined) {
|
||||
if (isNaN(Number(item.year))) return Infinity;
|
||||
return Number(item.year);
|
||||
}
|
||||
return Number(item.date.split('-')[0]);
|
||||
};
|
||||
|
||||
const yearA = getYear(a);
|
||||
const yearB = getYear(b);
|
||||
|
||||
if (isNaN(yearA) && isNaN(yearB)) return 0;
|
||||
if (isNaN(yearA)) return 1;
|
||||
if (isNaN(yearB)) return -1;
|
||||
|
||||
return yearA - yearB;
|
||||
});
|
||||
}
|
||||
|
||||
const finalContentHtml = buildTickerHtml(localItems, currentYear, formatted_date);
|
||||
|
||||
// Set the content
|
||||
tickerContent.html(finalContentHtml);
|
||||
nextTickerHtml = finalContentHtml; // For next update
|
||||
|
||||
if (startImmediately) {
|
||||
if (!animationId) {
|
||||
animationId = requestAnimationFrame(animateTicker);
|
||||
}
|
||||
// Clear injectionHtml after using it to prevent reuse in next cycle
|
||||
injectionHtml = null;
|
||||
// Fetch new for next cycle, which will fetch a new injection
|
||||
fetchAndDisplayTickerData(false);
|
||||
}
|
||||
|
||||
}).fail(function() {
|
||||
console.error("Failed to fetch data for the horizontal ticker.");
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function buildTickerHtml(items, currentYear, formatted_date) {
|
||||
let contentHtml = `<span style="display: inline-block; width: 100vw;"></span>`;
|
||||
|
||||
// First, add injection items at the very beginning
|
||||
const injectionItems = items.filter(item => item.type === 'injection');
|
||||
injectionItems.forEach(item => {
|
||||
contentHtml += `<span>${item.text}</span>`;
|
||||
});
|
||||
|
||||
// Add the "On This Day" header
|
||||
if (formatted_date) {
|
||||
contentHtml += `<span><span class="ticker-event">On This Day, ${formatted_date}:</span></span>`;
|
||||
}
|
||||
|
||||
// Add all other items (excluding injection items which we've already added)
|
||||
items.filter(item => item.type !== 'injection').forEach(item => {
|
||||
const year = item.year || parseInt(item.date.split('-')[0]);
|
||||
let textClass = `ticker-${item.type}`;
|
||||
// Add a specific class for holidays and upcoming events
|
||||
if (item.type === 'holiday') {
|
||||
textClass = 'ticker-holiday';
|
||||
} else if (item.type === 'upcoming') {
|
||||
textClass = 'ticker-upcoming';
|
||||
}
|
||||
const yearDiff = currentYear - year;
|
||||
let anniversaryPrefix = '';
|
||||
// Only show anniversary for positive year differences (past events)
|
||||
// Skip for holiday type
|
||||
if (item.type !== 'holiday' && yearDiff > 0 && yearDiff % 5 === 0) {
|
||||
anniversaryPrefix = `<span style="color: yellow; font-weight: bold;">${yearDiff} Years Ago: </span>`;
|
||||
}
|
||||
let itemText = item.text;
|
||||
let yearText = year;
|
||||
const arbitraryLength = 500;
|
||||
if (item.text.length > arbitraryLength) {
|
||||
const mazzaImgTag = '<img src="mazza.png" alt="Mazza" style="height: 1.2em; vertical-align: middle; margin: 0 0.3em;">';
|
||||
const imageCount = Math.floor((item.text.length - arbitraryLength) / 200);
|
||||
const imageTags = mazzaImgTag.repeat(imageCount);
|
||||
yearText = imageTags ? `${imageTags} ${year}` : year;
|
||||
}
|
||||
// For holidays and upcoming events, don't show the year prefix
|
||||
if (item.type === 'holiday' || item.type === 'upcoming') {
|
||||
contentHtml += `<span><span class="${textClass}">${itemText}</span></span>`;
|
||||
} else {
|
||||
contentHtml += `<span>${anniversaryPrefix}<span class="ticker-year">${yearText}:</span> <span class="${textClass}">${itemText}</span></span>`;
|
||||
}
|
||||
});
|
||||
|
||||
if (formatted_date) {
|
||||
contentHtml += `<span><span class="ticker-event">Office/Local Event</span></span>`;
|
||||
contentHtml += `<span><span class="ticker-wikimedia">World Event</span></span>`;
|
||||
contentHtml += `<span><span class="ticker-report">Local Weather Event</span></span>`;
|
||||
|
||||
// Add trivia question if available
|
||||
if (triviaQuestions.length > 0) {
|
||||
const trivia = triviaQuestions.shift();
|
||||
// Decode HTML entities in question and answers
|
||||
const question = $('<div>').html(trivia.question).text();
|
||||
const correctAnswer = $('<div>').html(trivia.correct_answer).text();
|
||||
const allAnswers = [correctAnswer, ...trivia.incorrect_answers.map(ans => $('<div>').html(ans).text())];
|
||||
|
||||
// Shuffle answers
|
||||
for (let i = allAnswers.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[allAnswers[i], allAnswers[j]] = [allAnswers[j], allAnswers[i]];
|
||||
}
|
||||
|
||||
// Build question with choices
|
||||
let questionHtml = `<span style="color: gold;">TRIVIA: ${question} `;
|
||||
const choices = ['A', 'B', 'C', 'D'];
|
||||
allAnswers.forEach((answer, index) => {
|
||||
questionHtml += `${choices[index]}) ${answer} `;
|
||||
});
|
||||
questionHtml += `</span>`;
|
||||
contentHtml += `<span>${questionHtml}</span>`;
|
||||
|
||||
// Store the correct answer for later display
|
||||
// Find which choice corresponds to the correct answer
|
||||
const correctIndex = allAnswers.indexOf(correctAnswer);
|
||||
const correctChoice = choices[correctIndex];
|
||||
window.lastTriviaAnswer = { correctChoice, correctAnswer };
|
||||
}
|
||||
|
||||
contentHtml += `<span><span class="ticker-event">Visit <b>calendar.wx4rlx.org</b> to make updates or see info for upcoming days!</span></span>`;
|
||||
|
||||
// Add trivia answer if available
|
||||
if (window.lastTriviaAnswer) {
|
||||
const { correctChoice, correctAnswer } = window.lastTriviaAnswer;
|
||||
contentHtml += `<span><span style="color: gold;">ANSWER: ${correctChoice}) ${correctAnswer}</span></span>`;
|
||||
// Clear the answer after displaying it
|
||||
window.lastTriviaAnswer = null;
|
||||
}
|
||||
}
|
||||
return contentHtml;
|
||||
}
|
||||
|
||||
function startTickerWatchdog() {
|
||||
// Clear any existing watchdog
|
||||
if (tickerWatchdogTimer) {
|
||||
clearInterval(tickerWatchdogTimer);
|
||||
}
|
||||
// Check every 30 seconds if the ticker hasn't updated in 3x the expected duration
|
||||
tickerWatchdogTimer = setInterval(() => {
|
||||
const timeSinceLastUpdate = Date.now() - lastTickerUpdateTime;
|
||||
const maxAllowedTime = (TARGET_BROADCAST_SECONDS + 5) * 3 * 1000; // 3x expected duration in ms
|
||||
if (timeSinceLastUpdate > maxAllowedTime) {
|
||||
console.warn('Ticker watchdog triggered - forcing refresh');
|
||||
fetchAndDisplayTickerData(true);
|
||||
}
|
||||
}, 30000);
|
||||
}
|
||||
|
||||
function updateTickerLastUpdateTime() {
|
||||
lastTickerUpdateTime = Date.now();
|
||||
}
|
||||
|
||||
// Debug function to print ticker info and force next cycle
|
||||
window.debugTicker = function() {
|
||||
console.log('=== TICKER DEBUG INFO ===');
|
||||
console.log('Current cycle count:', tickerCycleCount);
|
||||
console.log('Upcoming holidays:', upcomingHolidays);
|
||||
console.log('Current Wikimedia events count:', window.currentWikimediaEvents ? window.currentWikimediaEvents.length : 0);
|
||||
console.log('Current holidays:', window.currentHolidays);
|
||||
console.log('Next ticker HTML length:', nextTickerHtml ? nextTickerHtml.length : 'null');
|
||||
console.log('Current ticker content:', document.getElementById('ticker-content').innerHTML);
|
||||
|
||||
// Force next cycle
|
||||
console.log('Forcing next ticker cycle...');
|
||||
tickerCycleCount++;
|
||||
fetchAndDisplayTickerData(true);
|
||||
};
|
||||
|
||||
sadCheck();
|
||||
toggleForm();
|
||||
refreshTimer = setInterval(() => {
|
||||
fetchAndDisplayNews(currentNewsUrl);
|
||||
}, 300000);
|
||||
fetchAndDisplayNews(currentNewsUrl);
|
||||
// Start the ticker independently
|
||||
fetchAndDisplayTickerData(true);
|
||||
startTickerWatchdog();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
438
test.py
438
test.py
@@ -1,438 +0,0 @@
|
||||
import requests
|
||||
import json
|
||||
|
||||
# 1. Create a session object
|
||||
session = requests.Session()
|
||||
|
||||
# 2. Set the User-Agent for the session
|
||||
user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36"
|
||||
session.headers.update({'User-Agent': user_agent})
|
||||
|
||||
# 3. Define and add cookies to the session
|
||||
cookies_to_add = [
|
||||
("SID", "g.a000vwi83sZx47d1q9Po8BgPR3jBX7lpsrzWSuPIKyp6RycUEctVzyy0oo1gNvQbwZa53AWllwACgYKAVQSARMSFQHGX2MiUpZ3JZlRTzUS5L-5fPmgpBoVAUF8yKprZzPlNM_X83070Ct35bq_0076", "/", ".google.com"),
|
||||
("__Secure-1PSID", "g.a000vwi83sZx47d1q9Po8BgPR3jBX7lpsrzWSuPIKyp6RycUEctVKNqZm8qWU9ZC2DlRVPn0igACgYKAfQSARMSFQHGX2MiYGW66m_L_p1vlqiuEg-IrxoVAUF8yKrgRbA9tcA4VinZix0qlexX0076", "/", ".google.com"),
|
||||
("__Secure-3PSID", "g.a000vwi83sZx47d1q9Po8BgPR3jBX7lpsrzWSuPIKyp6RycUEctVnGF-cJAl9Wr1rJ-NOCW63wACgYKAZASARMSFQHGX2Mi1gYcRRnI8v2AdvofwvFG5BoVAUF8yKooSw-opCZ1-vxmkQXCB7330076", "/", ".google.com"),
|
||||
("HSID", "AJifEcy5MKbQSoqIz", "/", ".google.com"),
|
||||
("SSID", "AB87p4RIXK_USto4D", "/", ".google.com"),
|
||||
("APISID", "fQw9oTJbNnptFKdr/AIXxJuvoAk3qrIeWi", "/", ".google.com"),
|
||||
("SAPISID", "3zFHAXrGoL_XNe0X/A7AafTXBL2NRj7N2h", "/", ".google.com"),
|
||||
("__Secure-1PAPISID", "3zFHAXrGoL_XNe0X/A7AafTXBL2NRj7N2h", "/", ".google.com"),
|
||||
("__Secure-3PAPISID", "3zFHAXrGoL_XNe0X/A7AafTXBL2NRj7N2h", "/", ".google.com"),
|
||||
("AEC", "AVcja2e2MbzHDDL2yqJDMgUeDL-S3BEFB_yK293aRhQwshqv22Bd7IQ9mvg", "/", ".google.com"),
|
||||
("NID", "523=SVwTZRVo9GJ5sSI0guSXNWwegQ7YY0h597wyCkrqkuIRMnQqpH3qrPA0SGB77KF69ibosOMUd-VNbNg1R7TXjPYFxYTUTP0uLtg41CaQctv6j1NKBaVPJoUkK3wzQ1e3l5yGsfBwGtypz5vxHP6yeyRtVWmYSiDiHr7AN1dKYXwzVVi7Dp8bvtppEAwUX7dQCqQ-4qGlHcoMW44STYwNELgd6CVXWPIhypl4qx_Wwcv7sY3GGP04s2kb0ljX7rYXKagj_Uv3xJDujDa4XUTAJKficyiWOrZT5LpeewUp1Kt5RyEBH2U7IHocmsWC6lfAKsoIt21wc1QwYioj9XkIIasJ4tCu1F7yXHjrglyGwbe5i67stMHI2FL3KXdoxe3ly_MORZWlVNM1Co7W43Rab01HMj2Ad940eXU9aV1PVzwlTtqiF0R0gLO_ubD6kykDRVMVMdMjMapz_dgIUfbkGMluSVykNRKnO7yf_rS7DKjXZXsh18UEsLcz6WjKtEYgmvm51MdH2JN5dcElSK_SWxrejJl-UW_eT_EqUQaeCtK2N7dTMFT38PGAkZFEKCvMqpjU86iLbFbmq_lKT-dm6IjIxFXj8yv652EYoCBlS3MsTjaQWP4_yRJa3oWhnB1kgwiBgBVmidRShZOT09L77WL6jVKE6YE09QrjGnoH_RjZFTwwGiuSFCLKfz9SwVsJBNV-nn5nZrU40kWmlhnfBNY3Kphq0fwO9RQ6wvzMAGzz684-kxzePSX3CgA74-rppEZrkXFMFjSaZGE-D7NAQp1qD2ez0-H2n0OXbRaLDN7JXn9fqhZu_FwvHJGfTBPZOZnk7taSnZSipmFU8gsTRQSVdFX6SlCXGpKueSRjhho", "/", ".google.com"),
|
||||
("S", "maestro=IUwVdLn0rPZ27SY26uYPEonS9u1J9oQi8YzVJpqIc-w", "/", ".google.com"),
|
||||
("__Secure-1PSIDTS", "sidts-CjIB7pHptaI1HakO1xLmYgvHilIKZJuufs1na9HjqCHJL13_z6LJNW13liGWofxE3NQ-NxAA", "/", ".google.com"),
|
||||
("__Secure-3PSIDTS", "sidts-CjIB7pHptaI1HakO1xLmYgvHilIKZJuufs1na9HjqCHJL13_z6LJNW13liGWofxE3NQ-NxAA", "/", ".google.com"),
|
||||
("_gid", "GA1.3.1639311329.1744393279", "/", ".lookerstudio.google.com"), # Different domain
|
||||
("_ga", "GA1.1.1275703331.1743917675", "/", ".lookerstudio.google.com"), # Different domain
|
||||
("_ga_LPCKLD3Z7X", "GS1.1.1744393286.6.0.1744393286.0.0.0", "/", ".lookerstudio.google.com"), # Different domain
|
||||
("RAP_XSRF_TOKEN", "AImk1AJGP3sIKZ7N5-RA2jKHcJ0jdpxGKw:1744393288187", "/", "lookerstudio.google.com"), # Different domain (no leading dot)
|
||||
("_gat", "1", "/", ".lookerstudio.google.com"), # Different domain
|
||||
("SIDCC", "AKEyXzW9xrpFKS4Ox9-THfQ3DfB62JRx-bxxg0ZEiKYze2jaerhvWrVMFVCyjTjxIJfOhCOKQw4", "/", ".google.com"),
|
||||
("__Secure-1PSIDCC", "AKEyXzXdMIev0GvM5xA0kMifj4jnuGZYNiob-2fJssX_jTBlwE8M4Bm9edS4J_i7UTSMFFEbCIm_", "/", ".google.com"),
|
||||
("__Secure-3PSIDCC", "AKEyXzU8YysnVlR_9UcCx2GFo5hIUNPh6OqSCRE6Fpo9y12BNmobniOBCjTZc1_qHTS6VnivWX25", "/", ".google.com"),
|
||||
("_ga_S4FJY0X3VX", "GS1.1.1744393279.7.1.1744393369.0.0.0", "/", ".lookerstudio.google.com") # Different domain
|
||||
]
|
||||
|
||||
for name, value, path, domain in cookies_to_add:
|
||||
session.cookies.set(name=name, value=value, path=path, domain=domain)
|
||||
|
||||
# 4. Define the Target URL
|
||||
url = "https://lookerstudio.google.com/batchedDataV2?appVersion=20250324_0406"
|
||||
|
||||
# 5. Define Headers (User-Agent and Cookies are handled by the session)
|
||||
headers = {
|
||||
"authority": "lookerstudio.google.com",
|
||||
"accept": "application/json, text/plain, */*",
|
||||
"accept-encoding": "gzip, deflate, br, zstd", # requests usually handles this, but specifying can be safer
|
||||
"accept-language": "en-US,en;q=0.9",
|
||||
"cache-control": "no-cache",
|
||||
# "encoding": "null", # This header seems unusual/invalid for requests, omitting
|
||||
"origin": "https://lookerstudio.google.com",
|
||||
"pragma": "no-cache",
|
||||
"priority": "u=1, i",
|
||||
"referer": "https://lookerstudio.google.com/reporting/1413fcfb-1416-4e56-8967-55f8e9f30ec8/page/p_pbm4eo88qc",
|
||||
"sec-ch-ua": '"Google Chrome";v="135", "Not-A.Brand";v="8", "Chromium";v="135"',
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-ch-ua-platform": '"Windows"',
|
||||
"sec-fetch-dest": "empty",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-site": "same-origin",
|
||||
"x-client-data": "CIS2yQEIorbJAQipncoBCMHbygEIk6HLAQiFoM0BCP6lzgEIvdXOAQjJ4M4BCIbizgEIu+fOAQjS6M4BCKzpzgE=",
|
||||
"x-rap-xsrf-token": "AImk1AJGP3sIKZ7N5-RA2jKHcJ0jdpxGKw:1744393288187",
|
||||
# Content-Type will be set automatically by requests when using json=payload
|
||||
}
|
||||
|
||||
# 6. Define the JSON Body (Payload)
|
||||
# Use triple quotes for the multi-line string and parse it with json.loads
|
||||
body_string = """
|
||||
{
|
||||
"dataRequest": [
|
||||
{
|
||||
"requestContext": {
|
||||
"reportContext": {
|
||||
"reportId": "1413fcfb-1416-4e56-8967-55f8e9f30ec8",
|
||||
"pageId": "p_pbm4eo88qc",
|
||||
"mode": 1,
|
||||
"componentId": "cd-rdkny9a9qc",
|
||||
"displayType": "simple-table",
|
||||
"actionId": "crossFilters"
|
||||
},
|
||||
"requestMode": 0
|
||||
},
|
||||
"datasetSpec": {
|
||||
"dataset": [
|
||||
{
|
||||
"datasourceId": "c2fc8cdd-46bb-454c-bf09-90ebfd4067d7",
|
||||
"revisionNumber": 0,
|
||||
"parameterOverrides": []
|
||||
}
|
||||
],
|
||||
"queryFields": [
|
||||
{
|
||||
"name": "qt_3nwfu9yq1c",
|
||||
"datasetNs": "d0",
|
||||
"tableNs": "t0",
|
||||
"resultTransformation": {
|
||||
"analyticalFunction": 0,
|
||||
"isRelativeToBase": false
|
||||
},
|
||||
"dataTransformation": {
|
||||
"sourceFieldName": "_Event_Id_"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "qt_8yjok4izsc",
|
||||
"datasetNs": "d0",
|
||||
"tableNs": "t0",
|
||||
"resultTransformation": {
|
||||
"analyticalFunction": 0,
|
||||
"isRelativeToBase": false
|
||||
},
|
||||
"dataTransformation": {
|
||||
"sourceFieldName": "_DateTime_EST_"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "qt_sfkc163arc",
|
||||
"datasetNs": "d0",
|
||||
"tableNs": "t0",
|
||||
"dataTransformation": {
|
||||
"sourceFieldName": "_KYTC_Type_"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "qt_4e66idhbrc",
|
||||
"datasetNs": "d0",
|
||||
"tableNs": "t0",
|
||||
"dataTransformation": {
|
||||
"sourceFieldName": "_Incident_Source_"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "qt_re76qrqe2c",
|
||||
"datasetNs": "d0",
|
||||
"tableNs": "t0",
|
||||
"dataTransformation": {
|
||||
"sourceFieldName": "_District_",
|
||||
"aggregation": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "qt_tfkc163arc",
|
||||
"datasetNs": "d0",
|
||||
"tableNs": "t0",
|
||||
"dataTransformation": {
|
||||
"sourceFieldName": "_County_Name_"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "qt_ufkc163arc",
|
||||
"datasetNs": "d0",
|
||||
"tableNs": "t0",
|
||||
"dataTransformation": {
|
||||
"sourceFieldName": "_Route_Label_"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "qt_vfkc163arc",
|
||||
"datasetNs": "d0",
|
||||
"tableNs": "t0",
|
||||
"dataTransformation": {
|
||||
"sourceFieldName": "_BMP_Initial_"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "qt_o7kc163arc",
|
||||
"datasetNs": "d0",
|
||||
"tableNs": "t0",
|
||||
"dataTransformation": {
|
||||
"sourceFieldName": "_EMP_Initial_"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "qt_p7kc163arc",
|
||||
"datasetNs": "d0",
|
||||
"tableNs": "t0",
|
||||
"dataTransformation": {
|
||||
"sourceFieldName": "_Description_"
|
||||
}
|
||||
}
|
||||
],
|
||||
"sortData": [
|
||||
{
|
||||
"sortColumn": {
|
||||
"name": "qt_8yjok4izsc",
|
||||
"datasetNs": "d0",
|
||||
"tableNs": "t0",
|
||||
"dataTransformation": {
|
||||
"sourceFieldName": "_DateTime_EST_"
|
||||
}
|
||||
},
|
||||
"sortDir": 1
|
||||
}
|
||||
],
|
||||
"includeRowsCount": true,
|
||||
"relatedDimensionMask": {
|
||||
"addDisplay": false,
|
||||
"addUniqueId": false,
|
||||
"addLatLong": false
|
||||
},
|
||||
"paginateInfo": {
|
||||
"startRow": 1,
|
||||
"rowsCount": 50
|
||||
},
|
||||
"dsFilterOverrides": [],
|
||||
"filters": [
|
||||
{
|
||||
"filterDefinition": {
|
||||
"filterExpression": {
|
||||
"include": false,
|
||||
"conceptType": 0,
|
||||
"concept": {
|
||||
"ns": "t0",
|
||||
"name": "qt_exs3vib9qc"
|
||||
},
|
||||
"filterConditionType": "PT",
|
||||
"stringValues": [
|
||||
"Shoulder"
|
||||
],
|
||||
"numberValues": [],
|
||||
"queryTimeTransformation": {
|
||||
"dataTransformation": {
|
||||
"sourceFieldName": "_Source_Type_"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"dataSubsetNs": {
|
||||
"datasetNs": "d0",
|
||||
"tableNs": "t0",
|
||||
"contextNs": "c0"
|
||||
},
|
||||
"version": 3
|
||||
},
|
||||
{
|
||||
"filterDefinition": {
|
||||
"filterExpression": {
|
||||
"include": true,
|
||||
"conceptType": 0,
|
||||
"concept": {
|
||||
"name": "qt_kjyfx83arc",
|
||||
"ns": "t0"
|
||||
},
|
||||
"queryTimeTransformation": {
|
||||
"dataTransformation": {
|
||||
"sourceFieldName": "_County_Name_"
|
||||
}
|
||||
},
|
||||
"filterConditionType": "IN",
|
||||
"stringValues": [
|
||||
"Boyd",
|
||||
"Carter",
|
||||
"Greenup"
|
||||
]
|
||||
}
|
||||
},
|
||||
"dataSubsetNs": {
|
||||
"datasetNs": "d0",
|
||||
"tableNs": "t0",
|
||||
"contextNs": "c0"
|
||||
},
|
||||
"version": 3,
|
||||
"isCanvasFilter": true
|
||||
}
|
||||
],
|
||||
"features": [],
|
||||
"dateRanges": [],
|
||||
"contextNsCount": 1,
|
||||
"calculatedField": [],
|
||||
"needGeocoding": false,
|
||||
"geoFieldMask": [],
|
||||
"multipleGeocodeFields": [],
|
||||
"timezone": "America/New_York"
|
||||
},
|
||||
"role": "main",
|
||||
"retryHints": {
|
||||
"useClientControlledRetry": true,
|
||||
"isLastRetry": false,
|
||||
"retryCount": 0,
|
||||
"originalRequestId": "cd-rdkny9a9qc_0_0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"requestContext": {
|
||||
"reportContext": {
|
||||
"reportId": "1413fcfb-1416-4e56-8967-55f8e9f30ec8",
|
||||
"pageId": "p_pbm4eo88qc",
|
||||
"mode": 1,
|
||||
"componentId": "cd-hgodhfhbrc",
|
||||
"displayType": "dimension-filter",
|
||||
"actionId": "crossFilters"
|
||||
},
|
||||
"requestMode": 7
|
||||
},
|
||||
"datasetSpec": {
|
||||
"dataset": [
|
||||
{
|
||||
"datasourceId": "c2fc8cdd-46bb-454c-bf09-90ebfd4067d7",
|
||||
"revisionNumber": 0,
|
||||
"parameterOverrides": []
|
||||
}
|
||||
],
|
||||
"queryFields": [
|
||||
{
|
||||
"name": "qt_vwmdhfhbrc",
|
||||
"datasetNs": "d0",
|
||||
"tableNs": "t0",
|
||||
"dataTransformation": {
|
||||
"sourceFieldName": "_Incident_Source_"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "qt_d5jjfyu6wc",
|
||||
"datasetNs": "d0",
|
||||
"tableNs": "t0",
|
||||
"dataTransformation": {
|
||||
"sourceFieldName": "datastudio_record_count_system_field_id_98323387"
|
||||
}
|
||||
}
|
||||
],
|
||||
"sortData": [
|
||||
{
|
||||
"sortColumn": {
|
||||
"name": "qt_vwmdhfhbrc",
|
||||
"datasetNs": "d0",
|
||||
"tableNs": "t0",
|
||||
"dataTransformation": {
|
||||
"sourceFieldName": "_Incident_Source_"
|
||||
}
|
||||
},
|
||||
"sortDir": 0
|
||||
}
|
||||
],
|
||||
"includeRowsCount": true,
|
||||
"relatedDimensionMask": {
|
||||
"addDisplay": false,
|
||||
"addUniqueId": false,
|
||||
"addLatLong": false
|
||||
},
|
||||
"paginateInfo": {
|
||||
"startRow": 1,
|
||||
"rowsCount": 5001
|
||||
},
|
||||
"dsFilterOverrides": [],
|
||||
"filters": [
|
||||
{
|
||||
"filterDefinition": {
|
||||
"filterExpression": {
|
||||
"include": true,
|
||||
"conceptType": 0,
|
||||
"concept": {
|
||||
"name": "qt_kjyfx83arc",
|
||||
"ns": "t0"
|
||||
},
|
||||
"queryTimeTransformation": {
|
||||
"dataTransformation": {
|
||||
"sourceFieldName": "_County_Name_"
|
||||
}
|
||||
},
|
||||
"filterConditionType": "IN",
|
||||
"stringValues": [
|
||||
"Boyd",
|
||||
"Carter",
|
||||
"Greenup"
|
||||
]
|
||||
}
|
||||
},
|
||||
"dataSubsetNs": {
|
||||
"datasetNs": "d0",
|
||||
"tableNs": "t0",
|
||||
"contextNs": "c0"
|
||||
},
|
||||
"version": 3,
|
||||
"isCanvasFilter": true
|
||||
}
|
||||
],
|
||||
"features": [],
|
||||
"dateRanges": [],
|
||||
"contextNsCount": 1,
|
||||
"dateRangeDimensions": [
|
||||
{
|
||||
"name": "qt_ilkdhfhbrc",
|
||||
"datasetNs": "d0",
|
||||
"tableNs": "t0",
|
||||
"dataTransformation": {
|
||||
"sourceFieldName": "_Incident_Begin_Time_",
|
||||
"transformationConfig": {
|
||||
"transformationType": 5
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"calculatedField": [],
|
||||
"needGeocoding": false,
|
||||
"geoFieldMask": [],
|
||||
"multipleGeocodeFields": [],
|
||||
"timezone": "America/New_York"
|
||||
},
|
||||
"role": "main",
|
||||
"retryHints": {
|
||||
"useClientControlledRetry": true,
|
||||
"isLastRetry": false,
|
||||
"retryCount": 0,
|
||||
"originalRequestId": "cd-hgodhfhbrc_0_0"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
"""
|
||||
payload = json.loads(body_string)
|
||||
|
||||
# 7. Send the POST request using the session
|
||||
try:
|
||||
print(f"Sending POST request to {url}...")
|
||||
response = session.post(url, headers=headers, json=payload)
|
||||
|
||||
# Raise an exception for bad status codes (4xx or 5xx)
|
||||
response.raise_for_status()
|
||||
|
||||
# 8. Process the response
|
||||
print(f"Status Code: {response.status_code}")
|
||||
|
||||
# Attempt to print the response as JSON, fall back to text if decoding fails
|
||||
try:
|
||||
print(response.text)
|
||||
print("Response JSON:")
|
||||
# Use json.dumps for pretty printing the received JSON
|
||||
print(json.dumps(response.json(), indent=2))
|
||||
except json.JSONDecodeError:
|
||||
print("Response Text (non-JSON):")
|
||||
print(response.text)
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"An error occurred during the request: {e}")
|
||||
if hasattr(e, 'response') and e.response is not None:
|
||||
print(f"Response status code: {e.response.status_code}")
|
||||
print(f"Response text: {e.response.text}")
|
||||
Reference in New Issue
Block a user