DubbedEpisode
Inherits JSON::Serializable < Struct < Value < Object
Constants
DUBBED_RECENT_SELECT = "SELECT\n e.id AS episode_id,\n e.feed_id, f.title AS feed_title, f.image_url AS feed_image,\n e.title AS ep_title, e.image_url AS ep_image, e.duration_sec,\n e.original_language AS source_lang,\n de.language AS target_lang,\n de.completed_at,\n EXISTS (\n SELECT 1 FROM user_feeds uf\n WHERE uf.user_id = $1 AND uf.feed_id = e.feed_id\n ) AS subscribed,\n (de.completed_at > NOW() - INTERVAL '24 hours') AS is_new\nFROM dubbed_episodes de\nJOIN episodes e ON e.id = de.episode_id\nJOIN feeds f ON f.id = e.feed_id\nWHERE de.status = 'done' AND de.completed_at IS NOT NULL\n AND ($3::text[] IS NULL OR de.language = ANY($3))"
Shared column list + JOINs for the DubbedRecent projection. $1 = user_id
(drives the subscribed flag), $3 = optional text[] language filter.
Constructors
new(id : Int64, episode_id : Int64, language : String, status : String, step : String, r2_url : Nil | String, translation : Nil | String, error : Nil | String, expires_at : Time | Nil, created_at : Time, requester_telegram_id : Int64 | Nil)
Sourcenew(pull : JSON::PullParser)
Sourcenew(*, __pull_for_json_serializable pull : JSON::PullParser)
SourceClass methods
all_for_user(user_id : Int64, limit : Int32 = 100, langs : Array(String) | Nil = nil) : Array(DubbedRecent)
Full dubbed history for the dedicated Dubbed page: pure recency, optional
langs filter. Same DubbedRecent shape as the inbox widget.
distinct_done_languages
Distinct target languages across all done dubs whose episode + feed still exist — drives the Dubbed page's filter chips (unfiltered, so the chip row is stable regardless of the current selection).
recent_for_inbox(user_id : Int64, limit : Int32 = 12, langs : Array(String) | Nil = nil) : Array(DubbedRecent)
Inbox "Latest dubbed" widget: subscribed-first, then most recent. langs
(when present) restricts to those target languages before the limit, so a
selected language always surfaces its latest dub.
Instance methods
created_at
Sourceeffective_status
Sourceepisode_id
Sourceerror
Sourceexpired?
Sourceexpires_at
Sourceid
Sourcelanguage
Sourcer2_url
Sourcerequester_telegram_id
Sourcestatus
Sourcestep
Sourcetranslation
Source