Skip to content

Instantly share code, notes, and snippets.

@kaspth
Created February 6, 2024 20:54
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kaspth/c748bd3ac7a3bb516d7716b2fc1a1cef to your computer and use it in GitHub Desktop.
Save kaspth/c748bd3ac7a3bb516d7716b2fc1a1cef to your computer and use it in GitHub Desktop.
# Spotify Mix Playlists: Assuming we have a history of played songs for a user,
# we have song recommendations via nearest neighbor search,
# and we have categorizations (genre, mood, era, instrumental/vocal, cultural/regional, theme),
# let system admins create mix templates based on music categorizations
# and then generate refreshable custom playlists for each user.
class User
has_many :playlists
has_one :history
end
class History
has_many :listens
has_many :tracks, through: :listens
end
class History::Listen
belongs_to :history
belongs_to :track
end
class Track
has_many :categorizations
has_many :categories, through: :categorizations
end
track.inner_joins(Track::Category.genres).nearest(100)
Track::Category.genres.where(value: ["pop", "hiphop"])
Track::Category.eras.where(value: ["80s", "90s"])
class Track::Category
has_many :categorizations
has_many :tracks, through: :categorizations
belongs_to :details
end
class Track::Category::Categorization
belongs_to :track
belongs_to :category
end
class Playlist
end
class Mix::Template
has_many :categories
def build_for(user)
from_own_history = user.history.tracks.ordered_by_popularity.joins(:categories).where(categories:).limit(100).flat_map do |track|
[track, track.nearest(10)]
end.uniq.first(100)
if from_own_history >= 100
from_own_history
else
Track.ordered_by_popularity.joins(:categories).where(categories:).limit(100).flat_map do |track|
[track, track.nearest(10)]
end.including(from_own_history).uniq.first(100)
end
end
end
class Mix::Build
belongs_to :template
belongs_to :user
has_many :links
has_many :tracks, through: :links
def regenerate
update! tracks: template.build_for(user)
end
end
class Mix::Build::Link
belongs_to :build
belongs_to :track
end
@ziraqyoung
Copy link

This is super cool!.

On the Mix::Template class, you are defining has_many :categories which is used in Mix::Template#build_for(user) method. But I am left wondering how the mix-categories associations would look like. So I thought I would try to fill in the Mix::Template & has_many :categories gap. Let me know what modifications you would do to this.

# template.categories => get all categories for this template
# mix_category.templates => all templates that has this cateogory
class Mix::Category::Categorization
  belongs_to :category, class_name: 'Mix::Category'
  belongs_to :template
end

class Mix::Category
  has_many :categorizations, class_name: 'Mix::Category::Categorization'
  has_many :templates, through: :categorizations
end


# Modified 
class Mix::Template
  has_many :categorizations, class_name: 'Mix::Category::Categorization'
  has_many :categories, through: :categorizations
end

Also I am not sure if belongs_to :details on Track::Category is the same or should be the same with Mix::Category's belongs_to :details

@kaspth
Copy link
Author

kaspth commented Feb 15, 2024

@ziraqyoung hey, thank you so much! It's not the clearest from the gist since we didn't fill in class_name: but Mix::Template.has_many :categories is meant to point to Track::Category, if I recall correctly. And then the details become the same since there's only one class.

I forgot to update it here but @jeremysmithco and I posted how we riffed up this file on YouTube, if you want to see that https://www.youtube.com/watch?v=i1MM2EOniPg

@ziraqyoung
Copy link

@kaspth, I did watch it (them). They are very educative. Thank you.

@kaspth
Copy link
Author

kaspth commented Feb 15, 2024

@ziraqyoung ah ok, thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment