class MusicBox::Catalog
Attributes
albums[RW]
artists[RW]
catalog_dir[RW]
collection[RW]
config[RW]
extract_dir[RW]
extract_done_dir[RW]
groups[RW]
images_dir[RW]
import_dir[RW]
import_done_dir[RW]
masters[RW]
releases[RW]
root_dir[RW]
Public Class Methods
new(root: nil)
click to toggle source
# File lib/musicbox/catalog.rb, line 20 def initialize(root: nil) @root_dir = Path.new(root || ENV['MUSICBOX_ROOT'] || '~/Music/MusicBox').expand_path raise Error, "#{@root_dir} doesn't exist" unless @root_dir.exist? load_config @import_dir = @root_dir / 'import' @import_done_dir = @root_dir / 'import-done' @extract_dir = @root_dir / 'extract' @extract_done_dir = @root_dir / 'extract-done' @catalog_dir = @root_dir / 'catalog' @collection = Collection.new(root: @catalog_dir / 'collection') @releases = Releases.new(root: @catalog_dir / 'releases') @masters = Releases.new(root: @catalog_dir / 'masters') @artists = Artists.new(root: @catalog_dir / 'artists') @albums = Albums.new(root: @catalog_dir / 'albums') @images_dir = @catalog_dir / 'images' link_groups @prompt = TTY::Prompt.new end
Public Instance Methods
artist_keys(artists)
click to toggle source
# File lib/musicbox/catalog.rb, line 68 def artist_keys(artists) keys = {} names = {} non_personal_names = Set.new artists.map { |a| a.kind_of?(ReleaseArtist) ? a : ReleaseArtist.new(name: a) }.each do |artist| non_personal_names << artist.name if artist.name == artist.canonical_name key = artist.key (keys[key] ||= Set.new) << artist.name (names[artist.name] ||= Set.new) << key end { non_personal_names: non_personal_names.sort, keys: keys.sort.map { |k, s| [k, s.to_a] }.to_h, names: names.sort.map { |k, s| [k, s.to_a] }.to_h, } end
categorize_files(dir)
click to toggle source
# File lib/musicbox/catalog.rb, line 179 def categorize_files(dir) categories = {} dir.children.sort.each do |path| type = case (ext = path.extname.downcase) when '.m4a', '.m4p', '.mp3' :audio else ext.delete_prefix('.').to_sym end categories[type] ||= [] categories[type] << path end categories end
dirs_for_args(base_dir, args)
click to toggle source
# File lib/musicbox/catalog.rb, line 194 def dirs_for_args(base_dir, args) if args.empty? dirs = base_dir.children.select(&:dir?) else dirs = args.map { |p| Path.new(p) } end dirs.sort_by { |d| d.to_s.downcase } end
find(*selectors, group: nil, prompt: false, multiple: true)
click to toggle source
# File lib/musicbox/catalog.rb, line 98 def find(*selectors, group: nil, prompt: false, multiple: true) unless group.kind_of?(Group) group = case group&.to_sym when :releases, nil @releases when :masters @masters when :albums @albums else raise Error, "Unknown group: #{group.inspect}" end end ;;puts "searching #{group.items.count} items in #{group.class}" selectors = [selectors].compact.flatten selectors = [':all'] if selectors.empty? selected = [] selectors.each do |selector| case selector.to_s when ':all' selected += group.items when ':recent' selected += group.items.select { |c| (Date.today - c.date_added) < 7 } when ':recently-added' selected += @collection.items.select { |c| (Date.today - c.date_added) < 30 }.map(&:release) when ':multiformat' selected += group.items.select { |r| r.formats&.length > 1 } when ':cd' selected += group.items.select(&:cd?) when ':unripped' selected += group.items.select(&:cd?).reject(&:album) when ':no-cover' selected += group.items.select(&:album).reject { |r| r.album.has_cover? } when ':odd-positions' selected += group.items.select(&:cd?).select { |r| r.tracklist_flattened.find { |t| t.position !~ /^\d+$/ } } when /^-?\d+$/ n = selector.to_i item = group[n.abs] or raise Error, "Can't find item #{selector.inspect} in #{group.class}" if n > 0 selected += [group[n]] else selected -= [group[-n]] end else selected += group.search(query: selector.to_s, fields: [:title, :artists, :id]) end end selected.uniq.sort! if prompt choices = selected.map { |r| [r.to_s, r.id] }.to_h if multiple ids = @prompt.multi_select('Item?', filter: true, per_page: 100, quiet: true) do |menu| # menu.default *(1..choices.length).to_a choices.each do |name, value| menu.choice name, value end end selected = ids.map { |id| group[id] } else id = @prompt.select('Item?', choices, filter: true, per_page: 100, quiet: true) selected = [group[id]] if id end end selected end
find_dups(releases)
click to toggle source
# File lib/musicbox/catalog.rb, line 85 def find_dups(releases) dups = {} releases.select(&:master_id).each do |release| dups[release.master_id] ||= {} #FIXME: wrong release.formats.map(&:name).each do |format_name| dups[release.master_id][format_name] ||= [] dups[release.master_id][format_name] << release end end dups end
link_groups()
click to toggle source
# File lib/musicbox/catalog.rb, line 164 def link_groups @releases.items.each do |release| release.master = @masters[release.master_id] if release.master_id release.artists.each do |release_artist| release_artist.artist = @artists[release_artist.id] end release.album = @albums[release.id] release.link_images(@images_dir) release.master&.link_images(@images_dir) end @collection.items.each do |item| item.release = @releases[item.id] end end
load_config()
click to toggle source
# File lib/musicbox/catalog.rb, line 39 def load_config @config = YAML.load((@root_dir / 'config.yaml').read) ReleaseArtist.class_variable_set(:@@personal_names, @config['personal_names']) ReleaseArtist.class_variable_set(:@@canonical_names, @config['canonical_names']) end
orphaned()
click to toggle source
# File lib/musicbox/catalog.rb, line 45 def orphaned orphaned = %i[releases masters artists albums].map { |k| [k, send(k).items.dup] }.to_h @collection.items.each do |item| release = item.release or raise orphaned[:releases].delete(release) orphaned[:masters].delete(release.master) if release.master release.artists.each do |release_artist| orphaned[:artists].delete(release_artist.artist) end orphaned[:albums].delete(release.album) if release.album end orphaned end
orphaned_images()
click to toggle source
# File lib/musicbox/catalog.rb, line 59 def orphaned_images all_files = [@releases, @masters].map do |group| group.items.select(&:images).map do |release| release.images.map { |image| image['file'].basename.to_s } end end.flatten.compact @images_dir.children.map(&:basename).map(&:to_s) - all_files end