M4 wrap — playlist browse + addon settings + upstream PR-77 notes
Sidecar Playlist op via rustypipe playlist(). Returns playlist metadata
block (id, name, channel, video_count) + items array. Verified live
against LTT's 'Consumer Advocacy' (PL8mG-RkN2uTzwoF72GqeqAJMI-N7scqtI):
returns the single video with full metadata.
Addon ?action=playlist&id=PL... lists items via _add_video_items reuse.
Verified via Files.GetDirectory JSON-RPC.
resources/settings.xml gains a 'dash_enabled' toggle (boolean, default
off). main.py checks ADDON.getSettingBool('dash_enabled') OR the
TORTTUBE_DASH env fallback before attempting the DASH path. Toggle via
Kodi Settings → Add-on settings → torttube, OR via
Addons.SetSettings JSON-RPC.
docs/upstream.md: filed a 'watching' entry for rustypipe PR #77
(Schmiddiii's late-May YouTube parsing fixes) with our independent
test data — player(), search(), and channel_videos() all still work
against current YouTube on 0.11.4, suggesting the PR fixes code paths
torttube doesn't yet exercise. Endorsement comment pending: gated on
creating a Sulkta-Coop codeberg account.
Observation from kodi.log: plugin.video.youtube successfully parsed a
DASH MPD with 26 streams via inputstream.adaptive on this same Pi —
proves DASH is solvable on our setup, just need to match the URL
pattern they use. M7 stabilization carrying forward.
Addon version 0.0.9.
This commit is contained in:
parent
d463781aae
commit
a784321759
7 changed files with 94 additions and 7 deletions
|
|
@ -56,6 +56,12 @@ enum Request {
|
|||
#[serde(default = "default_search_limit")]
|
||||
limit: u32,
|
||||
},
|
||||
/// List a playlist's videos. `id` is a YouTube playlist ID (PL…).
|
||||
Playlist {
|
||||
id: String,
|
||||
#[serde(default = "default_search_limit")]
|
||||
limit: u32,
|
||||
},
|
||||
}
|
||||
|
||||
fn default_search_limit() -> u32 {
|
||||
|
|
@ -173,6 +179,10 @@ async fn handle_line(line: &str) -> Response {
|
|||
Ok(v) => Response::ok(v),
|
||||
Err(e) => e.into(),
|
||||
},
|
||||
Request::Playlist { id, limit } => match resolve::playlist(&id, limit).await {
|
||||
Ok(v) => Response::ok(v),
|
||||
Err(e) => e.into(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -76,6 +76,41 @@ pub(crate) async fn channel_videos(channel_id: &str, limit: u32) -> Result<Value
|
|||
}))
|
||||
}
|
||||
|
||||
/// List a playlist's videos. Returns the same VideoItem shape as search/channel.
|
||||
pub(crate) async fn playlist(playlist_id: &str, limit: u32) -> Result<Value, HandlerError> {
|
||||
use rustypipe::client::RustyPipe;
|
||||
|
||||
let rp = RustyPipe::new();
|
||||
let pl = rp
|
||||
.query()
|
||||
.playlist(playlist_id)
|
||||
.await
|
||||
.map_err(|e| classify_rustypipe_error(&e))?;
|
||||
|
||||
let items_json: Vec<Value> = pl
|
||||
.videos
|
||||
.items
|
||||
.iter()
|
||||
.take(limit as usize)
|
||||
.filter_map(|v| serde_json::to_value(v).ok())
|
||||
.collect();
|
||||
|
||||
tracing::info!(playlist_id, count = items_json.len(), "playlist ok");
|
||||
|
||||
Ok(serde_json::json!({
|
||||
"source": "rustypipe",
|
||||
"playlist": {
|
||||
"id": pl.id,
|
||||
"name": pl.name,
|
||||
"description": pl.description,
|
||||
"video_count": pl.video_count,
|
||||
"channel": pl.channel,
|
||||
"thumbnail": pl.thumbnail,
|
||||
},
|
||||
"items": items_json,
|
||||
}))
|
||||
}
|
||||
|
||||
/// DASH-ready resolve: returns rustypipe's full `video_only_streams` +
|
||||
/// `audio_streams` arrays + `details`. The Python addon builds an MPD
|
||||
/// from these and hands it to inputstream.adaptive — unlocks 1080p+ via
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue