Fix album fetching, populate artists, auto-migrate on startup

This commit is contained in:
Jeremy Penner 2025-05-18 16:46:39 -04:00
parent 5231c50962
commit 09997c8401
9 changed files with 70 additions and 11 deletions

4
config/config.exs Normal file
View file

@ -0,0 +1,4 @@
import Config
config :spindleybot,
ecto_repos: [SpindleyBot.Repo]

View file

@ -1,8 +1,5 @@
import Config
config :spindleybot,
ecto_repos: [SpindleyBot.Repo]
config :spindleybot, SpindleyBot.Repo,
database: System.get_env("SPINDLEYBOT_DB", if config_env() == "test" do ":memory:" else "spindleybot.sqlite" end)

View file

@ -53,7 +53,7 @@
let pkgs = nixpkgs.legacyPackages.${system};
in {
devShells.default = pkgs.mkShell {
buildInputs = [ pkgs.bashInteractive pkgs.erlang_27 pkgs.rebar3 pkgs.elixir pkgs.beamPackages.hex pkgs.sqlite pkgs.mix2nix ];
buildInputs = [ pkgs.bashInteractive pkgs.erlang_27 pkgs.rebar3 pkgs.elixir pkgs.beamPackages.hex pkgs.sqlite pkgs.mix2nix pkgs.rlwrap ];
};
packages.default = (make-spindleybot pkgs);
}));

View file

@ -17,7 +17,10 @@ defmodule SpindleyBot.Supervisor do
def init(:ok) do
children = [
SpindleyBot.Repo,
{SpindleyBot.Consumer, name: SpindleyBot.Consumer}
{SpindleyBot.Consumer, name: SpindleyBot.Consumer},
{Ecto.Migrator,
repos: Application.fetch_env!(:spindleybot, :ecto_repos),
skip: System.get_env("SKIP_MIGRATIONS") == "true"}
]
Supervisor.init(children, strategy: :one_for_all)
end
@ -40,7 +43,7 @@ defmodule SpindleyBot.Consumer do
})
{:ok, message} = Interaction.original_response(interaction)
songs = from(s in Song, as: :s,
where: not exists(from(v in Vote, select: 1, where: parent_as(:s).id == v.song_id)),
where: not exists(from(v in Vote, select: 1, where: parent_as(:s).id == v.song_id)) and not s.excluded,
order_by: fragment("random()"),
limit: 3)
|> Repo.all()

View file

@ -0,0 +1,8 @@
defmodule SpindleyBot.Artist do
use Ecto.Schema
schema "artists" do
field :name, :string
has_many :songs, SpindleyBot.Song
end
end

View file

@ -5,6 +5,7 @@ defmodule SpindleyBot.Song do
field :title, :string
field :page_id, :integer
field :youtube_id, :string
many_to_many(:albums, SpindleyBot.Album, join_through: "songs_albums")
belongs_to :artist, SpindleyBot.Artist
many_to_many :albums, SpindleyBot.Album, join_through: "songs_albums"
end
end

View file

@ -55,11 +55,20 @@ defmodule TMBW do
|> Enum.filter(fn song -> song["ns"] == 0 end) # ignore category pages
end
def fetch_albums(song_title) do
link_regex = ~r/\[\[([^\]\|]+)(?:\|[^\]]+)?\]\]/
link_regex = ~r/(?:\[\[|{{)(?:wp\|)?([^\]^}\|]+)(?:\|[^\]]+)?(?:\]\]|}})|(Unreleased)/
albums = MediaWiki.wikitext(@wiki, song_title)
|> MediaWiki.find_template_param("Album")
Regex.scan(link_regex, albums)
|> Enum.map(fn [_, album_name] -> album_name end)
|> IO.inspect()
|> Enum.map(fn
[_, album_name] -> album_name
[_, _, unreleased] -> unreleased
end)
end
def fetch_artist(song_title) do
MediaWiki.wikitext(@wiki, song_title)
|> MediaWiki.find_template_param("Artist")
|> String.trim()
end
def fetch_youtube_id(song_title) do
MediaWiki.wikitext(@wiki, "Download:" <> song_title)

View file

@ -3,7 +3,7 @@ defmodule SpindleyBot.Tasks do
@repo SpindleyBot.Repo
require Logger
alias SpindleyBot.{Song, Album}
alias SpindleyBot.{Song, Album, Artist}
require Ecto.Query
import Ecto.Query, only: [from: 2]
@ -25,8 +25,11 @@ defmodule SpindleyBot.Tasks do
end)
end
def fetch_albums() do
def fetch_albums(opts \\ []) do
with_repo(fn repo ->
case Keyword.fetch(opts, :clear) do
{:ok, true} -> from(sa in "songs_albums", as: :sa) |> repo.delete_all()
end
from(s in Song, as: :s,
where: not exists(from(sa in "songs_albums", select: 1, where: parent_as(:s).id == sa.song_id)),
preload: [:albums])
@ -49,6 +52,23 @@ defmodule SpindleyBot.Tasks do
end)
end
def populate_artists() do
with_repo(fn repo ->
from(s in Song, as: :s, where: is_nil(s.artist_id), preload: [:artist])
|> repo.all()
|> Enum.each(fn song ->
artist_name = TMBW.fetch_artist(song.title)
artist = case repo.get_by(Artist, name: artist_name) do
nil -> repo.insert!(%Artist{ name: artist_name })
album -> album
end
Ecto.Changeset.change(song)
|> Ecto.Changeset.put_assoc(:artist, artist)
|> repo.update!()
end)
end)
end
def fetch_links() do
with_repo(fn repo ->
Song

View file

@ -0,0 +1,17 @@
defmodule SpindleyBot.Repo.Migrations.ExcludedSongs do
use Ecto.Migration
def change do
create table(:artists) do
add :name, :string
end
alter table(:songs) do
add :excluded, :boolean, default: false
add :artist_id, references(:artists)
end
create unique_index(:artists, [:name])
create index(:songs, [:excluded])
create index(:songs, [:artist_id])
create index(:votes, [:song_id])
end
end