diff --git a/Dockerfile b/Dockerfile index 9a79cf29e..bd15f0a57 100644 --- a/Dockerfile +++ b/Dockerfile @@ -38,11 +38,9 @@ RUN yarn install COPY . . -# Expose Shrine attachments as public cacheable URLs +# TODO: Remove after grace period +# Expose legacy Shrine files RUN ln -sf /content/tracks/audio_files ./public/audio -# Expose ActiveStorage attachments as public cacheable URLs -RUN ln -sf /content/active_storage ./public/attachments - EXPOSE 3000 CMD bundle exec puma -b tcp://0.0.0.0:3000 diff --git a/Gemfile b/Gemfile index c1936ffba..726014ca5 100644 --- a/Gemfile +++ b/Gemfile @@ -4,9 +4,7 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" } ruby "3.3.3" gem "actionpack-action_caching" -gem "chunky_png" gem "chronic" -gem "dalli" gem "friendly_id" gem "dry-initializer" gem "geocoder" @@ -18,7 +16,6 @@ gem "grape-swagger-entity" gem "htmlentities" gem "image_processing" gem "jwt" -gem "highline" gem "nokogiri" gem "pg" gem "pg_search" @@ -35,7 +32,6 @@ gem "sidekiq" gem "sidekiq-scheduler" gem "sitemap_generator" gem "shakapacker" -gem "shrine" gem "slim" gem "sorcery" gem "typhoeus" diff --git a/Gemfile.lock b/Gemfile.lock index fa605fde8..2f0788b0b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -106,10 +106,8 @@ GEM chunky_png (1.4.0) concurrent-ruby (1.3.4) connection_pool (2.4.1) - content_disposition (1.0.0) crass (1.0.6) csv (3.3.0) - dalli (3.2.8) date (3.4.0) declarative (0.0.20) diff-lcs (1.5.1) @@ -118,8 +116,6 @@ GEM dotenv-rails (3.1.4) dotenv (= 3.1.4) railties (>= 6.1) - down (5.4.2) - addressable (~> 2.8) drb (2.2.1) dry-core (1.0.2) concurrent-ruby (~> 1.0) @@ -214,8 +210,6 @@ GEM grape-entity (~> 1) grape-swagger (~> 2) hashie (5.0.0) - highline (3.1.1) - reline htmlentities (4.3.4) httpclient (2.8.3) i18n (1.14.6) @@ -389,7 +383,7 @@ GEM rubocop-ast (>= 1.32.2, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.33.0) + rubocop-ast (1.33.1) parser (>= 3.3.1.0) rubocop-capybara (2.21.0) rubocop (~> 1.41) @@ -450,9 +444,6 @@ GEM semantic_range (>= 2.3.0) shoulda-matchers (6.4.0) activesupport (>= 5.2.0) - shrine (3.6.0) - content_disposition (~> 1.0) - down (~> 5.1) sidekiq (7.3.4) connection_pool (>= 2.3.0) logger @@ -524,8 +515,6 @@ DEPENDENCIES capybara-email capybara-screenshot chronic - chunky_png - dalli dotenv-rails dry-initializer factory_bot_rails @@ -537,7 +526,6 @@ DEPENDENCIES grape-entity grape-swagger grape-swagger-entity - highline htmlentities image_processing jwt @@ -565,7 +553,6 @@ DEPENDENCIES sentry-ruby shakapacker shoulda-matchers - shrine sidekiq sidekiq-scheduler simplecov diff --git a/app/api/api_v2/search.rb b/app/api/api_v2/search.rb index 523e7f14b..4143f8be9 100644 --- a/app/api/api_v2/search.rb +++ b/app/api/api_v2/search.rb @@ -49,7 +49,7 @@ class ApiV2::Search < ApiV2::Base helpers do def fetch_results(term, scope) Rails.cache.fetch("api/v2/search/#{term}/#{scope}") do - SearchService.new(term, scope).call + SearchService.call(term, scope) end end diff --git a/app/controllers/api/v1/search_controller.rb b/app/controllers/api/v1/search_controller.rb index ed57de1ef..84603eb5b 100644 --- a/app/controllers/api/v1/search_controller.rb +++ b/app/controllers/api/v1/search_controller.rb @@ -7,7 +7,7 @@ def index private def results - @results ||= SearchService.new(params[:term]).call + @results ||= SearchService.call(params[:term]) end def respond_with_invalid_term diff --git a/app/controllers/downloads_controller.rb b/app/controllers/downloads_controller.rb index 959a7a372..babccb7ce 100644 --- a/app/controllers/downloads_controller.rb +++ b/app/controllers/downloads_controller.rb @@ -1,55 +1,25 @@ class DownloadsController < ApplicationController def download_track raise ActiveRecord::RecordNotFound if track.blank? - - if track.mp3_audio.attached? - send_active_storage_audio_as_attachment - elsif track.audio_file.exists? - send_shrine_audio_as_attachment - else - head :not_found - end + return head(:not_found) unless track.mp3_audio.attached? + send_file_response(track.mp3_audio, "attachment", "Phish #{track.show.date} #{track.title}.mp3") end def download_blob raise ActiveRecord::RecordNotFound if blob.blank? - send_blob_file_inline + send_file_response(blob, "inline", blob.filename.to_s) end private - def send_active_storage_audio_as_attachment - add_cache_header - send_file \ - ActiveStorage::Blob.service.send(:path_for, track.mp3_audio.blob.key), - type: "audio/mpeg", - disposition: "attachment", - filename: "Phish #{track.show.date} #{track.title}.mp3", - length: track.mp3_audio.blob.byte_size - rescue ActionController::MissingFile - head :not_found - end - - def send_shrine_audio_as_attachment - add_cache_header - send_file \ - track.audio_file.to_io.path, - type: "audio/mpeg", - disposition: "attachment", - filename: "Phish #{track.show.date} #{track.title}.mp3", - length: track.audio_file.size - rescue ActionController::MissingFile - head :not_found - end - - def send_blob_file_inline + def send_file_response(file, disposition, filename) add_cache_header send_file \ - ActiveStorage::Blob.service.send(:path_for, blob.key), - type: blob.content_type || "application/octet-stream", - disposition: "inline", - filename: blob.filename.to_s, - length: blob.byte_size + ActiveStorage::Blob.service.send(:path_for, file.key), + type: file.content_type || "application/octet-stream", + disposition:, + filename:, + length: file.byte_size rescue ActionController::MissingFile head :not_found end diff --git a/app/jobs/jamcharts_job.rb b/app/jobs/jamcharts_job.rb index cb945d4df..d600b5a50 100644 --- a/app/jobs/jamcharts_job.rb +++ b/app/jobs/jamcharts_job.rb @@ -2,7 +2,7 @@ class JamchartsJob include Sidekiq::Job def perform - JamchartsImporter.new(api_key).call + JamchartsImporter.call(api_key) end private diff --git a/app/models/track.rb b/app/models/track.rb index ddda071db..15199e506 100644 --- a/app/models/track.rb +++ b/app/models/track.rb @@ -12,11 +12,6 @@ class Track < ApplicationRecord has_one_attached :mp3_audio has_one_attached :png_waveform - # Deprecated Shrine attachments - include AudioFileUploader::Attachment(:audio_file) - # validates :audio_file, presence: true - include WaveformPngUploader::Attachment(:waveform_png) - include PgSearch::Model pg_search_scope( :kinda_matching, @@ -29,7 +24,6 @@ class Track < ApplicationRecord validates :songs, length: { minimum: 1 } before_save :generate_slug - after_update :process_audio_file, if: :saved_change_to_audio_file_data scope :chronological, -> { joins(:show).order("shows.date") } scope :tagged_with, ->(tag_slug) { joins(:tags).where(tags: { slug: tag_slug }) } @@ -48,22 +42,20 @@ def set_name end def apply_id3_tags - Id3TagService.new(self).call + Id3TagService.call(self) end def generate_slug(force: false) return if !force && slug.present? - self.slug = TrackSlugGenerator.new(self).call + self.slug = TrackSlugGenerator.call(self) end def mp3_url - blob_url(mp3_audio) || - audio_file.url(host: App.content_base_url).gsub("tracks/audio_files", "audio") + blob_url(mp3_audio) end def waveform_image_url - blob_url(png_waveform) || - waveform_png&.url(host: App.content_base_url).gsub("tracks/audio_files", "audio") + blob_url(png_waveform) end def urls @@ -74,21 +66,22 @@ def urls } end - def save_duration - mp3_audio.analyze unless mp3_audio.analyzed? - duration_ms = (mp3_audio.blob.metadata[:duration] * 1000).round - update_column(:duration, duration_ms) - end - def generate_waveform_image(purge_cache: false) - WaveformImageService.new(self).call + WaveformImageService.call(self) end - def process_audio_file - return if Rails.env.test? + def process_mp3_audio save_duration show.save_duration apply_id3_tags generate_waveform_image end + + private + + def save_duration + mp3_audio.analyze unless mp3_audio.analyzed? + duration_ms = (mp3_audio.blob.metadata[:duration] * 1000).round + update_column(:duration, duration_ms) + end end diff --git a/app/services/album_cover_service.rb b/app/services/album_cover_service.rb index ef6c6f614..9ad339e8b 100644 --- a/app/services/album_cover_service.rb +++ b/app/services/album_cover_service.rb @@ -1,6 +1,6 @@ require "mini_magick" -class AlbumCoverService < BaseService +class AlbumCoverService < ApplicationService param :show def call diff --git a/app/services/base_service.rb b/app/services/application_service.rb similarity index 75% rename from app/services/base_service.rb rename to app/services/application_service.rb index ac42f04a7..4b6d2bc6d 100644 --- a/app/services/base_service.rb +++ b/app/services/application_service.rb @@ -1,4 +1,4 @@ -class BaseService +class ApplicationService extend Dry::Initializer def self.call(...) diff --git a/app/services/bustout_tag_service.rb b/app/services/bustout_tag_service.rb index fd03a7d3e..a1ca2db3e 100644 --- a/app/services/bustout_tag_service.rb +++ b/app/services/bustout_tag_service.rb @@ -1,4 +1,4 @@ -class BustoutTagService < BaseService +class BustoutTagService < ApplicationService MIN_GAP = 100 param :show diff --git a/app/services/cover_art_generator.rb b/app/services/cover_art_generator.rb deleted file mode 100644 index f418b326a..000000000 --- a/app/services/cover_art_generator.rb +++ /dev/null @@ -1,37 +0,0 @@ -class CoverArtGenerator < BaseService - param :show - option :force, default: -> { false } - - def call - generate_prompt_and_image_assets - end - - private - - def generate_prompt_and_image_assets - if force || (show.cover_art_prompt.blank? && show.cover_art_parent_show_id.blank?) - CoverArtPromptService.new(show).call - if show.cover_art_parent_show_id.present? - puts "PROMPT (DEFER): #{show.cover_art_parent_show_id}" - else - puts "PROMPT (NEW): #{show.cover_art_prompt}" - end - end - - if force || !show.cover_art.attached? - CoverArtImageService.new(show).call - # sleep 5 # for Dall-E API rate limiting - puts show.cover_art_urls[:large] - end - - if force || !show.album_cover.attached? - AlbumCoverService.new(show).call - puts show.album_cover_url - - # Apply cover art to mp3 files - show.tracks.each do |track| - track.apply_id3_tags - end - end - end -end diff --git a/app/services/cover_art_image_service.rb b/app/services/cover_art_image_service.rb index fdc877a89..7a0d0d586 100644 --- a/app/services/cover_art_image_service.rb +++ b/app/services/cover_art_image_service.rb @@ -1,4 +1,4 @@ -class CoverArtImageService < BaseService +class CoverArtImageService < ApplicationService param :show option :dry_run, default: -> { false } diff --git a/app/services/cover_art_prompt_service.rb b/app/services/cover_art_prompt_service.rb index 2ad7b914a..50eb3a6cb 100644 --- a/app/services/cover_art_prompt_service.rb +++ b/app/services/cover_art_prompt_service.rb @@ -1,4 +1,4 @@ -class CoverArtPromptService < BaseService +class CoverArtPromptService < ApplicationService param :show HUES = %w[ diff --git a/app/services/debut_tag_service.rb b/app/services/debut_tag_service.rb index a9709014b..91c3ee23f 100644 --- a/app/services/debut_tag_service.rb +++ b/app/services/debut_tag_service.rb @@ -1,4 +1,4 @@ -class DebutTagService < BaseService +class DebutTagService < ApplicationService param :show def call diff --git a/app/services/gap_service.rb b/app/services/gap_service.rb index 29b07202e..de86a343f 100644 --- a/app/services/gap_service.rb +++ b/app/services/gap_service.rb @@ -1,4 +1,4 @@ -class GapService < BaseService +class GapService < ApplicationService param :show def call diff --git a/app/services/google_spreadsheet_fetcher.rb b/app/services/google_spreadsheet_fetcher.rb index 15b8be65b..1cdb595f1 100644 --- a/app/services/google_spreadsheet_fetcher.rb +++ b/app/services/google_spreadsheet_fetcher.rb @@ -1,14 +1,12 @@ -class GoogleSpreadsheetFetcher +class GoogleSpreadsheetFetcher < ApplicationService attr_reader :spreadsheet_id, :range, :has_headers OOB_URI = "urn:ietf:wg:oauth:2.0:oob".freeze TOKEN_PATH = Rails.root.join("config/google_api.yml") - def initialize(spreadsheet_id, range, opts = {}) - @spreadsheet_id = spreadsheet_id - @range = range - @has_headers = opts[:headers].nil? ? true : opts[:headers] - end + param :spreadsheet_id + param :range + option :opts, optional: true, default: -> { {} } def call service.authorization = authorize @@ -75,4 +73,8 @@ def authorize base_url: OOB_URI ) end + + def has_headers + @has_headers = opts[:headers].nil? ? true : opts[:headers] + end end diff --git a/app/services/id3_tag_service.rb b/app/services/id3_tag_service.rb index 3b317af00..4725dc43c 100644 --- a/app/services/id3_tag_service.rb +++ b/app/services/id3_tag_service.rb @@ -1,18 +1,15 @@ require "mp3info" -class Id3TagService < BaseService +class Id3TagService < ApplicationService param :track - attr_reader :show - def call - @show = track.show apply_default_tags reattach_modified_audio_file rescue ActiveStorage::FileNotFoundError => e - # puts "File not found: #{e.message}" # For dev env + Rails.logger.error "File not found: #{e.message}" ensure - @temp_audio_file&.close! # Clean up Tempfile + @temp_audio_file&.close! end private @@ -90,4 +87,8 @@ def artist def album @album ||= "#{show.date} #{show.venue_name}" end + + def show + @show ||= track.show + end end diff --git a/app/services/interactive_cover_art_service.rb b/app/services/interactive_cover_art_service.rb index 84bc10fd1..7d6fb587f 100644 --- a/app/services/interactive_cover_art_service.rb +++ b/app/services/interactive_cover_art_service.rb @@ -1,4 +1,4 @@ -class InteractiveCoverArtService < BaseService +class InteractiveCoverArtService < ApplicationService include ActionView::Helpers::TextHelper class InterruptError < StandardError; end diff --git a/app/services/jamcharts_importer.rb b/app/services/jamcharts_importer.rb index 9bc530e4a..56e313ca5 100644 --- a/app/services/jamcharts_importer.rb +++ b/app/services/jamcharts_importer.rb @@ -1,19 +1,18 @@ -class JamchartsImporter +class JamchartsImporter < ApplicationService include ActionView::Helpers::SanitizeHelper BASE_URL = "https://api.phish.net/v5".freeze API_KEY = ENV.fetch("PNET_API_KEY", nil) - attr_reader :api_key, :invalid_items, :missing_shows, :matched_ids + attr_reader :invalid_items, :missing_shows, :matched_ids - def initialize(api_key) - @api_key = api_key - end + param :api_key def call @invalid_items = [] @missing_shows = [] @matched_ids = [] + sync_jamcharts end diff --git a/app/services/meta_tag_service.rb b/app/services/meta_tag_service.rb index 00e926a92..a4e930e92 100644 --- a/app/services/meta_tag_service.rb +++ b/app/services/meta_tag_service.rb @@ -1,4 +1,4 @@ -class MetaTagService < BaseService +class MetaTagService < ApplicationService param :path TITLE_SUFFIX = " - #{App.app_name}" diff --git a/app/services/search_service.rb b/app/services/search_service.rb index 935b4eafc..0f5760efa 100644 --- a/app/services/search_service.rb +++ b/app/services/search_service.rb @@ -1,4 +1,4 @@ -class SearchService < BaseService +class SearchService < ApplicationService param :term param :scope, default: proc { "all" } diff --git a/app/services/show_importer/cli.rb b/app/services/show_importer/cli.rb index 21c843850..2c62633fa 100644 --- a/app/services/show_importer/cli.rb +++ b/app/services/show_importer/cli.rb @@ -4,7 +4,7 @@ class ShowImporter::Cli attr_reader :orch def initialize(date) - puts "Preparing #{date}" + puts "🗓️ Preparing #{date}" @orch = ShowImporter::Orchestrator.new(date) ShowImporter::TrackReplacer.new(date) && return if orch.show_found @@ -15,7 +15,7 @@ def initialize(date) def main_menu print_header orch.pp_list - puts "\n\nTrack #, (f)ilenames, (l)ist, (i)nsert, (d)elete, (s)ave, e(x)it: " + puts "\n\nTrack #, (f)ilenames, (l)ist, (i)nsert, (d)elete, (s)ave, e(x)it" end def print_header @@ -26,14 +26,14 @@ def print_header def print_show_title puts \ - "🏟 #{orch.show.date} - #{orch.show.venue.name_on(orch.show.date)} " \ + "📍 #{orch.show.date} - #{orch.show.venue.name_on(orch.show.date)} " \ "- #{orch.show.venue.location}\n" end def print_notes notes = orch.show.taper_notes&.encode! \ "UTF-8", "binary", invalid: :replace, undef: :replace, replace: "" - puts "📒 Taper Notes: #{pluralize(notes.split("\n").size, 'line')}" if notes.present? + puts "📝 Taper Notes: #{pluralize(notes.split("\n").size, 'line')}" if notes.present? puts "\n" end @@ -62,7 +62,7 @@ def help_str # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength def process_pos(pos) - while (line = Readline.readline("➡ ", false)) + while (line = Readline.readline("👉 ", false)) case line.downcase when "u" puts( @@ -93,20 +93,18 @@ def process_pos(pos) # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength def insert_new_track - puts "Before track #:" - line = Readline.readline("➡ ", true) + puts + line = Readline.readline("Before track # 👉 ", true) orch.insert_before(line.to_i) end def delete_track - puts "Delete track #:" - line = Readline.readline("➡ ", true) + line = Readline.readline("Delete track # 👉 ", true) orch.delete(line.to_i) end def update_song_for_pos(pos) - puts "Enter exact song title:" - line = Readline.readline("➡ ", true) + line = Readline.readline("Song title 👉 ", true) matched = orch.fm.find_song(line, exact: true) if matched puts "Found \"#{matched.title}\". Adding Song." @@ -117,23 +115,20 @@ def update_song_for_pos(pos) end def update_title_for_pos(pos) - puts "Enter new title:" - line = Readline.readline("➡ ", true) + line = Readline.readline("Title 👉 ", true) orch.get_track(pos).title = line puts end def update_set_for_pos(pos) - puts "Enter new set abbrev [S,1,2,3,4,E,E2,E3]:" - line = Readline.readline("➡ ", true) + line = Readline.readline("Set [S,1,2,3,4,E,E2,E3] 👉 ", true) orch.get_track(pos).set = line puts end def update_file_for_pos(pos) # rubocop:disable Metrics/MethodLength - puts "Choose a file:" filenames = print_filenames - while (line = Readline.readline("1-#{filenames.length} ➡ ")) + while (line = Readline.readline("File 1-#{filenames.length} 👉 ")) choice = line.to_i next unless choice.positive? new_filename = filenames[choice - 1] diff --git a/app/services/show_importer/orchestrator.rb b/app/services/show_importer/orchestrator.rb index c6f727f78..985a36c41 100644 --- a/app/services/show_importer/orchestrator.rb +++ b/app/services/show_importer/orchestrator.rb @@ -183,6 +183,7 @@ def save_track(track) io: File.open("#{@fm.dir}/#{track.filename}"), filename: track.filename, content_type: "audio/mpeg" + track.process_mp3_audio end def populate_tracks diff --git a/app/services/show_importer/track_replacer.rb b/app/services/show_importer/track_replacer.rb index e2ca17a12..85a175fab 100644 --- a/app/services/show_importer/track_replacer.rb +++ b/app/services/show_importer/track_replacer.rb @@ -1,5 +1,3 @@ -require "highline" - class ShowImporter::TrackReplacer attr_reader :date, :track_hash @@ -11,7 +9,7 @@ def initialize(date) ensure_tracks_present ensure_all_tracks_matched - replace_audio_on_tracks if HighLine.new.ask(question) == "Y" + replace_audio_on_tracks if prompt_for_replacement == "Y" end def match_files_to_tracks @@ -25,6 +23,11 @@ def match_files_to_tracks private + def prompt_for_replacement + print "#{question} " + gets.strip.upcase + end + def question "❓ #{date} already imported, replace track data? [Y/n]" end @@ -40,7 +43,7 @@ def replace_audio_on_tracks track_hash.sort_by { |_k, v| v.position } .each do |filename, track| - track.update!(audio_file: File.open(filename)) + track.mp3_audio.attach(io: File.open(filename), filename: File.basename(filename)) pbar.increment end pbar.finish diff --git a/app/services/syncable.rb b/app/services/syncable.rb deleted file mode 100644 index 8bdbc93a2..000000000 --- a/app/services/syncable.rb +++ /dev/null @@ -1,32 +0,0 @@ -module Syncable - private - - def seconds_or_nil(str) - return if str.blank? - min, sec = str.split(":") - (min.to_i * 60) + sec.to_i - end - - def find_track_by_url(url) - Track.find_by( - slug: track_slug(url), - show: show_from_url(url) - ) - end - - def show_from_url(url) - Show.published.find_by(date: show_slug(url)) - end - - def path_segments(url) - url.split("/") - end - - def track_slug(url) - path_segments(url).last - end - - def show_slug(url) - path_segments(url)[-2] - end -end diff --git a/app/services/track_attachment_service.rb b/app/services/track_attachment_service.rb deleted file mode 100644 index 0cd939393..000000000 --- a/app/services/track_attachment_service.rb +++ /dev/null @@ -1,28 +0,0 @@ -class TrackAttachmentService < BaseService - param :track - - def call - convert_attachment(track.audio_file, :mp3_audio, "mp3") - convert_attachment(track.waveform_png, :png_waveform, "png") - end - - private - - def convert_attachment(shrine_attachment, active_storage_attachment, ext) - return if track.public_send(active_storage_attachment).attached? - return unless shrine_attachment&.exists? - - # Attach file to ActiveStorage - track.public_send(active_storage_attachment).attach \ - io: shrine_attachment.download, - filename: filename(ext), - content_type: shrine_attachment.mime_type - - # Delete Shrine attachment if ActiveStorage attachment is successful - # shrine_attachment.delete if track.public_send(active_storage_attachment).attached? - end - - def filename(ext) - "#{track.show.date} - #{format('%02d', track.position)} - #{track.title}.#{ext}" - end -end diff --git a/app/services/track_inserter.rb b/app/services/track_inserter.rb index d598979ef..e50bb58d2 100644 --- a/app/services/track_inserter.rb +++ b/app/services/track_inserter.rb @@ -17,7 +17,6 @@ def initialize(opts = {}) def call shift_track_positions insert_new_track - update_show_duration end private @@ -34,20 +33,16 @@ def show end def insert_new_track - track = Track.new( + track = Track.new \ show:, title:, songs: [ Song.find(song_id) ], position:, set: - ) track.slug = slug if slug.present? - track.save!(validate: false) # Generate ID for audio_file storage - track.update!(audio_file: File.open(file)) - end - - def update_show_duration - show.save_duration + track.save! + track.mp3_audio.attach(io: File.open(file), filename: File.basename(file)) + track.process_mp3_audio end def ensure_valid_options diff --git a/app/services/track_slug_generator.rb b/app/services/track_slug_generator.rb index 868e8df32..f9e3ee1f3 100644 --- a/app/services/track_slug_generator.rb +++ b/app/services/track_slug_generator.rb @@ -1,9 +1,5 @@ -class TrackSlugGenerator - attr_reader :track - - def initialize(track) - @track = track - end +class TrackSlugGenerator < ApplicationService + param :track def call unique_slug_scoped_to_show diff --git a/app/services/track_tag_sync_service.rb b/app/services/track_tag_sync_service.rb index 0d7a5f9f0..f9cda69b2 100644 --- a/app/services/track_tag_sync_service.rb +++ b/app/services/track_tag_sync_service.rb @@ -1,26 +1,29 @@ require "csv" -class TrackTagSyncService +class TrackTagSyncService < ApplicationService include ActionView::Helpers::SanitizeHelper - include Syncable - attr_reader :tag, :data, :track, :created_ids, :updated_ids, :dupes, :missing_tracks + attr_reader :track, :created_ids, :updated_ids, :missing_tracks - def initialize(tag_name, data) - @data = data - @tag = Tag.find_by!(name: tag_name) + param :tag_name + param :data + + def call + @track = nil @missing_tracks = [] @created_ids = [] @updated_ids = [] - end - def call sync_track_tags print_summary end private + def tag + @tag ||= Tag.find_by!(name: tag_name) + end + def print_errors return if missing_tracks.none? @@ -39,7 +42,7 @@ def print_summary def sync_track_tags data.each do |row| - @track = find_track_by_url(row["URL"]) + @track = Track.by_url(row["URL"]) existing = existing_track_tag(row) existing ? update_track_tag(existing, row) : create_track_tag(row) end @@ -89,4 +92,10 @@ def update_track_tag(track_tag, row) ) @updated_ids << track_tag.id end + + def seconds_or_nil(str) + return if str.blank? + min, sec = str.split(":") + (min.to_i * 60) + sec.to_i + end end diff --git a/app/services/user_jwt_service.rb b/app/services/user_jwt_service.rb index 0126b0aed..81567f0cb 100644 --- a/app/services/user_jwt_service.rb +++ b/app/services/user_jwt_service.rb @@ -1,4 +1,4 @@ -class UserJwtService < BaseService +class UserJwtService < ApplicationService param :user def call diff --git a/app/services/waveform_image_service.rb b/app/services/waveform_image_service.rb index 5d1b7a645..673af08d8 100644 --- a/app/services/waveform_image_service.rb +++ b/app/services/waveform_image_service.rb @@ -1,9 +1,5 @@ -class WaveformImageService - attr_reader :track - - def initialize(track) - @track = track - end +class WaveformImageService < ApplicationService + param :track def call create_temp_mp3_file diff --git a/app/uploaders/audio_file_uploader.rb b/app/uploaders/audio_file_uploader.rb deleted file mode 100644 index b2eb4fb07..000000000 --- a/app/uploaders/audio_file_uploader.rb +++ /dev/null @@ -1,5 +0,0 @@ -class AudioFileUploader < PhishinUploader - def generate_location(_io, record: nil, _name: nil, **) - "#{partition_path(record)}/#{record.id}.mp3" - end -end diff --git a/app/uploaders/phishin_uploader.rb b/app/uploaders/phishin_uploader.rb deleted file mode 100644 index 1bd7bfe9f..000000000 --- a/app/uploaders/phishin_uploader.rb +++ /dev/null @@ -1,8 +0,0 @@ -class PhishinUploader < Shrine - protected - - # Example: ID 34123 => 000/034/123 - def partition_path(record) - record.id.to_s.rjust(9, "0").gsub(/(.{3})(?=.)/, '\1/\2') - end -end diff --git a/app/uploaders/waveform_png_uploader.rb b/app/uploaders/waveform_png_uploader.rb deleted file mode 100644 index e260c3465..000000000 --- a/app/uploaders/waveform_png_uploader.rb +++ /dev/null @@ -1,5 +0,0 @@ -class WaveformPngUploader < PhishinUploader - def generate_location(_io, record: nil, _name: nil, **) - "#{partition_path(record)}/waveform-#{record.id}.png" - end -end diff --git a/app/views/layouts/application.html.slim b/app/views/layouts/application.html.slim index 39b346c8a..b0527e637 100644 --- a/app/views/layouts/application.html.slim +++ b/app/views/layouts/application.html.slim @@ -8,8 +8,6 @@ html = javascript_pack_tag "application" = stylesheet_pack_tag "application" = render "layouts/meta" - = render "analytics/google" body #root = react_component("App", props: @react_props) - diff --git a/config/initializers/shrine.rb b/config/initializers/shrine.rb deleted file mode 100644 index e7913f32a..000000000 --- a/config/initializers/shrine.rb +++ /dev/null @@ -1,11 +0,0 @@ -require "shrine" -require "shrine/storage/file_system" - -Shrine.storages = { - cache: Shrine::Storage::FileSystem.new("tmp/cache"), - store: Shrine::Storage::FileSystem.new(App.content_path, prefix: "tracks/audio_files") -} - -Shrine.plugin :activerecord -Shrine.plugin :determine_mime_type, analyzer: :marcel -Shrine.plugin :model, cache: false diff --git a/config/initializers/sidekiq.rb b/config/initializers/sidekiq.rb index 4ebe7b8ef..7984970ae 100644 --- a/config/initializers/sidekiq.rb +++ b/config/initializers/sidekiq.rb @@ -11,7 +11,5 @@ config.redis = redis_config end -# Disable connection message on rspec runs and rake tasks in prod -if Rails.env.test? || Rails.env.production? - Sidekiq.logger.level = Logger::WARN -end +# Disable spammy connection messages +Sidekiq.logger.level = Logger::WARN diff --git a/lib/tasks/phishnet.rake b/lib/tasks/pnet.rake similarity index 97% rename from lib/tasks/phishnet.rake rename to lib/tasks/pnet.rake index 1bbc91384..a85fc8de2 100644 --- a/lib/tasks/phishnet.rake +++ b/lib/tasks/pnet.rake @@ -1,4 +1,4 @@ -namespace :phishnet do +namespace :pnet do desc 'Populate known dates' task known_dates: :environment do puts 'Fetching known dates from Phish.net API...' @@ -27,7 +27,7 @@ namespace :phishnet do desc 'Sync jamcharts data' task jamcharts: :environment do puts 'Fetching Jamcharts data from Phish.net API...' - JamchartsImporter.new(ENV['PNET_API_KEY']).call + JamchartsImporter.call(ENV['PNET_API_KEY']) end desc 'Sync Unfinished tag from setlist notes' diff --git a/lib/tasks/shows.rake b/lib/tasks/shows.rake index 46dfc90e1..adc724caa 100644 --- a/lib/tasks/shows.rake +++ b/lib/tasks/shows.rake @@ -1,5 +1,5 @@ namespace :shows do - desc "Generate cover prompts, images, and zips for all shows or specific date" + desc "Generate cover art" task art: :environment do date = ENV.fetch("DATE", nil) start_date = ENV.fetch("START_DATE", nil) @@ -20,31 +20,9 @@ namespace :shows do InteractiveCoverArtService.call(rel, pbar) end - desc "Convert Shrine to ActiveStorage" - task shrine: :environment do - start_id = ENV.fetch("START_ID", nil) - - rel = Show.includes(:tracks) - rel = rel.where('id >= ?', start_id) if start_id.present? - - pbar = ProgressBar.create \ - total: rel.count, - format: "%a %B %c/%C %p%% %E" - - rel.find_each do |show| - show.tracks.each do |track| - TrackAttachmentService.call(track) - end - puts "🎉 Attachments converted for #{show.date} / #{show.id}" - pbar.increment - end - - pbar.finish - end - - desc "Insert a track into a show at given position" + desc "Insert a track" task insert_track: :environment do - opts = { + TrackInserter.call \ date: ENV["DATE"], position: ENV["POSITION"], file: ENV["FILE"], @@ -53,13 +31,10 @@ namespace :shows do set: ENV["SET"], is_sbd: ENV["SBD"].present?, slug: ENV["SLUG"] - } - - TrackInserter.new(opts).call puts "Track inserted" end - desc "Import a show" + desc "Import show(s) using PNet API and local MP3 audio files" task import: :environment do require "#{Rails.root}/app/services/show_importer" include ActionView::Helpers::TextHelper @@ -67,7 +42,7 @@ namespace :shows do dates = Dir.entries(App.content_import_path).grep(/\d{4}\-\d{1,2}\-\d{1,2}\z/).sort next puts "❌ No shows found in #{App.content_import_path}" unless dates.any? - puts "🔎 #{pluralize(dates.size, 'folder')} found" + puts "📂 #{pluralize(dates.size, 'folder')} found" dates.each { |date| ShowImporter::Cli.new(date) } end end diff --git a/lib/tasks/songs.rake b/lib/tasks/songs.rake deleted file mode 100644 index 10520ed27..000000000 --- a/lib/tasks/songs.rake +++ /dev/null @@ -1,47 +0,0 @@ -namespace :songs do - desc "Import cover artists from Genius API" - task import_artists: :environment do - relation = Song.where(original: false, artist: nil).order(title: :asc) - pbar = ProgressBar.create( - total: relation.count, - format: "%a %B %c/%C %p%% %E" - ) - - missing_songs = [] - - relation.find_each do |song| - data = search_for_song(song) - song_path = data.response.hits.first&.result&.api_path - next missing_songs << song.title if song_path.blank? - - data = fetch_genius_data(song_path) - artist = data.response.song&.primary_artist&.name - - next missing_songs << sont.title if artist.blank? - - puts "#{song.title} => #{artist}" - song.update!(artist: artist) - - pbar.increment - end - - pbar.finish - end - - def fetch_genius_data(path) - JSON.parse( - Typhoeus.get( - "https://api.genius.com#{path}", - headers: { "Authorization" => "Bearer #{ENV['GENIUS_API_TOKEN']}" } - ).body, - object_class: OpenStruct - ) - end - - def search_for_song(song) - artist = song.original? ? "phish" : song.artist&.downcase - term = CGI.escape("#{song.title} #{artist}".squish) - path = "/search?q=#{term}" - data = fetch_genius_data(path) - end -end diff --git a/lib/tasks/tagin.rake b/lib/tasks/tagin.rake index 49453b276..674df0d25 100644 --- a/lib/tasks/tagin.rake +++ b/lib/tasks/tagin.rake @@ -1,220 +1,56 @@ -require 'google/apis/sheets_v4' -require 'googleauth' -require 'googleauth/stores/file_token_store' -require 'fileutils' -require 'csv' +require "google/apis/sheets_v4" +require "googleauth" +require "googleauth/stores/file_token_store" +require "csv" namespace :tagin do - desc 'Sync data from remote spreadsheet' + desc "Sync data from remote spreadsheet" task sync: :environment do TAGIN_TAGS.each do |tag_name| - puts '========================' + puts "========================" puts " Syncing Tag: #{tag_name}" - puts '========================' - + puts "========================" range = "#{tag_name}!A1:G5000" - data = GoogleSpreadsheetFetcher.new(ENV['TAGIN_GSHEET_ID'], range, headers: true).call - - TrackTagSyncService.new(tag_name, data).call + data = GoogleSpreadsheetFetcher.call(ENV["TAGIN_GSHEET_ID"], range, headers: true) + TrackTagSyncService.call(tag_name, data) end end - desc 'Sync jam_starts_at_second data from spreadsheet' + desc "Sync jam_starts_at_second data from spreadsheet" task jamstart: :environment do - include Syncable - - data = GoogleSpreadsheetFetcher.new(ENV['TAGIN_GSHEET_ID'], "JAMSTART!A1:G5000", headers: true).call + data = GoogleSpreadsheetFetcher.call(ENV["TAGIN_GSHEET_ID"], "JAMSTART!A1:G5000", headers: true) data.each do |row| - @track = find_track_by_url(row['URL']) - next puts "Invalid track: #{row['URL']}" if @track.blank? - @track.update(jam_starts_at_second: seconds_or_nil(row['Starts At'])) - print '.' - end - end - - desc 'Pull data from remote narration spreadsheet' - # Track not found: 1989-08-26 / Fly Famous Mockingbird (incomplete show) - # Track not found: 1990-04-04 / Rhombus Narration (narration not present this show) - # Track not found: 1991-11-10 / Llama (no recording) - # Track not found: 1992-04-04 / Harpua (incomplete show) - task narration: :environment do - SPREADSHEET_ID = '10boHKbXnR7V5qFCUc7rtDVBrFg-jmgoOWQLcLRWdz6o' - SPREADSHEET_RANGE = 'Narration Chart!A1:E200' - - data = GoogleSpreadsheetFetcher.new(SPREADSHEET_ID, SPREADSHEET_RANGE).call - - csv_data = - data.map do |d| - date = d['date'] - title = d['song'] - show = Show.find_by(date: date) - track = Track.find_by(show: show, title: title) - next puts "Track not found: #{date} / #{title} :: #{d['summary']}" unless show && track - [track.url, '', '', d['summary']] - end.compact - - CSV.open("#{Rails.root}/tmp/narration.csv", 'w') do |csv| - csv_data.each do |d| - csv << d - end - end - end - - desc 'Tease Chart HTML' - task teases_html: :environment do - URL = 'https://phish.net/tease-chart' - response = Typhoeus.get(URL) - - tag = Tag.find_by(name: 'Tease') - - headers = %i[song artist times dates] - data = [] - Nokogiri.HTML(response.body).search('table').first.search('tr').each_with_index do |tr| - record = {} - tr.search('th, td').each_with_index do |cell, cell_idx| - key = headers[cell_idx] - record[key] = cell.text.strip - end - data << record - end - - csv_data = [] - data.each do |record| - record[:dates].split(',').each do |date_song| - date_song.strip! - next puts "Skipping #{date_song}" unless date_song =~ /\A(\d{4}-\d{2}-\d{2})(.*)\z/ - - date = Regexp.last_match[1].strip - title = Regexp.last_match[2].strip - title = title_abbreviations[title] if title_abbreviations[title] - - show = Show.find_by(date: date) - next puts "Missing show: #{date}" unless show - - track = - Track.where(show: show) - .where( - 'title = ? or title LIKE ? or title LIKE ? or title LIKE ? or title LIKE ?', - title, - "%> #{title}", - "#{title} >%", - "%> #{title} >%", - "#{title}, %" - ).first - next puts "Missing track: #{date} #{title}" unless track - - next if TrackTag.find_by(tag: tag, track: track) - - song = record[:song] - song += " by #{record[:artist]}" unless record[:artist] == 'Phish' - csv_data << [track.url, '', '', song, 'Imported from Phish.net Tease Chart'] - end - end - - CSV.open("#{Rails.root}/tmp/teases_html.csv", 'w') do |csv| - csv_data.each do |d| - csv << d - end - end - - puts "Processed #{csv_data.size} entries" - end - - desc 'Pull data from remote tease spreadsheet' - task teases: :environment do - SPREADSHEET_ID = '1gtR1yVQXA-4hZ2UEfXMl0bvCNLTmDOICHEXElZ1MK9g' - - # SPREADSHEET_RANGE = 'Tease Chart!A2:I1000' - SPREADSHEET_RANGE = 'Timings!A2:I1000' - - data = GoogleSpreadsheetFetcher.new(SPREADSHEET_ID, SPREADSHEET_RANGE, headers: false).call - - csv_data = [] - song = '' - artist = '' - data.each do |d| - if d.first.present? # If `Song` field is blank, refers to previous one - song = d.first - artist = d.second - end - - notes = song - notes += " by #{artist}" if artist.present? && artist != 'Phish' - - (2..8).each do |idx| - next unless d[idx] - - words = d[idx].split(' ') - date_parts = words.first.split('/') - year = date_parts[2].to_i - year = - if year < 10 - "200#{year}" - elsif year < 80 - "20#{year}" - elsif year < 100 - "19#{year}" + track = Track.by_url(row["URL"]) + next puts "Invalid track: #{row['URL']}" if track.blank? + jam_starts_at_second = + if str.include?(":") + min, sec = str.split(":") + (min.to_i * 60) + sec.to_i else - year + nil end - date = Date.parse("#{year}-#{date_parts.first}-#{date_parts.second}") - - # The last word is not always a time (0:32) - starts_at = words.last.include?(':') ? words.last : nil - if starts_at - starts_at = starts_at.split('/').first if starts_at.include?('/') - starts_at = starts_at.tr('*', '') if starts_at.include?('*') - end - last_title_idx = starts_at ? -2 : -1 - - # Title may be abbreviated - title = words[1..last_title_idx].join(' ') - title = title_abbreviations[title] if title_abbreviations[title] - - show = Show.find_by(date: date) - track = - Track.where(show: show) - .where( - 'title = ? or title LIKE ? or title LIKE ? or title LIKE ? or title LIKE ?', - title, - "%> #{title}", - "#{title} >%", - "%> #{title} >%", - "#{title}, %" - ).first - next puts "No match: #{date} / #{title}" unless show && track - - csv_data << [track.url, starts_at, '', notes, 'Imported from Phish.net Tease Chart'] - end - end - csv_data.compact! - - CSV.open("#{Rails.root}/tmp/teases.csv", 'w') do |csv| - csv_data.each do |d| - csv << d - end + track.update!(jam_starts_at_second:) + print "." end - - puts "Processed #{csv_data.size} entries" end - desc 'Calculate Grind days counts' + desc "Calculate Grind days counts" task grind: :environment do include ActionView::Helpers::NumberHelper - first_date = Date.parse('2009-03-06'); + first_date = Date.parse("2009-03-06"); first_days_lived = { - 'Page' => 16_730, - 'Fish' => 16_086, - 'Trey' => 16_228, - 'Mike' => 15_982 + "Page" => 16_730, + "Fish" => 16_086, + "Trey" => 16_228, + "Mike" => 15_982 } csv_data = [] Track.joins(:show) - .where('tracks.title = ?', 'Grind') - .where('shows.date > ?', first_date) - .order('shows.date asc') + .where("tracks.title = ?", "Grind") + .where("shows.date > ?", first_date) + .order("shows.date asc") .each do |track| delta = (track.show.date - first_date).to_i total = 0 @@ -225,266 +61,13 @@ namespace :tagin do end.join("\n") notes += "\nGrand total: #{number_with_delimiter(total)} days" - csv_data << [track.url, '', '', notes] + csv_data << [track.url, "", "", notes] end - CSV.open("#{Rails.root}/tmp/grind.csv", 'w') do |csv| + CSV.open("#{Rails.root}/tmp/grind.csv", "w") do |csv| csv_data.each do |d| csv << d end end end - - def title_abbreviations - { - "'A' Train" => "Take the 'A' Train", - "1st Alumni" => "Alumni Blues", - "1st Antelope" => "Run Like an Antelope", - "1st Ass Handed" => "Ass Handed", - "1st BBFCFM" => "Big Black Furry Creature from Mars", - "1st Bowie" => "David Bowie", - "1st CDT" => "Chalk Dust Torture", - "1st Crosseyed" => "Crosseyed and Painless", - "1st DWD" => "Down with Disease", - "1st HYHU" => "Hold Your Head Up", - "1st Love You" => "Love You", - "1st Mikes" => "Mike's Song", - "1st Mr. Completely" => "Mr. Completely", - "1st Seven Below" => "Sevent Below", - "1st show Bug" => "Bug", - "1st Tweezer" => "Tweezer", - "1st YEM" => "You Enjoy Myself", - "1stAntelope" => "Run Like an Antelope", - "1stASZ" => "Also Sprach Zarathustra", - "1stBowie" => "David Bowie", - "1stCDT" => "Chalk Dust Torture", - "1stCities" => "Cities", - "1stCold As Ice" => "Cold as Ice", - "1stGhost" => "Ghost", - "1stHarpua" => "Harpua", - "1stHydrogen" => "I Am Hydrogen", - "1stHYHU" => "Hold Your Head Up", - "1stKung" => "Kung", - "1stLet's Go" => "Let's Go", - "1stLight" => "Light", - "1stMikes" => "Mike's Song", - "1stMockingbird" => "Fly Famous Mockingbird", - "1stScent" => "Scent of a Mule", - "1stStash" => "Stash", - "1stSuzy" => "Suzy Greenberg", - "1stTweezer" => "Tweezer", - "1stWeekapaug" => "Weekapaug Groove", - "1stYEM" => "You Enjoy Myself", - "2001" => "Also Sprach Zarathustra", - "2nd 20YL" => "Twenty Years Later", - "2nd Bowie" => "David Bowie", - "2nd CDT Reprise" => "Chalk Dust Torture Reprise", - "2nd Ghost" => "Ghost", - "2nd Harpua" => "Harpua", - "2nd Hood" => "Harry Hood", - "2nd HYHU" => "Hold Your Head Up", - "2nd Light" => "Light", - "2nd Martian Monster" => "Martian Monster", - "2nd Terrapin" => "Terrapin", - "2nd Weekapaug" => "Weekapaug Groove", - "2nd YEM" => "You Enjoy Myself", - "2nd Your Pet Cat" => "Your Pet Cat", - "2ndASZ" => "Also Sprach Zarathustra", - "2ndBathtub" => "Bathtub Gin", - "2ndBowie" => "David Bowie", - "2ndCities" => "Cities", - "2ndCold As Ice" => "Cold as Ice", - "2ndDWD" => "Down with Disease", - "2ndHarpua" => "Harpua", - "2ndHood" => "Harry Hood", - "2ndHydrogen" => "I Am Hydrogen", - "2ndHYHU" => "Hold Your Head Up", - "2ndIcculus" => "Icculus", - "2ndKung" => "Kung", - "2ndLight" => "Light", - "2ndMakisupa" => "Makisupa Policeman", - "2ndMockingbird" => "Fly Famous Mockingbird", - "2ndStash" => "Stash", - "2ndSuzy" => "Suzy Greenberg", - "2ndTweezer" => "Tweezer", - "2ndWeekapaug" => "Weekapaug Groove", - "2ndYEM" => "You Enjoy Myself", - "3rd Harpua" => "Harpua", - "3rd Tweezer" => "Tweezer", - "3rdStash" => "Stash", - "500 Miles" => "I'm Gonna Be (500 Miles)", - "ACDCBag" => "AC/DC Bag", - "All The Pain" => "All the Pain Through the Years", - "Alumni" => "Alumni Blues", - "Antelope" => "Run Like an Antelope", - "ASIHTOS" => "A Song I Heard the Ocean Sing", - "ASZ" => "Also Sprach Zarathustra", - "ATrain" => "Take the 'A' Train", - "Axilla II" => "Axilla (Part II)", - "Bag" => "AC/DC Bag", - "Bathtub" => "Bathtub Gin", - "BBCFCM" => "Big Black Furry Creature from Mars", - "BBCFM" => "Big Black Furry Creature from Mars", - "BBFCFM Jam" => "Big Black Furry Creature from Mars", - "BBFCFM" => "Big Black Furry Creature from Mars", - "BBJ" => "Big Ball Jam", - "BDTNL" => "Backwards Down the Number Line", - "Big Black Furry Creature from Mars" => "Big Black Furry Creature from Mars", - "Big Black Furry Creatures from Mars" => "Big Black Furry Creature from Mars", - "Billie Jean Jam" => "Billie Jean", - "Bittersweet" => "Bittersweet Motel", - "BOAF" => "Birds of a Feather", - "Boogie On" => "Boogie On Reggae Woman", - "Boogie" => "Boogie On Reggae Woman", - "BOTT" => "Back on the Train", - "Bouncin" => "Bouncing Around the Room", - "Bouncin'" => "Bouncing Around the Room", - "Bowie" => "David Bowie", - "Buried" => "Buried Alive", - "C&P" => "Crosseyed and Painless", - "Camel" => "Camel Walk", - "Cantaloupe" => "Roll Like a Cantaloupe", - "Caspian" => "Prince Caspian", - "CDT" => "Chalk Dust Torture", - "Chalk Dust" => "Chalk Dust Torture", - "Chalkdust" => "Chalk Dust Torture", - "Character" => "Character Zero", - "Chracter" => "Character Zero", - "Coil" => "The Squirming Coil", - "Cold As Ice" => "Cold as Ice", - "Crosseyed" => "Crosseyed and Painless", - "CTB" => "Cars Trucks Buses", - "Curtain With" => "The Curtain With", - "Curtis Loew" => "The Ballad of Curtis Loew", - "DDLJ" => "Digital Delay Loop Jam", - "Dear Mrs Reagan" => "Dear Mrs. Reagan", - "DEG" => "Dave's Energy Guide", - "Dinner" => "Dinner and a Movie", - "Divided" => "Divided Sky", - "DWD Jam" => "Down with Disease", - "DWD" => "Down with Disease", - "DwD" => "Down with Disease", - "DWDReprise" => "Down with Disease", # 1996-11-27 !! it's the second one - "Feats" => "Feats Don't Fail Me Now", - "Feel The Heat" => "Feel the Heat", - "FEFY" => "Fast Enough for You", - "Funky" => "Funky Bitch", - "FYF" => "Fuck Your Face", - "Gin" => "Bathtub Gin", - "Golgi" => "Golgi Apparatus", - "Great Gig in the Sky" => "The Great Gig in the Sky", - "Great Gig" => "The Great Gig in the Sky", - "GTBT" => "Good Times Bad Times", - "Guelah" => "Guelah Papyrus", - "GuyForget" => "Guy Forget", - "HaHaHa" => "Ha Ha Ha", - "Halfway" => "Halfway to the Moon", - "Halley's" => "Halley's Comet", - "Halleys" => "Halley's Comet", - "Happy Birthday" => "Happy Birthday to You", - "Heavy" => "Heavy Things", - "Highway" => "Highway to Hell", - "Hole" => "In a Hole", - "Hood" => "Harry Hood", - "Horse" => "The Horse", - "Houses" => "Houses in Motion", - "Hydrogen" => "I Am Hydrogen", - "HYHU" => "Hold Your Head Up", - "I AM Hydrogen" => "I Am Hydrogen", - "IDK" => "I Didn't Know", - "Its Ice" => "It's Ice", - "JBG" => "Johnny B. Goode", - "Jibboo" => "Gotta Jibboo", - "JJLC" => "Jesus Just Left Chicago", - "KDF" => "Kill Devil Falls", - "LaGrange" => "La Grange", - "Landlady" => "The Landlady", - "Light Up" => "Light Up Or Leave Me Alone", - "Limb" => "Limb By Limb", - "Lizards" => "The Lizards", - "Low Rider Jam" => "Low Rider", - "LxL" => "Limb By Limb", - "Makisupa" => "Makisupa Policeman", - "Mango" => "The Mango Song", - "McGrupp" => "McGrupp and the Watchful Hosemasters", - "Melt" => "Split Open and Melt", - "MFMF" => "My Friend, My Friend", - "Mike's" => "Mike's Song", - "Mikes" => "Mike's Song", - "Mockingbird" => "Fly Famous Mockingbird", - "Moma" => "The Moma Dance", - "Monkey" => "Sleeping Monkey", - "Moose" => "Moose the Mooche", - "Mr P.C." => "Mr. P.C.", - "MSO" => "My Sweet One", - "MTG" => "Melt the Guns", - "Mule" => "Scent of a Mule", - "My Friend My Friend" => "My Friend, My Friend", - "NMINML" => "No Men In No Man's Land", - "Once" => "Once in a Lifetime", - "P.Funk Medley" => "P-Funk Medley", - "Peaches" => "Peaches en Regalia", - "Punch You in the Eye" => "Punch You In the Eye", - "PYITE" => "Punch You In the Eye", - "Quinn" => "Quinn the Eskimo", - "R&R" => "Rock and Roll", - "Rhombus" => "Rhombus Narration", - "Rock And Roll" => "Rock and Roll", - "Rock" => "Rock and Roll", - "Runaway" => "Runaway Jim", - "Sally" => "Sneakin' Sally Through the Alley", - "Sample" => "Sample in a Jar", - "Scent" => "Scent of a Mule", - "Scents" => "Scents and Subtle Sounds", - "Seven" => "Seven Below", - "SevenBelow" => "Seven Below", - "Sevent Below" => "Seven Below", - "Skin It" => "Skin It Back", - "Slave" => "Slave to the Traffic Light", # wokeignore:rule=slave - "SLI" => "Secret Language Instructions", - "Sloth" => "The Sloth", - "Smoke" => "Smoke on the Water", - "Sneakin" => "Sneakin' Sally Through the Alley", - "Sneakin' Sally" => "Sneakin' Sally Through the Alley", - "Sneakin'" => "Sneakin' Sally Through the Alley", - "SOAMelt" => "Split Open and Melt", - "SOAMule" => "Scent of a Mule", - "SOYF" => "Sunshine of Your Feeling", - "STFTFP" => "Stealing Time From the Faulty Plan", - "STTFTFP" => "Stealing Time From the Faulty Plan", - "Subtle" => "Scents and Subtle Sounds", - "Suzy" => "Suzy Greenberg", - "Sweet Emotion Jam" => "Sweet Emotion", - "The Way" => "The Way It Goes", - "Theme from the Bottom" => "Theme From the Bottom", - "Theme" => "Theme From the Bottom", - "Timber Ho" => "Timber (Jerry The Mule)", - "Timber" => "Timber (Jerry The Mule)", - "TMWSIY" => "The Man Who Stepped Into Yesterday", - "Tweeprise" => "Tweezer Reprise", - "Tweezer Reprise Jam" => "Tweezer Reprise", - "Tweezer Reprise" => "Ass Handed Reprise", - "TweezerReprise" => "Tweezer Reprise", - "Twqeezer" => "Tweezer", - "TYL" => "Twenty Years Later", - "Vibration of Life" => "The Vibration of Life", - "Walls" => "Walls of the Cave", - "Walrus" => "I Am the Walrus", - "Wedge" => "The Wedge", - "Weekapaug" => "Weekapaug Groove", - "What's The Use" => "What's the Use?", - "What's the Use" => "What's the Use?", - "Whipping Post Jam" => "Whipping Post", - "Whipping" => "Whipping Post", - "Wolfman's" => "Wolfman's Brother", - "Wolfmans" => "Wolfman's Brother", - "WotC" => "Walls of the Cave", - "WOTC" => "Walls of the Cave", - "WTU?" => "What's the Use?", - "YaMar" => "Ya Mar", - "Yarmouth" => "Yarmouth Road", - "YEM" => "You Enjoy Myself", - "YPC" => "Your Pet Cat", - } - end end diff --git a/lib/tasks/tracks.rake b/lib/tasks/tracks.rake index 73bb5dcae..b3b9b8ed2 100644 --- a/lib/tasks/tracks.rake +++ b/lib/tasks/tracks.rake @@ -15,7 +15,7 @@ namespace :tracks do pbar.finish end - desc "Regenerate waveform images" + desc "Regenerate waveform images (resizing)" task generate_images: :environment do relation = Track.select(:id) pbar = ProgressBar.create( diff --git a/spec/factories/api_request.rb b/spec/factories/api_request.rb deleted file mode 100644 index f7e5ddb3c..000000000 --- a/spec/factories/api_request.rb +++ /dev/null @@ -1,6 +0,0 @@ -FactoryBot.define do - factory :api_request do - api_key - path { '/some/request/path' } - end -end diff --git a/spec/fixtures/textfile.txt b/spec/fixtures/textfile.txt deleted file mode 100644 index e920016b1..000000000 --- a/spec/fixtures/textfile.txt +++ /dev/null @@ -1 +0,0 @@ -I am not an mp3 file \ No newline at end of file diff --git a/spec/models/track_spec.rb b/spec/models/track_spec.rb index 99e6c3639..6aa3bba4b 100644 --- a/spec/models/track_spec.rb +++ b/spec/models/track_spec.rb @@ -111,12 +111,6 @@ end end - it 'provides #save_duration' do - track.save - track.save_duration - expect(track.duration).to eq(2_011) - end - describe '#set_name' do it 'recognizes nil' do track.set = nil diff --git a/spec/models/venue_spec.rb b/spec/models/venue_spec.rb index 4ed2ccd31..2f9aa0dd6 100644 --- a/spec/models/venue_spec.rb +++ b/spec/models/venue_spec.rb @@ -26,11 +26,6 @@ expect(venue.slug).to eq('madison-square-garden') end - # geocoded_by :address - it 'responds to geocode' do - expect(venue).to respond_to(:geocode) - end - describe 'scopes' do describe '#name_starting_with' do let!(:a_venue) { create(:venue, name: 'Allstate Arena') } diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 2eb282557..3f85b952f 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -13,12 +13,9 @@ end RSpec.configure do |config| - ReactOnRails::TestHelper.configure_rspec_to_compile_assets(config) - - # ReactOnRails::TestHelper.configure_rspec_to_compile_assets(config, :requires_webpack_assets) - # config.define_derived_metadata(file_path: %r{spec/features}) do |metadata| - # metadata[:requires_webpack_assets] = true - # end + # Commented to suppress announcement message + # Uncomment to run feature specs remotely + # ReactOnRails::TestHelper.configure_rspec_to_compile_assets(config) config.fixture_paths = [ "#{Rails.root}/spec/fixtures" ] config.use_transactional_fixtures = true diff --git a/spec/services/gap_service_spec.rb b/spec/services/gap_service_spec.rb index 47663a789..5989278d1 100644 --- a/spec/services/gap_service_spec.rb +++ b/spec/services/gap_service_spec.rb @@ -1,7 +1,7 @@ require "rails_helper" RSpec.describe GapService do - subject(:service) { described_class.new(current_show).call } + subject(:service) { described_class.call(current_show) } let!(:venue) { create(:venue, name: "Madison Square Garden") } let!(:known_dates) do diff --git a/spec/services/meta_tag_service_spec.rb b/spec/services/meta_tag_service_spec.rb index 9e8ca3c4e..586bd37ea 100644 --- a/spec/services/meta_tag_service_spec.rb +++ b/spec/services/meta_tag_service_spec.rb @@ -3,7 +3,7 @@ RSpec.describe MetaTagService do let(:title_suffix) { " - #{App.app_name}" } - subject(:service) { described_class.new(path).call } + subject(:service) { described_class.call(path) } context "when the path is root" do let(:path) { "/" } diff --git a/spec/uploaders/audio_file_uploader_spec.rb b/spec/uploaders/audio_file_uploader_spec.rb deleted file mode 100644 index 218fefefa..000000000 --- a/spec/uploaders/audio_file_uploader_spec.rb +++ /dev/null @@ -1,14 +0,0 @@ -require 'rails_helper' - -RSpec.describe AudioFileUploader do - let(:track) do - create(:track, audio_file: File.open("#{Rails.root}/spec/fixtures/audio_file.mp3", 'rb')) - end - let(:audio_file) { track.audio_file } - - it 'extracts metadata' do - expect(audio_file.mime_type).to eq('audio/mpeg') - expect(audio_file.extension).to eq('mp3') - expect(audio_file.size).to be_instance_of(Integer) - end -end