mirror of
https://github.com/FluxaMedia/fluxa-core.git
synced 2026-08-18 04:55:55 +00:00
Plan Discover per selected catalog
This commit is contained in:
parent
83df69a7dd
commit
c2b0e610ec
5 changed files with 76 additions and 102 deletions
|
|
@ -390,7 +390,6 @@ fn route_search_plan(method: &str, args_json: &str) -> Outcome {
|
|||
field_str(&args, "selectedType")?,
|
||||
))
|
||||
}
|
||||
"discoverSortPlan" => opt_json(search_plan::discover_sort_plan_json(args_json)),
|
||||
"librarySortPlan" => opt_json(search_plan::library_sort_plan_json(args_json)),
|
||||
"detailSeriesLookupId" => Ok(Value::String(search_plan::detail_series_lookup_id(
|
||||
&arg_str(args_json, "id")?,
|
||||
|
|
|
|||
|
|
@ -84,6 +84,8 @@ pub(super) fn dispatch_catalog_filters(
|
|||
let generation = engine.bump_generation(GenerationKey::Discover);
|
||||
let profile_value = profile.unwrap_or_else(|| engine.state.profile.active.clone());
|
||||
let profile_id = active_profile_id(&engine.state, &profile_value);
|
||||
engine.state.discover.content_type = content_type.clone();
|
||||
engine.state.discover.catalogs = serde_json::json!([]);
|
||||
vec![engine.effect(
|
||||
EffectKind::ReadDiscoverCatalogFilters,
|
||||
generation,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
use crate::addon_protocol::{
|
||||
build_resource_url, catalog_supports_extra as manifest_catalog_supports_extra, supports_resource,
|
||||
build_resource_url, catalog_supports_extra as manifest_catalog_supports_extra,
|
||||
supports_resource,
|
||||
};
|
||||
use crate::content_identity::parse_extra_args_json;
|
||||
use crate::content_identity::{parse_extra_args_json, stable_feed_part};
|
||||
use crate::repository_flow::addon_streams_with_provider_json;
|
||||
use crate::stream_policy::stream_playback_info_json;
|
||||
use serde::Deserialize;
|
||||
|
|
@ -23,6 +24,8 @@ struct ResourceFetchPlanRequest {
|
|||
#[serde(default)]
|
||||
catalog_id: Option<String>,
|
||||
#[serde(default)]
|
||||
catalog_key: Option<String>,
|
||||
#[serde(default)]
|
||||
id: Option<String>,
|
||||
#[serde(default)]
|
||||
request_ids: Vec<String>,
|
||||
|
|
@ -150,25 +153,44 @@ pub(crate) fn resource_fetch_plan_json(request_json: &str) -> Option<String> {
|
|||
}
|
||||
}
|
||||
"discover" => {
|
||||
let genre = request.genre.as_deref();
|
||||
for catalog in discover_catalog_options(
|
||||
&request.addons,
|
||||
request.content_type.as_deref().unwrap_or(""),
|
||||
) {
|
||||
let extra = genre
|
||||
.filter(|_| catalog.supports_genre)
|
||||
.map(|value| json!({"genre": value}).to_string());
|
||||
requests.push(json!({
|
||||
"url": build_resource_url(
|
||||
&catalog.transport_url,
|
||||
"catalog",
|
||||
&catalog.content_type,
|
||||
&catalog.id,
|
||||
extra.as_deref()
|
||||
),
|
||||
"kind": "discover",
|
||||
"catalogKey": catalog.key
|
||||
}));
|
||||
let catalog_key = request.catalog_key.as_deref()?;
|
||||
for addon in &request.addons {
|
||||
let Some(transport_url) = addon_transport_url(addon) else {
|
||||
continue;
|
||||
};
|
||||
for catalog in addon_catalogs(addon) {
|
||||
let Some(content_type) = catalog.get("type").and_then(Value::as_str) else {
|
||||
continue;
|
||||
};
|
||||
let Some(id) = catalog.get("id").and_then(Value::as_str) else {
|
||||
continue;
|
||||
};
|
||||
let key = format!(
|
||||
"discover:{}:{}:{}",
|
||||
stable_feed_part(transport_url),
|
||||
stable_feed_part(content_type),
|
||||
stable_feed_part(id),
|
||||
);
|
||||
if key != catalog_key {
|
||||
continue;
|
||||
}
|
||||
let extra = request
|
||||
.extra
|
||||
.iter()
|
||||
.filter(|(name, _)| catalog_supports_extra(&catalog, name))
|
||||
.map(|(name, value)| (name.clone(), value.clone()))
|
||||
.collect::<Map<_, _>>();
|
||||
let extra = (!extra.is_empty()).then(|| Value::Object(extra).to_string());
|
||||
requests.push(json!({
|
||||
"url": build_resource_url(transport_url, "catalog", content_type, id, extra.as_deref()),
|
||||
"kind": "discover",
|
||||
"catalogKey": key
|
||||
}));
|
||||
break;
|
||||
}
|
||||
if !requests.is_empty() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
"metaDetail" => {
|
||||
|
|
@ -545,42 +567,6 @@ fn search_category_name(addon: &Value, catalog: &Value, content_type: &str) -> S
|
|||
format!("{addon_name} - {catalog_name}")
|
||||
}
|
||||
|
||||
struct DiscoverCatalog {
|
||||
key: String,
|
||||
transport_url: String,
|
||||
content_type: String,
|
||||
id: String,
|
||||
supports_genre: bool,
|
||||
}
|
||||
|
||||
fn discover_catalog_options(addons: &[Value], selected_type: &str) -> Vec<DiscoverCatalog> {
|
||||
let mut options = Vec::new();
|
||||
for addon in addons {
|
||||
let Some(transport_url) = addon_transport_url(addon) else {
|
||||
continue;
|
||||
};
|
||||
for catalog in addon_catalogs(addon) {
|
||||
let Some(content_type) = catalog.get("type").and_then(Value::as_str) else {
|
||||
continue;
|
||||
};
|
||||
let Some(id) = catalog.get("id").and_then(Value::as_str) else {
|
||||
continue;
|
||||
};
|
||||
if !selected_type.is_empty() && content_type != selected_type {
|
||||
continue;
|
||||
}
|
||||
options.push(DiscoverCatalog {
|
||||
key: format!("{}:{}", transport_url, id),
|
||||
transport_url: transport_url.to_string(),
|
||||
content_type: content_type.to_string(),
|
||||
id: id.to_string(),
|
||||
supports_genre: catalog_supports_extra(&catalog, "genre"),
|
||||
});
|
||||
}
|
||||
}
|
||||
options
|
||||
}
|
||||
|
||||
fn playback_title(meta: Option<&Value>, episode: Option<&Value>, stream: &Value) -> Value {
|
||||
let content_title = meta
|
||||
.and_then(|value| value.get("name"))
|
||||
|
|
|
|||
|
|
@ -131,47 +131,36 @@ fn discover_catalog_label(raw_name: Option<&str>, id: &str) -> String {
|
|||
}
|
||||
}
|
||||
|
||||
fn catalog_extra_options(catalog: &Value, extra_name: &str) -> Vec<String> {
|
||||
fn catalog_extras(catalog: &Value) -> Vec<Value> {
|
||||
catalog
|
||||
.get("extra")
|
||||
.and_then(Value::as_array)
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.filter(|extra| {
|
||||
extra
|
||||
.get("name")
|
||||
.and_then(Value::as_str)
|
||||
.is_some_and(|name| name.eq_ignore_ascii_case(extra_name))
|
||||
})
|
||||
.flat_map(|extra| {
|
||||
extra
|
||||
.filter_map(|extra| {
|
||||
let name = extra.get("name").and_then(Value::as_str)?.trim();
|
||||
if name.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let options = extra
|
||||
.get("options")
|
||||
.and_then(Value::as_array)
|
||||
.cloned()
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.filter_map(|option| option.as_str().map(str::trim).map(str::to_string))
|
||||
.filter(|option| !option.is_empty())
|
||||
.collect::<Vec<_>>();
|
||||
(!options.is_empty()).then(|| {
|
||||
json!({
|
||||
"name": name,
|
||||
"options": options,
|
||||
"isRequired": catalog_requires_extra(catalog, name)
|
||||
})
|
||||
})
|
||||
})
|
||||
.filter_map(|value| value.as_str().map(str::trim).map(str::to_string))
|
||||
.filter(|value| !value.is_empty())
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn catalog_genres(catalog: &Value) -> Vec<String> {
|
||||
let mut genres = catalog
|
||||
.get("genres")
|
||||
.and_then(Value::as_array)
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.filter_map(|value| value.as_str().map(str::trim).map(str::to_string))
|
||||
.filter(|value| !value.is_empty())
|
||||
.collect::<Vec<_>>();
|
||||
for option in catalog_extra_options(catalog, "genre") {
|
||||
if !genres.contains(&option) {
|
||||
genres.push(option);
|
||||
}
|
||||
}
|
||||
genres
|
||||
}
|
||||
|
||||
fn manifest_supports_catalog(manifest: &Value) -> bool {
|
||||
serde_json::to_string(manifest)
|
||||
.ok()
|
||||
|
|
@ -276,11 +265,6 @@ pub(crate) fn discover_catalog_options_json(
|
|||
continue;
|
||||
}
|
||||
let transport_url = addon_transport_url(&addon);
|
||||
let source_key = manifest
|
||||
.get("id")
|
||||
.and_then(Value::as_str)
|
||||
.filter(|value| !value.is_empty())
|
||||
.unwrap_or(transport_url);
|
||||
for catalog in manifest
|
||||
.get("catalogs")
|
||||
.and_then(Value::as_array)
|
||||
|
|
@ -304,24 +288,28 @@ pub(crate) fn discover_catalog_options_json(
|
|||
else {
|
||||
continue;
|
||||
};
|
||||
if catalog_has_required_extra_except(catalog, &["genre"]) {
|
||||
let extras = catalog_extras(catalog);
|
||||
let supported_extra_names = extras
|
||||
.iter()
|
||||
.filter_map(|extra| extra.get("name").and_then(Value::as_str))
|
||||
.collect::<Vec<_>>();
|
||||
if catalog_has_required_extra_except(catalog, &supported_extra_names) {
|
||||
continue;
|
||||
}
|
||||
let label = discover_catalog_label(catalog.get("name").and_then(Value::as_str), id);
|
||||
let genres = catalog_genres(catalog);
|
||||
let catalog_label =
|
||||
discover_catalog_label(catalog.get("name").and_then(Value::as_str), id);
|
||||
options.push(json!({
|
||||
"key": format!(
|
||||
"discover:{}:{}:{}",
|
||||
content_identity::stable_feed_part(source_key),
|
||||
content_identity::stable_feed_part(transport_url),
|
||||
content_identity::stable_feed_part(type_value),
|
||||
content_identity::stable_feed_part(&label)
|
||||
content_identity::stable_feed_part(id)
|
||||
),
|
||||
"label": label,
|
||||
"label": format!("{}: {}", addon_manifest_name(&addon), catalog_label),
|
||||
"transportUrl": transport_url,
|
||||
"type": type_value,
|
||||
"id": id,
|
||||
"genres": genres,
|
||||
"requiresGenre": catalog_requires_extra(catalog, "genre")
|
||||
"extras": extras
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ detailSeasonLoadPlan
|
|||
detailSeriesLookupId
|
||||
detectAnimePlayback
|
||||
discoverCatalogOptions
|
||||
discoverSortPlan
|
||||
effectiveMetadataFeedSelection
|
||||
engine.completeEffect
|
||||
engine.create
|
||||
|
|
|
|||
Loading…
Reference in a new issue