Initial commit: monorepo Match Live TV.
Rails API, app Flutter, infrastruttura Docker/MediaMTX, sito marketing e documentazione di deploy. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
101
backend/app/services/mediamtx/client.rb
Normal file
101
backend/app/services/mediamtx/client.rb
Normal file
@@ -0,0 +1,101 @@
|
||||
require "set"
|
||||
|
||||
module Mediamtx
|
||||
class Client
|
||||
class Error < StandardError; end
|
||||
|
||||
def initialize(base_url: MatchLiveTv.mediamtx_api_url)
|
||||
@conn = Faraday.new(url: base_url) do |f|
|
||||
f.request :json
|
||||
f.response :json
|
||||
f.adapter Faraday.default_adapter
|
||||
end
|
||||
end
|
||||
|
||||
def create_path(session)
|
||||
path = session.mediamtx_path_name
|
||||
record = session.match.team.entitlements.recording_enabled_for_mediamtx?
|
||||
body = {
|
||||
source: "publisher",
|
||||
overridePublisher: true,
|
||||
record: record,
|
||||
recordPath: "/recordings/%path/%Y-%m-%d_%H-%M-%S",
|
||||
recordSegmentDuration: "60s"
|
||||
}
|
||||
unless session.matchlivetv_platform?
|
||||
body[:runOnReady] = run_on_ready_script(session)
|
||||
body[:runOnReadyRestart] = true
|
||||
body[:runOnNotReady] = webhook_curl(session, "disconnect")
|
||||
end
|
||||
response = @conn.post("/v3/config/paths/add/#{CGI.escape(path)}", body)
|
||||
unless response.success?
|
||||
err = response.body.is_a?(Hash) ? response.body["error"] : response.body
|
||||
raise Error, "MediaMTX path create failed: #{response.status} #{err}"
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
def delete_path(session)
|
||||
delete_path_name(session.mediamtx_path_name)
|
||||
end
|
||||
|
||||
def delete_path_name(path_name)
|
||||
@conn.post("/v3/config/paths/delete/#{CGI.escape(path_name)}")
|
||||
end
|
||||
|
||||
def list_paths
|
||||
response = @conn.get("/v3/paths/list")
|
||||
return [] unless response.success?
|
||||
|
||||
body = response.body
|
||||
body.is_a?(Hash) ? (body["items"] || []) : []
|
||||
rescue Error, Faraday::Error
|
||||
[]
|
||||
end
|
||||
|
||||
def online_path_names
|
||||
Set.new(list_paths.filter_map { |item| item["name"] if item["online"] })
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def publish_webhook(session)
|
||||
webhook_curl(session, "connect")
|
||||
end
|
||||
|
||||
def disconnect_webhook(session)
|
||||
webhook_curl(session, "disconnect")
|
||||
end
|
||||
|
||||
def webhook_curl(session, event)
|
||||
secret = MatchLiveTv.mediamtx_webhook_secret
|
||||
rails = ENV.fetch("RAILS_WEBHOOK_URL", "http://rails:3000")
|
||||
payload = %({"session_id":"#{session.id}"})
|
||||
# MediaMTX image non include curl; wget è disponibile nell'immagine ufficiale
|
||||
<<~SCRIPT.squish
|
||||
wget -q -O- --post-data='#{payload}' --header='Content-Type: application/json'
|
||||
--header="X-MediaMTX-Signature: $(printf '%s' '#{payload}' | openssl dgst -sha256 -hmac '#{secret}' | cut -d' ' -f2)"
|
||||
#{rails}/webhooks/mediamtx/#{event}
|
||||
SCRIPT
|
||||
end
|
||||
|
||||
def run_on_ready_script(session)
|
||||
connect = webhook_curl(session, "connect")
|
||||
return connect if session.matchlivetv_platform?
|
||||
|
||||
"#{connect} & #{relay_script(session)}"
|
||||
end
|
||||
|
||||
def relay_script(session)
|
||||
return "echo 'no youtube key'" if session.stream_key.blank?
|
||||
return "echo 'youtube relay skipped'" unless session.platform == "youtube"
|
||||
|
||||
key = session.stream_key
|
||||
path = session.mediamtx_path_name
|
||||
<<~SCRIPT.squish
|
||||
ffmpeg -re -i rtmp://127.0.0.1:1935/#{path} -c copy -f flv
|
||||
rtmp://a.rtmp.youtube.com/live2/#{key} 2>/var/log/ffmpeg-#{path}.log
|
||||
SCRIPT
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user