mirror of
https://github.com/Death916/deathclock.git
synced 2026-04-10 03:04:40 -07:00
base of reflex re write. centered clock and weather
This commit is contained in:
parent
aba3a7b641
commit
3bec50f40e
24 changed files with 1563 additions and 6838 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
|
@ -1,3 +1,9 @@
|
||||||
|
.web
|
||||||
|
.states
|
||||||
|
assets/external/
|
||||||
|
*.db
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
*.png
|
*.png
|
||||||
*.txt
|
*.txt
|
||||||
chromedriver
|
chromedriver
|
||||||
|
|
|
||||||
|
|
@ -1,85 +0,0 @@
|
||||||
/* assets/styles.css */
|
|
||||||
|
|
||||||
/* Basic ticker styling */
|
|
||||||
.ticker-wrap {
|
|
||||||
width: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
background-color: #f0f0f0; /* Light background for visibility */
|
|
||||||
padding: 10px 0;
|
|
||||||
margin-top: 20px;
|
|
||||||
border-top: 1px solid #ccc;
|
|
||||||
border-bottom: 1px solid #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ticker-move {
|
|
||||||
/* Animation properties will be set dynamically via style prop */
|
|
||||||
display: inline-block;
|
|
||||||
white-space: nowrap;
|
|
||||||
padding-right: 100%; /* Ensures the loop effect */
|
|
||||||
animation-name: ticker;
|
|
||||||
animation-timing-function: linear;
|
|
||||||
animation-iteration-count: infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The animation */
|
|
||||||
@keyframes ticker {
|
|
||||||
0% {
|
|
||||||
transform: translateX(0);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
/* Translate left by the width of the text */
|
|
||||||
/* The actual value is set dynamically if possible, otherwise estimate */
|
|
||||||
transform: translateX(-100%); /* Simplified fallback */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Style for individual news items if needed */
|
|
||||||
.news-item {
|
|
||||||
margin: 0 15px; /* Spacing between items */
|
|
||||||
font-size: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Styling for score boxes */
|
|
||||||
.score-container {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column; /* Stack games vertically */
|
|
||||||
gap: 8px; /* Space between score boxes */
|
|
||||||
align-items: center; /* Center boxes if container is wider */
|
|
||||||
}
|
|
||||||
|
|
||||||
.score-box {
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
padding: 8px 12px;
|
|
||||||
border-radius: 4px;
|
|
||||||
background-color: #f9f9f9;
|
|
||||||
min-width: 200px; /* Ensure minimum width */
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.game-score {
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 1.1em;
|
|
||||||
display: block; /* Put score on its own line */
|
|
||||||
margin-bottom: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.game-period, .game-status {
|
|
||||||
font-size: 0.9em;
|
|
||||||
color: #555;
|
|
||||||
display: block; /* Put status on its own line */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make MLB scores display in columns if desired */
|
|
||||||
.mlb-score-container {
|
|
||||||
display: block; /* Override flex */
|
|
||||||
column-count: 2;
|
|
||||||
column-gap: 15px;
|
|
||||||
padding: 0 10px; /* Add some padding */
|
|
||||||
}
|
|
||||||
/* Ensure MLB boxes break correctly */
|
|
||||||
.mlb-score-container .score-box {
|
|
||||||
display: inline-block; /* Necessary for column break */
|
|
||||||
width: 95%; /* Adjust width as needed */
|
|
||||||
margin-bottom: 10px; /* Space below items in columns */
|
|
||||||
break-inside: avoid-column; /* Try to prevent breaking inside a box */
|
|
||||||
}
|
|
||||||
4
deathclock/.gitignore
vendored
4
deathclock/.gitignore
vendored
|
|
@ -1,4 +0,0 @@
|
||||||
*.png
|
|
||||||
*.txt
|
|
||||||
chromedriver
|
|
||||||
*.pyc
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
__version__ = '0.1.0'
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
import datetime
|
|
||||||
from dash import html, dcc, Input, Output, State
|
|
||||||
import alarm
|
|
||||||
|
|
||||||
class AlarmModule:
|
|
||||||
def __init__(self, app):
|
|
||||||
self.app = app
|
|
||||||
self.alarm_obj = self.get_alarm_object()
|
|
||||||
self._alarm_time = None
|
|
||||||
self.setup_callbacks()
|
|
||||||
|
|
||||||
def get_alarm_object(self):
|
|
||||||
return alarm.Alarm()
|
|
||||||
|
|
||||||
def setup_callbacks(self):
|
|
||||||
@self.app.callback(
|
|
||||||
Output('time-input', 'style'),
|
|
||||||
Input('clock-display', 'n_clicks'),
|
|
||||||
State('time-input', 'style')
|
|
||||||
)
|
|
||||||
def toggle_time_input(n_clicks, current_style):
|
|
||||||
if n_clicks and n_clicks % 2 == 1:
|
|
||||||
return {'display': 'block', 'margin': '0 auto'}
|
|
||||||
return {'display': 'none', 'margin': '0 auto'}
|
|
||||||
|
|
||||||
@self.app.callback(
|
|
||||||
Output('output-selected-time', 'children'),
|
|
||||||
Input('time-input', 'value')
|
|
||||||
)
|
|
||||||
def process_selected_time(time_value):
|
|
||||||
if time_value:
|
|
||||||
self._alarm_time = time_value
|
|
||||||
self.alarm_obj.add_alarm(time_value, datetime.datetime.now())
|
|
||||||
return f'Alarm time: {time_value}'
|
|
||||||
return 'No time selected yet.'
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
||||||
from dash import Dash, html, dcc
|
|
||||||
from weather_module import WeatherModule
|
|
||||||
from news_module import NewsModule
|
|
||||||
from scores_module import ScoresModule
|
|
||||||
from alarm_module import AlarmModule
|
|
||||||
from clock_module import ClockModule
|
|
||||||
|
|
||||||
def create_app():
|
|
||||||
app = Dash(__name__)
|
|
||||||
|
|
||||||
app.layout = html.Div([
|
|
||||||
html.H1(id='clock-display', style={'textAlign': 'center', 'cursor': 'pointer'}),
|
|
||||||
dcc.Input(id='time-input', type='time', style={'display': 'none', 'margin': '0 auto'}),
|
|
||||||
html.Div(id='output-selected-time', style={'textAlign': 'center', 'marginBottom': '20px'}),
|
|
||||||
|
|
||||||
html.Div([
|
|
||||||
html.Div([
|
|
||||||
html.H2("NBA Scores"),
|
|
||||||
html.Div(id='nba-scores-display', className='score-container')
|
|
||||||
], id='nba-container', style={'flex': '1'}),
|
|
||||||
|
|
||||||
html.Div(id='weather-display', style={"display": "flex", "justify-content": "center", "margin-bottom":"20px", 'flex':'1'}),
|
|
||||||
|
|
||||||
html.Div([
|
|
||||||
html.H2("MLB Scores"),
|
|
||||||
html.Div(id='mlb-scores-display', className='score-container',style={'column-count': '2', 'column-gap': '10px'})
|
|
||||||
], id='mlb-container', style={'flex': '1'}),
|
|
||||||
|
|
||||||
], id='main-content-container', style={"display": "flex", "gap": "20px", 'flex-wrap': 'wrap'}),
|
|
||||||
|
|
||||||
html.Div(id='news-ticker'),
|
|
||||||
|
|
||||||
dcc.Interval(id='clock-interval', interval=60000, n_intervals=0),
|
|
||||||
dcc.Interval(id='weather-interval', interval=550000, n_intervals=0),
|
|
||||||
dcc.Interval(id='news-interval', interval=300000, n_intervals=0),
|
|
||||||
dcc.Interval(id='nba-interval', interval=300000, n_intervals=0),
|
|
||||||
dcc.Interval(id='mlb-interval', interval=300000, n_intervals=0)
|
|
||||||
])
|
|
||||||
|
|
||||||
ClockModule(app)
|
|
||||||
WeatherModule(app)
|
|
||||||
NewsModule(app)
|
|
||||||
scores_module = ScoresModule(app)
|
|
||||||
scores_module.setup_mlb_callbacks()
|
|
||||||
alarm_module = AlarmModule(app)
|
|
||||||
|
|
||||||
def check_alarms():
|
|
||||||
trigg = alarm_module.alarm_obj.check_alarm()
|
|
||||||
if trigg:
|
|
||||||
print("ALARM TRIGGERED!")
|
|
||||||
|
|
||||||
check_alarms()
|
|
||||||
return app
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
app = create_app()
|
|
||||||
app.run_server(debug=False, host='0.0.0.0', port=8050)
|
|
||||||
|
|
@ -1,224 +0,0 @@
|
||||||
body {
|
|
||||||
background-color: #1a1a2e;
|
|
||||||
color: #e6e6fa;
|
|
||||||
font-family: 'Arial', sans-serif;
|
|
||||||
margin: 0;
|
|
||||||
padding: 10px;
|
|
||||||
font-size: 16px;
|
|
||||||
overflow-x: hidden;
|
|
||||||
min-width: 360px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: 2rem;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-size: 1.5rem;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Main Content Container (Scores and Weather) */
|
|
||||||
#main-content-container {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 20px;
|
|
||||||
width: 100%;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
#nba-container,
|
|
||||||
#mlb-container {
|
|
||||||
flex: 1;
|
|
||||||
min-width: 300px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Individual Score Containers */
|
|
||||||
.score-container {
|
|
||||||
width: 100%;
|
|
||||||
padding: 0; /* Remove padding from score container */
|
|
||||||
margin: 0; /* remove margin from score container */
|
|
||||||
}
|
|
||||||
|
|
||||||
#mlb-scores-display {
|
|
||||||
column-count: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.score-box {
|
|
||||||
background-color: #232338;
|
|
||||||
padding: 2px 5px; /* Reduced padding on score boxes */
|
|
||||||
margin-bottom: 2px; /* Reduced margin on score boxes */
|
|
||||||
border-radius: 6px;
|
|
||||||
border: 1px solid #4a4a82;
|
|
||||||
display: flex; /* Use flexbox for inner alignment */
|
|
||||||
flex-direction: column; /* Stack the game-score and game-period vertically */
|
|
||||||
justify-content: center; /* Center vertically */
|
|
||||||
}
|
|
||||||
|
|
||||||
.game-score {
|
|
||||||
font-size: 0.9em;
|
|
||||||
color: #e6e6fa;
|
|
||||||
text-align: center;
|
|
||||||
margin: 2px 0; /* Add a small top/bottom margin */
|
|
||||||
}
|
|
||||||
|
|
||||||
.game-period {
|
|
||||||
font-size: 0.8em;
|
|
||||||
color: #b39ddb;
|
|
||||||
text-align: center;
|
|
||||||
margin: 2px 0; /* Add a small top/bottom margin */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Weather Styles */
|
|
||||||
#weather-display {
|
|
||||||
background-color: #232338;
|
|
||||||
border-radius: 10px;
|
|
||||||
padding: 10px;
|
|
||||||
margin: 10px auto;
|
|
||||||
max-width: 100%;
|
|
||||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2);
|
|
||||||
border: 1px solid #4a4a82;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#weather-display:hover {
|
|
||||||
box-shadow: 0 6px 8px rgba(179, 157, 219, 0.2);
|
|
||||||
transform: translateY(-2px);
|
|
||||||
}
|
|
||||||
|
|
||||||
#weather-display img {
|
|
||||||
width: 100%;
|
|
||||||
border-radius: 8px;
|
|
||||||
margin-top: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* News Ticker Styles */
|
|
||||||
.ticker {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 0;
|
|
||||||
width: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
white-space: nowrap;
|
|
||||||
background-color: #232338;
|
|
||||||
padding: 5px;
|
|
||||||
border-radius: 8px;
|
|
||||||
border: 1px solid #4a4a82;
|
|
||||||
}
|
|
||||||
|
|
||||||
.news-item {
|
|
||||||
display: inline-block;
|
|
||||||
padding-right: 30px;
|
|
||||||
color: #d1c4e9;
|
|
||||||
animation: ticker linear infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes ticker {
|
|
||||||
0% {
|
|
||||||
transform: translateX(100%);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: translateX(-100%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Media Queries */
|
|
||||||
@media (min-width: 750px) {
|
|
||||||
/* Landscape layout */
|
|
||||||
body {
|
|
||||||
padding: 20px;
|
|
||||||
font-size: 18px;
|
|
||||||
max-width: 1500px;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
#main-content-container {
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
justify-content: space-around;
|
|
||||||
}
|
|
||||||
|
|
||||||
#mlb-scores-display {
|
|
||||||
column-count: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.score-container {
|
|
||||||
padding: 0; /* Remove padding from score container */
|
|
||||||
margin: 0; /* remove margin from score container */
|
|
||||||
}
|
|
||||||
|
|
||||||
.score-box {
|
|
||||||
padding: 2px 5px; /* Reduced padding on score boxes */
|
|
||||||
margin-bottom: 2px; /* Reduced margin on score boxes */
|
|
||||||
}
|
|
||||||
|
|
||||||
#weather-display {
|
|
||||||
padding: 20px;
|
|
||||||
margin: 0;
|
|
||||||
max-width: 400px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ticker {
|
|
||||||
padding: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.news-item {
|
|
||||||
padding-right: 50px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 480px) {
|
|
||||||
/* Phone screens */
|
|
||||||
body {
|
|
||||||
font-size: 14px;
|
|
||||||
padding: 0;
|
|
||||||
transform-origin: top left;
|
|
||||||
transform: scale(0.6);
|
|
||||||
width: 166.66%;
|
|
||||||
margin-left: -33.33%;
|
|
||||||
min-width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-size: 1.2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
#main-content-container {
|
|
||||||
gap: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#nba-container,
|
|
||||||
#mlb-container {
|
|
||||||
min-width: 0;
|
|
||||||
}
|
|
||||||
.score-container {
|
|
||||||
padding: 0; /* Remove padding from score container */
|
|
||||||
margin: 0; /* remove margin from score container */
|
|
||||||
}
|
|
||||||
.score-box {
|
|
||||||
padding: 2px 5px; /* Reduced padding on score boxes */
|
|
||||||
margin-bottom: 2px; /* Reduced margin on score boxes */
|
|
||||||
}
|
|
||||||
|
|
||||||
.game-score {
|
|
||||||
font-size: 0.8em;
|
|
||||||
margin: 2px 0; /* Add a small top/bottom margin */
|
|
||||||
}
|
|
||||||
|
|
||||||
.game-period {
|
|
||||||
font-size: 0.7em;
|
|
||||||
margin: 2px 0; /* Add a small top/bottom margin */
|
|
||||||
}
|
|
||||||
|
|
||||||
.ticker {
|
|
||||||
padding: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.news-item {
|
|
||||||
padding-right: 15px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
File diff suppressed because it is too large
Load diff
Binary file not shown.
|
|
@ -1,15 +0,0 @@
|
||||||
from time import strftime, localtime
|
|
||||||
from dash import Input, Output
|
|
||||||
|
|
||||||
class ClockModule:
|
|
||||||
def __init__(self, app):
|
|
||||||
self.app = app
|
|
||||||
self.setup_callbacks()
|
|
||||||
|
|
||||||
def setup_callbacks(self):
|
|
||||||
@self.app.callback(
|
|
||||||
Output('clock-display', 'children'),
|
|
||||||
Input('clock-interval', 'n_intervals')
|
|
||||||
)
|
|
||||||
def update_time(n):
|
|
||||||
return strftime("%B %d, %I:%M %p", localtime())
|
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
"""Welcome to Reflex! This file outlines the steps to create a basic app."""
|
||||||
|
|
||||||
|
import reflex as rx
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
from rxconfig import config
|
||||||
|
from utils.weather import Weather
|
||||||
|
from utils.scores import NBAScores, mlbScores
|
||||||
|
from utils.news import News
|
||||||
|
from utils.alarm import Alarm
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class State(rx.State):
|
||||||
|
"""The app state."""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def index() -> rx.Component:
|
||||||
|
|
||||||
|
return rx.container(
|
||||||
|
rx.center(
|
||||||
|
rx.vstack(
|
||||||
|
rx.button(
|
||||||
|
rx.moment(interval=1000, format="HH:mm:ss"),
|
||||||
|
font_size="4xl",
|
||||||
|
font_weight="bold",
|
||||||
|
color="white",
|
||||||
|
background_color="#6f42c1",
|
||||||
|
),
|
||||||
|
rx.box(
|
||||||
|
rx.image(
|
||||||
|
src=Weather().get_weather_screenshot(),
|
||||||
|
alt="Weather",
|
||||||
|
width="100%",
|
||||||
|
height="auto",
|
||||||
|
background_color="white",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
app = rx.App()
|
||||||
|
app.add_page(index)
|
||||||
|
|
@ -1,107 +0,0 @@
|
||||||
#deathclock
|
|
||||||
import datetime
|
|
||||||
import time
|
|
||||||
import sys
|
|
||||||
from PySide6.QtGui import QGuiApplication
|
|
||||||
from PySide6.QtQml import QQmlApplicationEngine
|
|
||||||
from PySide6.QtCore import QTimer, QObject, Signal, Slot, Property
|
|
||||||
from time import strftime, localtime
|
|
||||||
import requests
|
|
||||||
from selenium import webdriver
|
|
||||||
from selenium.webdriver.chrome.service import Service
|
|
||||||
import os
|
|
||||||
import news
|
|
||||||
import weather
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class clock():
|
|
||||||
def update_time(self):
|
|
||||||
curr_time = strftime("%B %d, %I:%M %p", localtime())
|
|
||||||
|
|
||||||
engine.rootObjects()[0].setProperty('currTime', curr_time)
|
|
||||||
|
|
||||||
|
|
||||||
return curr_time
|
|
||||||
|
|
||||||
|
|
||||||
def time_and_date():
|
|
||||||
print(time.asctime())
|
|
||||||
|
|
||||||
def alarm():
|
|
||||||
alarm_time = input("what time should the alarm be set?")
|
|
||||||
|
|
||||||
|
|
||||||
def ring():
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
class gui():
|
|
||||||
def handleTouchAreaPressed(self, signal):
|
|
||||||
# Implement your desired behavior when the left area is pressed
|
|
||||||
print("here touch area")
|
|
||||||
leftTouchAreaMouse = engine.rootObjects()[0].findChild("leftTouchAreaMouse")
|
|
||||||
leftTouchAreaMouse.connect(b"touchAreaPressed", self.handleTouchAreaPressed)
|
|
||||||
print("Left area pressed!")
|
|
||||||
"""
|
|
||||||
def main():
|
|
||||||
#gui_obj = gui()
|
|
||||||
|
|
||||||
app = QGuiApplication(sys.argv)
|
|
||||||
global engine
|
|
||||||
engine = QQmlApplicationEngine()
|
|
||||||
engine.quit.connect(app.quit)
|
|
||||||
|
|
||||||
engine.load( 'main.qml')
|
|
||||||
# create instance of weather class
|
|
||||||
weather_obj = weather.Weather()
|
|
||||||
weather_obj.weatherUpdated.connect(lambda weather_map_path: engine.rootContext().setContextProperty("weatherMapPath", weather_map_path))
|
|
||||||
|
|
||||||
# set timer for weather map
|
|
||||||
weatherTimer = QTimer()
|
|
||||||
weatherTimer.setInterval(300000) # 10 minutes
|
|
||||||
weatherTimer.timeout.connect(weather_obj.download_sacramento_weather_map(engine))
|
|
||||||
weather_obj.download_sacramento_weather_map(engine)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
weatherTimer.start()
|
|
||||||
|
|
||||||
|
|
||||||
# create instance of clock class
|
|
||||||
timeupdate = clock()
|
|
||||||
|
|
||||||
# start timer for clock
|
|
||||||
timer = QTimer()
|
|
||||||
timer.setInterval(100) # msecs 100 = 1/10th sec
|
|
||||||
timer.timeout.connect(timeupdate.update_time)
|
|
||||||
timer.start()
|
|
||||||
|
|
||||||
# create instance of news class
|
|
||||||
news_obj = news.news()
|
|
||||||
news_ticker = news_obj.get_news()
|
|
||||||
#print(news_obj._news_dict)
|
|
||||||
#print(news_ticker)
|
|
||||||
news_context = engine.rootContext()
|
|
||||||
news_context.setContextProperty("news", str(news_ticker))
|
|
||||||
|
|
||||||
#start timer for news
|
|
||||||
news_timer = QTimer()
|
|
||||||
news_timer.timeout.connect(news_obj.get_news)
|
|
||||||
news_timer.setInterval(300000) # 10 minutes #changed to 5 mins
|
|
||||||
|
|
||||||
news_timer.start()
|
|
||||||
|
|
||||||
|
|
||||||
sys.exit(app.exec_())
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
import datetime
|
|
||||||
import asyncio
|
|
||||||
from dash import html, Input, Output, callback, no_update
|
|
||||||
from dash.exceptions import PreventUpdate
|
|
||||||
from news import News
|
|
||||||
|
|
||||||
class NewsModule:
|
|
||||||
def __init__(self, app):
|
|
||||||
self.app = app
|
|
||||||
self.news_obj = self.get_news_object()
|
|
||||||
self._last_news_update = datetime.datetime(2000, 1, 1)
|
|
||||||
self._cached_news = self.create_loading_message() # Initial loading message
|
|
||||||
self._initial_run = True
|
|
||||||
self.setup_callbacks()
|
|
||||||
|
|
||||||
def get_news_object(self):
|
|
||||||
return News()
|
|
||||||
|
|
||||||
def create_loading_message(self):
|
|
||||||
return html.Div("Loading...")
|
|
||||||
|
|
||||||
def setup_callbacks(self):
|
|
||||||
@self.app.callback(
|
|
||||||
Output('news-ticker', 'children'),
|
|
||||||
Input('news-interval', 'n_intervals')
|
|
||||||
)
|
|
||||||
def update_news(n):
|
|
||||||
if n is None:
|
|
||||||
return self._cached_news
|
|
||||||
|
|
||||||
current_time = datetime.datetime.now()
|
|
||||||
time_since_update = (current_time - self._last_news_update).total_seconds()
|
|
||||||
|
|
||||||
# Only update if it's been more than 5 minutes or it's the initial run
|
|
||||||
if time_since_update < 300 and not self._initial_run:
|
|
||||||
return self._cached_news
|
|
||||||
|
|
||||||
try:
|
|
||||||
print("UPDATING NEWS...")
|
|
||||||
# Create a new event loop for this request
|
|
||||||
loop = asyncio.new_event_loop()
|
|
||||||
asyncio.set_event_loop(loop)
|
|
||||||
headlines_dict = loop.run_until_complete(self.news_obj.get_news())
|
|
||||||
loop.close()
|
|
||||||
|
|
||||||
if not headlines_dict:
|
|
||||||
return html.Div("No news available at this time.", className="ticker")
|
|
||||||
|
|
||||||
combined_items = " | ".join([f"{data['source']}: {headline}"
|
|
||||||
for headline, data in headlines_dict.items()])
|
|
||||||
text_px = len(combined_items) * 8
|
|
||||||
scroll_speed = 75
|
|
||||||
duration = max(text_px / scroll_speed, 20)
|
|
||||||
ticker_style = {"animationDuration": f"{duration}s"}
|
|
||||||
|
|
||||||
self._cached_news = html.Div(
|
|
||||||
html.Span(combined_items, className="news-item", style=ticker_style),
|
|
||||||
className='ticker'
|
|
||||||
)
|
|
||||||
|
|
||||||
self._last_news_update = current_time
|
|
||||||
self._initial_run = False
|
|
||||||
return self._cached_news
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error updating news: {e}")
|
|
||||||
return html.Div("No news available.")
|
|
||||||
|
|
@ -1,69 +0,0 @@
|
||||||
from dash import html, Input, Output
|
|
||||||
from scores import NBAScores # Import NBAScores class
|
|
||||||
from scores import mlbScores # Import mlbScores class
|
|
||||||
|
|
||||||
class ScoresModule:
|
|
||||||
def __init__(self, app):
|
|
||||||
self.app = app
|
|
||||||
self.scores_obj = self.get_scores_object()
|
|
||||||
self.mlb_scores_obj = self.get_mlb_scores_object()
|
|
||||||
self.setup_callbacks()
|
|
||||||
|
|
||||||
|
|
||||||
def get_scores_object(self):
|
|
||||||
return NBAScores()
|
|
||||||
|
|
||||||
def setup_callbacks(self):
|
|
||||||
@self.app.callback(
|
|
||||||
Output('nba-scores-display', 'children'),
|
|
||||||
Input('nba-interval', 'n_intervals')
|
|
||||||
)
|
|
||||||
def update_scores(n):
|
|
||||||
try:
|
|
||||||
games = self.scores_obj.get_scores()
|
|
||||||
if not games:
|
|
||||||
print("no nba games found")
|
|
||||||
return html.Div("No games available", className='text-center')
|
|
||||||
return html.Div([
|
|
||||||
html.Div([
|
|
||||||
html.Div([
|
|
||||||
html.Span(f"{game['away_team']} {game['away_score']}"),
|
|
||||||
html.Span(" @ "),
|
|
||||||
html.Span(f"{game['home_team']} {game['home_score']}")
|
|
||||||
], className='game-score'),
|
|
||||||
html.Div(f"Period: {game['period']}", className='game-period')
|
|
||||||
], className='score-box')
|
|
||||||
for game in games
|
|
||||||
], className='score-container')
|
|
||||||
except Exception as e:
|
|
||||||
return html.Div("Scores unavailable")
|
|
||||||
def get_mlb_scores_object(self):
|
|
||||||
return mlbScores()
|
|
||||||
|
|
||||||
def setup_mlb_callbacks(self):
|
|
||||||
@self.app.callback(
|
|
||||||
Output('mlb-scores-display', 'children'),
|
|
||||||
Input('mlb-interval', 'n_intervals')
|
|
||||||
)
|
|
||||||
def update_mlb_scores(n):
|
|
||||||
try:
|
|
||||||
games = self.mlb_scores_obj.get_scores()
|
|
||||||
print("Updating MLB Scores")
|
|
||||||
|
|
||||||
if not games:
|
|
||||||
print("no mlb games found")
|
|
||||||
return html.Div("No games available", className='text-center')
|
|
||||||
return html.Div([
|
|
||||||
html.Div([
|
|
||||||
html.Div([
|
|
||||||
html.Span(f"{game['away_team']} {game['away_score']}"),
|
|
||||||
html.Span(" @ "),
|
|
||||||
html.Span(f"{game['home_team']} {game['home_score']}")
|
|
||||||
], className='game-score'),
|
|
||||||
html.Div(f"Status: {game['status']}", className='game-period')
|
|
||||||
], className='score-box')
|
|
||||||
for game in games
|
|
||||||
], className='score-container')
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error updating MLB Scores: {e}")
|
|
||||||
return html.Div("Scores unavailable")
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
import datetime
|
|
||||||
import os
|
|
||||||
from dash import html, Input, Output
|
|
||||||
from weather import Weather # Import Weather class
|
|
||||||
|
|
||||||
class WeatherModule:
|
|
||||||
def __init__(self, app):
|
|
||||||
self.app = app
|
|
||||||
self.weather_obj = self.get_weather_object()
|
|
||||||
self.setup_callbacks()
|
|
||||||
|
|
||||||
def get_weather_object(self):
|
|
||||||
return Weather()
|
|
||||||
|
|
||||||
def setup_callbacks(self):
|
|
||||||
@self.app.callback(
|
|
||||||
Output('weather-display', 'children'),
|
|
||||||
Input('weather-interval', 'n_intervals')
|
|
||||||
)
|
|
||||||
def update_weather(n):
|
|
||||||
try:
|
|
||||||
print("UPDATING WEATHER...")
|
|
||||||
screenshot_path = self.weather_obj.get_weather_screenshot()
|
|
||||||
image_name = os.path.basename(screenshot_path)
|
|
||||||
return html.Div(
|
|
||||||
[
|
|
||||||
html.H2("Sacramento Weather"),
|
|
||||||
html.Img(
|
|
||||||
src=self.app.get_asset_url(image_name + f"?v={datetime.datetime.now().timestamp()}"),
|
|
||||||
style={"width": "100%", "display": "block", "image-rendering": "crisp-edges"}
|
|
||||||
),
|
|
||||||
],
|
|
||||||
style={"width": "600px", "margin": "0 auto", "border": "1px solid black"}
|
|
||||||
)
|
|
||||||
except Exception as e:
|
|
||||||
return html.Div(f"Weather update error: {str(e)}")
|
|
||||||
|
|
@ -5,17 +5,16 @@ description = ""
|
||||||
authors = [{ name = "Death916", email = "tavn1992@gmail.com" }]
|
authors = [{ name = "Death916", email = "tavn1992@gmail.com" }]
|
||||||
requires-python = ">=3.9,<3.11.4"
|
requires-python = ">=3.9,<3.11.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"pyside6>=6.6.1,<7",
|
|
||||||
"requests>=2.31.0,<3",
|
"requests>=2.31.0,<3",
|
||||||
"selenium>=4.16.0,<5",
|
|
||||||
"feedparser>=6.0.11,<7",
|
"feedparser>=6.0.11,<7",
|
||||||
"rich>=13.7.1,<14",
|
"rich>=13.7.1,<14",
|
||||||
"dash>=2.18.2,<3",
|
"dash>=2.18.2,<3",
|
||||||
"nba-api>=1.6.1,<2",
|
"nba-api>=1.6.1,<2",
|
||||||
"playwright>=1.49.1,<2",
|
"playwright>=1.49.1,<2",
|
||||||
"aiofiles>=24.1.0",
|
"aiofiles>=24.1.0",
|
||||||
"aiohttp>=3.11.13",
|
|
||||||
"mlb-statsapi>=1.8.1",
|
"mlb-statsapi>=1.8.1",
|
||||||
|
"reflex>=0.6.8",
|
||||||
|
"aiohttp>=3.11.18",
|
||||||
]
|
]
|
||||||
|
|
||||||
[dependency-groups]
|
[dependency-groups]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
from deathclock import __version__
|
|
||||||
|
|
||||||
|
|
||||||
def test_version():
|
|
||||||
assert __version__ == '0.1.0'
|
|
||||||
|
|
@ -25,4 +25,3 @@ class Alarm:
|
||||||
print("Alarm triggered!")
|
print("Alarm triggered!")
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
@ -104,4 +104,4 @@ class News:
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error writing to news.txt: {e}")
|
print(f"Error writing to news.txt: {e}")
|
||||||
|
|
||||||
return self._news_dict
|
return self._news_dict
|
||||||
|
|
@ -93,4 +93,4 @@ if __name__ == "__main__":
|
||||||
f"{game['home_team']} {game['home_score']} "
|
f"{game['home_team']} {game['home_score']} "
|
||||||
f"(Status: {game['status']})")
|
f"(Status: {game['status']})")
|
||||||
else:
|
else:
|
||||||
print("No games available")
|
print("No games available")
|
||||||
|
|
@ -52,4 +52,4 @@ class Weather:
|
||||||
return None
|
return None
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"An unexpected error occurred: {e}")
|
print(f"An unexpected error occurred: {e}")
|
||||||
return None
|
return None
|
||||||
Loading…
Add table
Add a link
Reference in a new issue