Get Jellyfin Sink working with TVDB#1767
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (2)
WalkthroughThe PR refactors JSON response parsing in IGDB by introducing logging and token-redaction helpers, applies them across all IGDB API call sites, refactors TVDB translation deserialization, and adjusts Jellyfin's TVDB identifier precedence to prefer series over item. ChangesIGDB JSON response parsing helpers
TVDB integration improvements
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@crates/providers/tvdb/src/base.rs`:
- Around line 28-44: json_response currently deserializes and logs the entire
response body even on non-2xx responses; change json_response to first check
response.status() and if !status.is_success() read the body bytes and return a
clear error containing the HTTP status and a bounded preview (e.g., first 256
bytes) plus total byte length instead of attempting serde deserialization, and
only for successful statuses read the body, log a truncated preview (limit to N
bytes) with the byte length, then deserialize with serde_json::from_slice; refer
to json_response, response, status, body and ensure errors propagate as a
meaningful HTTP error when not success.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 1e0f6b5f-5814-49b4-bb5a-9b5e7adfb80d
📒 Files selected for processing (4)
crates/providers/tvdb/src/base.rscrates/providers/tvdb/src/movies.rscrates/providers/tvdb/src/non_metadata.rscrates/providers/tvdb/src/shows.rs
| pub(crate) async fn json_response<T>(response: reqwest::Response, label: &str) -> Result<T> | ||
| where | ||
| T: serde::de::DeserializeOwned, | ||
| { | ||
| let status = response.status(); | ||
| let body = response.bytes().await?; | ||
|
|
||
| ryot_log!( | ||
| debug, | ||
| "TVDB {} response body ({}): {}", | ||
| label, | ||
| status, | ||
| String::from_utf8_lossy(&body) | ||
| ); | ||
|
|
||
| Ok(serde_json::from_slice(&body)?) | ||
| } |
There was a problem hiding this comment.
Handle non-2xx responses explicitly and avoid full-body debug dumps.
json_response currently attempts deserialization even for HTTP errors and logs entire payloads. That can turn API failures into opaque serde errors and create very large logs for extended series/season responses. Gate on status and log only a bounded preview plus byte size.
Suggested patch
pub(crate) async fn json_response<T>(response: reqwest::Response, label: &str) -> Result<T>
where
T: serde::de::DeserializeOwned,
{
let status = response.status();
let body = response.bytes().await?;
+ let preview = String::from_utf8_lossy(&body);
+ let preview = preview.chars().take(1024).collect::<String>();
ryot_log!(
debug,
- "TVDB {} response body ({}): {}",
+ "TVDB {} response (status={}, bytes={}, preview={}...)",
label,
status,
- String::from_utf8_lossy(&body)
+ body.len(),
+ preview
);
+ if !status.is_success() {
+ bail!(
+ "TVDB {} request failed (status={}, body_preview={}...)",
+ label,
+ status,
+ preview
+ );
+ }
+
Ok(serde_json::from_slice(&body)?)
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| pub(crate) async fn json_response<T>(response: reqwest::Response, label: &str) -> Result<T> | |
| where | |
| T: serde::de::DeserializeOwned, | |
| { | |
| let status = response.status(); | |
| let body = response.bytes().await?; | |
| ryot_log!( | |
| debug, | |
| "TVDB {} response body ({}): {}", | |
| label, | |
| status, | |
| String::from_utf8_lossy(&body) | |
| ); | |
| Ok(serde_json::from_slice(&body)?) | |
| } | |
| pub(crate) async fn json_response<T>(response: reqwest::Response, label: &str) -> Result<T> | |
| where | |
| T: serde::de::DeserializeOwned, | |
| { | |
| let status = response.status(); | |
| let body = response.bytes().await?; | |
| let preview = String::from_utf8_lossy(&body); | |
| let preview = preview.chars().take(1024).collect::<String>(); | |
| ryot_log!( | |
| debug, | |
| "TVDB {} response (status={}, bytes={}, preview={}...)", | |
| label, | |
| status, | |
| body.len(), | |
| preview | |
| ); | |
| if !status.is_success() { | |
| bail!( | |
| "TVDB {} request failed (status={}, body_preview={}...)", | |
| label, | |
| status, | |
| preview | |
| ); | |
| } | |
| Ok(serde_json::from_slice(&body)?) | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@crates/providers/tvdb/src/base.rs` around lines 28 - 44, json_response
currently deserializes and logs the entire response body even on non-2xx
responses; change json_response to first check response.status() and if
!status.is_success() read the body bytes and return a clear error containing the
HTTP status and a bounded preview (e.g., first 256 bytes) plus total byte length
instead of attempting serde deserialization, and only for successful statuses
read the body, log a truncated preview (limit to N bytes) with the byte length,
then deserialize with serde_json::from_slice; refer to json_response, response,
status, body and ensure errors propagate as a meaningful HTTP error when not
success.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@crates/providers/igdb/src/lib.rs`:
- Around line 237-263: The json_response_redacted function currently returns
Ok(serde_json::from_slice(&body)?) without context; update the final
deserialization to include error context like json_response does by using
serde_json::from_slice(&body) with a Context/with_context call (or map_err) that
attaches the label and the response body (String::from_utf8_lossy(&body)) to the
error message so failures in json_response_redacted produce the same contextual
error as json_response; apply this change to the final return in
json_response_redacted.
- Around line 219-235: The json_response function currently returns
serde_json::from_slice(&body)? which loses endpoint context on deserialization
errors; modify json_response (function name json_response) to map or wrap the
serde_json::from_slice error with context that includes the label (and
optionally status and a truncated body) using anyhow::Context or map_err to
build an anyhow error so failures indicate which IGDB endpoint/label failed
during deserialization.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: c1999ad4-3fef-45b8-bac5-88c27b4056a1
📒 Files selected for processing (2)
crates/providers/igdb/src/lib.rscrates/services/integration/src/sink/jellyfin.rs
| async fn json_response<T>(response: Response, label: &str) -> Result<T> | ||
| where | ||
| T: DeserializeOwned, | ||
| { | ||
| let status = response.status(); | ||
| let body = response.bytes().await?; | ||
|
|
||
| ryot_log!( | ||
| debug, | ||
| "IGDB {} response body ({}): {}", | ||
| label, | ||
| status, | ||
| String::from_utf8_lossy(&body) | ||
| ); | ||
|
|
||
| Ok(serde_json::from_slice(&body)?) | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial | ⚡ Quick win
Add context to deserialization errors for easier debugging.
When from_slice fails, the error loses the label context. Wrapping with anyhow! would preserve which endpoint failed.
♻️ Proposed fix
async fn json_response<T>(response: Response, label: &str) -> Result<T>
where
T: DeserializeOwned,
{
let status = response.status();
let body = response.bytes().await?;
ryot_log!(
debug,
"IGDB {} response body ({}): {}",
label,
status,
String::from_utf8_lossy(&body)
);
- Ok(serde_json::from_slice(&body)?)
+ serde_json::from_slice(&body)
+ .map_err(|e| anyhow!("Failed to parse IGDB '{}' response ({}): {}", label, status, e))
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| async fn json_response<T>(response: Response, label: &str) -> Result<T> | |
| where | |
| T: DeserializeOwned, | |
| { | |
| let status = response.status(); | |
| let body = response.bytes().await?; | |
| ryot_log!( | |
| debug, | |
| "IGDB {} response body ({}): {}", | |
| label, | |
| status, | |
| String::from_utf8_lossy(&body) | |
| ); | |
| Ok(serde_json::from_slice(&body)?) | |
| } | |
| async fn json_response<T>(response: Response, label: &str) -> Result<T> | |
| where | |
| T: DeserializeOwned, | |
| { | |
| let status = response.status(); | |
| let body = response.bytes().await?; | |
| ryot_log!( | |
| debug, | |
| "IGDB {} response body ({}): {}", | |
| label, | |
| status, | |
| String::from_utf8_lossy(&body) | |
| ); | |
| serde_json::from_slice(&body) | |
| .map_err(|e| anyhow!("Failed to parse IGDB '{}' response ({}): {}", label, status, e)) | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@crates/providers/igdb/src/lib.rs` around lines 219 - 235, The json_response
function currently returns serde_json::from_slice(&body)? which loses endpoint
context on deserialization errors; modify json_response (function name
json_response) to map or wrap the serde_json::from_slice error with context that
includes the label (and optionally status and a truncated body) using
anyhow::Context or map_err to build an anyhow error so failures indicate which
IGDB endpoint/label failed during deserialization.
…PI calls" This reverts commit 46657b6.
Implements functionality to integrate Jellyfin Sink with TVDB by introducing a new
json_responsefunction for handling API responses. This enhancement improves error logging and response handling across various TVDB service calls.Fixes #1766
Summary by CodeRabbit
Bug Fixes
Refactor