@@ -27,6 +27,8 @@ defmodule ReencodarrWeb.FailuresLive do
2727 alias Reencodarr.Repo
2828
2929 @ update_interval 30_000
30+ @ stage_filter_values [ "all" , "analysis" , "crf_search" , "encoding" , "post_process" ]
31+ @ category_filter_values [ "all" , "file_access" , "process_failure" , "timeout" , "codec_issues" ]
3032
3133 @ impl true
3234 def mount ( _params , _session , socket ) do
@@ -47,7 +49,7 @@ defmodule ReencodarrWeb.FailuresLive do
4749 @ impl true
4850 def handle_info ( :update_failures_data , socket ) do
4951 schedule_periodic_update ( )
50- { :noreply , load_failures_data ( socket ) }
52+ { :noreply , async_load_failures ( socket ) }
5153 end
5254
5355 # Handle events that might affect failures (video state changes, encoding completion, etc.)
@@ -60,8 +62,7 @@ defmodule ReencodarrWeb.FailuresLive do
6062 :video_failed
6163 ] do
6264 # Reload failures when pipeline events occur that might change failure state
63- socket = load_failures_data ( socket )
64- { :noreply , socket }
65+ { :noreply , async_load_failures ( socket ) }
6566 end
6667
6768 # Catch-all for other Events we don't need to handle
@@ -85,8 +86,10 @@ defmodule ReencodarrWeb.FailuresLive do
8586 Media . resolve_video_failures ( video . id )
8687
8788 # Reload the failures data
88- socket = load_failures_data ( socket )
89- { :noreply , put_flash ( socket , :info , "Video #{ video . id } marked for retry" ) }
89+ { :noreply ,
90+ socket
91+ |> put_flash ( :info , "Video #{ video . id } marked for retry" )
92+ |> async_load_failures ( ) }
9093 end
9194
9295 { :error , _ } ->
@@ -100,22 +103,23 @@ defmodule ReencodarrWeb.FailuresLive do
100103 Media . reset_failed_videos ( )
101104
102105 # Reload the failures data
103- socket = load_failures_data ( socket )
104- { :noreply , put_flash ( socket , :info , "All failed videos have been reset" ) }
106+ { :noreply ,
107+ socket
108+ |> put_flash ( :info , "All failed videos have been reset" )
109+ |> async_load_failures ( ) }
105110 end
106111
107112 @ impl true
108113 def handle_event ( "retry_failure_code" , % { "code" => failure_code } , socket ) do
109114 result = Media . retry_failed_videos_by_failure_code ( failure_code )
110115
111- socket = load_failures_data ( socket )
112-
113116 { :noreply ,
114- put_flash (
115- socket ,
117+ socket
118+ |> put_flash (
116119 :info ,
117120 "Queued retry for #{ result . videos_retried } failed videos with #{ failure_code } "
118- ) }
121+ )
122+ |> async_load_failures ( ) }
119123 end
120124
121125 @ impl true
@@ -173,7 +177,7 @@ defmodule ReencodarrWeb.FailuresLive do
173177 socket =
174178 socket
175179 |> assign ( :selected_videos , MapSet . new ( ) )
176- |> load_failures_data ( )
180+ |> async_load_failures ( )
177181
178182 count = Enum . count ( selected_ids )
179183 { :noreply , put_flash ( socket , :info , "Retrying #{ count } selected videos" ) }
@@ -182,24 +186,28 @@ defmodule ReencodarrWeb.FailuresLive do
182186
183187 @ impl true
184188 def handle_event ( "filter_failures" , % { "filter" => filter } , socket ) do
189+ normalized_filter = if filter in @ stage_filter_values , do: filter , else: "all"
190+
185191 socket =
186192 socket
187- |> assign ( :failure_filter , filter )
193+ |> assign ( :failure_filter , normalized_filter )
188194 # Reset to first page when filtering
189195 |> assign ( :page , 1 )
190- |> load_failures_data ( )
196+ |> async_load_failures ( )
191197
192198 { :noreply , socket }
193199 end
194200
195201 @ impl true
196202 def handle_event ( "filter_category" , % { "category" => category } , socket ) do
203+ normalized_category = if category in @ category_filter_values , do: category , else: "all"
204+
197205 socket =
198206 socket
199- |> assign ( :category_filter , category )
207+ |> assign ( :category_filter , normalized_category )
200208 # Reset to first page when filtering
201209 |> assign ( :page , 1 )
202- |> load_failures_data ( )
210+ |> async_load_failures ( )
203211
204212 { :noreply , socket }
205213 end
@@ -212,19 +220,19 @@ defmodule ReencodarrWeb.FailuresLive do
212220 |> assign ( :category_filter , "all" )
213221 |> assign ( :search_term , "" )
214222 |> assign ( :page , 1 )
215- |> load_failures_data ( )
223+ |> async_load_failures ( )
216224
217225 { :noreply , socket }
218226 end
219227
220228 @ impl true
221229 def handle_event ( "change_page" , % { "page" => page } , socket ) do
222- page = Parsers . parse_int ( page , 1 )
230+ page = page |> Parsers . parse_int ( 1 ) |> max ( 1 )
223231
224232 socket =
225233 socket
226234 |> assign ( :page , page )
227- |> load_failures_data ( )
235+ |> async_load_failures ( )
228236
229237 { :noreply , socket }
230238 end
@@ -233,14 +241,24 @@ defmodule ReencodarrWeb.FailuresLive do
233241 def handle_event ( "search" , % { "search" => search_term } , socket ) do
234242 socket =
235243 socket
236- |> assign ( :search_term , search_term )
244+ |> assign ( :search_term , normalize_search_term ( search_term ) )
237245 # Reset to first page when searching
238246 |> assign ( :page , 1 )
239- |> load_failures_data ( )
247+ |> async_load_failures ( )
240248
241249 { :noreply , socket }
242250 end
243251
252+ @ impl true
253+ def handle_async ( :load_failures , { :ok , payload } , socket ) do
254+ { :noreply , assign_failure_payload ( socket , payload ) }
255+ end
256+
257+ @ impl true
258+ def handle_async ( :load_failures , { :exit , _reason } , socket ) do
259+ { :noreply , socket |> assign ( :loading , false ) |> put_flash ( :error , "Failed to load failures" ) }
260+ end
261+
244262 # Private helper functions
245263
246264 defp retry_video ( video_id ) do
@@ -784,12 +802,32 @@ defmodule ReencodarrWeb.FailuresLive do
784802 end
785803
786804 defp load_failures_data ( socket ) do
805+ assign_failure_payload ( socket , fetch_failure_payload ( socket . assigns ) )
806+ end
807+
808+ defp async_load_failures ( socket ) do
809+ load_assigns = % {
810+ page: socket . assigns . page ,
811+ per_page: socket . assigns . per_page ,
812+ failure_filter: socket . assigns . failure_filter ,
813+ category_filter: socket . assigns . category_filter ,
814+ search_term: socket . assigns . search_term
815+ }
816+
817+ show_loading? = socket . assigns . failed_videos == [ ]
818+
819+ socket
820+ |> assign ( :loading , show_loading? )
821+ |> start_async ( :load_failures , fn -> fetch_failure_payload ( load_assigns ) end )
822+ end
823+
824+ defp fetch_failure_payload ( assigns ) do
787825 # Get pagination info
788- page = socket . assigns . page
789- per_page = socket . assigns . per_page
790- filter = socket . assigns . failure_filter
791- category_filter = socket . assigns . category_filter
792- search_term = socket . assigns . search_term
826+ page = assigns . page
827+ per_page = assigns . per_page
828+ filter = assigns . failure_filter
829+ category_filter = assigns . category_filter
830+ search_term = assigns . search_term
793831
794832 # Get failed videos with pagination and filtering
795833 { failed_videos , total_count } =
@@ -806,7 +844,7 @@ defmodule ReencodarrWeb.FailuresLive do
806844 # Calculate pagination info
807845 total_pages = ceil ( total_count / per_page )
808846
809- assign_changed ( socket , % {
847+ % {
810848 loading: false ,
811849 failed_videos: failed_videos ,
812850 video_failures: video_failures ,
@@ -815,7 +853,11 @@ defmodule ReencodarrWeb.FailuresLive do
815853 failure_code_actions: failure_code_actions ,
816854 total_count: total_count ,
817855 total_pages: total_pages
818- } )
856+ }
857+ end
858+
859+ defp assign_failure_payload ( socket , payload ) do
860+ assign_changed ( socket , payload )
819861 end
820862
821863 defp get_failed_videos_paginated ( page , per_page , stage_filter , category_filter , search_term ) do
@@ -895,6 +937,11 @@ defmodule ReencodarrWeb.FailuresLive do
895937 from v in query , where: ^ case_insensitive_like_condition
896938 end
897939
940+ defp normalize_search_term ( search_term ) when is_binary ( search_term ) ,
941+ do: String . trim ( search_term )
942+
943+ defp normalize_search_term ( _search_term ) , do: ""
944+
898945 defp apply_ordering ( query ) do
899946 from v in query , order_by: [ desc: v . inserted_at ]
900947 end
0 commit comments