199 lines
6.5 KiB
Python
199 lines
6.5 KiB
Python
import requests
|
|
import os
|
|
from datetime import datetime
|
|
from feedgen.feed import FeedGenerator
|
|
from feedgen.entry import FeedEntry
|
|
|
|
API_BASE_URL = "https://repebblesearch.com/api/v1/apps"
|
|
OUTPUT_FOLDER = "feeds"
|
|
|
|
def format_description(text):
|
|
"""Convert release notes text to HTML with paragraph and list support."""
|
|
if not text:
|
|
return ""
|
|
|
|
html = ""
|
|
lines = text.split("\n")
|
|
in_list = False
|
|
|
|
for line in lines:
|
|
line = line.strip()
|
|
if not line:
|
|
if in_list:
|
|
html += "</ul>"
|
|
in_list = False
|
|
continue
|
|
|
|
# Check if line is a list item (starts with -, *, or •)
|
|
if line.startswith(("-", "*", "•")):
|
|
if not in_list:
|
|
html += "<ul>"
|
|
in_list = True
|
|
item_text = line[1:].strip()
|
|
html += f"<li>{item_text}</li>"
|
|
else:
|
|
if in_list:
|
|
html += "</ul>"
|
|
in_list = False
|
|
html += f"<p>{line}</p>"
|
|
|
|
if in_list:
|
|
html += "</ul>"
|
|
|
|
return html
|
|
|
|
def create_description_with_screenshots(app_data):
|
|
"""Build description with screenshots on a single line, then release notes."""
|
|
description = ""
|
|
|
|
# Add screenshots on a single line at the top
|
|
screenshots = app_data.get("screenshots", [])
|
|
if screenshots:
|
|
screenshot_html = '<div style="display: flex; gap: 10px; margin-bottom: 20px; flex-wrap: nowrap; overflow-x: auto;">'
|
|
for idx, screenshot in enumerate(screenshots, 1):
|
|
url = screenshot.get("url", "")
|
|
width = screenshot.get("width", "auto")
|
|
height = screenshot.get("height", "auto")
|
|
hardware = screenshot.get("hardware", "")
|
|
|
|
label = f"Screenshot {idx}"
|
|
if hardware:
|
|
label += f" ({hardware})"
|
|
|
|
screenshot_html += f'<img src="{url}" alt="{label}" title="{label}" width="{width}" height="{height}" style="max-height: 300px; flex-shrink: 0;" />'
|
|
|
|
screenshot_html += '</div>'
|
|
description += screenshot_html
|
|
|
|
# Add release notes below screenshots
|
|
changelog = app_data.get("changelog", [])
|
|
if changelog:
|
|
for entry in changelog:
|
|
version = entry.get("version", "Unknown")
|
|
published_date = entry.get("published_date", "")
|
|
release_notes = entry.get("release_notes", "")
|
|
|
|
# Format the date
|
|
if published_date:
|
|
try:
|
|
date_obj = datetime.fromisoformat(published_date.replace('Z', '+00:00'))
|
|
formatted_date = date_obj.strftime("%Y-%m-%d %H:%M UTC")
|
|
except:
|
|
formatted_date = published_date
|
|
else:
|
|
formatted_date = "Unknown"
|
|
|
|
description += f"<h4>Version {version}</h4>"
|
|
description += f"<em>Released: {formatted_date}</em><br/>"
|
|
description += format_description(release_notes)
|
|
else:
|
|
# Fallback to latest_release_notes
|
|
latest_notes = app_data.get("latest_release_notes", "")
|
|
if latest_notes:
|
|
description += format_description(latest_notes)
|
|
|
|
return description
|
|
|
|
def fetch_apps(query, platform="basalt"):
|
|
"""Fetch apps from the Pebble Search API."""
|
|
params = {
|
|
"query": query,
|
|
"platform": platform,
|
|
"limit": 100
|
|
}
|
|
|
|
try:
|
|
response = requests.get(API_BASE_URL, params=params)
|
|
response.raise_for_status()
|
|
data = response.json()
|
|
return data.get("apps", [])
|
|
except requests.exceptions.RequestException as e:
|
|
print(f"Error fetching apps for query '{query}': {e}")
|
|
return []
|
|
|
|
def create_rss_feed(filename, title, description, apps):
|
|
"""Create an RSS feed from app data."""
|
|
fg = FeedGenerator()
|
|
fg.title(title)
|
|
fg.link(href="https://repebblesearch.com", rel="alternate")
|
|
fg.description(description)
|
|
fg.language("en")
|
|
|
|
for app in apps:
|
|
fe = fg.add_entry()
|
|
|
|
app_title = app.get("title", "Unknown App")
|
|
app_id = app.get("uuid", "")
|
|
app_url = f"https://repebblesearch.com/app/{app_id}" if app_id else "https://repebblesearch.com"
|
|
|
|
fe.title(app_title)
|
|
fe.link(href=app_url)
|
|
fe.guid(app_url)
|
|
|
|
# Build description with screenshots and release notes
|
|
description_html = create_description_with_screenshots(app)
|
|
fe.description(description_html)
|
|
|
|
# Add enclosures for screenshots (for readers that support them)
|
|
screenshots = app.get("screenshots", [])
|
|
for screenshot in screenshots:
|
|
url = screenshot.get("url", "")
|
|
if url:
|
|
fe.enclosure(url=url, type="image/png")
|
|
|
|
# Set publication date from latest changelog entry or fallback
|
|
pub_date = None
|
|
changelog = app.get("changelog", [])
|
|
if changelog and len(changelog) > 0:
|
|
pub_date_str = changelog[0].get("published_date", "")
|
|
if pub_date_str:
|
|
try:
|
|
pub_date = datetime.fromisoformat(pub_date_str.replace('Z', '+00:00'))
|
|
except:
|
|
pub_date = datetime.now()
|
|
else:
|
|
pub_date = datetime.now()
|
|
|
|
if pub_date:
|
|
fe.pubDate(pub_date)
|
|
|
|
# Ensure output folder exists
|
|
os.makedirs(OUTPUT_FOLDER, exist_ok=True)
|
|
|
|
# Write RSS feed to file
|
|
output_path = os.path.join(OUTPUT_FOLDER, filename)
|
|
fg.rss_file(output_path, pretty=True)
|
|
print(f"Feed created: {output_path}")
|
|
|
|
def main():
|
|
"""Main function to generate RSS feeds."""
|
|
print("Fetching Pebble apps and generating RSS feeds...")
|
|
|
|
# Fetch new apps
|
|
print("Fetching new apps...")
|
|
new_apps = fetch_apps("*", platform="basalt")
|
|
|
|
# Fetch updated apps (you might want to adjust the query)
|
|
print("Fetching updated apps...")
|
|
updated_apps = fetch_apps("*", platform="basalt")
|
|
|
|
# Create RSS feeds
|
|
create_rss_feed(
|
|
"new_apps.xml",
|
|
"New Pebble Apps",
|
|
"Recently released Pebble apps from the Pebble Search database",
|
|
new_apps[:20] # Limit to 20 most recent
|
|
)
|
|
|
|
create_rss_feed(
|
|
"updated_apps.xml",
|
|
"Updated Pebble Apps",
|
|
"Recently updated Pebble apps from the Pebble Search database",
|
|
updated_apps[:20] # Limit to 20 most recent
|
|
)
|
|
|
|
print("Done!")
|
|
|
|
if __name__ == "__main__":
|
|
main()
|