shows all news but in one box

This commit is contained in:
Death916 2025-01-15 03:09:52 -08:00
parent b8a702d4be
commit a6b77a3c37
4 changed files with 121 additions and 100 deletions

View file

@ -11,22 +11,33 @@ app = Dash(__name__)
weather_obj = Weather()
news_obj = News()
scores_obj = NBAScores()
#uses arbitrary date in the past as initial value
_last_news_update = datetime.datetime(2000, 1, 1)
_cached_news = []
_initial_run = True
_timer_elapsed = False
app.layout = html.Div([
html.H1(id='clock-display', style={'textAlign': 'center'}),
html.Div(id='weather-display', style={'textAlign': 'center'}),
html.Div([
# Container for scores and weather
html.Div([
html.Div([
html.H2("NBA Scores"),
html.Div(id='nba-scores-display', className='score-container')
]),
html.Div(id='weather-display')
], id='scores-weather-container'),
]),
html.Div(id='news-ticker', className='ticker'),
# Intervals
dcc.Interval(id='clock-interval', interval=1000, n_intervals=0),
dcc.Interval(id='weather-interval', interval=300000, n_intervals=0),
dcc.Interval(id='news-interval', interval=300000, n_intervals=0),
html.Div([
html.H2("NBA Scores"),
html.Div(id='nba-scores-display', className='score-container'),
dcc.Interval(id='nba-interval', interval=60000, n_intervals=0)
])
dcc.Interval(id='nba-interval', interval=60000, n_intervals=0)
])
@app.callback(
@ -56,13 +67,52 @@ def update_weather(n):
Input('news-interval', 'n_intervals')
)
def update_news(n):
try:
news_dict = news_obj.get_news()
items = [html.Span(f"{headline} | ", className='news-item')
for headline in news_dict.keys()]
return html.Div(items)
except Exception as e:
return html.Div(f"News feed error: {str(e)}")
global _last_news_update, _cached_news, _initial_run
current_time = datetime.datetime.now()
# On first run or if 5 minutes have elapsed since last update
if _initial_run or (current_time - _last_news_update).total_seconds() >= 300:
print("Fetching fresh news...")
try:
headlines_dict = news_obj.get_news()
if not isinstance(headlines_dict, dict):
return html.Div("News update error: Invalid data format")
if not headlines_dict:
return html.Div("No news fetched")
combined_text = " | ".join(headlines_dict.keys())
text_px = len(combined_text) * 8 # Approx 8px per character
scroll_speed = 500 # px per second
duration = text_px / scroll_speed # seconds to scroll across
# Enforce a floor duration so it's not too quick for short text
if duration < 20:
duration = 20
ticker_style = {"animationDuration": f"{duration}s", "whiteSpace": "nowrap"}
items = [
html.Div(
f"{headline} | ",
className="news-item",
style=ticker_style
)
for headline in headlines_dict.keys()
]
_cached_news = html.Div(items, style=ticker_style)
_last_news_update = current_time
_initial_run = False
return _cached_news
except Exception as e:
return html.Div(f"News feed error: {str(e)}")
print("Returning cached news...")
return _cached_news
#get the scores from the scores API
@app.callback(
@ -72,7 +122,10 @@ def update_news(n):
def update_scores(n):
try:
games = scores_obj.get_scores()
return [
if not games:
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']}"),
@ -80,9 +133,10 @@ def update_scores(n):
html.Span(f"{game['home_team']} {game['home_score']}")
], className='game-score'),
html.Div(f"Period: {game['period']}", className='game-period')
], className='score-box')
], className='score-box')
for game in games
]
], className='score-container')
except Exception as e:
return html.Div("Scores unavailable")

View file

@ -1,26 +1,4 @@
/* assets/style.css */
/* News ticker container */
.ticker {
overflow: hidden;
white-space: nowrap;
background-color: #f0f0f0;
padding: 10px;
}
/* Each headline or news item */
.news-item {
display: inline-block;
padding: 0 2rem;
animation: scroll-left 20s linear infinite;
}
/* Keyframes for scrolling left */
@keyframes scroll-left {
0% { transform: translateX(100%); }
100% { transform: translateX(-100%); }
}
body {
body {
background-color: #1a1a2e;
color: #e6e6fa;
font-family: 'Arial', sans-serif;
@ -28,13 +6,42 @@
padding: 20px;
}
#curr-time {
font-size: 4em;
color: #b39ddb;
text-shadow: 0 0 10px rgba(179, 157, 219, 0.3);
margin: 20px 0;
/* Container for the scores and weather */
#scores-weather-container {
display: flex;
justify-content: space-between;
align-items: flex-start;
width: 100%;
}
/* Scores Styles */
.score-container {
max-width: 300px;
padding: 10px;
flex: 1;
}
.score-box {
background-color: #232338;
padding: 8px;
margin-bottom: 8px;
border-radius: 6px;
border: 1px solid #4a4a82;
}
.game-score {
font-size: 0.9em;
color: #e6e6fa;
text-align: center;
}
.game-period {
font-size: 0.8em;
color: #b39ddb;
text-align: center;
}
/* Weather Styles */
#weather-display {
background-color: #232338;
border-radius: 10px;
@ -43,64 +50,17 @@
max-width: 600px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2);
border: 1px solid #4a4a82;
transition: all 0.3s ease;
flex: 2;
}
#weather-display img {
max-width: 100%;
border-radius: 8px;
margin-top: 10px;
}
.ticker {
background-color: #232338;
padding: 15px;
border-radius: 8px;
margin: 20px 0;
border: 1px solid #4a4a82;
overflow: hidden;
white-space: nowrap;
}
.news-item {
display: inline-block;
padding: 0 30px;
color: #d1c4e9;
animation: ticker 30s linear infinite;
}
@keyframes ticker {
0% { transform: translateX(100%); }
100% { transform: translateX(-100%); }
}
/* Add subtle hover effects */
#weather-display:hover {
box-shadow: 0 6px 8px rgba(179, 157, 219, 0.2);
transform: translateY(-2px);
transition: all 0.3s ease;
}
.score-box {
background-color: #232338;
margin: 10px 0;
padding: 15px;
#weather-display img {
width: 100%;
border-radius: 8px;
border: 1px solid #4a4a82;
}
.game-score {
font-size: 1.2em;
color: #e6e6fa;
margin-bottom: 5px;
}
.game-period {
font-size: 0.9em;
color: #b39ddb;
}
.score-box:hover {
transform: translateY(-2px);
box-shadow: 0 4px 6px rgba(179, 157, 219, 0.2);
transition: all 0.3s ease;
margin-top: 10px;
}

View file

@ -16,7 +16,7 @@ class News:
# Get latest news from each feed
for feed in feeds:
d = feedparser.parse(feed)
for post in d.entries[:3]: # Limit to 3 entries per feed
for post in d.entries[:10]: # Limit to 3 entries per feed
if self._news_dict_length >= 20: # Max 20 total entries
return self._news_dict
@ -27,5 +27,12 @@ class News:
'summary': post.summary
}
self._news_dict_length += 1
# Store last 20 news items in text file
with open("news.txt", "w") as f:
for headline in list(self._news_dict.keys())[-20:]:
f.write(f"{headline}\n")
return self._news_dict