mirror of
https://github.com/FluxaMedia/fluxa-core.git
synced 2026-08-09 08:27:31 +00:00
Preserve plugin-sourced subtitles and scraper overrides across re-fetch
plugin_result_to_stream only populated subtitle_tracks, not the subtitles field Kotlin's Stream model actually reads, silently dropping plugin subtitles. Also add pluginScraperSettingsUpdated and make repository re-fetch (on manual refresh or app-start replay) carry over a scraper's existing enabled/settings instead of resetting to manifest defaults.
This commit is contained in:
parent
80657b75bf
commit
f9000b4dbd
4 changed files with 132 additions and 0 deletions
|
|
@ -320,6 +320,11 @@ pub(super) enum AppAction {
|
|||
PluginRepositoryRemoveRequested { manifest_url: String },
|
||||
#[serde(rename = "pluginScraperToggled")]
|
||||
PluginScraperToggled { scraper_id: String, enabled: bool },
|
||||
#[serde(rename = "pluginScraperSettingsUpdated")]
|
||||
PluginScraperSettingsUpdated {
|
||||
scraper_id: String,
|
||||
settings: Value,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize)]
|
||||
|
|
|
|||
|
|
@ -550,6 +550,10 @@ impl HeadlessEngine {
|
|||
scraper_id,
|
||||
enabled,
|
||||
} => plugins::dispatch_toggle_scraper(self, scraper_id, enabled),
|
||||
AppAction::PluginScraperSettingsUpdated {
|
||||
scraper_id,
|
||||
settings,
|
||||
} => plugins::dispatch_update_scraper_settings(self, scraper_id, settings),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1770,6 +1774,78 @@ mod tests {
|
|||
assert!(destroy_headless_engine(handle));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn plugin_repository_refetch_preserves_disabled_state_and_settings() {
|
||||
let handle = create_headless_engine("{}");
|
||||
let manifest_value = json!({
|
||||
"manifestUrl": "https://example.com/manifest.json",
|
||||
"manifest": {
|
||||
"name": "Phisher's Repo",
|
||||
"version": "1.0.0",
|
||||
"scrapers": [
|
||||
{"id": "MoviesDrive", "name": "MoviesDrive", "version": "1.1.1", "filename": "src/providers/moviesdrive.js"}
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
let requested: Value = serde_json::from_str(
|
||||
&headless_engine_dispatch_json(
|
||||
handle,
|
||||
r#"{"type":"pluginRepositoryAddRequested","manifestUrl":"https://example.com/manifest.json"}"#,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
headless_engine_complete_effect_json(
|
||||
handle,
|
||||
&json!({
|
||||
"effectId": requested["effects"][0]["id"].as_str().unwrap(),
|
||||
"status": "ok",
|
||||
"value": manifest_value
|
||||
})
|
||||
.to_string(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
headless_engine_dispatch_json(
|
||||
handle,
|
||||
r#"{"type":"pluginScraperToggled","scraperId":"MoviesDrive","enabled":false}"#,
|
||||
)
|
||||
.unwrap();
|
||||
headless_engine_dispatch_json(
|
||||
handle,
|
||||
r#"{"type":"pluginScraperSettingsUpdated","scraperId":"MoviesDrive","settings":{"quality":"1080p"}}"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let refetch_requested: Value = serde_json::from_str(
|
||||
&headless_engine_dispatch_json(
|
||||
handle,
|
||||
r#"{"type":"pluginRepositoryAddRequested","manifestUrl":"https://example.com/manifest.json"}"#,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
let refetched: Value = serde_json::from_str(
|
||||
&headless_engine_complete_effect_json(
|
||||
handle,
|
||||
&json!({
|
||||
"effectId": refetch_requested["effects"][0]["id"].as_str().unwrap(),
|
||||
"status": "ok",
|
||||
"value": manifest_value
|
||||
})
|
||||
.to_string(),
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let scraper = &refetched["state"]["plugins"]["scrapers"][0];
|
||||
assert_eq!(scraper["enabled"], false);
|
||||
assert_eq!(scraper["settings"]["quality"], "1080p");
|
||||
assert!(destroy_headless_engine(handle));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn calendar_completion_plans_os_side_effects_in_core() {
|
||||
let handle = create_headless_engine("{}");
|
||||
|
|
|
|||
|
|
@ -77,6 +77,22 @@ pub(super) fn dispatch_toggle_scraper(
|
|||
vec![]
|
||||
}
|
||||
|
||||
pub(super) fn dispatch_update_scraper_settings(
|
||||
engine: &mut HeadlessEngine,
|
||||
scraper_id: String,
|
||||
settings: Value,
|
||||
) -> Vec<EffectEnvelope> {
|
||||
if let Some(items) = engine.state.plugins.scrapers.as_array_mut() {
|
||||
if let Some(scraper) = items
|
||||
.iter_mut()
|
||||
.find(|scraper| scraper["id"].as_str() == Some(scraper_id.as_str()))
|
||||
{
|
||||
scraper["settings"] = settings;
|
||||
}
|
||||
}
|
||||
vec![]
|
||||
}
|
||||
|
||||
pub(super) fn complete(
|
||||
engine: &mut HeadlessEngine,
|
||||
generation: u64,
|
||||
|
|
@ -114,11 +130,43 @@ pub(super) fn complete(
|
|||
repository_entry,
|
||||
);
|
||||
|
||||
let previous_by_id: std::collections::HashMap<String, Value> = engine
|
||||
.state
|
||||
.plugins
|
||||
.scrapers
|
||||
.as_array()
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.filter(|scraper| scraper["repositoryUrl"].as_str() == Some(manifest_url))
|
||||
.filter_map(|scraper| {
|
||||
scraper["id"]
|
||||
.as_str()
|
||||
.map(|id| (id.to_string(), scraper.clone()))
|
||||
})
|
||||
.collect();
|
||||
|
||||
if let Some(items) = engine.state.plugins.scrapers.as_array_mut() {
|
||||
items.retain(|scraper| scraper["repositoryUrl"].as_str() != Some(manifest_url));
|
||||
}
|
||||
for mut scraper in scrapers {
|
||||
scraper["repositoryUrl"] = Value::String(manifest_url.to_string());
|
||||
let manifest_enabled = scraper["enabled"].as_bool().unwrap_or(true);
|
||||
if let Some(previous) = scraper["id"]
|
||||
.as_str()
|
||||
.and_then(|id| previous_by_id.get(id))
|
||||
{
|
||||
if manifest_enabled {
|
||||
if let Some(previous_enabled) = previous["enabled"].as_bool() {
|
||||
scraper["enabled"] = Value::Bool(previous_enabled);
|
||||
}
|
||||
}
|
||||
if let Some(previous_settings) = previous.get("settings") {
|
||||
scraper["settings"] = previous_settings.clone();
|
||||
}
|
||||
}
|
||||
if scraper.get("settings").is_none() {
|
||||
scraper["settings"] = json!({});
|
||||
}
|
||||
if let Some(items) = engine.state.plugins.scrapers.as_array_mut() {
|
||||
items.push(scraper);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -166,6 +166,7 @@ fn plugin_result_to_stream(result: PluginStreamResult) -> Stream {
|
|||
title: Some(result.title),
|
||||
info_hash: result.info_hash,
|
||||
headers: result.headers,
|
||||
subtitles: subtitle_tracks.clone(),
|
||||
subtitle_tracks,
|
||||
extra,
|
||||
..Default::default()
|
||||
|
|
@ -257,6 +258,8 @@ mod tests {
|
|||
let subs = stream.subtitle_tracks.as_ref().unwrap();
|
||||
assert_eq!(subs[0].lang, "en");
|
||||
assert_eq!(subs[0].url, "https://example.com/sub.srt");
|
||||
let subs_alias = stream.subtitles.as_ref().unwrap();
|
||||
assert_eq!(subs_alias[0].url, "https://example.com/sub.srt");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
Loading…
Reference in a new issue