mirror of
https://github.com/Death916/deathclock.git
synced 2026-04-10 03:04:40 -07:00
shows all news but in one box
This commit is contained in:
parent
b8a702d4be
commit
a6b77a3c37
4 changed files with 121 additions and 100 deletions
Binary file not shown.
|
|
@ -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")
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue