A desktop notifier is a Python application that displays short messages through the operating system's notification system. It can deliver news headlines, reminders, task updates, and other alerts without requiring users to open a separate application.
In this article, we will create a news desktop notifier that reads headlines from an RSS feed and displays them as desktop notifications using Python.
Installation
- Feedparser: This library retrieves and parses RSS and Atom feeds, allowing Python applications to access news headlines and summaries.
- Desktop-notifier: This library sends notifications through supported operating system APIs on Linux, Windows, and macOS. Platform-specific settings may affect notification delivery.
python -m pip install feedparser desktop-notifier
1. Importing Required Libraries
Import asyncio to execute asynchronous operations, feedparser to read news, and DesktopNotifier to display notifications.
import feedparser
from desktop_notifier import DesktopNotifier
2. Defining RSS Feel URL
We will use the BBC News RSS feed to retrieve the latest available headlines.
RSS_FEED_URL = "https://feeds.bbci.co.uk/news/rss.xml"
MAX_HEADLINES = 5
Explanation:
- RSS_FEED_URL stores the source of the news headlines.
- MAX_HEADLINES limits the number of notifications displayed in one run.
- DesktopNotifier initializes the notification service with an application name.
3. Cleaning News Text
RSS feeds may contain HTML tags and encoded characters. Define a function to make the text more readable before displaying it.
def clean_text(value):
"""Remove HTML tags and decode HTML entities."""
text = re.sub(r"<[^>]+>", " ", value)
return unescape(text).strip()
Explanation:
- clean_text() accepts a string containing a headline or summary.
- re.sub() replaces HTML tags with spaces.
- unescape() converts encoded characters, such as &, into their readable equivalents.
- strip() removes unnecessary whitespace from the beginning and end.
4. Retrieving and Validate News Headlines
Creating an asynchronous main() function to retrieve news entries from the RSS feed.
async def main():
feed = feedparser.parse(RSS_FEED_URL)
if not feed.entries:
print("No headlines found. Check the feed URL or internet connection.")
return
print(f"Retrieved {len(feed.entries)} news entries.")
Explanation:
- feedparser.parse() retrieves and parses the RSS feed.
- feed.entries contains the available news items.
- If condition checks whether the feed returned any entries.
- print() displays the number of entries retrieved.
- return stops execution when no headlines are available.
5. Displaying Desktop Notifications
Following code inside the main() function, immediately after the validation step.
for entry in feed.entries[:MAX_HEADLINES]:
title = clean_text(entry.get("title", "News Update"))
summary = clean_text(entry.get("summary", ""))
if not summary:
summary = "Open the news website to read the full story."
await notifier.send(
title=title,
message=summary[:250]
)
print(f"Notification sent: {title}")
await asyncio.sleep(2)
Explanation:
- For loop processes up to five news entries.
- entry.get() retrieves each headline and summary, using a default value when a field is missing.
- clean_text() removes HTML tags and cleans the extracted text.
- If condition provides a fallback message when a summary is unavailable.
- notifier.send() displays the headline and its summary as a desktop notification.
- summary[:250] limits the notification message to 250 characters.
- asyncio.sleep(2) adds a two-second delay between notifications.
6. Running Asynchronous Program
Add the following code at the end of desktop_notifier.py.
if __name__ == "__main__":
asyncio.run(main())
Explanation:
- if condition checks whether the file is being executed directly.
- asyncio.run() starts the asynchronous main() function and manages its event loop.
- This entry point runs the news retrieval and notification process.
7. Execute Program
Run the following command in your terminal.
python desktop_notifier.py
Complete Program
import asyncio
import re
from html import unescape
import feedparser
from desktop_notifier import DesktopNotifier
RSS_FEED_URL = "https://feeds.bbci.co.uk/news/rss.xml"
MAX_HEADLINES = 5
DELAY_SECONDS = 2
notifier = DesktopNotifier(app_name="News Notifier")
def clean_text(value):
"""Remove HTML tags and clean the text."""
text = re.sub(r"<[^>]+>", " ", value or "")
text = unescape(text)
return re.sub(r"\s+", " ", text).strip()
async def main():
try:
feed = feedparser.parse(RSS_FEED_URL)
except Exception as error:
print(f"Error retrieving news: {error}")
return
if not feed.entries:
print("No headlines found.")
print("Check your internet connection or RSS feed URL.")
return
headlines = feed.entries[:MAX_HEADLINES]
print(f"Found {len(headlines)} news headlines.\n")
for entry in headlines:
title = clean_text(entry.get("title", "News Update"))
summary = clean_text(entry.get("summary", ""))
if not title:
title = "News Update"
if not summary:
summary = "Open the news website to read the full story."
try:
await notifier.send(
title=title,
message=summary[:250]
)
print(f"Notification requested: {title}")
except Exception as error:
print(f"Could not display notification: {error}")
await asyncio.sleep(DELAY_SECONDS)
print("\nNews notification process completed.")
if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
print("\nProgram stopped by the user.")
Output
Found 5 news headlines.
Notification requested: [Latest news headline]
Notification requested: [Second news headline]
Notification requested: [Third news headline]
Notification requested: [Fourth news headline]
Notification requested: [Fifth news headline]
News notification process completed.