soundcloud9000 0.1.0
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/.gitignore +5 -0
 - data/Gemfile +4 -0
 - data/LICENSE +7 -0
 - data/README.md +65 -0
 - data/Rakefile +46 -0
 - data/bin/soundcloud9000 +9 -0
 - data/lib/soundcloud9000.rb +22 -0
 - data/lib/soundcloud9000/application.rb +93 -0
 - data/lib/soundcloud9000/client.rb +51 -0
 - data/lib/soundcloud9000/controllers/controller.rb +19 -0
 - data/lib/soundcloud9000/controllers/player_controller.rb +75 -0
 - data/lib/soundcloud9000/controllers/track_controller.rb +90 -0
 - data/lib/soundcloud9000/download_thread.rb +51 -0
 - data/lib/soundcloud9000/events.rb +17 -0
 - data/lib/soundcloud9000/models/collection.rb +42 -0
 - data/lib/soundcloud9000/models/player.rb +138 -0
 - data/lib/soundcloud9000/models/playlist.rb +22 -0
 - data/lib/soundcloud9000/models/track.rb +56 -0
 - data/lib/soundcloud9000/models/track_collection.rb +71 -0
 - data/lib/soundcloud9000/models/user.rb +26 -0
 - data/lib/soundcloud9000/time_helper.rb +23 -0
 - data/lib/soundcloud9000/ui/canvas.rb +21 -0
 - data/lib/soundcloud9000/ui/color.rb +46 -0
 - data/lib/soundcloud9000/ui/input.rb +56 -0
 - data/lib/soundcloud9000/ui/rect.rb +14 -0
 - data/lib/soundcloud9000/ui/table.rb +132 -0
 - data/lib/soundcloud9000/ui/view.rb +73 -0
 - data/lib/soundcloud9000/views/player_view.rb +63 -0
 - data/lib/soundcloud9000/views/splash.rb +69 -0
 - data/lib/soundcloud9000/views/tracks_table.rb +14 -0
 - data/soundcloud9000 +8 -0
 - data/soundcloud9000.gemspec +27 -0
 - data/spec/controllers/track_controller_spec.rb +59 -0
 - data/spec/spec_helper.rb +2 -0
 - metadata +165 -0
 
| 
         @@ -0,0 +1,51 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'net/https'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require_relative 'events'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module Soundcloud9000
         
     | 
| 
      
 5 
     | 
    
         
            +
              class DownloadThread
         
     | 
| 
      
 6 
     | 
    
         
            +
                attr_reader :events, :url, :progress, :total, :file
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                def initialize(url, filename)
         
     | 
| 
      
 9 
     | 
    
         
            +
                  @events = Events.new
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @url = URI.parse(url)
         
     | 
| 
      
 11 
     | 
    
         
            +
                  @file = File.open(filename, "w")
         
     | 
| 
      
 12 
     | 
    
         
            +
                  @progress = 0
         
     | 
| 
      
 13 
     | 
    
         
            +
                  start!
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                def log(s)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  Soundcloud9000::Application.logger.debug("DownloadThread #{s}")
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                def start!
         
     | 
| 
      
 21 
     | 
    
         
            +
                  Thread.start do
         
     | 
| 
      
 22 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 23 
     | 
    
         
            +
                      log :start
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                      http = Net::HTTP.new(url.host, url.port)
         
     | 
| 
      
 26 
     | 
    
         
            +
                      http.use_ssl = true
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                      http.request(Net::HTTP::Get.new(url.request_uri)) do |res|
         
     | 
| 
      
 29 
     | 
    
         
            +
                        log "response: #{res.code}"
         
     | 
| 
      
 30 
     | 
    
         
            +
                        raise res.body if res.code != '200'
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                        @total = res.header['Content-Length'].to_i
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                        res.read_body do |chunk|
         
     | 
| 
      
 35 
     | 
    
         
            +
                          @progress += chunk.size
         
     | 
| 
      
 36 
     | 
    
         
            +
                          @file << chunk
         
     | 
| 
      
 37 
     | 
    
         
            +
                          @file.close if @progress == @total
         
     | 
| 
      
 38 
     | 
    
         
            +
                        end
         
     | 
| 
      
 39 
     | 
    
         
            +
                      end
         
     | 
| 
      
 40 
     | 
    
         
            +
                    rescue => e
         
     | 
| 
      
 41 
     | 
    
         
            +
                      log e.message
         
     | 
| 
      
 42 
     | 
    
         
            +
                    end
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                  sleep 0.1 while @total.nil?
         
     | 
| 
      
 46 
     | 
    
         
            +
                  sleep 0.1
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                  self
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
              end
         
     | 
| 
      
 51 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,17 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Soundcloud9000
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Events
         
     | 
| 
      
 3 
     | 
    
         
            +
                def initialize
         
     | 
| 
      
 4 
     | 
    
         
            +
                  @handlers = Hash.new { |h, k| h[k] = [] }
         
     | 
| 
      
 5 
     | 
    
         
            +
                end
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                def on(event, &block)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  @handlers[event] << block
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                def trigger(event, *args)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  @handlers[event].each do |handler|
         
     | 
| 
      
 13 
     | 
    
         
            +
                    handler.call(*args)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  end
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,42 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require_relative '../events'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Soundcloud9000
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Models
         
     | 
| 
      
 5 
     | 
    
         
            +
                # stores the tracks displayed in the track controller
         
     | 
| 
      
 6 
     | 
    
         
            +
                class Collection
         
     | 
| 
      
 7 
     | 
    
         
            +
                  include Enumerable
         
     | 
| 
      
 8 
     | 
    
         
            +
                  attr_reader :events, :rows, :page
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  def initialize(client)
         
     | 
| 
      
 11 
     | 
    
         
            +
                    @client = client
         
     | 
| 
      
 12 
     | 
    
         
            +
                    @events = Events.new
         
     | 
| 
      
 13 
     | 
    
         
            +
                    clear
         
     | 
| 
      
 14 
     | 
    
         
            +
                  end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                  def [](*args)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    @rows[*args]
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  def clear
         
     | 
| 
      
 21 
     | 
    
         
            +
                    @page = 0
         
     | 
| 
      
 22 
     | 
    
         
            +
                    @rows = []
         
     | 
| 
      
 23 
     | 
    
         
            +
                    @loaded = false
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                  def each(&block)
         
     | 
| 
      
 27 
     | 
    
         
            +
                    @rows.each(&block)
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                  def replace(rows)
         
     | 
| 
      
 31 
     | 
    
         
            +
                    clear
         
     | 
| 
      
 32 
     | 
    
         
            +
                    @rows = rows
         
     | 
| 
      
 33 
     | 
    
         
            +
                    events.trigger(:replace)
         
     | 
| 
      
 34 
     | 
    
         
            +
                  end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                  def append(rows)
         
     | 
| 
      
 37 
     | 
    
         
            +
                    @rows += rows
         
     | 
| 
      
 38 
     | 
    
         
            +
                    events.trigger(:append)
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
                end
         
     | 
| 
      
 41 
     | 
    
         
            +
              end
         
     | 
| 
      
 42 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,138 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'audite'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require_relative '../download_thread'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module Soundcloud9000
         
     | 
| 
      
 5 
     | 
    
         
            +
              module Models
         
     | 
| 
      
 6 
     | 
    
         
            +
                # responsible for drawing and updating the player above tracklist
         
     | 
| 
      
 7 
     | 
    
         
            +
                class Player
         
     | 
| 
      
 8 
     | 
    
         
            +
                  attr_reader :track, :events
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  def initialize
         
     | 
| 
      
 11 
     | 
    
         
            +
                    @track = nil
         
     | 
| 
      
 12 
     | 
    
         
            +
                    @events = Events.new
         
     | 
| 
      
 13 
     | 
    
         
            +
                    @folder = File.expand_path('~/.soundcloud9000')
         
     | 
| 
      
 14 
     | 
    
         
            +
                    @seek_speed = {}
         
     | 
| 
      
 15 
     | 
    
         
            +
                    @seek_time = {}
         
     | 
| 
      
 16 
     | 
    
         
            +
                    create_player
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                    Dir.mkdir(@folder) unless File.exist?(@folder)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  def create_player
         
     | 
| 
      
 22 
     | 
    
         
            +
                    @player = Audite.new
         
     | 
| 
      
 23 
     | 
    
         
            +
                    @player.events.on(:position_change) do
         
     | 
| 
      
 24 
     | 
    
         
            +
                      events.trigger(:progress)
         
     | 
| 
      
 25 
     | 
    
         
            +
                    end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                    @player.events.on(:complete) do
         
     | 
| 
      
 28 
     | 
    
         
            +
                      events.trigger(:complete)
         
     | 
| 
      
 29 
     | 
    
         
            +
                    end
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                  def play(track, location)
         
     | 
| 
      
 33 
     | 
    
         
            +
                    log :play, track.id
         
     | 
| 
      
 34 
     | 
    
         
            +
                    @track = track
         
     | 
| 
      
 35 
     | 
    
         
            +
                    load(track, location)
         
     | 
| 
      
 36 
     | 
    
         
            +
                    start
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  def play_progress
         
     | 
| 
      
 40 
     | 
    
         
            +
                    seconds_played / duration
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  def duration
         
     | 
| 
      
 44 
     | 
    
         
            +
                    @track.duration.to_f / 1000
         
     | 
| 
      
 45 
     | 
    
         
            +
                  end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                  def title
         
     | 
| 
      
 48 
     | 
    
         
            +
                    [@track.title, @track.user.username].join(' - ')
         
     | 
| 
      
 49 
     | 
    
         
            +
                  end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                  def length_in_seconds
         
     | 
| 
      
 52 
     | 
    
         
            +
                    mpg = Mpg123.new(@file)
         
     | 
| 
      
 53 
     | 
    
         
            +
                    mpg.length * mpg.tpf / mpg.spf
         
     | 
| 
      
 54 
     | 
    
         
            +
                  end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                  def load(track, location)
         
     | 
| 
      
 57 
     | 
    
         
            +
                    @file = "#{@folder}/#{track.id}.mp3"
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                    if !File.exist?(@file) || track.duration / 1000 > length_in_seconds * 0.95
         
     | 
| 
      
 60 
     | 
    
         
            +
                      File.unlink(@file) rescue nil
         
     | 
| 
      
 61 
     | 
    
         
            +
                      @download = DownloadThread.new(location, @file)
         
     | 
| 
      
 62 
     | 
    
         
            +
                    else
         
     | 
| 
      
 63 
     | 
    
         
            +
                      @download = nil
         
     | 
| 
      
 64 
     | 
    
         
            +
                    end
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                    @player.load(@file)
         
     | 
| 
      
 67 
     | 
    
         
            +
                  end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                  def log(*args)
         
     | 
| 
      
 70 
     | 
    
         
            +
                    Soundcloud9000::Application.logger.debug 'Player: ' + args.join(' ')
         
     | 
| 
      
 71 
     | 
    
         
            +
                  end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                  def level
         
     | 
| 
      
 74 
     | 
    
         
            +
                    @player.level
         
     | 
| 
      
 75 
     | 
    
         
            +
                  end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                  def seconds_played
         
     | 
| 
      
 78 
     | 
    
         
            +
                    @player.position
         
     | 
| 
      
 79 
     | 
    
         
            +
                  end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                  def download_progress
         
     | 
| 
      
 82 
     | 
    
         
            +
                    @download ? @download.progress / @download.total.to_f : 1
         
     | 
| 
      
 83 
     | 
    
         
            +
                  end
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                  def playing?
         
     | 
| 
      
 86 
     | 
    
         
            +
                    @player.active
         
     | 
| 
      
 87 
     | 
    
         
            +
                  end
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                  def seek_speed(direction)
         
     | 
| 
      
 90 
     | 
    
         
            +
                    if @seek_time[direction] && Time.now - @seek_time[direction] < 0.5
         
     | 
| 
      
 91 
     | 
    
         
            +
                      @seek_speed[direction] *= 1.05
         
     | 
| 
      
 92 
     | 
    
         
            +
                    else
         
     | 
| 
      
 93 
     | 
    
         
            +
                      @seek_speed[direction] = 1
         
     | 
| 
      
 94 
     | 
    
         
            +
                    end
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                    @seek_time[direction] =  Time.now
         
     | 
| 
      
 97 
     | 
    
         
            +
                    @seek_speed[direction]
         
     | 
| 
      
 98 
     | 
    
         
            +
                  end
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                  # change song position
         
     | 
| 
      
 101 
     | 
    
         
            +
                  def seek_position(position)
         
     | 
| 
      
 102 
     | 
    
         
            +
                    position *= 0.1
         
     | 
| 
      
 103 
     | 
    
         
            +
                    relative_position = position * duration
         
     | 
| 
      
 104 
     | 
    
         
            +
                    if relative_position < seconds_played
         
     | 
| 
      
 105 
     | 
    
         
            +
                      difference = seconds_played - relative_position
         
     | 
| 
      
 106 
     | 
    
         
            +
                      @player.rewind(difference)
         
     | 
| 
      
 107 
     | 
    
         
            +
                    elsif download_progress > (relative_position / duration) && relative_position > seconds_played
         
     | 
| 
      
 108 
     | 
    
         
            +
                      log download_progress
         
     | 
| 
      
 109 
     | 
    
         
            +
                      difference = relative_position - seconds_played
         
     | 
| 
      
 110 
     | 
    
         
            +
                      @player.forward(difference)
         
     | 
| 
      
 111 
     | 
    
         
            +
                    end
         
     | 
| 
      
 112 
     | 
    
         
            +
                  end
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
      
 114 
     | 
    
         
            +
                  def rewind
         
     | 
| 
      
 115 
     | 
    
         
            +
                    @player.rewind(seek_speed(:rewind))
         
     | 
| 
      
 116 
     | 
    
         
            +
                  end
         
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
                  def forward
         
     | 
| 
      
 119 
     | 
    
         
            +
                    seconds = seek_speed(:forward)
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
                    seek_percentage = (seconds + seconds_played) / duration
         
     | 
| 
      
 122 
     | 
    
         
            +
                    @player.forward(seconds) if seek_percentage < download_progress
         
     | 
| 
      
 123 
     | 
    
         
            +
                  end
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
                  def stop
         
     | 
| 
      
 126 
     | 
    
         
            +
                    @player.stop_stream
         
     | 
| 
      
 127 
     | 
    
         
            +
                  end
         
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
                  def start
         
     | 
| 
      
 130 
     | 
    
         
            +
                    @player.start_stream
         
     | 
| 
      
 131 
     | 
    
         
            +
                  end
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
                  def toggle
         
     | 
| 
      
 134 
     | 
    
         
            +
                    @player.toggle
         
     | 
| 
      
 135 
     | 
    
         
            +
                  end
         
     | 
| 
      
 136 
     | 
    
         
            +
                end
         
     | 
| 
      
 137 
     | 
    
         
            +
              end
         
     | 
| 
      
 138 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,22 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Soundcloud9000
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Models
         
     | 
| 
      
 3 
     | 
    
         
            +
                # stores information on a playlist or set from soundcloud
         
     | 
| 
      
 4 
     | 
    
         
            +
                class Playlist
         
     | 
| 
      
 5 
     | 
    
         
            +
                  def initialize(hash)
         
     | 
| 
      
 6 
     | 
    
         
            +
                    @hash = hash
         
     | 
| 
      
 7 
     | 
    
         
            +
                  end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                  def id
         
     | 
| 
      
 10 
     | 
    
         
            +
                    @hash['id']
         
     | 
| 
      
 11 
     | 
    
         
            +
                  end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                  def title
         
     | 
| 
      
 14 
     | 
    
         
            +
                    @hash['title']
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  def uri
         
     | 
| 
      
 18 
     | 
    
         
            +
                    @hash['uri']
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
              end
         
     | 
| 
      
 22 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,56 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require_relative 'user'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Soundcloud9000
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Models
         
     | 
| 
      
 5 
     | 
    
         
            +
                # stores information for each track that hits the player
         
     | 
| 
      
 6 
     | 
    
         
            +
                class Track
         
     | 
| 
      
 7 
     | 
    
         
            +
                  def initialize(hash)
         
     | 
| 
      
 8 
     | 
    
         
            +
                    @hash = hash
         
     | 
| 
      
 9 
     | 
    
         
            +
                  end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                  def id
         
     | 
| 
      
 12 
     | 
    
         
            +
                    @hash['id']
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  def title
         
     | 
| 
      
 16 
     | 
    
         
            +
                    @hash['title']
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                  def url
         
     | 
| 
      
 20 
     | 
    
         
            +
                    @hash['permalink_url']
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  def user
         
     | 
| 
      
 24 
     | 
    
         
            +
                    @user ||= User.new(@hash['user'])
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  def username
         
     | 
| 
      
 28 
     | 
    
         
            +
                    user.username
         
     | 
| 
      
 29 
     | 
    
         
            +
                  end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                  def duration
         
     | 
| 
      
 32 
     | 
    
         
            +
                    @hash['duration']
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                  def length
         
     | 
| 
      
 36 
     | 
    
         
            +
                    TimeHelper.duration(duration)
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  def plays
         
     | 
| 
      
 40 
     | 
    
         
            +
                    @hash['playback_count']
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  def likes
         
     | 
| 
      
 44 
     | 
    
         
            +
                    @hash['favoritings_count']
         
     | 
| 
      
 45 
     | 
    
         
            +
                  end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                  def comments
         
     | 
| 
      
 48 
     | 
    
         
            +
                    @hash['comments']
         
     | 
| 
      
 49 
     | 
    
         
            +
                  end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                  def stream_url
         
     | 
| 
      
 52 
     | 
    
         
            +
                    @hash['stream_url']
         
     | 
| 
      
 53 
     | 
    
         
            +
                  end
         
     | 
| 
      
 54 
     | 
    
         
            +
                end
         
     | 
| 
      
 55 
     | 
    
         
            +
              end
         
     | 
| 
      
 56 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,71 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require_relative 'collection'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require_relative 'track'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require_relative 'playlist'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module Soundcloud9000
         
     | 
| 
      
 6 
     | 
    
         
            +
              module Models
         
     | 
| 
      
 7 
     | 
    
         
            +
                # This model deals with the different types of tracklists that populate
         
     | 
| 
      
 8 
     | 
    
         
            +
                # the tracklist section
         
     | 
| 
      
 9 
     | 
    
         
            +
                class TrackCollection < Collection
         
     | 
| 
      
 10 
     | 
    
         
            +
                  DEFAULT_LIMIT = 50
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  attr_reader :limit
         
     | 
| 
      
 13 
     | 
    
         
            +
                  attr_accessor :collection_to_load, :user, :playlist
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  def initialize(client)
         
     | 
| 
      
 16 
     | 
    
         
            +
                    super
         
     | 
| 
      
 17 
     | 
    
         
            +
                    @limit = DEFAULT_LIMIT
         
     | 
| 
      
 18 
     | 
    
         
            +
                    @collection_to_load = :recent
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  def size
         
     | 
| 
      
 22 
     | 
    
         
            +
                    @rows.size
         
     | 
| 
      
 23 
     | 
    
         
            +
                  end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                  def clear_and_replace
         
     | 
| 
      
 26 
     | 
    
         
            +
                    clear
         
     | 
| 
      
 27 
     | 
    
         
            +
                    load_more
         
     | 
| 
      
 28 
     | 
    
         
            +
                    events.trigger(:replace)
         
     | 
| 
      
 29 
     | 
    
         
            +
                  end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                  def load
         
     | 
| 
      
 32 
     | 
    
         
            +
                    clear
         
     | 
| 
      
 33 
     | 
    
         
            +
                    load_more
         
     | 
| 
      
 34 
     | 
    
         
            +
                  end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                  def load_more
         
     | 
| 
      
 37 
     | 
    
         
            +
                    unless @loaded
         
     | 
| 
      
 38 
     | 
    
         
            +
                      tracks = send(@collection_to_load.to_s + '_tracks')
         
     | 
| 
      
 39 
     | 
    
         
            +
                      @loaded = true if tracks.empty?
         
     | 
| 
      
 40 
     | 
    
         
            +
                      append tracks.map { |hash| Track.new hash }
         
     | 
| 
      
 41 
     | 
    
         
            +
                      @page += 1
         
     | 
| 
      
 42 
     | 
    
         
            +
                    end
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                  def favorites_tracks
         
     | 
| 
      
 46 
     | 
    
         
            +
                    return [] if @client.current_user.nil?
         
     | 
| 
      
 47 
     | 
    
         
            +
                    @client.get(@client.current_user.uri + '/favorites', offset: @limit * @page, limit: @limit)
         
     | 
| 
      
 48 
     | 
    
         
            +
                  end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                  def recent_tracks
         
     | 
| 
      
 51 
     | 
    
         
            +
                    @client.get('/tracks', offset: @page * limit, limit: @limit)
         
     | 
| 
      
 52 
     | 
    
         
            +
                  end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                  def user_tracks
         
     | 
| 
      
 55 
     | 
    
         
            +
                    return [] if @client.current_user.nil?
         
     | 
| 
      
 56 
     | 
    
         
            +
                    user_tracks = @client.get(@client.current_user.uri + '/tracks', offset: @limit * @page, limit: @limit)
         
     | 
| 
      
 57 
     | 
    
         
            +
                    if user_tracks.empty?
         
     | 
| 
      
 58 
     | 
    
         
            +
                      UI::Input.error("'#{@client.current_user.username}' has not authored any tracks. Use f to switch to their favorites, or s to switch to their playlists.")
         
     | 
| 
      
 59 
     | 
    
         
            +
                      return []
         
     | 
| 
      
 60 
     | 
    
         
            +
                    else
         
     | 
| 
      
 61 
     | 
    
         
            +
                      return user_tracks
         
     | 
| 
      
 62 
     | 
    
         
            +
                    end
         
     | 
| 
      
 63 
     | 
    
         
            +
                  end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                  def playlist_tracks
         
     | 
| 
      
 66 
     | 
    
         
            +
                    return [] if @playlist.nil?
         
     | 
| 
      
 67 
     | 
    
         
            +
                    @client.get(@playlist.uri + '/tracks', offset: @limit * @page, limit: @limit)
         
     | 
| 
      
 68 
     | 
    
         
            +
                  end
         
     | 
| 
      
 69 
     | 
    
         
            +
                end
         
     | 
| 
      
 70 
     | 
    
         
            +
              end
         
     | 
| 
      
 71 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,26 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Soundcloud9000
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Models
         
     | 
| 
      
 3 
     | 
    
         
            +
                # stores information on the current user we are looking at
         
     | 
| 
      
 4 
     | 
    
         
            +
                class User
         
     | 
| 
      
 5 
     | 
    
         
            +
                  def initialize(hash)
         
     | 
| 
      
 6 
     | 
    
         
            +
                    @hash = hash
         
     | 
| 
      
 7 
     | 
    
         
            +
                  end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                  def id
         
     | 
| 
      
 10 
     | 
    
         
            +
                    @hash['id']
         
     | 
| 
      
 11 
     | 
    
         
            +
                  end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                  def username
         
     | 
| 
      
 14 
     | 
    
         
            +
                    @hash['username']
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  def uri
         
     | 
| 
      
 18 
     | 
    
         
            +
                    @hash['uri']
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  def permalink
         
     | 
| 
      
 22 
     | 
    
         
            +
                    @hash['permalink']
         
     | 
| 
      
 23 
     | 
    
         
            +
                  end
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
              end
         
     | 
| 
      
 26 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,23 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'time'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Soundcloud9000
         
     | 
| 
      
 4 
     | 
    
         
            +
              # handles proper time display
         
     | 
| 
      
 5 
     | 
    
         
            +
              # TODO: make this better looking or find an alternative
         
     | 
| 
      
 6 
     | 
    
         
            +
              module TimeHelper
         
     | 
| 
      
 7 
     | 
    
         
            +
                HOUR    = 1000 * 60 * 60
         
     | 
| 
      
 8 
     | 
    
         
            +
                MINUTE  = 1000 * 60
         
     | 
| 
      
 9 
     | 
    
         
            +
                SECONDS = 1000
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                def self.duration(milliseconds)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  parts = [
         
     | 
| 
      
 13 
     | 
    
         
            +
                    milliseconds / 1000 / 60 / 60,      # hours
         
     | 
| 
      
 14 
     | 
    
         
            +
                    milliseconds / 1000 / 60 % 60,      # minutes
         
     | 
| 
      
 15 
     | 
    
         
            +
                    milliseconds / 1000 % 60,           # seconds
         
     | 
| 
      
 16 
     | 
    
         
            +
                  ]
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  parts.shift if parts.first.zero?
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  [parts.first, *parts[1..-1].map { |part| format('%02d', part) }].join('.')
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
            end
         
     |