muzak 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
 - data/LICENSE +21 -0
 - data/README.md +38 -0
 - data/bin/muzak +50 -0
 - data/bin/muzakd +32 -0
 - data/lib/muzak.rb +11 -0
 - data/lib/muzak/album.rb +11 -0
 - data/lib/muzak/cmd.rb +18 -0
 - data/lib/muzak/cmd/config.rb +76 -0
 - data/lib/muzak/cmd/index.rb +63 -0
 - data/lib/muzak/cmd/meta.rb +19 -0
 - data/lib/muzak/cmd/player.rb +79 -0
 - data/lib/muzak/cmd/playlist.rb +101 -0
 - data/lib/muzak/const.rb +14 -0
 - data/lib/muzak/index.rb +84 -0
 - data/lib/muzak/instance.rb +47 -0
 - data/lib/muzak/player.rb +13 -0
 - data/lib/muzak/player/mpv.rb +222 -0
 - data/lib/muzak/player/stub_player.rb +69 -0
 - data/lib/muzak/playlist.rb +45 -0
 - data/lib/muzak/plugin.rb +20 -0
 - data/lib/muzak/plugin/cava.rb +44 -0
 - data/lib/muzak/plugin/notify.rb +16 -0
 - data/lib/muzak/plugin/scrobble.rb +81 -0
 - data/lib/muzak/plugin/stub_plugin.rb +25 -0
 - data/lib/muzak/song.rb +44 -0
 - data/lib/muzak/utils.rb +68 -0
 - metadata +85 -0
 
    
        checksums.yaml
    ADDED
    
    | 
         @@ -0,0 +1,7 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ---
         
     | 
| 
      
 2 
     | 
    
         
            +
            SHA1:
         
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 1a171d18242a3650ec6a70d1cedb0bb9e156229c
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 5e5552a3b45cd2ced07e1ff2a79508bd8820dcd6
         
     | 
| 
      
 5 
     | 
    
         
            +
            SHA512:
         
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: b02efb2b8ef6f3d2811cf469267c4e4f183459267c8027794a76ce04a2a08738b588ecfbeef8b091aa737b66b6dcea7a7fceadf348a2ae35747c13bb7b0cab50
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: b49dea00fefd160228bedc48e5b133b46ce781e5630052068f4f2d632db6c73f35201075173bdf873027821b2dd4e107e74df219834b01ae7027b056909b053f
         
     | 
    
        data/LICENSE
    ADDED
    
    | 
         @@ -0,0 +1,21 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            The MIT License (MIT)
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            Copyright (c) 2016 William Woodruff <william @ tuffbizz.com>
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            Permission is hereby granted, free of charge, to any person obtaining a copy
         
     | 
| 
      
 6 
     | 
    
         
            +
            of this software and associated documentation files (the "Software"), to deal
         
     | 
| 
      
 7 
     | 
    
         
            +
            in the Software without restriction, including without limitation the rights
         
     | 
| 
      
 8 
     | 
    
         
            +
            to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
         
     | 
| 
      
 9 
     | 
    
         
            +
            copies of the Software, and to permit persons to whom the Software is
         
     | 
| 
      
 10 
     | 
    
         
            +
            furnished to do so, subject to the following conditions:
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            The above copyright notice and this permission notice shall be included in
         
     | 
| 
      
 13 
     | 
    
         
            +
            all copies or substantial portions of the Software.
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
         
     | 
| 
      
 16 
     | 
    
         
            +
            IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
         
     | 
| 
      
 17 
     | 
    
         
            +
            FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
         
     | 
| 
      
 18 
     | 
    
         
            +
            AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
         
     | 
| 
      
 19 
     | 
    
         
            +
            LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
         
     | 
| 
      
 20 
     | 
    
         
            +
            OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
         
     | 
| 
      
 21 
     | 
    
         
            +
            THE SOFTWARE.
         
     | 
    
        data/README.md
    ADDED
    
    | 
         @@ -0,0 +1,38 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            muzak
         
     | 
| 
      
 2 
     | 
    
         
            +
            =====
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            muzak is an attempt at a metamusic player.
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            It indexes a filesystem tree, providing metadata to a user's preferred media
         
     | 
| 
      
 7 
     | 
    
         
            +
            player. It also provides a pseudo-shell for controlling the indexed files
         
     | 
| 
      
 8 
     | 
    
         
            +
            and the state of the player.
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            ### Screenshot
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            ### Usage
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            Muzak is still a work in process. Don't expect stability or pleasant output.
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            On the command-line:
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
            ```shell
         
     | 
| 
      
 21 
     | 
    
         
            +
            $ ruby -Ilib muzak.rb # flags: --verbose, --debug
         
     | 
| 
      
 22 
     | 
    
         
            +
            muzak> help
         
     | 
| 
      
 23 
     | 
    
         
            +
            ```
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            Daemonized:
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            ```shell
         
     | 
| 
      
 28 
     | 
    
         
            +
            $ ruby -Ilib muzakd.rb
         
     | 
| 
      
 29 
     | 
    
         
            +
            echo "command" > ~/.config/muzak/muzak.fifo
         
     | 
| 
      
 30 
     | 
    
         
            +
            ```
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
            ### TODO
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
            * current indexing/sorting logic is terrible
         
     | 
| 
      
 35 
     | 
    
         
            +
            * index's timestamp should be used for automatic reindexing
         
     | 
| 
      
 36 
     | 
    
         
            +
            * album art logic for `mpv` is funky
         
     | 
| 
      
 37 
     | 
    
         
            +
            * all the documentation
         
     | 
| 
      
 38 
     | 
    
         
            +
            * readline's tab complete is terrible with spaces (maybe use `bond`?)
         
     | 
    
        data/bin/muzak
    ADDED
    
    | 
         @@ -0,0 +1,50 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #!/usr/bin/env ruby
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require "muzak"
         
     | 
| 
      
 4 
     | 
    
         
            +
            require "readline"
         
     | 
| 
      
 5 
     | 
    
         
            +
            require "shellwords"
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            opts = {
         
     | 
| 
      
 8 
     | 
    
         
            +
              debug: ARGV.include?("--debug") || ARGV.include?("-d"),
         
     | 
| 
      
 9 
     | 
    
         
            +
              verbose: ARGV.include?("--verbose") || ARGV.include?("-v"),
         
     | 
| 
      
 10 
     | 
    
         
            +
              batch: ARGV.include?("--batch") || ARGV.include?("-b")
         
     | 
| 
      
 11 
     | 
    
         
            +
            }
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            Thread.abort_on_exception = opts[:debug]
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            muzak = Muzak::Instance.new(opts)
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            COMMANDS = Muzak::Cmd.commands
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            CONFIG_REGEX = /^config-(get)|(set)|(del)/
         
     | 
| 
      
 20 
     | 
    
         
            +
            ARTIST_REGEX = Regexp.union COMMANDS.select{ |c| c =~ /artist/ }.map { |c| /^#{c}/ }
         
     | 
| 
      
 21 
     | 
    
         
            +
            ALBUM_REGEX = Regexp.union COMMANDS.select{ |c| c =~ /album/ }.map { |c| /^#{c}/ }
         
     | 
| 
      
 22 
     | 
    
         
            +
            PLAYLIST_REGEX = /^playlist-(load)|(delete)/
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            comp = proc do |s|
         
     | 
| 
      
 25 
     | 
    
         
            +
              case Readline.line_buffer
         
     | 
| 
      
 26 
     | 
    
         
            +
              when CONFIG_REGEX
         
     | 
| 
      
 27 
     | 
    
         
            +
                muzak.config.keys.grep(Regexp.new(Regexp.escape(s)))
         
     | 
| 
      
 28 
     | 
    
         
            +
              when ARTIST_REGEX
         
     | 
| 
      
 29 
     | 
    
         
            +
                ss = Readline.line_buffer.split(" ")
         
     | 
| 
      
 30 
     | 
    
         
            +
                muzak.index.artists.grep(Regexp.new(Regexp.escape(ss[1..-1].join(" "))))
         
     | 
| 
      
 31 
     | 
    
         
            +
              when ALBUM_REGEX
         
     | 
| 
      
 32 
     | 
    
         
            +
                muzak.index.album_names.grep(Regexp.new(Regexp.escape(s)))
         
     | 
| 
      
 33 
     | 
    
         
            +
              when PLAYLIST_REGEX
         
     | 
| 
      
 34 
     | 
    
         
            +
                Muzak::Playlist.playlist_names.grep(Regexp.new(Regexp.escape(s)))
         
     | 
| 
      
 35 
     | 
    
         
            +
              else
         
     | 
| 
      
 36 
     | 
    
         
            +
                COMMANDS.grep(Regexp.new(Regexp.escape(s)))
         
     | 
| 
      
 37 
     | 
    
         
            +
              end
         
     | 
| 
      
 38 
     | 
    
         
            +
            end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
            Readline.completion_append_character = " "
         
     | 
| 
      
 41 
     | 
    
         
            +
            Readline.completion_proc = comp
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
            # ignore interrupts
         
     | 
| 
      
 44 
     | 
    
         
            +
            trap("INT", "SIG_IGN")
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
            while line = Readline.readline("muzak> ", true)
         
     | 
| 
      
 47 
     | 
    
         
            +
              cmd_argv = Shellwords.split(line) rescue next
         
     | 
| 
      
 48 
     | 
    
         
            +
              next if cmd_argv.empty? || cmd_argv.any?(&:empty?)
         
     | 
| 
      
 49 
     | 
    
         
            +
              muzak.send Muzak::Cmd.resolve_command(cmd_argv.shift), *cmd_argv
         
     | 
| 
      
 50 
     | 
    
         
            +
            end
         
     | 
    
        data/bin/muzakd
    ADDED
    
    | 
         @@ -0,0 +1,32 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #!/usr/bin/env ruby
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require "muzak"
         
     | 
| 
      
 4 
     | 
    
         
            +
            require "shellwords"
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            opts = {
         
     | 
| 
      
 7 
     | 
    
         
            +
              debug: ARGV.include?("--debug") || ARGV.include?("-d"),
         
     | 
| 
      
 8 
     | 
    
         
            +
              verbose: ARGV.include?("--verbose") || ARGV.include?("-v"),
         
     | 
| 
      
 9 
     | 
    
         
            +
              batch: ARGV.include?("--batch") || ARGV.include?("-b")
         
     | 
| 
      
 10 
     | 
    
         
            +
            }
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            Process.daemon unless opts[:debug] || opts[:verbose]
         
     | 
| 
      
 13 
     | 
    
         
            +
            Thread.abort_on_exception = opts[:debug]
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            muzak = Muzak::Instance.new(opts)
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            fifo_path = File.join(Muzak::CONFIG_DIR, "muzak.fifo")
         
     | 
| 
      
 18 
     | 
    
         
            +
            File.delete(fifo_path) if File.exist?(fifo_path) # just in case a previous session died
         
     | 
| 
      
 19 
     | 
    
         
            +
            File.mkfifo(fifo_path)
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            File.open(fifo_path, "r") do |fifo|
         
     | 
| 
      
 22 
     | 
    
         
            +
              loop do
         
     | 
| 
      
 23 
     | 
    
         
            +
                cmd_argv = Shellwords.split(fifo.readline) rescue next
         
     | 
| 
      
 24 
     | 
    
         
            +
                next if cmd_argv.empty? || cmd_argv.any?(&:empty?)
         
     | 
| 
      
 25 
     | 
    
         
            +
                muzak.send Muzak::Cmd.resolve_command(cmd_argv.shift), *cmd_argv
         
     | 
| 
      
 26 
     | 
    
         
            +
              end
         
     | 
| 
      
 27 
     | 
    
         
            +
            end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            # there is definitely a cleaner way to do this.
         
     | 
| 
      
 30 
     | 
    
         
            +
            at_exit do
         
     | 
| 
      
 31 
     | 
    
         
            +
              File.delete(fifo_path) if File.exist?(fifo_path)
         
     | 
| 
      
 32 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/muzak.rb
    ADDED
    
    | 
         @@ -0,0 +1,11 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require_relative "muzak/const"
         
     | 
| 
      
 2 
     | 
    
         
            +
            require_relative "muzak/utils"
         
     | 
| 
      
 3 
     | 
    
         
            +
            require_relative "muzak/plugin"
         
     | 
| 
      
 4 
     | 
    
         
            +
            require_relative "muzak/song"
         
     | 
| 
      
 5 
     | 
    
         
            +
            require_relative "muzak/album"
         
     | 
| 
      
 6 
     | 
    
         
            +
            require_relative "muzak/playlist"
         
     | 
| 
      
 7 
     | 
    
         
            +
            require_relative "muzak/index"
         
     | 
| 
      
 8 
     | 
    
         
            +
            require_relative "muzak/cmd"
         
     | 
| 
      
 9 
     | 
    
         
            +
            require_relative "muzak/player"
         
     | 
| 
      
 10 
     | 
    
         
            +
            require_relative "muzak/instance"
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
    
        data/lib/muzak/album.rb
    ADDED
    
    
    
        data/lib/muzak/cmd.rb
    ADDED
    
    | 
         @@ -0,0 +1,18 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            Dir.glob(File.join(__dir__, "cmd/*")) { |f| require_relative f }
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Muzak
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Cmd
         
     | 
| 
      
 5 
     | 
    
         
            +
                def self.resolve_command(cmd)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  cmd.tr "-", "_"
         
     | 
| 
      
 7 
     | 
    
         
            +
                end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def self.resolve_method(meth)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  meth.to_s.tr "_", "-"
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def self.commands
         
     | 
| 
      
 14 
     | 
    
         
            +
                  commands = instance_methods.map(&:to_s).reject { |m| m.start_with?("_") }
         
     | 
| 
      
 15 
     | 
    
         
            +
                  commands.map { |c| c.tr "_", "-" }
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,76 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "yaml"
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Muzak
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Cmd
         
     | 
| 
      
 5 
     | 
    
         
            +
                def _config_available?
         
     | 
| 
      
 6 
     | 
    
         
            +
                  File.file?(CONFIG_FILE)
         
     | 
| 
      
 7 
     | 
    
         
            +
                end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def _config_loaded?
         
     | 
| 
      
 10 
     | 
    
         
            +
                  !!@config
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def _config_sync
         
     | 
| 
      
 14 
     | 
    
         
            +
                  debug "syncing config hash with #{CONFIG_FILE}"
         
     | 
| 
      
 15 
     | 
    
         
            +
                  File.open(CONFIG_FILE, "w") { |io| io.write @config.to_yaml }
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                def _config_init
         
     | 
| 
      
 19 
     | 
    
         
            +
                  debug "creating a config file in #{CONFIG_FILE}"
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  @config = {
         
     | 
| 
      
 22 
     | 
    
         
            +
                    "music" => File.expand_path("~/music"),
         
     | 
| 
      
 23 
     | 
    
         
            +
                    "player" => "mpv",
         
     | 
| 
      
 24 
     | 
    
         
            +
                  }
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                  Dir.mkdir(CONFIG_DIR) unless Dir.exist?(CONFIG_DIR)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  _config_sync
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                def _config_plugin?(name)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  @config.key?("plugin-#{name}")
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                def config_load
         
     | 
| 
      
 35 
     | 
    
         
            +
                  verbose "loading config from #{CONFIG_FILE}"
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                  @config = YAML::load_file(CONFIG_FILE)
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                def config_set(*args)
         
     | 
| 
      
 41 
     | 
    
         
            +
                  return unless _config_loaded?
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  fail_arity(args, 2)
         
     | 
| 
      
 44 
     | 
    
         
            +
                  key, value = args
         
     | 
| 
      
 45 
     | 
    
         
            +
                  return if key.nil? || value.nil?
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                  debug "setting '#{key}' to '#{value}' in config"
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                  @config[key] = value
         
     | 
| 
      
 50 
     | 
    
         
            +
                  _config_sync
         
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                def config_del(*args)
         
     | 
| 
      
 54 
     | 
    
         
            +
                  return unless _config_loaded?
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                  fail_arity(args, 1)
         
     | 
| 
      
 57 
     | 
    
         
            +
                  key = args.shift
         
     | 
| 
      
 58 
     | 
    
         
            +
                  return if key.nil?
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                  debug "removing '#{key}' from config"
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                  @config.delete(key)
         
     | 
| 
      
 63 
     | 
    
         
            +
                  _config_sync
         
     | 
| 
      
 64 
     | 
    
         
            +
                end
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                def config_get(*args)
         
     | 
| 
      
 67 
     | 
    
         
            +
                  return unless _config_loaded?
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                  fail_arity(args, 1)
         
     | 
| 
      
 70 
     | 
    
         
            +
                  key = args.shift
         
     | 
| 
      
 71 
     | 
    
         
            +
                  return if key.nil?
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                  info "#{key}: #{@config[key]}"
         
     | 
| 
      
 74 
     | 
    
         
            +
                end
         
     | 
| 
      
 75 
     | 
    
         
            +
              end
         
     | 
| 
      
 76 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,63 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Muzak
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Cmd
         
     | 
| 
      
 3 
     | 
    
         
            +
                def _index_available?
         
     | 
| 
      
 4 
     | 
    
         
            +
                  File.file?(INDEX_FILE)
         
     | 
| 
      
 5 
     | 
    
         
            +
                end
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                def _index_loaded?
         
     | 
| 
      
 8 
     | 
    
         
            +
                  !!@index
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                def _index_sync
         
     | 
| 
      
 12 
     | 
    
         
            +
                  debug "syncing index hash with #{INDEX_FILE}"
         
     | 
| 
      
 13 
     | 
    
         
            +
                  File.open(INDEX_FILE, "w") { |io| io.write @index.hash.to_yaml }
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                def index_load
         
     | 
| 
      
 17 
     | 
    
         
            +
                  debug "loading index from #{INDEX_FILE}"
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                  @index = Index.load_index(INDEX_FILE)
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                def index_build(*args)
         
     | 
| 
      
 23 
     | 
    
         
            +
                  warn_arity(args, 0)
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                  @index = Index.new(@config["music"])
         
     | 
| 
      
 26 
     | 
    
         
            +
                  _index_sync
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                def list_artists(*args)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  return unless _index_loaded?
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                  warn_arity(args, 0)
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                  puts @index.artists.join("\n")
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                def list_albums(*args)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  return unless _index_loaded?
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                  warn_arity(args, 0)
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                  puts @index.album_names.join("\n")
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                def albums_by_artist(*args)
         
     | 
| 
      
 46 
     | 
    
         
            +
                  return unless _index_loaded?
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                  artist = args.join(" ")
         
     | 
| 
      
 49 
     | 
    
         
            +
                  return if artist.nil?
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                  puts @index.albums_by(artist).keys
         
     | 
| 
      
 52 
     | 
    
         
            +
                end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                def songs_by_artist(*args)
         
     | 
| 
      
 55 
     | 
    
         
            +
                  return unless _index_loaded?
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                  artist = args.join(" ")
         
     | 
| 
      
 58 
     | 
    
         
            +
                  return if artist.nil?
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                  puts @index.songs_by(artist)
         
     | 
| 
      
 61 
     | 
    
         
            +
                end
         
     | 
| 
      
 62 
     | 
    
         
            +
              end
         
     | 
| 
      
 63 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,19 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Muzak
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Cmd
         
     | 
| 
      
 3 
     | 
    
         
            +
                def help(*args)
         
     | 
| 
      
 4 
     | 
    
         
            +
                  commands = Muzak::Cmd.commands.join(", ")
         
     | 
| 
      
 5 
     | 
    
         
            +
                  info "available commands: #{commands}"
         
     | 
| 
      
 6 
     | 
    
         
            +
                end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                def list_plugins
         
     | 
| 
      
 9 
     | 
    
         
            +
                  plugins = Plugin.plugin_names.join(", ")
         
     | 
| 
      
 10 
     | 
    
         
            +
                  puts "available plugins: #{plugins}"
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def quit
         
     | 
| 
      
 14 
     | 
    
         
            +
                  debug "muzak is quitting..."
         
     | 
| 
      
 15 
     | 
    
         
            +
                  @player.deactivate!
         
     | 
| 
      
 16 
     | 
    
         
            +
                  exit
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
              end
         
     | 
| 
      
 19 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,79 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Muzak
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Cmd
         
     | 
| 
      
 3 
     | 
    
         
            +
                def player_activate
         
     | 
| 
      
 4 
     | 
    
         
            +
                  if @player.running?
         
     | 
| 
      
 5 
     | 
    
         
            +
                    warn "player is already running"
         
     | 
| 
      
 6 
     | 
    
         
            +
                    return
         
     | 
| 
      
 7 
     | 
    
         
            +
                  end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                  @player.activate!
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                def player_deactivate
         
     | 
| 
      
 13 
     | 
    
         
            +
                  warn "player is not running" unless @player.running?
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  # do cleanup even if the player isn't running, just in case
         
     | 
| 
      
 16 
     | 
    
         
            +
                  @player.deactivate!
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                def play
         
     | 
| 
      
 20 
     | 
    
         
            +
                  @player.play
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                def pause
         
     | 
| 
      
 24 
     | 
    
         
            +
                  @player.pause
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                def next
         
     | 
| 
      
 28 
     | 
    
         
            +
                  @player.next_song
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                def previous
         
     | 
| 
      
 32 
     | 
    
         
            +
                  @player.previous_song
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                def enqueue_artist(*args)
         
     | 
| 
      
 36 
     | 
    
         
            +
                  artist = args.join(" ")
         
     | 
| 
      
 37 
     | 
    
         
            +
                  return if artist.nil?
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  album_hashes = @index.albums_by(artist)
         
     | 
| 
      
 40 
     | 
    
         
            +
                  return if album_hashes.empty?
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                  albums = album_hashes.map do |album_name, album_hash|
         
     | 
| 
      
 43 
     | 
    
         
            +
                    Album.new(album_name, album_hash)
         
     | 
| 
      
 44 
     | 
    
         
            +
                  end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                  albums.each do |album|
         
     | 
| 
      
 47 
     | 
    
         
            +
                    @player.enqueue_album album
         
     | 
| 
      
 48 
     | 
    
         
            +
                  end
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                def enqueue_album(*args)
         
     | 
| 
      
 52 
     | 
    
         
            +
                  album_name = args.join(" ")
         
     | 
| 
      
 53 
     | 
    
         
            +
                  return if album_name.nil?
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                  album_hash = @index.albums[album_name]
         
     | 
| 
      
 56 
     | 
    
         
            +
                  return if album_hash.nil?
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                  album = Album.new(album_name, album_hash)
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                  @player.enqueue_album album
         
     | 
| 
      
 61 
     | 
    
         
            +
                end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                def list_queue
         
     | 
| 
      
 64 
     | 
    
         
            +
                  puts @player.list_queue.map(&:title)
         
     | 
| 
      
 65 
     | 
    
         
            +
                end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                def shuffle_queue
         
     | 
| 
      
 68 
     | 
    
         
            +
                  @player.shuffle_queue
         
     | 
| 
      
 69 
     | 
    
         
            +
                end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                def clear_queue
         
     | 
| 
      
 72 
     | 
    
         
            +
                  @player.clear_queue
         
     | 
| 
      
 73 
     | 
    
         
            +
                end
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                def now_playing
         
     | 
| 
      
 76 
     | 
    
         
            +
                  info @player.now_playing.full_title
         
     | 
| 
      
 77 
     | 
    
         
            +
                end
         
     | 
| 
      
 78 
     | 
    
         
            +
              end
         
     | 
| 
      
 79 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,101 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Muzak
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Cmd
         
     | 
| 
      
 3 
     | 
    
         
            +
                def _playlist_file(pname)
         
     | 
| 
      
 4 
     | 
    
         
            +
                  File.join(PLAYLIST_DIR, pname) + ".yml"
         
     | 
| 
      
 5 
     | 
    
         
            +
                end
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                def _playlist_available?(pname)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  File.exist?(_playlist_file(pname))
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                def _playlist_loaded?
         
     | 
| 
      
 12 
     | 
    
         
            +
                  !!@playlist
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                def list_playlists
         
     | 
| 
      
 16 
     | 
    
         
            +
                  Playlist.playlist_names.each do |playlist|
         
     | 
| 
      
 17 
     | 
    
         
            +
                    info playlist
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                def playlist_load(*args)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  fail_arity(args, 1)
         
     | 
| 
      
 23 
     | 
    
         
            +
                  pname = args.shift
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                  if _playlist_available?(pname)
         
     | 
| 
      
 26 
     | 
    
         
            +
                    info "loading playlist '#{pname}'"
         
     | 
| 
      
 27 
     | 
    
         
            +
                    @playlist = Playlist.load_playlist(_playlist_file(pname))
         
     | 
| 
      
 28 
     | 
    
         
            +
                  else
         
     | 
| 
      
 29 
     | 
    
         
            +
                    info "creating playlist '#{pname}'"
         
     | 
| 
      
 30 
     | 
    
         
            +
                    @playlist = Playlist.new(pname, [])
         
     | 
| 
      
 31 
     | 
    
         
            +
                    playlist_sync
         
     | 
| 
      
 32 
     | 
    
         
            +
                  end
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                def playlist_delete(*args)
         
     | 
| 
      
 36 
     | 
    
         
            +
                  fail_arity(args, 1)
         
     | 
| 
      
 37 
     | 
    
         
            +
                  pname = args.shift
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  debug "deleting playist '#{pname}'"
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  File.delete(_playlist_file(pname)) if _playlist_available?(pname)
         
     | 
| 
      
 42 
     | 
    
         
            +
                  @playlist = nil
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                def playlist_sync(*args)
         
     | 
| 
      
 46 
     | 
    
         
            +
                  return unless _playlist_loaded?
         
     | 
| 
      
 47 
     | 
    
         
            +
                  fail_arity(args, 0)
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                  debug "syncing playlist '#{@playlist.name}'"
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                  Dir.mkdir(PLAYLIST_DIR) unless Dir.exist?(PLAYLIST_DIR)
         
     | 
| 
      
 52 
     | 
    
         
            +
                  File.open(_playlist_file(@playlist.name), "w") { |io| io.write @playlist.to_hash.to_yaml }
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                def enqueue_playlist
         
     | 
| 
      
 56 
     | 
    
         
            +
                  return unless _playlist_loaded?
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                  @player.enqueue_playlist(@playlist)
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                def playlist_add_album(*args)
         
     | 
| 
      
 62 
     | 
    
         
            +
                  return unless _playlist_loaded?
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                  album_name = args.join(" ")
         
     | 
| 
      
 65 
     | 
    
         
            +
                  return if album_name.nil?
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                  album_hash = @index.albums[album_name]
         
     | 
| 
      
 68 
     | 
    
         
            +
                  return if album_hash.nil?
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                  album = Album.new(album_name, album_hash)
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                  album.songs.each { |song| @playlist.add song }
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                  playlist_sync
         
     | 
| 
      
 75 
     | 
    
         
            +
                end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                def playlist_add_current
         
     | 
| 
      
 78 
     | 
    
         
            +
                  return unless @player.running? && _playlist_loaded?
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                  @playlist.add @player.now_playing
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                  playlist_sync
         
     | 
| 
      
 83 
     | 
    
         
            +
                end
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                def playlist_del_current
         
     | 
| 
      
 86 
     | 
    
         
            +
                  return unless @player.running? && _playlist_loaded?
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                  @playlist.delete(@player.now_playing)
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                  playlist_sync
         
     | 
| 
      
 91 
     | 
    
         
            +
                end
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
                def playlist_shuffle
         
     | 
| 
      
 94 
     | 
    
         
            +
                  return unless _playlist_loaded?
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                  @playlist.shuffle!
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                  playlist_sync
         
     | 
| 
      
 99 
     | 
    
         
            +
                end
         
     | 
| 
      
 100 
     | 
    
         
            +
              end
         
     | 
| 
      
 101 
     | 
    
         
            +
            end
         
     |