red_haze 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.
Files changed (60) hide show
  1. data/.gitignore +7 -0
  2. data/.rspec +2 -0
  3. data/Gemfile +4 -0
  4. data/Rakefile +1 -0
  5. data/config.template.yml +4 -0
  6. data/lib/red_haze/activity.rb +5 -0
  7. data/lib/red_haze/client.rb +58 -0
  8. data/lib/red_haze/collection.rb +16 -0
  9. data/lib/red_haze/comment.rb +6 -0
  10. data/lib/red_haze/group.rb +28 -0
  11. data/lib/red_haze/helpers/resource.rb +91 -0
  12. data/lib/red_haze/helpers.rb +8 -0
  13. data/lib/red_haze/me.rb +66 -0
  14. data/lib/red_haze/playlist.rb +6 -0
  15. data/lib/red_haze/request.rb +22 -0
  16. data/lib/red_haze/track.rb +23 -0
  17. data/lib/red_haze/user.rb +35 -0
  18. data/lib/red_haze/version.rb +3 -0
  19. data/lib/red_haze.rb +28 -0
  20. data/red_haze.gemspec +28 -0
  21. data/spec/fixtures/vcr_cassettes/collection_next.yml +348 -0
  22. data/spec/fixtures/vcr_cassettes/comment_sync.yml +56 -0
  23. data/spec/fixtures/vcr_cassettes/group_contributors.yml +55 -0
  24. data/spec/fixtures/vcr_cassettes/group_members.yml +55 -0
  25. data/spec/fixtures/vcr_cassettes/group_moderators.yml +55 -0
  26. data/spec/fixtures/vcr_cassettes/group_sync.yml +55 -0
  27. data/spec/fixtures/vcr_cassettes/group_users.yml +55 -0
  28. data/spec/fixtures/vcr_cassettes/me.yml +55 -0
  29. data/spec/fixtures/vcr_cassettes/me_activities.yml +429 -0
  30. data/spec/fixtures/vcr_cassettes/me_activities_limit.yml +127 -0
  31. data/spec/fixtures/vcr_cassettes/playlist.yml +60 -0
  32. data/spec/fixtures/vcr_cassettes/track_comments.yml +79 -0
  33. data/spec/fixtures/vcr_cassettes/track_favorite_get.yml +50 -0
  34. data/spec/fixtures/vcr_cassettes/track_favorite_put.yml +50 -0
  35. data/spec/fixtures/vcr_cassettes/track_favoriters.yml +172 -0
  36. data/spec/fixtures/vcr_cassettes/track_sync.yml +82 -0
  37. data/spec/fixtures/vcr_cassettes/track_unfavorite_put.yml +50 -0
  38. data/spec/fixtures/vcr_cassettes/user_comments.yml +89 -0
  39. data/spec/fixtures/vcr_cassettes/user_favorites.yml +479 -0
  40. data/spec/fixtures/vcr_cassettes/user_follow_put.yml +65 -0
  41. data/spec/fixtures/vcr_cassettes/user_followers.yml +431 -0
  42. data/spec/fixtures/vcr_cassettes/user_follows_.yml +104 -0
  43. data/spec/fixtures/vcr_cassettes/user_follows_get.yml +50 -0
  44. data/spec/fixtures/vcr_cassettes/user_groups.yml +66 -0
  45. data/spec/fixtures/vcr_cassettes/user_playlists.yml +482 -0
  46. data/spec/fixtures/vcr_cassettes/user_sync.yml +57 -0
  47. data/spec/fixtures/vcr_cassettes/user_unfollow_put.yml +54 -0
  48. data/spec/lib/red_haze/activity_spec.rb +18 -0
  49. data/spec/lib/red_haze/client_spec.rb +43 -0
  50. data/spec/lib/red_haze/collection_spec.rb +26 -0
  51. data/spec/lib/red_haze/comment_spec.rb +30 -0
  52. data/spec/lib/red_haze/group_spec.rb +57 -0
  53. data/spec/lib/red_haze/me_spec.rb +117 -0
  54. data/spec/lib/red_haze/playlist_spec.rb +41 -0
  55. data/spec/lib/red_haze/request_spec.rb +17 -0
  56. data/spec/lib/red_haze/track_spec.rb +96 -0
  57. data/spec/lib/red_haze/user_spec.rb +110 -0
  58. data/spec/lib/red_haze_spec.rb +13 -0
  59. data/spec/spec_helper.rb +45 -0
  60. metadata +212 -0
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ config.yml
6
+ tags
7
+ .rvmrc
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in hypem.gemspec
4
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,4 @@
1
+ :client_id: CLIENT_ID
2
+ :client_secret: CLIENT_SECRET
3
+ :redirect_uri: http://myredirect.uri/
4
+
@@ -0,0 +1,5 @@
1
+ module RedHaze
2
+ class Activity
3
+ include Helpers::Resource
4
+ end
5
+ end
@@ -0,0 +1,58 @@
1
+ require "httparty"
2
+
3
+ module RedHaze
4
+ class Client
5
+ include HTTParty
6
+ attr_accessor :client_id, :client_secret, :redirect_uri,
7
+ :access_token, :expires_in, :refresh_token
8
+
9
+ TOKEN_ENDPOINT = "https://api.soundcloud.com/oauth2/token"
10
+ CONNECT_ENDPOINT = "https://soundcloud.com/connect"
11
+
12
+ def initialize(options={})
13
+ options_check(options)
14
+ update_from_response(options)
15
+ end
16
+
17
+ def authorize_url
18
+ raise "Missing redirect_uri" unless redirect_uri
19
+ params = "client_id=#{client_id}&redirect_uri=#{redirect_uri}&response_type=code"
20
+ URI.encode "#{CONNECT_ENDPOINT}?#{params}"
21
+ end
22
+
23
+ def get_token_from_code(code)
24
+ body = { client_id: client_id,
25
+ client_secret: client_secret,
26
+ redirect_uri: redirect_uri,
27
+ code: code,
28
+ grant_type: 'authorization_code' }
29
+
30
+ response = self.class.post TOKEN_ENDPOINT, body: body,
31
+ headers: {'Content-Type' => 'application/x-www-form-urlencoded'}
32
+
33
+ raise response.inspect unless response.code == 200
34
+ update_from_response(response)
35
+ self
36
+ end
37
+
38
+ private
39
+
40
+ def options_check(options)
41
+ keys = options.keys
42
+ unless (keys.include?(:client_id) && keys.include?(:client_secret)) ||
43
+ keys.include?(:access_token)
44
+ raise "missing client_id and client_secret, or access_token"
45
+ end
46
+ end
47
+
48
+ def update_from_response(response)
49
+ @client_id = response[:client_id]
50
+ @client_secret = response[:client_secret]
51
+ @redirect_uri = response[:redirect_uri]
52
+ @access_token = response[:access_token]
53
+ @expires_in = response[:expires_in]
54
+ @refresh_token = response[:refresh_token]
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,16 @@
1
+ module RedHaze
2
+ class Collection
3
+ include Helpers::Resource
4
+ attr_reader :items, :next_href, :future_href
5
+ def initialize(arg)
6
+ @items = arg['collection'].collect { |r| Activity.new(r) }
7
+ @next_href = arg['next_href']
8
+ @future_href = arg['future_href']
9
+ end
10
+
11
+ def next
12
+ self.class.new Request.get(@next_href)
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,6 @@
1
+ module RedHaze
2
+ class Comment
3
+ include Helpers::Resource
4
+
5
+ end
6
+ end
@@ -0,0 +1,28 @@
1
+ module RedHaze
2
+ class Group
3
+ include Helpers::Resource
4
+
5
+ attr_reader :id
6
+
7
+ def members
8
+ get_endpoint("/members")
9
+ end
10
+
11
+ def moderators
12
+ get_endpoint("/moderators")
13
+ end
14
+
15
+ def contributors
16
+ get_endpoint("/contributors")
17
+ end
18
+
19
+ def contributors
20
+ get_endpoint("/contributors")
21
+ end
22
+
23
+ def users
24
+ get_endpoint("/users")
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,91 @@
1
+ module RedHaze
2
+ module Helpers
3
+
4
+ module Resource
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+ end
8
+
9
+ attr_reader :id
10
+
11
+ def initialize(arg)
12
+ case arg
13
+ when Fixnum then @id = arg
14
+ when Hash then initialize_from_hash(arg)
15
+ else raise "Not a valid Resource initialize arg: #{arg.inspect}"
16
+ end
17
+ end
18
+
19
+ def sync
20
+ initialize_from_hash Request.get(url)
21
+ self
22
+ end
23
+
24
+ def get_endpoint(endpoint, args={})
25
+ self.class.import_from_response Request.get(url + endpoint, args)
26
+ end
27
+
28
+ def put_endpoint(endpoint, args={})
29
+ default_args = {headers: {'Content-Length' => "0"}}
30
+ args.merge! default_args
31
+ Request.put(url + endpoint, args).parsed_response
32
+ end
33
+
34
+ def delete_endpoint(endpoint, args={})
35
+ Request.delete(url + endpoint, args).parsed_response
36
+ end
37
+
38
+ def url
39
+ class_name = self.class.name.downcase.split('::')[-1]
40
+ class_name == 'me' ? '/me' : "/#{class_name}s/#{id}"
41
+ end
42
+
43
+ private
44
+
45
+ def initialize_from_hash(arg)
46
+ arg.each_pair do |key, value|
47
+ case key
48
+ when 'created_at'
49
+ value = DateTime.parse(value)
50
+ when 'user', 'creator', 'track', 'origin'
51
+ value = self.class.instance_from_hash(value)
52
+ when 'tags'
53
+ value = value.split(',')
54
+ end
55
+ instance_variable_set "@#{key}", value
56
+ self.class.class_eval { attr_reader key }
57
+ end
58
+ end
59
+
60
+ module ClassMethods
61
+
62
+ def instance_from_hash(arg)
63
+ case
64
+ when arg['kind']
65
+ class_name = arg.delete('kind').capitalize
66
+ eval(class_name).new(arg)
67
+ when arg['type']
68
+ Activity.new arg
69
+ when arg['collection']
70
+ Collection.new arg
71
+ when arg.values.first['kind']
72
+ instance_from_hash arg.values.first
73
+ else
74
+ raise arg.inspect
75
+ end
76
+ end
77
+
78
+
79
+ def import_from_response(response)
80
+ if response.is_a? Array
81
+ response.collect { |i| instance_from_hash(i) }
82
+ elsif response.is_a? Hash
83
+ instance_from_hash response
84
+ end
85
+ end
86
+
87
+ end
88
+
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,8 @@
1
+ require_relative 'helpers/resource'
2
+
3
+ module RedHaze
4
+ module Helpers
5
+
6
+
7
+ end
8
+ end
@@ -0,0 +1,66 @@
1
+ require 'red_haze/user'
2
+
3
+ module RedHaze
4
+ class Me < User
5
+ FILTERS = [:all, :tracks_affiliated, :tracks_exclusive, :own]
6
+
7
+ def initialize
8
+ unless RedHaze.client.access_token
9
+ raise "You cannot access this object without a client access_token"
10
+ end
11
+ sync
12
+ end
13
+
14
+ def activities(args = {})
15
+ filter = args.delete(:filter) || :all
16
+ raise "Bad Activities filter: #{filter}" unless FILTERS.include?(filter)
17
+
18
+ filter = filter.to_s.sub('_','/')
19
+
20
+ get_endpoint("/activities/#{filter}", query: args)
21
+ end
22
+
23
+ def follow!(arg)
24
+ put_endpoint "/followings/#{item_id(arg)}"
25
+ end
26
+
27
+ def unfollow!(arg)
28
+ delete_endpoint "/followings/#{item_id(arg)}"
29
+ end
30
+
31
+ def follows?(arg)
32
+ existence_check "/me/followings", arg
33
+ end
34
+
35
+ def favorite!(arg)
36
+ put_endpoint "/favorites/#{item_id(arg)}"
37
+ end
38
+
39
+ def unfavorite!(arg)
40
+ delete_endpoint "/favorites/#{item_id(arg)}"
41
+ end
42
+
43
+ def favorite?(arg)
44
+ existence_check "/me/favorites", arg
45
+ end
46
+
47
+ private
48
+
49
+ def item_id(arg)
50
+ unless [RedHaze::User, RedHaze::Track, Fixnum].include?(arg.class)
51
+ raise ArgumentError
52
+ end
53
+ arg.is_a?(Fixnum) ? arg : arg.id
54
+ end
55
+
56
+ # if the resource exists, we are redirected to a 404 page
57
+ # this will rescue on the first redirect and thus return true
58
+ def existence_check(path, arg)
59
+ response = Request.get "#{path}/#{item_id(arg)}", no_follow: true
60
+ response.code == 200
61
+ rescue HTTParty::RedirectionTooDeep
62
+ true
63
+ end
64
+
65
+ end
66
+ end
@@ -0,0 +1,6 @@
1
+ module RedHaze
2
+ class Playlist
3
+ include Helpers::Resource
4
+
5
+ end
6
+ end
@@ -0,0 +1,22 @@
1
+ require 'httparty'
2
+
3
+ module RedHaze
4
+ class Request
5
+ include HTTParty
6
+ debug_output
7
+ headers 'Accept' => 'application/json'
8
+
9
+ def self.setup(client_id,access_token=nil)
10
+ params = {}
11
+ if access_token
12
+ base_uri 'https://api.soundcloud.com'
13
+ params[:oauth_token] = access_token
14
+ else
15
+ base_uri 'http://api.soundcloud.com'
16
+ params[:client_id] = client_id
17
+ end
18
+ default_params params
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,23 @@
1
+ module RedHaze
2
+ class Track
3
+ include Helpers::Resource
4
+
5
+ def favoriters
6
+ get_endpoint('/favoriters')
7
+ end
8
+
9
+ def comments
10
+ get_endpoint('/comments')
11
+ end
12
+
13
+ def shared_to
14
+ get_endpoint('/shared_to/users')
15
+ end
16
+
17
+ def owner
18
+ sync if user_id.nil?
19
+ User.new(user_id)
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,35 @@
1
+ module RedHaze
2
+ class User
3
+ include Helpers::Resource
4
+
5
+ def followings(user_id=nil)
6
+ if user_id.nil?
7
+ get_endpoint('/followings')
8
+ else
9
+ response = get("/followings/#{user_id}")
10
+ end
11
+ end
12
+
13
+ def followers
14
+ get_endpoint('/followers')
15
+ end
16
+
17
+ def comments
18
+ get_endpoint('/comments')
19
+ end
20
+
21
+ def favorites
22
+ get_endpoint('/favorites')
23
+ end
24
+
25
+ def groups
26
+ get_endpoint('/groups')
27
+ end
28
+
29
+ def playlists
30
+ get_endpoint('/playlists')
31
+ end
32
+
33
+ end
34
+
35
+ end
@@ -0,0 +1,3 @@
1
+ module RedHaze
2
+ VERSION = "0.0.1"
3
+ end
data/lib/red_haze.rb ADDED
@@ -0,0 +1,28 @@
1
+ require "red_haze/version"
2
+ require 'red_haze/helpers'
3
+ require "red_haze/client"
4
+ require "red_haze/request"
5
+ require "red_haze/playlist"
6
+ require "red_haze/me"
7
+ require "red_haze/user"
8
+ require "red_haze/track"
9
+ require "red_haze/comment"
10
+ require "red_haze/group"
11
+ require "red_haze/activity"
12
+ require "red_haze/collection"
13
+
14
+ module RedHaze
15
+ class << self
16
+ attr_accessor :client
17
+
18
+ def configure(options = {})
19
+ @client = Client.new(options)
20
+ Request.setup(@client.client_id, @client.access_token)
21
+ self
22
+ end
23
+
24
+ def configure_from_file(path)
25
+ configure YAML.load_file(path)
26
+ end
27
+ end
28
+ end
data/red_haze.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "red_haze/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "red_haze"
7
+ s.version = RedHaze::VERSION
8
+ s.authors = ["Jack Anderson"]
9
+ s.email = ["hi@janderson.me"]
10
+ s.homepage = "https://github.com/JackCA/red_haze"
11
+ s.summary = "a robust Ruby wrapper for the Soundcloud API"
12
+
13
+ s.rubyforge_project = "red_haze"
14
+ s.required_ruby_version = Gem::Requirement.new(">= 1.9.2")
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_development_dependency "webmock"
22
+ s.add_development_dependency "vcr"
23
+ s.add_development_dependency "rspec"
24
+ s.add_development_dependency "rake"
25
+ s.add_dependency 'httparty'
26
+ s.add_dependency 'multi_json'
27
+
28
+ end