Filter options
All checks were successful
Android Build Final Fixed / build-android (push) Successful in 12m29s

This commit is contained in:
2026-03-06 16:55:28 +01:00
parent 9518385718
commit ef98a11bb8
4 changed files with 330 additions and 60 deletions

Submodule src-tauri/easy-nostr updated: 1becf76264...9845dd025d

View File

@@ -6,7 +6,13 @@ use tauri::{AppHandle, Manager, State};
#[derive(Serialize, Deserialize, Default, Clone)]
pub struct RssConfig {
pub urls: Vec<String>,
pub feeds: Vec<RssFeed>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct RssFeed {
pub url: String,
pub category: String,
}
#[derive(Default)]
@@ -22,6 +28,7 @@ pub struct NewsArticle {
pub content: String,
pub author: String,
pub created_at: String,
pub category: String,
}
fn get_config_path(app: &AppHandle) -> PathBuf {
@@ -31,6 +38,81 @@ fn get_config_path(app: &AppHandle) -> PathBuf {
.join("rss.ron")
}
fn default_feeds() -> Vec<RssFeed> {
vec![
// 💻 Technik
RssFeed {
url: "https://www.heise.de/rss/heise-atom.xml".into(),
category: "Technik".into(),
},
RssFeed {
url: "https://www.golem.de/rss.php?feed=ATOM1.0".into(),
category: "Technik".into(),
},
RssFeed {
url: "https://www.theverge.com/rss/index.xml".into(),
category: "Technik".into(),
},
RssFeed {
url: "https://arstechnica.com/feed/".into(),
category: "Technik".into(),
},
RssFeed {
url: "https://www.phoronix.com/rss.php".into(),
category: "Technik".into(),
},
// 📰 Nachrichten
RssFeed {
url: "https://www.tagesschau.de/xml/rss2".into(),
category: "Nachrichten".into(),
},
RssFeed {
url: "https://www.spiegel.de/schlagzeilen/index.rss".into(),
category: "Nachrichten".into(),
},
RssFeed {
url: "https://feeds.bbci.co.uk/news/technology/rss.xml".into(),
category: "Nachrichten".into(),
},
RssFeed {
url: "https://feeds.reuters.com/reuters/technologyNews".into(),
category: "Nachrichten".into(),
},
// 🔭 Wissenschaft
RssFeed {
url: "https://www.nasa.gov/news-release/feed/".into(),
category: "Wissenschaft".into(),
},
RssFeed {
url: "https://www.sciencedaily.com/rss/computers_math/artificial_intelligence.xml"
.into(),
category: "Wissenschaft".into(),
},
RssFeed {
url: "https://deepmind.google/blog/rss.xml".into(),
category: "Wissenschaft".into(),
},
// 🤖 KI
RssFeed {
url: "https://openai.com/blog/rss.xml".into(),
category: "KI".into(),
},
RssFeed {
url: "https://venturebeat.com/feed/".into(),
category: "KI".into(),
},
// 🐧 Open Source
RssFeed {
url: "https://lwn.net/headlines/rss".into(),
category: "Open Source".into(),
},
RssFeed {
url: "https://github.blog/feed/".into(),
category: "Open Source".into(),
},
]
}
#[tauri::command]
pub async fn save_openrouter_key(key: String, state: State<'_, NewsState>) -> Result<(), String> {
let mut lock = state.openrouter_key.lock().map_err(|_| "Lock failed")?;
@@ -49,39 +131,45 @@ pub async fn save_groq_key(key: String, state: State<'_, NewsState>) -> Result<(
pub async fn load_rss_config(
app: AppHandle,
state: State<'_, NewsState>,
) -> Result<Vec<String>, String> {
) -> Result<Vec<RssFeed>, String> {
let path = get_config_path(&app);
if !path.exists() {
let default_urls = vec![
"https://www.nasa.gov/news-release/feed/".to_string(),
"https://www.heise.de/rss/heise-atom.xml".to_string(),
];
let config = RssConfig {
urls: default_urls.clone(),
};
if let Some(parent) = path.parent() {
fs::create_dir_all(parent).map_err(|e| e.to_string())?;
let defaults = default_feeds();
let existing_config: Option<RssConfig> = if path.exists() {
let content = fs::read_to_string(&path).map_err(|e| e.to_string())?;
ron::from_str(&content).ok()
} else {
None
};
// Datei fehlt ODER hat weniger als 3 Einträge → defaults schreiben
let feeds = match existing_config {
Some(config) if config.feeds.len() >= 3 => config.feeds,
_ => {
let config = RssConfig {
feeds: defaults.clone(),
};
if let Some(parent) = path.parent() {
fs::create_dir_all(parent).map_err(|e| e.to_string())?;
}
let ron_str = ron::to_string(&config).map_err(|e| e.to_string())?;
fs::write(&path, ron_str).map_err(|e| e.to_string())?;
defaults
}
let ron_str = ron::to_string(&config).map_err(|e| e.to_string())?;
fs::write(&path, ron_str).map_err(|e| e.to_string())?;
let mut lock = state.rss_config.lock().unwrap();
lock.urls = default_urls.clone();
return Ok(default_urls);
}
let content = fs::read_to_string(path).map_err(|e| e.to_string())?;
let config: RssConfig = ron::from_str(&content).map_err(|e| e.to_string())?;
};
let mut lock = state.rss_config.lock().unwrap();
*lock = config.clone();
Ok(config.urls)
lock.feeds = feeds.clone();
Ok(feeds)
}
#[tauri::command]
pub async fn save_rss_urls(
urls: Vec<String>,
feeds: Vec<RssFeed>,
app: AppHandle,
state: State<'_, NewsState>,
) -> Result<(), String> {
let config = RssConfig { urls };
let config = RssConfig { feeds };
let path = get_config_path(&app);
if let Some(parent) = path.parent() {
fs::create_dir_all(parent).map_err(|e| e.to_string())?;
@@ -152,17 +240,18 @@ pub async fn fetch_ai_news(
content,
author: author.into(),
created_at: "Gerade eben".into(),
category: "KI".into(),
}])
}
#[tauri::command]
pub async fn fetch_rss_news(state: State<'_, NewsState>) -> Result<Vec<NewsArticle>, String> {
let urls = state.rss_config.lock().unwrap().urls.clone();
let feeds = state.rss_config.lock().unwrap().feeds.clone();
let mut all_articles = Vec::new();
let client = reqwest::Client::new();
for url in urls {
if let Ok(res) = client.get(&url).send().await {
for feed_cfg in feeds {
if let Ok(res) = client.get(&feed_cfg.url).send().await {
if let Ok(bytes) = res.bytes().await {
if let Ok(feed) = feed_rs::parser::parse(&bytes[..]) {
let source = feed
@@ -184,6 +273,7 @@ pub async fn fetch_rss_news(state: State<'_, NewsState>) -> Result<Vec<NewsArtic
),
author: source.clone(),
created_at: date,
category: feed_cfg.category.clone(),
});
}
}