Skip to main content

๐ŸŽง Music Monday โ†” Spotify ์ž๋™ ๋™๊ธฐํ™” Ruby Bot ๋งŒ๋“ค๊ธฐ

Published 4 min readMarkdown

(Spotifyโ€ฏํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ ์ž๋™ํ™”ยทRubyโ€ฏ์Šคํฌ๋ฆฝํŠธยทMusicโ€ฏMonday ์—ฐ๋™)


# ๐Ÿ“ ์„œ๋ก  โ€“ โ€œ๋Œ“๊ธ€์— ์ ํžŒ ๊ณก์„ ์ผ์ผ์ด ์ถ”๊ฐ€ํ•˜๋Š” ๋ถˆํŽธํ•จ, ์ด์ œ๋Š” ๋!โ€

ํ”„๋ก ํŠธ์—”๋“œยท๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž๋ผ๋ฉด API ํ™œ์šฉ์„ ํ†ตํ•ด ์—ฌ๋Ÿฌ ์„œ๋น„์Šค๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” ์žฌ๋ฏธ๋ฅผ ๋งŽ์ด ๋А๊ปด๋ณด์…จ์„ ๊ฒ๋‹ˆ๋‹ค.

๊ทธ ์ค‘์—์„œ๋„ Music Monday๋Š” ๋งค์ฃผ ์›”์š”์ผ ์ปค๋ฎค๋‹ˆํ‹ฐ ๋ฉค๋ฒ„๋“ค์ด ๋Œ“๊ธ€์— ์ž์‹ ์ด ์ข‹์•„ํ•˜๋Š” ๊ณก์„ ๊ณต์œ ํ•˜๋Š” ์Œ์•… ์ถ”์ฒœ ์ด๋ฒคํŠธ์ž…๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์ด๋ ‡๊ฒŒ ๊ณต์œ ๋œ ๊ณก์„ Spotify ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ์— ์ง์ ‘ ์ถ”๊ฐ€ํ•˜๋ ค๋ฉด ๋Œ“๊ธ€์„ ํ•˜๋‚˜์”ฉ ๋ณต์‚ฌํ•˜๊ณ , ๊ฒ€์ƒ‰ํ•˜๊ณ , โ€˜๋‚ด ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ์— ์ถ”๊ฐ€โ€™ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ž‘์€ ํŒ€์ด๋‚˜ ๊ฐœ์ธ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ์ด ์ž‘์—…์ด ์‹œ๊ฐ„ ๋‚ญ๋น„์ด์ž ์˜ค๋ฅ˜ ๋ฐœ์ƒ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์•„์ง‘๋‹ˆ๋‹ค.

๋ฌธ์ œ: Music Monday์— ๋‹ฌ๋ฆฐ ๋Œ“๊ธ€์„ ์ž๋™์œผ๋กœ ์ฝ์–ดโ€ฏSpotifyโ€ฏํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ์— ๋™๊ธฐํ™”ํ•˜๊ณ  ์‹ถ๋‹ค.

์ด ๊ธ€์—์„œ๋Š” Ruby ๋กœ ๋งŒ๋“  ๊ฐ€๋ฒผ์šด ์˜คํ”ˆ์†Œ์Šค Sync Bot์„ ์ด์šฉํ•ด, ์œ„ ๋ฌธ์ œ๋ฅผ ์ดˆ๋ณด์ž๋„ 30๋ถ„ ์•ˆ์— ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋‹จ๊ณ„๋ณ„๋กœ ์•ˆ๋‚ดํ•ฉ๋‹ˆ๋‹ค.

SEO ํ‚ค์›Œ๋“œ

  1. Spotifyโ€ฏํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธโ€ฏ์ž๋™ํ™”

  2. Rubyโ€ฏ์Šคํฌ๋ฆฝํŠธ

  3. Musicโ€ฏMondayโ€ฏ์—ฐ๋™


# ๐Ÿ› ๏ธ 1. ์ค€๋น„ ๋‹จ๊ณ„ โ€“ ํ•„์ˆ˜ ๋„๊ตฌ์™€ ๊ณ„์ • ์„ค์ •

| ํ•ญ๋ชฉ | ์ด์œ  | ์„ค์ • ๋ฐฉ๋ฒ• |

|------|------|----------|

| Ruby (โ‰ฅโ€ฏ2.7) | ์Šคํฌ๋ฆฝํŠธ ์‹คํ–‰ ํ™˜๊ฒฝ | rbenv ํ˜น์€ rvm ์œผ๋กœ ์„ค์น˜ โ†’ ruby -v ํ™•์ธ |

| Bundler | ์˜์กด์„ฑ ๊ด€๋ฆฌ | gem install bundler |

| Spotifyโ€ฏDeveloperโ€ฏAccount | APIโ€ฏํ‚ค(ํด๋ผ์ด์–ธํŠธโ€ฏID/์‹œํฌ๋ฆฟ) ๋ฐœ๊ธ‰ | https://developer.spotify.com/dashboard โ†’ โ€œCreate Appโ€ โ†’ Client ID์™€ Client Secret ๋ณต์‚ฌ |

| Musicโ€ฏMondayโ€ฏAPI (๋น„๊ณต์‹) | ๋Œ“๊ธ€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๊ธฐ ์œ„ํ•œ ์—”๋“œํฌ์ธํŠธ | https://api.musicmonday.com/v1/comments?topic=spotify (์˜ˆ์‹œ) |

| dotenv | ํ™˜๊ฒฝ ๋ณ€์ˆ˜(.env) ํŒŒ์ผ ๊ด€๋ฆฌ | .env ํŒŒ์ผ์— ํ‚ค๊ฐ’ ์ €์žฅ, .gitignore์— ์ถ”๊ฐ€ |

Tip: Ruby ์ดˆ๋ณด์ž๋Š” irb ๋กœ ํ•œ ์ค„์”ฉ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•ด ๋ณด๋ฉด์„œ ๋™์ž‘์„ ํ™•์ธํ•˜๋ฉด ๋””๋ฒ„๊น…์ด ์‰ฌ์›Œ์ง‘๋‹ˆ๋‹ค.


# ๐Ÿ“‚ 2. ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ์™€ ํ•ต์‹ฌ ํŒŒ์ผ


music-monday-spotify-bot/

โ”‚
โ”œโ”€ Gemfile          # ์‚ฌ์šฉ gem ์ •์˜

โ”œโ”€ .env             # API ํ‚คยทํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ ID ์ €์žฅ

โ”œโ”€ bot.rb           # ๋ฉ”์ธ ์‹คํ–‰ ํŒŒ์ผ

โ””โ”€ lib/

   โ””โ”€ spotify_client.rb   # Spotify API ๋ž˜ํผ

# 2โ€‘1. Gemfile

ruby

source 'https://rubygems.org'

gem 'httparty'      # HTTP ์š”์ฒญ

gem 'rspotify'      # Spotify API ๋ž˜ํผ

gem 'dotenv'        # .env ๋กœ ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๋กœ๋“œ
bash

bundle install

# 2โ€‘2. Spotify ํด๋ผ์ด์–ธํŠธ ๊ตฌํ˜„ (lib/spotify_client.rb)

ruby

require 'rspotify'

require 'dotenv/load'

# Spotify ์ธ์ฆ (ํด๋ผ์ด์–ธํŠธ ID/์‹œํฌ๋ฆฟ)

RSpotify.authenticate(ENV['SPOTIFY_CLIENT_ID'],

                      ENV['SPOTIFY_CLIENT_SECRET'])

class SpotifyClient

  def initialize(playlist_id)

    user      = RSpotify::User.find('me')

    @playlist = user.playlists.find { |p| p.id == playlist_id }

  end

  # ํŠธ๋ž™ ๊ฒ€์ƒ‰ โ†’ ์—†์œผ๋ฉด ์ถ”๊ฐ€

  def add_track(track_name, artist_name)

    results = RSpotify::Track.search('#{track_name} #{artist_name}')

    track   = results.first

    return unless track

    if @playlist.tracks.map(&:id).include?(track.id)

      puts 'โ„น๏ธ '#{track_name}' ์€(๋Š”) ์ด๋ฏธ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.'

    else

      @playlist.add_tracks!([track])

      puts 'โœ… '#{track_name}' - #{artist_name} ๋ฅผ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.'

    end

  end

end

# 2โ€‘3. ๋ฉ”์ธ ๋กœ์ง (bot.rb)

ruby

require 'httparty'

require 'json'

require_relative './lib/spotify_client'

# 1๏ธโƒฃ Music Monday ๋Œ“๊ธ€์„ ๋ฐ›์•„์˜ค๋Š” ํ•จ์ˆ˜

def fetch_comments

  url = 'https://api.musicmonday.com/v1/comments?topic=spotify'

  resp = HTTParty.get(url)

  JSON.parse(resp.body)['data']   # [{ 'track':'Bad Guy','artist':'Billie Eilish' }, ...]

end

# 2๏ธโƒฃ Spotify์— ๋™๊ธฐํ™”

def sync_to_spotify

  playlist_id = ENV['SPOTIFY_PLAYLIST_ID']

  client      = SpotifyClient.new(playlist_id)

  fetch_comments.each do |c|

    client.add_track(c['track'], c['artist'])

  end

end

# ์‹คํ–‰

sync_to_spotify

ํ•ต์‹ฌ ํฌ์ธํŠธ

  • RSpotify ๋กœ ์ธ์ฆ โ†’ ํ˜„์žฌ ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž์˜ ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ์— ์ ‘๊ทผ

  • ๋Œ“๊ธ€์—์„œ ์ถ”์ถœํ•œ trackยทartist ๋ฅผ ์กฐํ•ฉํ•ด ๊ฒ€์ƒ‰ โ†’ ์ถ”๊ฐ€ ํ๋ฆ„ ๊ตฌํ˜„

  • ์ด๋ฏธ ์กด์žฌํ•˜๋Š” ํŠธ๋ž™์€ ์ค‘๋ณต ์ถ”๊ฐ€๋ฅผ ๋ฐฉ์ง€ํ•˜๋„๋ก ๋กœ์ง์„ ๋„ฃ์—ˆ์Šต๋‹ˆ๋‹ค.


# ๐Ÿš€ 3. ์‹ค์ œ ์šด์˜ ํŒ โ€“ ์ž๋™ํ™”ยท์—๋Ÿฌยท๋ณด์•ˆ

# 3โ€‘1. ํฌ๋ก  ์žก์œผ๋กœ ๋งค์ฃผ ์ž๋™ ์‹คํ–‰

bash

# ๋งค์ฃผ ์›”์š”์ผ ์ƒˆ๋ฒฝ 6์‹œ (ํ•œ๊ตญ์‹œ๊ฐ„ 15์‹œ) ์‹คํ–‰

0 6 * * 1 /usr/local/bin/ruby /path/to/bot.rb >> /var/log/music_monday_bot.log 2>&1

# 3โ€‘2. ์—๋Ÿฌ ๋กœ๊ทธ์™€ ์•Œ๋ฆผ

ruby

begin

  sync_to_spotify

rescue => e

  File.open('error.log', 'a') { |f| f.puts('[#{Time.now}] #{e.message}') }

  # Slack webhook ์œผ๋กœ ์‹ค์‹œ๊ฐ„ ์•Œ๋ฆผ๋„ ๊ฐ€๋Šฅ

end

# 3โ€‘3. ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๋ณด์•ˆ

  • .env ํŒŒ์ผ์— SPOTIFY_CLIENT_ID, SPOTIFY_CLIENT_SECRET, SPOTIFY_PLAYLIST_ID ๋ฅผ ์ €์žฅ

  • .gitignore ์— .env ๋ฅผ ๋ฐ˜๋“œ์‹œ ์ถ”๊ฐ€ํ•ด ๋ ˆํฌ์— ๋…ธ์ถœ๋˜์ง€ ์•Š๊ฒŒ

# 3โ€‘4. ๊ฒ€์ƒ‰ ์ •ํ™•๋„ ํ–ฅ์ƒ

ruby

results = RSpotify::Track.search('#{track_name} #{artist_name}',

                                 limit: 1,

                                 market: 'KR')

market ์˜ต์…˜์„ ์ง€์ •ํ•˜๋ฉด ํ•œ๊ตญ ๋‚ด ์ธ๊ธฐ ๋ฒ„์ „์„ ์šฐ์„  ๋ฐ˜ํ™˜ํ•ด ๊ฒ€์ƒ‰ ์ •ํ™•๋„๊ฐ€ ๋†’์•„์ง‘๋‹ˆ๋‹ค.


# ๐Ÿ“Š 4. ๊ธฐ๋Œ€ ํšจ๊ณผ์™€ ํ™œ์šฉ ์•„์ด๋””์–ด

| ๊ธฐ๋Œ€ ํšจ๊ณผ | ๊ตฌ์ฒด์  ํ™œ์šฉ |

|-----------|-------------|

| ์‹œ๊ฐ„ ์ ˆ๊ฐ | ์ˆ˜์‹ญ ๊ฐœ์˜ ๋Œ“๊ธ€์„ ์ผ์ผ์ด ๋ณต์‚ฌยท๋ถ™์—ฌ๋„ฃ๊ธฐ ํ•˜์ง€ ์•Š์•„๋„ ์ž๋™์œผ๋กœ ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ์— ๋ฐ˜์˜ |

| ์ปค๋ฎค๋‹ˆํ‹ฐ ํ™œ์„ฑํ™” | Music Monday ์ฐธ์—ฌ์ž๋“ค์ด ์ž์‹ ์˜ ๊ณก์ด ๋ฐ”๋กœ Spotify์— ์˜ฌ๋ผ๊ฐ€๋Š” ๋ชจ์Šต์„ ๋ณด๋ฉฐ ์ฐธ์—ฌ ์˜์š• ์ƒ์Šน |

| ๋ฐ์ดํ„ฐ ๋ถ„์„ | ๋Œ“๊ธ€ ๋ฐ์ดํ„ฐ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ฃผ๊ฐ„ ์ธ๊ธฐ ํŠธ๋ž™ ์ฐจํŠธ ์ž๋™ ์ƒ์„ฑ ๊ฐ€๋Šฅ |

| ๋ฉ€ํ‹ฐํ”Œ๋žซํผ ์—ฐ๋™ | ๋™์ผ ๋กœ์ง์„ Appleโ€ฏMusic, YouTubeโ€ฏMusic API ๋กœ ๊ต์ฒดํ•ด ๋‹ค์ค‘ ์ŠคํŠธ๋ฆฌ๋ฐ ์„œ๋น„์Šค ๊ด€๋ฆฌ ๊ฐ€๋Šฅ |


# ๐Ÿ ๊ฒฐ๋ก  โ€“ โ€œ์ฝ”๋“œ ํ•œ ์ค„๋กœ ์Œ์•… ๊ณต์œ ๋ฅผ ์ž๋™ํ™”ํ•˜๋ผ!โ€

Music Monday์—์„œ ๋งค์ฃผ ๊ณต์œ ๋˜๋Š” ๊ณก์„ ์ˆ˜๋™์œผ๋กœ ๊ด€๋ฆฌํ•˜๋А๋ผ ์‹œ๊ฐ„์„ ๋‚ญ๋น„ํ•˜๊ณ  ์žˆ๋‚˜์š”?

์œ„์—์„œ ์†Œ๊ฐœํ•œ Ruby ์ž๋™ํ™” ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, ๋Œ“๊ธ€ ํ•˜๋‚˜๋งŒ ๋‹ฌ์•„๋„ ์ž๋™์œผ๋กœ Spotifyโ€ฏํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ ๋งŒ๋“ค๊ธฐ๊ฐ€ ์™„๋ฃŒ๋ฉ๋‹ˆ๋‹ค.

1๏ธโƒฃ ํ”„๋กœ์ ํŠธ๋ฅผ ๋ณต์ œ(git clone) โ†’

2๏ธโƒฃ bundle install โ†’ .env ์„ค์ • โ†’ ruby bot.rb ์‹คํ–‰๋งŒ ํ•˜๋ฉด ๋!

ํ–‰๋™ ์œ ๋„

  • ์ง€๊ธˆ ๋ฐ”๋กœ GitHub(https://github.com/mikeydorje/music-monday-spotify-open-source-sync-bot) ์—์„œ ์ฝ”๋“œ๋ฅผ ํฌํฌํ•˜๊ณ , ์ž์‹ ๋งŒ์˜ ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ๋ฅผ ๋งŒ๋“ค์–ด ๋ณด์„ธ์š”.

  • ๊ตฌํ˜„ ์ค‘ ๊ถ๊ธˆํ•œ ์ ์€ Issue ๋กœ ๋‚จ๊ธฐ๊ฑฐ๋‚˜, Devโ€ฏto ๋Œ“๊ธ€์— ์งˆ๋ฌธํ•ด ์ฃผ์„ธ์š”. ์ปค๋ฎค๋‹ˆํ‹ฐ์™€ ํ•จ๊ป˜ ์„ฑ์žฅํ•˜๋Š” Music Monday ์—ฐ๋™ ํ”„๋กœ์ ํŠธ๊ฐ€ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค!

์Œ์•…์€ ๊ณต์œ ํ•˜๊ณ , ์ž๋™ํ™”๋Š” ์Šค์Šค๋กœ์—๊ฒŒ ๋งก๊ธฐ์„ธ์š”. ๐ŸŽถ๐Ÿš€

No comments yet. Be the first to comment.

More from this blog