From 06e44ab1d978680cc8afba89a79c76bd77b90ca7 Mon Sep 17 00:00:00 2001 From: Brandt Hill Date: Sat, 11 May 2024 01:37:04 -0500 Subject: [PATCH 1/2] Refactor executable checks and add version check for non-forked youtube-dl --- config/config.exs | 4 +-- lib/nostrum/application.ex | 65 +++++++++++++++++++++++--------------- lib/nostrum/dummy.ex | 2 +- lib/nostrum/voice.ex | 44 +++++++++++++++++++++++++- lib/nostrum/voice/audio.ex | 10 ++++-- 5 files changed, 91 insertions(+), 34 deletions(-) diff --git a/config/config.exs b/config/config.exs index da3677333..5e5ec874a 100644 --- a/config/config.exs +++ b/config/config.exs @@ -1,9 +1,7 @@ import Config config :nostrum, - token: "", - ffmpeg: "ffmpeg", - youtubedl: "youtube-dl" + token: "" config :logger, :console, metadata: [:shard, :guild, :channel] diff --git a/lib/nostrum/application.ex b/lib/nostrum/application.ex index d776280b0..2d3c206c5 100644 --- a/lib/nostrum/application.ex +++ b/lib/nostrum/application.ex @@ -4,6 +4,7 @@ defmodule Nostrum.Application do use Application alias Nostrum.Token + alias Nostrum.Voice require Logger @@ -41,34 +42,46 @@ defmodule Nostrum.Application do end defp check_executables do - ff = Application.get_env(:nostrum, :ffmpeg) - yt = Application.get_env(:nostrum, :youtubedl) - sl = Application.get_env(:nostrum, :streamlink) - - cond do - is_binary(ff) and is_nil(System.find_executable(ff)) -> - Logger.warning(""" - #{ff} was not found in your path. By default, Nostrum requires ffmpeg to use voice. - If you don't intend to use voice with ffmpeg, configure :nostrum, :ffmpeg to nil to suppress. - """) - - is_binary(yt) and is_nil(System.find_executable(yt)) -> - Logger.warning(""" - #{yt} was not found in your path. Nostrum supports youtube-dl for voice. - If you don't require youtube-dl support, configure :nostrum, :youtubedl to nil to suppress. - """) - - is_binary(sl) and is_nil(System.find_executable(sl)) -> - Logger.warning(""" - #{sl} was not found in your path. Nostrum supports streamlink for voice. - If you don't require streamlink support, configure :nostrum, :streamlink to nil to suppress. - """) - - true -> - :ok - end + ff = Voice.ffmpeg_executable() + yt = Voice.youtubedl_executable() + sl = Voice.streamlink_executable() + + ff_path = if ff, do: System.find_executable(ff) + yt_path = if yt, do: System.find_executable(yt) + sl_path = if sl, do: System.find_executable(sl) + + check_ffmpeg(ff_path, ff) + check_ytdl(ff_path, yt, yt_path) + check_streamlink(ff_path, sl, sl_path) + end + + defp check_ffmpeg(_ff_path = nil, ff) when is_binary(ff) do + Logger.warning(""" + #{ff} was not found in your path. By default, Nostrum requires ffmpeg to use voice. + If you don't intend to use voice with ffmpeg, configure :nostrum, :ffmpeg to nil or false to suppress all voice warnings. + """) + end + + defp check_ffmpeg(_ff_path, _ff), do: :noop + + defp check_ytdl(ff_path, yt, _yt_path = nil) when is_binary(ff_path) and is_binary(yt) do + Logger.warning(""" + #{yt} was not found in your path. Nostrum supports youtube-dl for voice. + If you don't require youtube-dl support, configure :nostrum, :youtubedl to nil or false to suppress. + """) + end + + defp check_ytdl(_ff_path, _yt, _yt_path), do: :noop + + defp check_streamlink(ff_path, sl, _sl_path = nil) when is_binary(ff_path) and is_binary(sl) do + Logger.warning(""" + #{sl} was not found in your path. Nostrum supports streamlink for voice. + If you don't require streamlink support, configure :nostrum, :streamlink to nil or false to suppress. + """) end + defp check_streamlink(_ff_path, _sl, _sl_path), do: :noop + defp check_otp_version do _module_info = :pg.module_info() diff --git a/lib/nostrum/dummy.ex b/lib/nostrum/dummy.ex index de6a469cd..9ba5d1154 100644 --- a/lib/nostrum/dummy.ex +++ b/lib/nostrum/dummy.ex @@ -12,7 +12,7 @@ defmodule DummySupervisor do end def init(_args) do - children = for id <- 0..1, do: Supervisor.child_spec({DummyConsumer, []}, id: id) + children = [DummyConsumer] Supervisor.init(children, strategy: :one_for_one) end end diff --git a/lib/nostrum/voice.ex b/lib/nostrum/voice.ex index 679e13a45..a6de581d4 100644 --- a/lib/nostrum/voice.ex +++ b/lib/nostrum/voice.ex @@ -33,7 +33,10 @@ defmodule Nostrum.Voice do """ alias Nostrum.Api - alias Nostrum.Struct.{Channel, Guild, VoiceState, VoiceWSState} + alias Nostrum.Struct.Channel + alias Nostrum.Struct.Guild + alias Nostrum.Struct.VoiceState + alias Nostrum.Struct.VoiceWSState alias Nostrum.Voice.Audio alias Nostrum.Voice.Opus alias Nostrum.Voice.Ports @@ -121,6 +124,13 @@ defmodule Nostrum.Voice do GenServer.cast(Nostrum.VoiceStateMap, {:remove, guild_id, pre_cleanup_args}) end + @doc false + defdelegate ffmpeg_executable, to: Audio + @doc false + defdelegate youtubedl_executable, to: Audio + @doc false + defdelegate streamlink_executable, to: Audio + @doc """ Joins or moves the bot to a voice channel. @@ -242,6 +252,8 @@ defmodule Nostrum.Voice do """ @spec play(Guild.id(), play_input(), play_type(), keyword()) :: :ok | {:error, String.t()} def play(guild_id, input, type \\ :url, options \\ []) do + maybe_warn(type) + voice = get_voice(guild_id) cond do @@ -834,4 +846,34 @@ defmodule Nostrum.Voice do end defp persistent_args(_voice), do: [] + + unless Application.compile_env(:nostrum, :suppress_youtubedl_version, false) do + @ytdl_old_version "2021.12.17" + + defp check_youtubedl_version do + with ytdl when is_binary(ytdl) <- youtubedl_executable(), + ["youtube-dl" | _] <- ytdl |> Path.basename() |> String.split("."), + {version, 0} <- System.cmd(ytdl, ["--version"]), + version when version <= @ytdl_old_version <- String.trim(version) do + Logger.warning(""" + Configured youtube-dl installation '#{System.find_executable(ytdl)}' is version #{version}. + + This version no longer compatible with recent YouTube updates. + + It is recommended to configure :nostrum, :youtubedl to point to a maintained fork such as 'yt-dlp'. + + If you know what you are doing, configure :nostrum, :suppress_youtubedl_version to `true` to suppress this. + """) + end + end + + defp maybe_warn(:ytdl) do + unless :persistent_term.get(:has_checked_youtubedl_version, false) do + :persistent_term.put(:has_checked_youtubedl_version, true) + {:ok, _pid} = Task.start(fn -> check_youtubedl_version() end) + end + end + end + + defp maybe_warn(_type), do: :noop end diff --git a/lib/nostrum/voice/audio.ex b/lib/nostrum/voice/audio.ex index ab43b147a..8171ec5f5 100644 --- a/lib/nostrum/voice/audio.ex +++ b/lib/nostrum/voice/audio.ex @@ -22,6 +22,10 @@ defmodule Nostrum.Voice.Audio do def encryption_mode, do: @encryption_mode + def ffmpeg_executable, do: Application.get_env(:nostrum, :ffmpeg, @ffmpeg) + def youtubedl_executable, do: Application.get_env(:nostrum, :youtubedl, @ytdl) + def streamlink_executable, do: Application.get_env(:nostrum, :streamlink, @streamlink) + # How many consecutive packets to send before resting def frames_per_burst, do: Application.get_env(:nostrum, :audio_frames_per_burst, @frames_per_burst) @@ -166,7 +170,7 @@ defmodule Nostrum.Voice.Audio do def spawn_youtubedl(url) do res = Ports.execute( - Application.get_env(:nostrum, :youtubedl, @ytdl), + youtubedl_executable(), [ ["-f", "bestaudio"], ["-o", "-"], @@ -189,7 +193,7 @@ defmodule Nostrum.Voice.Audio do def spawn_streamlink(url) do res = Ports.execute( - Application.get_env(:nostrum, :streamlink, @streamlink), + streamlink_executable(), [ ["--stdout"], ["--quiet"], @@ -226,7 +230,7 @@ defmodule Nostrum.Voice.Audio do res = Ports.execute( - Application.get_env(:nostrum, :ffmpeg, @ffmpeg), + ffmpeg_executable(), [ ffmpeg_options(options, input_url), ["-ac", "2"], From b2afaf7d872eeee62a817f1f4aed1061afa2da51 Mon Sep 17 00:00:00 2001 From: Brandt Hill Date: Sat, 11 May 2024 10:47:45 -0500 Subject: [PATCH 2/2] Namespace persistent_term keys --- lib/nostrum/voice.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/nostrum/voice.ex b/lib/nostrum/voice.ex index a6de581d4..64d2dfadf 100644 --- a/lib/nostrum/voice.ex +++ b/lib/nostrum/voice.ex @@ -868,8 +868,8 @@ defmodule Nostrum.Voice do end defp maybe_warn(:ytdl) do - unless :persistent_term.get(:has_checked_youtubedl_version, false) do - :persistent_term.put(:has_checked_youtubedl_version, true) + unless :persistent_term.get(:nostrum_has_checked_youtubedl_version, false) do + :persistent_term.put(:nostrum_has_checked_youtubedl_version, true) {:ok, _pid} = Task.start(fn -> check_youtubedl_version() end) end end