Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions lib/reencodarr/ab_av1/crf_search.ex
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,14 @@ defmodule Reencodarr.AbAv1.CrfSearch do
nil ->
false

_pid ->
try do
GenServer.call(__MODULE__, :running?) == :running
catch
:exit, _ -> false
pid when is_pid(pid) ->
case GenServer.call(__MODULE__, :running?, 1000) do
:running -> true
_ -> false
end

_ ->
false
end
end

Expand Down
11 changes: 9 additions & 2 deletions lib/reencodarr/ab_av1/helper.ex
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,15 @@ defmodule Reencodarr.AbAv1.Helper do
if File.exists?(temp_dir) do
temp_dir
else
File.mkdir_p!(temp_dir)
temp_dir
case File.mkdir_p(temp_dir) do
:ok ->
temp_dir

{:error, reason} ->
Logger.error("Failed to create temp directory #{temp_dir}: #{inspect(reason)}")
# Fallback to system temp directory
System.tmp_dir!()
end
end
end

Expand Down
140 changes: 48 additions & 92 deletions lib/reencodarr/analyzer/broadway.ex
Original file line number Diff line number Diff line change
Expand Up @@ -131,21 +131,7 @@ defmodule Reencodarr.Analyzer.Broadway do

# Process the batch using optimized batch mediainfo fetching
# This does ALL the mediainfo gathering first, then database operations at the end
result =
try do
process_batch_with_single_mediainfo(video_infos, context)
rescue
e ->
Logger.error("Broadway: Exception during batch processing: #{inspect(e)}")
Logger.error("Broadway: Exception stacktrace: #{inspect(__STACKTRACE__)}")
:error
end

# Only log failures
case result do
:error -> Logger.error("Broadway: Batch processing failed")
_ -> :ok
end
_result = process_batch_with_single_mediainfo(video_infos, context)

# Log completion and emit telemetry
duration = System.monotonic_time(:millisecond) - start_time
Expand All @@ -156,10 +142,9 @@ defmodule Reencodarr.Analyzer.Broadway do

# Get current queue length for progress calculation
current_queue_length =
try do
QueueManager.get_count()
catch
_error -> 0
case QueueManager.get_count() do
count when is_integer(count) and count >= 0 -> count
_ -> 0
end

Telemetry.emit_analyzer_throughput(batch_size, current_queue_length)
Expand All @@ -171,13 +156,8 @@ defmodule Reencodarr.Analyzer.Broadway do
{:batch_analysis_completed, batch_size}
)

# Transform successful results to success, all failed to failed for Broadway
Enum.map(messages, fn message ->
case result do
:ok -> message
:error -> Message.failed(message, "batch processing failed")
end
end)
# Return messages as-is since processing always succeeds
messages
end

@doc """
Expand Down Expand Up @@ -207,53 +187,46 @@ defmodule Reencodarr.Analyzer.Broadway do

Logger.debug("Video paths in batch: #{inspect(Enum.map(video_infos, & &1.path))}")

try do
# Extract all paths for batch mediainfo command
paths = Enum.map(video_infos, & &1.path)
Logger.debug("Broadway: Extracted #{length(paths)} paths for mediainfo")
# Extract all paths for batch mediainfo command
paths = Enum.map(video_infos, & &1.path)
Logger.debug("Broadway: Extracted #{length(paths)} paths for mediainfo")

mediainfo_start_time = System.monotonic_time(:millisecond)
mediainfo_start_time = System.monotonic_time(:millisecond)

case execute_chunked_mediainfo_command(paths, mediainfo_batch_size) do
{:ok, mediainfo_map} ->
mediainfo_duration = System.monotonic_time(:millisecond) - mediainfo_start_time
case execute_chunked_mediainfo_command(paths, mediainfo_batch_size) do
{:ok, mediainfo_map} ->
mediainfo_duration = System.monotonic_time(:millisecond) - mediainfo_start_time

# Record mediainfo batch performance for tuning
PerformanceMonitor.record_mediainfo_batch(length(paths), mediainfo_duration)
# Record mediainfo batch performance for tuning
PerformanceMonitor.record_mediainfo_batch(length(paths), mediainfo_duration)

Logger.debug(
"Successfully fetched mediainfo for #{length(video_infos)} videos in #{mediainfo_duration}ms"
)
Logger.debug(
"Successfully fetched mediainfo for #{length(video_infos)} videos in #{mediainfo_duration}ms"
)

Logger.debug("Mediainfo keys: #{inspect(Map.keys(mediainfo_map))}")
Logger.debug("Broadway: About to process videos with batch mediainfo")
result = process_videos_with_batch_mediainfo(video_infos, mediainfo_map)
Logger.debug("Mediainfo keys: #{inspect(Map.keys(mediainfo_map))}")
Logger.debug("Broadway: About to process videos with batch mediainfo")
result = process_videos_with_batch_mediainfo(video_infos, mediainfo_map)

Logger.debug(
"Broadway: Completed process_videos_with_batch_mediainfo with result: #{inspect(result)}"
)
Logger.debug(
"Broadway: Completed process_videos_with_batch_mediainfo with result: #{inspect(result)}"
)

result
result

{:error, reason} ->
Logger.warning(
"Batch mediainfo fetch failed: #{reason}, falling back to individual processing"
)
{:error, reason} ->
Logger.warning(
"Batch mediainfo fetch failed: #{reason}, falling back to individual processing"
)

Logger.debug("Broadway: About to process videos individually")
result = process_videos_individually(video_infos)
Logger.debug("Broadway: About to process videos individually")
result = process_videos_individually(video_infos)

Logger.debug(
"Broadway: Completed process_videos_individually with result: #{inspect(result)}"
)
Logger.debug(
"Broadway: Completed process_videos_individually with result: #{inspect(result)}"
)

result
end
rescue
e ->
Logger.error("Broadway: Exception in process_batch_with_single_mediainfo: #{inspect(e)}")
Logger.error("Broadway: Stacktrace: #{inspect(__STACKTRACE__)}")
:error
result
end
end

Expand Down Expand Up @@ -373,13 +346,9 @@ defmodule Reencodarr.Analyzer.Broadway do
handle_upsert_results(successful_data, upsert_results, failed_paths)

{:error, reason} ->
Logger.error("Broadway: perform_batch_upsert failed: #{inspect(reason)}")
{:error, reason}
end
rescue
e ->
Logger.error("Broadway: Exception during batch upsert and transition: #{inspect(e)}")
Logger.error("Broadway: Exception stacktrace: #{inspect(__STACKTRACE__)}")
:error
end

defp log_batch_operation(batch_size) when batch_size > 5 do
Expand Down Expand Up @@ -580,20 +549,13 @@ defmodule Reencodarr.Analyzer.Broadway do
defp decode_and_parse_single_mediainfo_json(json, path) do
Logger.debug("Decoding mediainfo JSON for #{path}")

try do
case Jason.decode(json) do
{:ok, data} ->
handle_decoded_single_mediainfo(data)
case Jason.decode(json) do
{:ok, data} ->
handle_decoded_single_mediainfo(data)

{:error, reason} ->
Logger.error("JSON decode failed: #{inspect(reason)}")
{:error, "JSON decode failed: #{inspect(reason)}"}
end
rescue
e ->
Logger.error("Error parsing mediainfo JSON: #{inspect(e)}")
Logger.error("Stacktrace: #{inspect(__STACKTRACE__)}")
{:error, "error parsing JSON: #{inspect(e)}"}
{:error, reason} ->
Logger.error("JSON decode failed: #{inspect(reason)}")
{:error, "JSON decode failed: #{inspect(reason)}"}
end
end

Expand Down Expand Up @@ -699,19 +661,13 @@ defmodule Reencodarr.Analyzer.Broadway do
defp decode_and_parse_batch_mediainfo_json(json, paths) do
Logger.debug("Decoding batch mediainfo JSON for #{length(paths)} files")

try do
case Jason.decode(json) do
{:ok, data} ->
handle_decoded_mediainfo_data(data, paths)
case Jason.decode(json) do
{:ok, data} ->
handle_decoded_mediainfo_data(data, paths)

{:error, reason} ->
Logger.error("JSON decode failed: #{inspect(reason)}")
{:error, "JSON decode failed: #{inspect(reason)}"}
end
rescue
e ->
Logger.error("Error parsing batch mediainfo JSON: #{inspect(e)}")
{:error, "error parsing JSON: #{inspect(e)}"}
{:error, reason} ->
Logger.error("JSON decode failed: #{inspect(reason)}")
{:error, "JSON decode failed: #{inspect(reason)}"}
end
end

Expand Down
63 changes: 22 additions & 41 deletions lib/reencodarr/core/parsers.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ defmodule Reencodarr.Core.Parsers do
for common data transformations needed throughout the application.
"""

require Logger

@doc """
Parses duration string in various formats to seconds.

Expand Down Expand Up @@ -262,15 +264,32 @@ defmodule Reencodarr.Core.Parsers do
end

# Convert captured string values to appropriate types
defp convert_value(value, :int), do: String.to_integer(value)
@spec convert_value(String.t(), :int) :: integer()
defp convert_value(value, :int) do
case Integer.parse(value) do
{int, ""} -> int
_ -> 0
end
Comment thread
mjc marked this conversation as resolved.
end

@spec convert_value(String.t(), :float) :: float()
defp convert_value(value, :float) do
case String.contains?(value, ".") do
true -> String.to_float(value)
false -> String.to_integer(value) |> Kernel.*(1.0)
true ->
case Float.parse(value) do
{float, ""} -> float
_ -> 0.0
end
Comment thread
mjc marked this conversation as resolved.

false ->
case Integer.parse(value) do
{int, ""} -> int * 1.0
_ -> 0.0
end
Comment thread
mjc marked this conversation as resolved.
end
end

@spec convert_value(String.t(), :string) :: String.t()
defp convert_value(value, :string), do: value

@doc """
Expand Down Expand Up @@ -323,42 +342,4 @@ defmodule Reencodarr.Core.Parsers do
end

def parse_float_exact(_), do: {:error, :invalid_input}

@doc """
Parses an integer with exact matching, raises on error.

## Examples

iex> Parsers.parse_integer_exact!("123")
123

iex> Parsers.parse_integer_exact!("123abc")
** (ArgumentError) Invalid integer format: "123abc"
"""
@spec parse_integer_exact!(String.t()) :: integer()
def parse_integer_exact!(value) do
case parse_integer_exact(value) do
{:ok, int} -> int
{:error, _} -> raise ArgumentError, "Invalid integer format: #{inspect(value)}"
end
end

@doc """
Parses a float with exact matching, raises on error.

## Examples

iex> Parsers.parse_float_exact!("123.45")
123.45

iex> Parsers.parse_float_exact!("invalid")
** (ArgumentError) Invalid float format: "invalid"
"""
@spec parse_float_exact!(String.t()) :: float()
def parse_float_exact!(value) do
case parse_float_exact(value) do
{:ok, float} -> float
{:error, _} -> raise ArgumentError, "Invalid float format: #{inspect(value)}"
end
end
end
12 changes: 9 additions & 3 deletions lib/reencodarr/dashboard_state.ex
Original file line number Diff line number Diff line change
Expand Up @@ -91,19 +91,25 @@ defmodule Reencodarr.DashboardState do

# Check actual status of Broadway pipelines for initial state
defp analyzer_running? do
Reencodarr.Analyzer.Broadway.running?()
case Reencodarr.Analyzer.Broadway.running?() do
result when is_boolean(result) -> result
end
rescue
_ -> false
end

defp crf_searcher_running? do
Reencodarr.CrfSearcher.Broadway.running?()
case Reencodarr.CrfSearcher.Broadway.running?() do
result when is_boolean(result) -> result
end
rescue
_ -> false
end

defp encoder_running? do
Reencodarr.Encoder.Broadway.running?()
case Reencodarr.Encoder.Broadway.running?() do
result when is_boolean(result) -> result
end
rescue
_ -> false
end
Expand Down
25 changes: 8 additions & 17 deletions lib/reencodarr/encoder/broadway/producer.ex
Original file line number Diff line number Diff line change
Expand Up @@ -249,26 +249,17 @@ defmodule Reencodarr.Encoder.Broadway.Producer do
false

pid ->
try do
case GenServer.call(pid, :running?, 1000) do
:not_running ->
Logger.debug(
"Producer: encoding_available? - Encode GenServer is :not_running - AVAILABLE"
)

true
case GenServer.call(pid, :running?, 1000) do
:not_running ->
Logger.debug(
"Producer: encoding_available? - Encode GenServer is :not_running - AVAILABLE"
)

status ->
Logger.debug(
"Producer: encoding_available? - Encode GenServer status: #{inspect(status)} - NOT AVAILABLE"
)
true

false
end
catch
:exit, reason ->
status when status != :not_running ->
Logger.debug(
"Producer: encoding_available? - Encode GenServer call failed: #{inspect(reason)}"
"Producer: encoding_available? - Encode GenServer status: #{inspect(status)} - NOT AVAILABLE"
)

false
Expand Down
Loading