mirror of
https://github.com/Death916/deathclock.git
synced 2026-04-10 03:04:40 -07:00
news
This commit is contained in:
parent
0b12a928f5
commit
2b09d76131
4 changed files with 138 additions and 66 deletions
|
|
@ -11,12 +11,12 @@ from typing import Any, Dict, List
|
||||||
|
|
||||||
import reflex as rx
|
import reflex as rx
|
||||||
|
|
||||||
|
|
||||||
from utils.news import News
|
from utils.news import News
|
||||||
from utils.scores import NBAScores, mlbScores, nflScores
|
from utils.scores import NBAScores, mlbScores, nflScores
|
||||||
|
|
||||||
# --- Import your Weather utility ---
|
|
||||||
from utils.weather import Weather
|
from utils.weather import Weather
|
||||||
|
|
||||||
|
|
||||||
# --- Constants ---
|
# --- Constants ---
|
||||||
WEATHER_IMAGE_PATH = "/weather.jpg" # Web path in assets folder
|
WEATHER_IMAGE_PATH = "/weather.jpg" # Web path in assets folder
|
||||||
WEATHER_FETCH_INTERVAL = 360
|
WEATHER_FETCH_INTERVAL = 360
|
||||||
|
|
@ -28,12 +28,13 @@ logging.basicConfig(
|
||||||
class State(rx.State):
|
class State(rx.State):
|
||||||
# --- State Variables ---
|
# --- State Variables ---
|
||||||
|
|
||||||
current_time: str = (
|
current_time: str = ""
|
||||||
"" # Note: rx.moment replaces the need for this if used for display
|
|
||||||
)
|
|
||||||
alarm_time: str = ""
|
alarm_time: str = ""
|
||||||
alarms: list = []
|
alarms: List = []
|
||||||
news: List[Dict[str, Any]] = []
|
news: List[Dict[str, Any]] = []
|
||||||
|
current_news_index: int = 0
|
||||||
|
news_rotate_interval: int = 10
|
||||||
|
news_text: str = ""
|
||||||
nba_scores: List[Dict[str, Any]] = []
|
nba_scores: List[Dict[str, Any]] = []
|
||||||
mlb_scores: List[Dict[str, Any]] = []
|
mlb_scores: List[Dict[str, Any]] = []
|
||||||
nfl_scores: List[Dict[str, Any]] = []
|
nfl_scores: List[Dict[str, Any]] = []
|
||||||
|
|
@ -75,7 +76,12 @@ class State(rx.State):
|
||||||
) # trying to test themes remove after
|
) # trying to test themes remove after
|
||||||
logging.info("Triggering background tasks: Weather")
|
logging.info("Triggering background tasks: Weather")
|
||||||
# Return a list containing the handler references
|
# Return a list containing the handler references
|
||||||
return [State.fetch_weather, State.fetch_sports]
|
return [
|
||||||
|
State.fetch_weather,
|
||||||
|
State.fetch_sports,
|
||||||
|
State.fetch_news,
|
||||||
|
State.cycle_news,
|
||||||
|
]
|
||||||
|
|
||||||
# --- Sports Background Task ---
|
# --- Sports Background Task ---
|
||||||
|
|
||||||
|
|
@ -140,10 +146,8 @@ class State(rx.State):
|
||||||
)
|
)
|
||||||
await asyncio.sleep(500)
|
await asyncio.sleep(500)
|
||||||
|
|
||||||
"""@rx.event(background=True)
|
@rx.event(background=True)
|
||||||
async def fetch_news(self):
|
async def fetch_news(self):
|
||||||
# Fetches news periodically
|
|
||||||
# Placeholder for the actual news fetching logic
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
logging.info("Fetching news...")
|
logging.info("Fetching news...")
|
||||||
|
|
@ -152,11 +156,13 @@ class State(rx.State):
|
||||||
logging.warning("No news items fetched.")
|
logging.warning("No news items fetched.")
|
||||||
async with self:
|
async with self:
|
||||||
self.news = []
|
self.news = []
|
||||||
yield # Update frontend
|
self.current_news_index = 0
|
||||||
|
yield
|
||||||
else:
|
else:
|
||||||
logging.info(f"Fetched {len(news_items)} news items.")
|
logging.info(f"Fetched {len(news_items)} news items.")
|
||||||
async with self:
|
async with self:
|
||||||
self.news = news_items
|
self.news = news_items
|
||||||
|
self.current_news_index = 0
|
||||||
yield
|
yield
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
@ -164,7 +170,22 @@ class State(rx.State):
|
||||||
f"Error in fetch_news background task: {e}", exc_info=True
|
f"Error in fetch_news background task: {e}", exc_info=True
|
||||||
)
|
)
|
||||||
await asyncio.sleep(500)
|
await asyncio.sleep(500)
|
||||||
"""
|
|
||||||
|
@rx.event(background=True)
|
||||||
|
async def cycle_news(self):
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
if self.news:
|
||||||
|
async with self:
|
||||||
|
self.current_news_index = (self.current_news_index + 1) % len(
|
||||||
|
self.news
|
||||||
|
)
|
||||||
|
yield
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(
|
||||||
|
f"Error in cycle_news background task: {e}", exc_info=True
|
||||||
|
)
|
||||||
|
await asyncio.sleep(self.news_rotate_interval)
|
||||||
|
|
||||||
# --- Weather Background Task ---
|
# --- Weather Background Task ---
|
||||||
@rx.event(background=True)
|
@rx.event(background=True)
|
||||||
|
|
@ -350,6 +371,36 @@ def index() -> rx.Component:
|
||||||
background_color="#6f42c1",
|
background_color="#6f42c1",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
news_card = rx.card(
|
||||||
|
rx.box(
|
||||||
|
rx.text("News Headlines"),
|
||||||
|
rx.center(
|
||||||
|
rx.cond(
|
||||||
|
State.news,
|
||||||
|
rx.text(
|
||||||
|
State.news[State.current_news_index]["title"],
|
||||||
|
font_size="lg",
|
||||||
|
color="gray.500",
|
||||||
|
no_of_lines=1,
|
||||||
|
white_space="nowrap",
|
||||||
|
overflow="hidden",
|
||||||
|
text_overflow="ellipsis",
|
||||||
|
),
|
||||||
|
rx.text(
|
||||||
|
"No news available",
|
||||||
|
font_size="lg",
|
||||||
|
color="gray.500",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
width="100%",
|
||||||
|
min_height="3.25rem",
|
||||||
|
),
|
||||||
|
padding="4",
|
||||||
|
),
|
||||||
|
variant="surface",
|
||||||
|
width="100%",
|
||||||
|
)
|
||||||
|
|
||||||
# Compose the page
|
# Compose the page
|
||||||
page = rx.container( # pyright: ignore[reportReturnType]
|
page = rx.container( # pyright: ignore[reportReturnType]
|
||||||
rx.theme_panel(default_open=False),
|
rx.theme_panel(default_open=False),
|
||||||
|
|
@ -357,6 +408,7 @@ def index() -> rx.Component:
|
||||||
rx.vstack(
|
rx.vstack(
|
||||||
clock_button,
|
clock_button,
|
||||||
main_flex,
|
main_flex,
|
||||||
|
news_card,
|
||||||
align="center",
|
align="center",
|
||||||
spacing="4",
|
spacing="4",
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ dependencies = [
|
||||||
"mlb-statsapi>=1.8.1",
|
"mlb-statsapi>=1.8.1",
|
||||||
"reflex>=0.6.8",
|
"reflex>=0.6.8",
|
||||||
"aiohttp>=3.11.18",
|
"aiohttp>=3.11.18",
|
||||||
|
"reflex-text-loop>=0.0.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[dependency-groups]
|
[dependency-groups]
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,13 @@ from time import localtime, strftime
|
||||||
import socket
|
import socket
|
||||||
import aiohttp
|
import aiohttp
|
||||||
|
|
||||||
|
|
||||||
def print_time():
|
def print_time():
|
||||||
print(strftime("%B %d, %I:%M %p", localtime()))
|
print(strftime("%B %d, %I:%M %p", localtime()))
|
||||||
|
|
||||||
|
|
||||||
class News:
|
class News:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._news_dict = {}
|
|
||||||
self._news_dict_length = 0
|
|
||||||
socket.setdefaulttimeout(10) # Set default timeout for socket operations
|
socket.setdefaulttimeout(10) # Set default timeout for socket operations
|
||||||
|
|
||||||
async def _fetch_feed(self, session, feed):
|
async def _fetch_feed(self, session, feed):
|
||||||
|
|
@ -30,7 +30,7 @@ class News:
|
||||||
text = await response.text()
|
text = await response.text()
|
||||||
d = feedparser.parse(text)
|
d = feedparser.parse(text)
|
||||||
|
|
||||||
if hasattr(d, 'status') and d.status != 200:
|
if hasattr(d, "status") and d.status != 200:
|
||||||
print(f"Skip feed {feed}: status {d.status}")
|
print(f"Skip feed {feed}: status {d.status}")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
@ -40,12 +40,18 @@ class News:
|
||||||
if i >= max_entries:
|
if i >= max_entries:
|
||||||
break # Stop parsing if we've reached the limit
|
break # Stop parsing if we've reached the limit
|
||||||
|
|
||||||
feed_entries.append({
|
feed_entries.append(
|
||||||
'title': post.title,
|
{
|
||||||
'source': d.feed.title if hasattr(d.feed, 'title') else 'Unknown',
|
"title": post.title,
|
||||||
'publish_date': post.published if hasattr(post, 'published') else '',
|
"source": d.feed.title
|
||||||
'summary': post.summary if hasattr(post, 'summary') else ''
|
if hasattr(d.feed, "title")
|
||||||
})
|
else "Unknown",
|
||||||
|
"publish_date": post.published
|
||||||
|
if hasattr(post, "published")
|
||||||
|
else "",
|
||||||
|
"summary": post.summary if hasattr(post, "summary") else "",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
print(f"Added {len(feed_entries)} entries from {feed}")
|
print(f"Added {len(feed_entries)} entries from {feed}")
|
||||||
return feed_entries
|
return feed_entries
|
||||||
|
|
@ -88,20 +94,19 @@ class News:
|
||||||
|
|
||||||
if not all_entries:
|
if not all_entries:
|
||||||
print("No entries collected")
|
print("No entries collected")
|
||||||
return {}
|
return []
|
||||||
|
|
||||||
if len(all_entries) > 30:
|
if len(all_entries) > 30:
|
||||||
all_entries = random.sample(all_entries, 30)
|
all_entries = random.sample(all_entries, 30)
|
||||||
|
|
||||||
for entry in all_entries:
|
|
||||||
self._news_dict[entry['title']] = entry
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
async with aiofiles.open("news.txt", "w") as f:
|
async with aiofiles.open("news.txt", "w") as f:
|
||||||
print("Writing news to file...")
|
print("Writing news to file...")
|
||||||
for entry in self._news_dict.values():
|
for entry in all_entries:
|
||||||
await f.write(f"[{entry['publish_date']}] {entry['source']}: {entry['title']}\n")
|
await f.write(
|
||||||
|
f"[{entry['publish_date']}] {entry['source']}: {entry['title']}\n"
|
||||||
|
)
|
||||||
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 all_entries
|
||||||
|
|
|
||||||
14
uv.lock
generated
14
uv.lock
generated
|
|
@ -268,6 +268,7 @@ dependencies = [
|
||||||
{ name = "nba-api" },
|
{ name = "nba-api" },
|
||||||
{ name = "playwright" },
|
{ name = "playwright" },
|
||||||
{ name = "reflex" },
|
{ name = "reflex" },
|
||||||
|
{ name = "reflex-text-loop" },
|
||||||
{ name = "requests" },
|
{ name = "requests" },
|
||||||
{ name = "rich" },
|
{ name = "rich" },
|
||||||
]
|
]
|
||||||
|
|
@ -287,6 +288,7 @@ requires-dist = [
|
||||||
{ name = "nba-api", specifier = ">=1.6.1,<2" },
|
{ name = "nba-api", specifier = ">=1.6.1,<2" },
|
||||||
{ name = "playwright", specifier = ">=1.49.1,<2" },
|
{ name = "playwright", specifier = ">=1.49.1,<2" },
|
||||||
{ name = "reflex", specifier = ">=0.6.8" },
|
{ name = "reflex", specifier = ">=0.6.8" },
|
||||||
|
{ name = "reflex-text-loop", specifier = ">=0.0.1" },
|
||||||
{ name = "requests", specifier = ">=2.31.0,<3" },
|
{ name = "requests", specifier = ">=2.31.0,<3" },
|
||||||
{ name = "rich", specifier = ">=13.7.1,<14" },
|
{ name = "rich", specifier = ">=13.7.1,<14" },
|
||||||
]
|
]
|
||||||
|
|
@ -1099,6 +1101,18 @@ wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/0a/4d/5526f5a21a01b6179e3ebe9abc46dce01d9692ef655e22002a08e10de8b7/reflex_hosting_cli-0.1.42-py3-none-any.whl", hash = "sha256:2742d9eb3576fa001ea2a4971cef1e1db56a08aad619aa035af3b6cc8f80de4c", size = 38668, upload-time = "2025-04-11T17:28:02.296Z" },
|
{ url = "https://files.pythonhosted.org/packages/0a/4d/5526f5a21a01b6179e3ebe9abc46dce01d9692ef655e22002a08e10de8b7/reflex_hosting_cli-0.1.42-py3-none-any.whl", hash = "sha256:2742d9eb3576fa001ea2a4971cef1e1db56a08aad619aa035af3b6cc8f80de4c", size = 38668, upload-time = "2025-04-11T17:28:02.296Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "reflex-text-loop"
|
||||||
|
version = "0.0.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "reflex" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/ac/eb/2bf65bab5474452b374951497f82338abc95569a5451dfade2ba52e05133/reflex_text_loop-0.0.1.tar.gz", hash = "sha256:4be9cb2b626a329f4de04dddc7c2571c1d204b6be2b6cc9eb87ed926c82ee47b", size = 6042, upload-time = "2024-09-13T09:48:59.681Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c2/e6/fc55aec3e78e34d7f226a60719d1e01da8d4a78c2743ec4716af2c74ca0d/reflex_text_loop-0.0.1-py3-none-any.whl", hash = "sha256:37772b301ca87b8195fd37c09e848299bafa8484e104b9c14d5e1182b2cf40b7", size = 6426, upload-time = "2024-09-13T09:48:57.768Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "requests"
|
name = "requests"
|
||||||
version = "2.32.3"
|
version = "2.32.3"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue