bremen 0.0.1 → 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.
data/Guardfile CHANGED
@@ -1,4 +1,3 @@
1
- notification :off
2
1
  guard 'minitest' do
3
2
  watch(%r|^spec/(.*)_spec\.rb|)
4
3
  watch(%r|^lib/(.*)([^/]+)\.rb|) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Bremen
2
2
 
3
- TODO: Write a gem description
3
+ **Bremen** provides common search interface for some music websites. it supports YouTube, SoundCloud, MixCloud and Nicovideo
4
4
 
5
5
  ## Installation
6
6
 
@@ -16,9 +16,62 @@ Or install it yourself as:
16
16
 
17
17
  $ gem install bremen
18
18
 
19
+ ## Setting
20
+
21
+ As far as Soundcloud concerned, you need to set consumer key before using.
22
+
23
+ Bremen::Soundcloud.consumer_key = 'your_consumer_key'
24
+
19
25
  ## Usage
20
26
 
21
- TODO: Write usage instructions here
27
+ ### Retrieving a single track
28
+
29
+ call `.find` method with uid(unique key) or url.
30
+
31
+ Bremen::Youtube.find('XXXXXXXXXXX')
32
+ Bremen::Youtube.find('http://www.youtube.com/watch?v=XXXXXXXXXXX')
33
+ Bremen::Soundcloud.find('1111111')
34
+ Bremen::Soundcloud.find('http://soundcloud.com/author/title')
35
+ Bremen::Mixcloud.find('/author/title/')
36
+ Bremen::Mixcloud.find('http://www.mixcloud.com/author/title/')
37
+ Bremen::Nicovideo.find('sm1111111')
38
+ Bremen::Nicovideo.find('http://www.nicovideo.jp/watch/sm1111111')
39
+
40
+ ### Retrieving multiple tracks
41
+
42
+ call `.search` method with keyword.
43
+
44
+ Bremen::Youtube.find(keyword: 'Perfume')
45
+
46
+ #### Optional params
47
+
48
+ You can add optional parameters for filtering. But not supports all official API's filters.
49
+
50
+ Bremen::Youtube.find(keyword: 'KyaryPamyuPamyu', order: 'relevance', limit: 10)
51
+
52
+ ### Track object
53
+
54
+ Retrieving methods return Track object(s).
55
+
56
+ attribute | |
57
+ -----------|----------------------|
58
+ uid | unique key in a site |
59
+ url | |
60
+ title | |
61
+ author | |
62
+ length | duration of track |
63
+ created_at | released datetime |
64
+ updated_at | modified datetime |
65
+
66
+ ## API References
67
+
68
+ - [Reference Guide: Data API Protocol - YouTube — Google Developers](https://developers.google.com/youtube/2.0/reference#Searching_for_videos)
69
+ - [Docs - API - Reference - SoundCloud Developers](http://developers.soundcloud.com/docs/api/reference#tracks)
70
+ - [API documentation | Mixcloud](http://www.mixcloud.com/developers/documentation/#search)
71
+
72
+ ## Supported versions
73
+
74
+ - Ruby 1.9.3 or higher
22
75
 
23
76
  ## Contributing
24
77
 
data/bremen.gemspec CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |gem|
8
8
  gem.version = Bremen::VERSION
9
9
  gem.authors = ["itzki"]
10
10
  gem.email = ["itzki.h@gmail.com"]
11
- gem.description = %q{integrated searcher of audio track on music sites}
12
- gem.summary = %q{integrated searcher of audio track on music sites}
11
+ gem.description = %q{integrated searcher of audio tracks on music sites}
12
+ gem.summary = %q{Bremen provides common search interface for some music websites. it supports YouTube, SoundCloud, MixCloud and Nicovideo}
13
13
  gem.homepage = "https://github.com/itzki/bremen"
14
14
 
15
15
  gem.files = `git ls-files`.split($/)
@@ -19,4 +19,5 @@ Gem::Specification.new do |gem|
19
19
 
20
20
  gem.add_development_dependency 'guard-minitest', ['>= 0']
21
21
  gem.add_development_dependency 'rb-fsevent', ['>= 0']
22
+ gem.add_development_dependency 'terminal-notifier-guard', ['>= 0']
22
23
  end
data/lib/bremen/base.rb CHANGED
@@ -9,14 +9,20 @@ module Bremen
9
9
  class << self
10
10
  attr_accessor :default_options
11
11
 
12
- def find options = {}
13
- convert_from_response(get(search_url(options)))
12
+ def find uid_or_url
13
+ convert_singly(get(find_url(uid_or_url)))
14
+ end
15
+
16
+ def search options = {}
17
+ convert_multiply(get(search_url(options)))
14
18
  end
15
19
 
16
20
  #abstract methods
21
+ def find_url uid_or_url; end
17
22
  def search_url options = {}; end
18
23
  private
19
- def convert_from_response response; end
24
+ def convert_singly response; end
25
+ def convert_multiply response; end
20
26
  end
21
27
  end
22
28
  end
@@ -3,13 +3,21 @@ require 'bremen/base'
3
3
 
4
4
  module Bremen
5
5
  class Mixcloud < Bremen::Base
6
- BASE_URL = 'http://api.mixcloud.com/search/'
6
+ BASE_URL = 'http://api.mixcloud.com/'
7
7
  self.default_options = {
8
8
  keyword: '',
9
9
  limit: 20,
10
10
  }
11
11
 
12
12
  class << self
13
+ def find_url uid_or_url
14
+ if uid_or_url.to_s.include?('www.mixcloud.com')
15
+ uid_or_url.sub('www.mixcloud.com', 'api.mixcloud.com')
16
+ else
17
+ "#{BASE_URL[0..-2]}#{uid_or_url}"
18
+ end
19
+ end
20
+
13
21
  def search_url options = {}
14
22
  options = default_options.merge(options)
15
23
  query = {
@@ -17,7 +25,7 @@ module Bremen
17
25
  limit: options[:limit],
18
26
  type: 'cloudcast',
19
27
  }
20
- "#{BASE_URL}?#{build_query(query)}"
28
+ "#{BASE_URL}search/?#{build_query(query)}"
21
29
  end
22
30
 
23
31
  def from_api hash = {}
@@ -34,7 +42,11 @@ module Bremen
34
42
  end
35
43
 
36
44
  private
37
- def convert_from_response response
45
+ def convert_singly response
46
+ from_api(JSON.parse(response))
47
+ end
48
+
49
+ def convert_multiply response
38
50
  JSON.parse(response)['data'].map{|t| from_api(t) }
39
51
  end
40
52
  end
@@ -3,7 +3,7 @@ require 'bremen/base'
3
3
 
4
4
  module Bremen
5
5
  class Nicovideo < Bremen::Base
6
- BASE_URL = 'http://www.nicovideo.jp/search/'
6
+ BASE_URL = 'http://www.nicovideo.jp/'
7
7
  self.default_options = {
8
8
  keyword: '',
9
9
  sort: 'f', #n(newer commented)/v(viewed)/r(most commented)/m(listed)/f(uploaded)/l(duration)
@@ -14,6 +14,14 @@ module Bremen
14
14
  }
15
15
 
16
16
  class << self
17
+ def find_url uid_or_url
18
+ unless uid_or_url.include?('www.nicovideo.jp')
19
+ "#{BASE_URL}watch/#{uid_or_url}"
20
+ else
21
+ uid_or_url
22
+ end
23
+ end
24
+
17
25
  def search_url options = {}
18
26
  options = default_options.merge(options)
19
27
  query = {
@@ -23,18 +31,33 @@ module Bremen
23
31
  l_range: options[:length],
24
32
  opt_md: options[:downloadable],
25
33
  }
26
- "#{BASE_URL}#{CGI.escape(options[:keyword])}?#{build_query(query)}"
34
+ "#{BASE_URL}search/#{CGI.escape(options[:keyword])}?#{build_query(query)}"
27
35
  end
28
36
 
29
37
  private
30
- def convert_from_response response
38
+ def convert_singly response
39
+ uid = response.scan(%r{<link rel="canonical" href="/watch/([^"]+)">}).flatten.first
40
+ title = CGI.unescape(response.scan(%r{<meta property="og:title" content="(.+)">}).flatten.first.to_s)
41
+ length = response.scan(%r{<meta property="video:duration" content="(\d+)">}).flatten.first.to_i
42
+ created_at = Time.parse(response.scan(%r{<meta property="video:release_date" content="(.+)">}).flatten.first.to_s)
43
+ new({
44
+ uid: uid,
45
+ url: "#{BASE_URL}watch/#{uid}",
46
+ title: title,
47
+ length: length,
48
+ created_at: created_at,
49
+ updated_at: created_at,
50
+ })
51
+ end
52
+
53
+ def convert_multiply response
31
54
  response.scan(%r{<div class="thumb_col_1">\n<!---->\n(.*?)\n<!---->\n</div></div>}m).flatten.map do |html|
32
55
  uid = html.scan(%r{<table [^>]+ summary="(.+)">}).flatten.first
33
56
  min, sec = html.scan(%r{<p class="vinfo_length"><span>([\d:]+)</span></p>}).flatten.first.to_s.split(':')
34
57
  created_at = Time.parse(html.scan(%r{<strong>(.+:\d\d)</strong>}).flatten.first.to_s.gsub(/\xE5\xB9\xB4|\xE6\x9C\x88|\xE6\x97\xA5/, ''))
35
58
  new({
36
59
  uid: uid,
37
- url: "http://www.nicovideo.jp/watch/#{uid}",
60
+ url: "#{BASE_URL}watch/#{uid}",
38
61
  title: CGI.unescape(html.scan(%r{<a [^>]+ class="watch" [^>]+>(.+)</a>}).flatten.first.to_s),
39
62
  length: min.to_i * 60 + sec.to_i,
40
63
  created_at: created_at,
@@ -3,7 +3,7 @@ require 'bremen/base'
3
3
 
4
4
  module Bremen
5
5
  class Soundcloud < Bremen::Base
6
- BASE_URL = 'http://api.soundcloud.com/tracks.json'
6
+ BASE_URL = 'http://api.soundcloud.com/'
7
7
  self.default_options = {
8
8
  keyword: '',
9
9
  order: 'created_at', #created_at/hotness
@@ -14,17 +14,28 @@ module Bremen
14
14
  class << self
15
15
  attr_accessor :consumer_key
16
16
 
17
- def search_url options = {}
17
+ def build_query options = {}
18
18
  raise %Q{"#{self.name}.consumer_key" must be set} unless consumer_key
19
+ super(options.merge(consumer_key: consumer_key))
20
+ end
21
+
22
+ def find_url uid_or_url
23
+ if uid_or_url.to_s =~ %r{\A\d+\Z}
24
+ "#{BASE_URL}tracks/#{uid_or_url}.json?#{build_query}"
25
+ else
26
+ "#{BASE_URL}resolve.json?#{build_query({url: uid_or_url})}"
27
+ end
28
+ end
29
+
30
+ def search_url options = {}
19
31
  options = default_options.merge(options)
20
32
  query = {
21
33
  q: options[:keyword],
22
34
  order: options[:order],
23
35
  limit: options[:limit],
24
36
  filter: options[:filter],
25
- consumer_key: consumer_key,
26
37
  }
27
- "#{BASE_URL}?#{build_query(query)}"
38
+ "#{BASE_URL}tracks.json?#{build_query(query)}"
28
39
  end
29
40
 
30
41
  def from_api hash = {}
@@ -40,7 +51,11 @@ module Bremen
40
51
  end
41
52
 
42
53
  private
43
- def convert_from_response response
54
+ def convert_singly response
55
+ from_api(JSON.parse(response))
56
+ end
57
+
58
+ def convert_multiply response
44
59
  JSON.parse(response).map{|t| from_api(t) }
45
60
  end
46
61
  end
@@ -1,3 +1,3 @@
1
1
  module Bremen
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -12,13 +12,21 @@ module Bremen
12
12
  }
13
13
 
14
14
  class << self
15
+ def build_query options = {}
16
+ super(options.merge(alt: 'json'))
17
+ end
18
+
19
+ def find_url uid_or_url
20
+ uid = uid_or_url.scan(%r{[?&]v=(.{11})}).flatten.first || uid_or_url
21
+ "#{BASE_URL}#{uid}?#{build_query}"
22
+ end
23
+
15
24
  def search_url options = {}
16
25
  options = default_options.merge(options)
17
26
  query = {
18
27
  vq: options[:keyword],
19
28
  orderby: options[:order],
20
29
  :"max-results" => options[:limit],
21
- alt: 'json',
22
30
  }
23
31
  "#{BASE_URL}-/#{options[:category]}/#{options[:tag]}/?#{build_query(query)}"
24
32
  end
@@ -37,7 +45,11 @@ module Bremen
37
45
  end
38
46
 
39
47
  private
40
- def convert_from_response response
48
+ def convert_singly response
49
+ from_api(JSON.parse(response)['entry'])
50
+ end
51
+
52
+ def convert_multiply response
41
53
  JSON.parse(response)['feed']['entry'].map{|t| from_api(t) }
42
54
  end
43
55
  end
@@ -2,6 +2,23 @@ $:.unshift(File.expand_path('../../', __FILE__))
2
2
  require 'spec_helper'
3
3
 
4
4
  describe Bremen::Mixcloud do
5
+ describe '.find_url' do
6
+ subject{ Bremen::Mixcloud.find_url(uid_or_url) }
7
+ describe 'given id' do
8
+ let(:uid_or_url){ '/author/permalink/' }
9
+ it 'generate' do
10
+ subject.must_equal 'http://api.mixcloud.com/author/permalink/'
11
+ end
12
+ end
13
+
14
+ describe 'given url' do
15
+ let(:uid_or_url){ 'http://www.mixcloud.com/author/permalink/' }
16
+ it 'generate' do
17
+ subject.must_equal 'http://api.mixcloud.com/author/permalink/'
18
+ end
19
+ end
20
+ end
21
+
5
22
  describe '.search_url' do
6
23
  subject{ Bremen::Mixcloud.search_url(params) }
7
24
  describe 'only keyword' do
@@ -19,9 +36,17 @@ describe Bremen::Mixcloud do
19
36
  end
20
37
  end
21
38
 
22
- describe '.convert_from_response' do
23
- subject{ Bremen::Mixcloud.send(:convert_from_response, response) }
24
- let(:response){ fixture('mixcloud.json') }
39
+ describe '.convert_singly' do
40
+ subject{ Bremen::Mixcloud.send(:convert_singly, response) }
41
+ let(:response){ fixture('mixcloud_single.json') }
42
+ it 'convert successfully' do
43
+ subject.title.must_equal 'Title'
44
+ end
45
+ end
46
+
47
+ describe '.convert_multiply' do
48
+ subject{ Bremen::Mixcloud.send(:convert_multiply, response) }
49
+ let(:response){ fixture('mixcloud_multi.json') }
25
50
  it 'convert successfully' do
26
51
  subject.first.title.must_equal 'Title'
27
52
  end
@@ -2,6 +2,23 @@ $:.unshift(File.expand_path('../../', __FILE__))
2
2
  require 'spec_helper'
3
3
 
4
4
  describe Bremen::Nicovideo do
5
+ describe '.find_url' do
6
+ subject{ Bremen::Nicovideo.find_url(uid_or_url) }
7
+ describe 'given id' do
8
+ let(:uid_or_url){ 'sm1111111' }
9
+ it 'generate' do
10
+ subject.must_equal 'http://www.nicovideo.jp/watch/sm1111111'
11
+ end
12
+ end
13
+
14
+ describe 'given url' do
15
+ let(:uid_or_url){ 'http://www.nicovideo.jp/watch/sm1111111' }
16
+ it 'generate' do
17
+ subject.must_equal 'http://www.nicovideo.jp/watch/sm1111111'
18
+ end
19
+ end
20
+ end
21
+
5
22
  describe '.search_url' do
6
23
  subject{ Bremen::Nicovideo.search_url(params) }
7
24
  describe 'only keyword' do
@@ -19,9 +36,17 @@ describe Bremen::Nicovideo do
19
36
  end
20
37
  end
21
38
 
22
- describe '.convert_from_response' do
23
- subject{ Bremen::Nicovideo.send(:convert_from_response, response) }
24
- let(:response){ fixture('nicovideo.html') }
39
+ describe '.convert_singly' do
40
+ subject{ Bremen::Nicovideo.send(:convert_singly, response) }
41
+ let(:response){ fixture('nicovideo_single.html') }
42
+ it 'convert successfully' do
43
+ subject.title.must_equal 'Title'
44
+ end
45
+ end
46
+
47
+ describe '.convert_multiply' do
48
+ subject{ Bremen::Nicovideo.send(:convert_multiply, response) }
49
+ let(:response){ fixture('nicovideo_multi.html') }
25
50
  it 'convert successfully' do
26
51
  subject.first.title.must_equal 'Title'
27
52
  end
@@ -2,34 +2,69 @@ $:.unshift(File.expand_path('../../', __FILE__))
2
2
  require 'spec_helper'
3
3
 
4
4
  describe Bremen::Soundcloud do
5
- describe '.search_url' do
5
+ describe '.build_query' do
6
6
  describe 'not set consumer_key' do
7
7
  it 'raise error' do
8
8
  lambda{ Bremen::Soundcloud.search_url }.must_raise RuntimeError
9
9
  end
10
10
  end
11
+
11
12
  describe 'set consumer_key' do
12
13
  before{ Bremen::Soundcloud.consumer_key = 'CK' }
13
- subject{ Bremen::Soundcloud.search_url(params) }
14
- describe 'only keyword' do
15
- let(:params){ {keyword: 'searchword'} }
16
- it 'generate' do
17
- subject.must_equal 'http://api.soundcloud.com/tracks.json?q=searchword&order=created_at&limit=50&filter=&consumer_key=CK'
18
- end
14
+ subject{ Bremen::Soundcloud.build_query({a: 'b'}) }
15
+ it 'return query string' do
16
+ subject.must_equal 'a=b&consumer_key=CK'
17
+ end
18
+ end
19
+ end
20
+
21
+ describe '.find_url' do
22
+ before{ Bremen::Soundcloud.consumer_key = 'CK' }
23
+ subject{ Bremen::Soundcloud.find_url(uid_or_url) }
24
+ describe 'given id' do
25
+ let(:uid_or_url){ 100 }
26
+ it 'generate directly' do
27
+ subject.must_equal 'http://api.soundcloud.com/tracks/100.json?consumer_key=CK'
19
28
  end
29
+ end
20
30
 
21
- describe 'full params' do
22
- let(:params){ {keyword: 'searchword', order: 'hotness', limit: 1, filter: 'public'} }
23
- it 'generate' do
24
- subject.must_equal 'http://api.soundcloud.com/tracks.json?q=searchword&order=hotness&limit=1&filter=public&consumer_key=CK'
25
- end
31
+ describe 'given url' do
32
+ let(:uid_or_url){ 'http://soundcloud.com/author/permalink' }
33
+ it 'generate with resolve resource' do
34
+ subject.must_equal 'http://api.soundcloud.com/resolve.json?url=http%3A%2F%2Fsoundcloud.com%2Fauthor%2Fpermalink&consumer_key=CK'
26
35
  end
27
36
  end
28
37
  end
29
38
 
30
- describe '.convert_from_response' do
31
- subject{ Bremen::Soundcloud.send(:convert_from_response, response) }
32
- let(:response){ fixture('soundcloud.json') }
39
+ describe '.search_url' do
40
+ before{ Bremen::Soundcloud.consumer_key = 'CK' }
41
+ subject{ Bremen::Soundcloud.search_url(params) }
42
+ describe 'only keyword' do
43
+ let(:params){ {keyword: 'searchword'} }
44
+ it 'generate' do
45
+ subject.must_equal 'http://api.soundcloud.com/tracks.json?q=searchword&order=created_at&limit=50&filter=&consumer_key=CK'
46
+ end
47
+ end
48
+
49
+ describe 'full params' do
50
+ let(:params){ {keyword: 'searchword', order: 'hotness', limit: 1, filter: 'public'} }
51
+ it 'generate' do
52
+ subject.must_equal 'http://api.soundcloud.com/tracks.json?q=searchword&order=hotness&limit=1&filter=public&consumer_key=CK'
53
+ end
54
+ end
55
+ end
56
+
57
+ describe '.convert_singly' do
58
+ subject{ Bremen::Soundcloud.send(:convert_singly, response) }
59
+ let(:response){ fixture('soundcloud_single.json') }
60
+ it 'convert successfully' do
61
+ subject.title.must_equal 'Title'
62
+ end
63
+ end
64
+
65
+ describe '.convert_multiply' do
66
+ subject{ Bremen::Soundcloud.send(:convert_multiply, response) }
67
+ let(:response){ fixture('soundcloud_multi.json') }
33
68
  it 'convert successfully' do
34
69
  subject.first.title.must_equal 'Title'
35
70
  end
@@ -2,6 +2,23 @@ $:.unshift(File.expand_path('../../', __FILE__))
2
2
  require 'spec_helper'
3
3
 
4
4
  describe Bremen::Youtube do
5
+ describe '.find_url' do
6
+ subject{ Bremen::Youtube.find_url(uid_or_url) }
7
+ describe 'given id' do
8
+ let(:uid_or_url){ 'XXXXXXXXXXX' }
9
+ it 'generate' do
10
+ subject.must_equal 'http://gdata.youtube.com/feeds/api/videos/XXXXXXXXXXX?alt=json'
11
+ end
12
+ end
13
+
14
+ describe 'given url' do
15
+ let(:uid_or_url){ 'http://www.youtube.com/watch?v=XXXXXXXXXXX' }
16
+ it 'generate' do
17
+ subject.must_equal 'http://gdata.youtube.com/feeds/api/videos/XXXXXXXXXXX?alt=json'
18
+ end
19
+ end
20
+ end
21
+
5
22
  describe '.search_url' do
6
23
  subject{ Bremen::Youtube.search_url(params) }
7
24
  describe 'only keyword' do
@@ -19,9 +36,17 @@ describe Bremen::Youtube do
19
36
  end
20
37
  end
21
38
 
22
- describe '.convert_from_response' do
23
- subject{ Bremen::Youtube.send(:convert_from_response, response) }
24
- let(:response){ fixture('youtube.json') }
39
+ describe '.convert_singly' do
40
+ subject{ Bremen::Youtube.send(:convert_singly, response) }
41
+ let(:response){ fixture('youtube_single.json') }
42
+ it 'convert successfully' do
43
+ subject.title.must_equal 'Title'
44
+ end
45
+ end
46
+
47
+ describe '.convert_multiply' do
48
+ subject{ Bremen::Youtube.send(:convert_multiply, response) }
49
+ let(:response){ fixture('youtube_multi.json') }
25
50
  it 'convert successfully' do
26
51
  subject.first.title.must_equal 'Title'
27
52
  end
@@ -0,0 +1,43 @@
1
+ {
2
+ "listener_count": 111,
3
+ "name": "Title",
4
+ "tags": [
5
+ {
6
+ "url": "http://www.mixcloud.com/tag/tag1/",
7
+ "name": "Inna",
8
+ "key": "/tag/tag1/"
9
+ }
10
+ ],
11
+ "url": "http://www.mixcloud.com/author/title/",
12
+ "pictures": {
13
+ "medium": "http://images-mix.netdna-ssl.com/w/100/h/100/q/85/upload/images/extaudio/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.png",
14
+ "extra_large": "http://images-mix.netdna-ssl.com/w/600/h/600/q/85/upload/images/extaudio/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.png",
15
+ "large": "http://images-mix.netdna-ssl.com/w/300/h/300/q/85/upload/images/extaudio/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.png",
16
+ "medium_mobile": "http://images-mix.netdna-ssl.com/w/80/h/80/q/75/upload/images/extaudio/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.png",
17
+ "small": "http://images-mix.netdna-ssl.com/w/25/h/25/q/85/upload/images/extaudio/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.png",
18
+ "thumbnail": "http://images-mix.netdna-ssl.com/w/50/h/50/q/85/upload/images/extaudio/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.png"
19
+ },
20
+ "updated_time": "2012-01-01T00:00:00Z",
21
+ "play_count": 1111,
22
+ "comment_count": 1,
23
+ "percentage_music": 100,
24
+ "user": {
25
+ "url": "http://www.mixcloud.com/author/",
26
+ "username": "author",
27
+ "name": "Author",
28
+ "key": "/author/",
29
+ "pictures": {
30
+ "medium": "http://images-mix.netdna-ssl.com/w/100/h/100/q/85/upload/images/profile/xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx.png",
31
+ "extra_large": "http://images-mix.netdna-ssl.com/w/600/h/600/q/85/upload/images/profile/xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx.png",
32
+ "large": "http://images-mix.netdna-ssl.com/w/300/h/300/q/85/upload/images/profile/xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx.png",
33
+ "medium_mobile": "http://images-mix.netdna-ssl.com/w/80/h/80/q/75/upload/images/profile/xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx.png",
34
+ "small": "http://images-mix.netdna-ssl.com/w/25/h/25/q/85/upload/images/profile/xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx.png",
35
+ "thumbnail": "http://images-mix.netdna-ssl.com/w/50/h/50/q/85/upload/images/profile/xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx.png"
36
+ }
37
+ },
38
+ "key": "/author/title/",
39
+ "created_time": "2011-06-12T10:40:19Z",
40
+ "audio_length": 1111,
41
+ "slug": "title",
42
+ "favorite_count": 11
43
+ }
@@ -0,0 +1,91 @@
1
+ <html><head>
2
+ <meta name="keywords" content="">
3
+ <meta name="description" content="音ズレ修正">
4
+ <meta http-equiv="Pragma" content="no-cache">
5
+ <meta http-equiv="Cache-Control" content="no-store, no-cache, must-revalidate, post-check=0, pre-check=0">
6
+ <meta http-equiv="Expires" content="Thu, 01 Dec 1994 16:00:00 GMT">
7
+ <meta property="og:title" content="Title">
8
+ <meta property="og:description" content="This is a description.">
9
+ <meta property="og:type" content="video">
10
+ <meta property="og:video" content="http://ext.nicovideo.jp/thumb_watch/sm1111111?thumb_mode=swf&amp;ap=1&amp;c=1">
11
+ <meta property="og:video:width" content="485">
12
+ <meta property="og:video:height" content="385">
13
+ <meta property="og:video:type" content="application/x-shockwave-flash">
14
+ <meta property="og:site_name" content="Niconico">
15
+ <meta property="og:url" content="http://www.nicovideo.jp/watch/sm1111111">
16
+ <meta property="og:image" content="http://tn-skr2.smilevideo.jp/smile?i=1111111">
17
+ <meta property="og:locale:alternate" content="ja_JP"><meta property="og:locale:alternate" content="zh_TW"><meta property="og:locale" content="en_US">
18
+ <meta property="video:duration" content="1111">
19
+ <meta property="video:release_date" content="2012-01-01T00:00+0900">
20
+ <meta property="mixi:device-mobile" content="http://m.nicovideo.jp/watch/sm1111111?cp_webto=mixi_check_pc">
21
+ <meta property="mixi:device-docomo" content="http://m.nicovideo.jp/watch/sm1111111?uid=NULLGWDOCOMO&guid=ON&cp_webto=mixi_check_pc">
22
+ <link rel="alternate" media="handheld" href="http://nicomoba.jp/watch/sm1111111" />
23
+ <link rel="canonical" href="/watch/sm1111111">
24
+ <link rel="alternate" media="only screen and (max-width: 640px)" href="http://sp.nicovideo.jp/watch/sm1111111" />
25
+ <title>Title - niconico video Q</title>
26
+ </head>
27
+
28
+ <body>
29
+ <!--↓↓-->
30
+ <div style="width:144px; float:left; overflow:hidden;">
31
+ <p class="hLine"><img src="http://res.nimg.jp/img/watch/logout/icon_vinfo.png" alt="Video Info">Video Info</p>
32
+ <!--↓thumbnail↓-->
33
+ <div style="width:132px; border:solid 2px #C9CFCF; margin:4px;">
34
+ <p><img alt="" src="http://tn-skr2.smilevideo.jp/smile?i=1111111" class="img_std128"></p>
35
+ <p class="vinfo_length"><span>11:11</span></p>
36
+ </div>
37
+ <!--↑thumbnail↑-->
38
+ </div>
39
+ <div style="width:528px; float:left; overflow:hidden;">
40
+ <div style="padding:4px;">
41
+ <p class="font12" style="color:#696F6F; margin:0 0 4px;">
42
+ Uploaded on: <strong>Jan 1, 2012, 00:00</strong>
43
+ </p>
44
+ <!-- google_ad_section_start -->
45
+ <h1 itemprop="name">Title</h1>
46
+ <!-- google_ad_section_end -->
47
+ </div>
48
+ <table cellpadding="0" cellspacing="4" class="font12" style="clear:both;">
49
+ <tr>
50
+ <td><img src="http://res.nimg.jp/img/x.gif" alt="Views " class="icon_view"></td>
51
+ <td>Views:<strong>11,111</strong></td>
52
+ </tr>
53
+ <tr>
54
+ <td><img src="http://res.nimg.jp/img/x.gif" alt="Comments " class="icon_comment"></td>
55
+ <td>Comments:<strong>1,111</strong></td>
56
+ </tr>
57
+ <tr>
58
+ <td><img src="http://res.nimg.jp/img/x.gif" alt="Uploader" class="icon_owner"></td>
59
+ <td itemprop="author" itemscope itemtype="http://schema.org/Person">
60
+ Uploader: <strong itemprop="name">Author</strong>
61
+ </td>
62
+ </tr>
63
+ </table>
64
+ </div>
65
+
66
+
67
+
68
+ <!--↑↑-->
69
+
70
+ <!--↓動画説明文↓-->
71
+ <div class="mb8p4" style="clear:both;">
72
+ <div id="des_full">
73
+ <p class="font12" style="color:#494F4F; margin:0 0 4px;"><strong>Video Description:</strong></p>
74
+ <!-- google_ad_section_start -->
75
+ <p class="font12" style="margin-left:16px;" itemprop="description">This is a description.</p>
76
+ <!-- google_ad_section_end -->
77
+ </div>
78
+ </div>
79
+ <!--↑動画説明文↑-->
80
+
81
+ <!--↓↓-->
82
+ <div class="mb8p4">
83
+ <p class="font12" style="color:#494F4F; margin:0 0 4px;"><strong>Registered tags:</strong></p>
84
+ <p class="font12" style="margin-left:16px;"><span style="color:#999F9F;">There are no registered tags</span></p>
85
+ </div>
86
+ <div class="mb8p4" style="clear:both;"><p class="dotline_2"></p></div>
87
+ <p class="font12" style="padding:4px;">You will need to <strong>log in</strong> before you can view videos.</p>
88
+ <div id="suggest_login" class="clearfix"><a href="https://secure.nicovideo.jp/secure/register" class="registerButton button">Register New Account</a><a href="https://secure.nicovideo.jp/secure/login_form?next_url=%2Fwatch%2Fsm1111111&site=niconico&time=1111111111&hash_key=1f1f1f1f" class="loginButton button">To log in screen</a></div><div id="ext_login" class="clearfix"><a href="https://secure.nicovideo.jp/secure/login_ext/facebook?site=niconico&next_url=%2Fwatch%2Fsm1111111" id="Login_fb" title="Login using Facebook"><img src="http://res.nimg.jp/img/watch/logout/icon_facebook.png"><span>Login using Facebook</span></a><p>You can log in using Facebook→ </p></div>
89
+ <!--↑↑-->
90
+ </body>
91
+ </html>
@@ -0,0 +1,53 @@
1
+ {
2
+ "artwork_url": "http://i1.sndcdn.com/artworks-000011111111-1cfbic-large.jpg?5c687d0",
3
+ "attachments_uri": "http://api.soundcloud.com/tracks/11111111/attachments",
4
+ "bpm": null,
5
+ "comment_count": 0,
6
+ "commentable": true,
7
+ "created_at": "2012/01/01 00:08:00 +0000",
8
+ "description": "",
9
+ "download_count": 0,
10
+ "downloadable": false,
11
+ "duration": 111111,
12
+ "embeddable_by": "all",
13
+ "favoritings_count": 0,
14
+ "genre": "Garage",
15
+ "id": 11111111,
16
+ "isrc": "",
17
+ "key_signature": "",
18
+ "kind": "track",
19
+ "label_id": null,
20
+ "label_name": "",
21
+ "license": "all-rights-reserved",
22
+ "original_content_size": 1111111,
23
+ "original_format": "mp3",
24
+ "permalink": "permalink",
25
+ "permalink_url": "http://soundcloud.com/author/permalink",
26
+ "playback_count": 4,
27
+ "purchase_title": null,
28
+ "purchase_url": null,
29
+ "release": "",
30
+ "release_day": null,
31
+ "release_month": null,
32
+ "release_year": null,
33
+ "sharing": "public",
34
+ "state": "finished",
35
+ "stream_url": "http://api.soundcloud.com/tracks/11111111/stream",
36
+ "streamable": true,
37
+ "tag_list": "tag1 tag2 tag3",
38
+ "title": "Title",
39
+ "track_type": "",
40
+ "uri": "http://api.soundcloud.com/tracks/11111111",
41
+ "user": {
42
+ "avatar_url": "http://i1.sndcdn.com/avatars-000011111111-zzjvpd-large.jpg?5c687d0",
43
+ "id": 11111111,
44
+ "kind": "user",
45
+ "permalink": "author",
46
+ "permalink_url": "http://soundcloud.com/author",
47
+ "uri": "http://api.soundcloud.com/users/11111111",
48
+ "username": "Author"
49
+ },
50
+ "user_id": 11111111,
51
+ "video_url": null,
52
+ "waveform_url": "http://w1.sndcdn.com/XXXXXXXXXXXX_m.png"
53
+ }
File without changes
@@ -0,0 +1,262 @@
1
+ {
2
+ "version":"1.0",
3
+ "encoding":"UTF-8",
4
+ "entry":{
5
+ "xmlns":"http://www.w3.org/2005/Atom",
6
+ "xmlns$media":"http://search.yahoo.com/mrss/",
7
+ "xmlns$gd":"http://schemas.google.com/g/2005",
8
+ "xmlns$yt":"http://gdata.youtube.com/schemas/2007",
9
+ "gd$etag":"W/\"CEQDQX47eCp7I2A9WhNXF04.\"",
10
+ "id":{
11
+ "$t":"tag:youtube.com,2008:video:XXXXXXXXXXX"
12
+ },
13
+ "published":{
14
+ "$t":"2012-01-01T00:00:00.000Z"
15
+ },
16
+ "updated":{
17
+ "$t":"2012-01-01T00:00:00.000Z"
18
+ },
19
+ "category":[
20
+ {
21
+ "scheme":"http://schemas.google.com/g/2005#kind",
22
+ "term":"http://gdata.youtube.com/schemas/2007#video"
23
+ },
24
+ {
25
+ "scheme":"http://gdata.youtube.com/schemas/2007/categories.cat",
26
+ "term":"Music",
27
+ "label":"Music"
28
+ }
29
+ ],
30
+ "title":{
31
+ "$t":"Title"
32
+ },
33
+ "content":{
34
+ "type":"application/x-shockwave-flash",
35
+ "src":"https://www.youtube.com/v/XXXXXXXXXXX?version=3&f=videos&app=youtube_gdata"
36
+ },
37
+ "link":[
38
+ {
39
+ "rel":"http://gdata.youtube.com/schemas/2007#video.in-response-to",
40
+ "type":"application/atom+xml",
41
+ "href":"https://gdata.youtube.com/feeds/api/videos/XXXXXXXXXXX"
42
+ },
43
+ {
44
+ "rel":"alternate",
45
+ "type":"text/html",
46
+ "href":"https://www.youtube.com/watch?v=XXXXXXXXXXX&feature=youtube_gdata"
47
+ },
48
+ {
49
+ "rel":"http://gdata.youtube.com/schemas/2007#video.responses",
50
+ "type":"application/atom+xml",
51
+ "href":"https://gdata.youtube.com/feeds/api/videos/XXXXXXXXXXX/responses"
52
+ },
53
+ {
54
+ "rel":"http://gdata.youtube.com/schemas/2007#video.related",
55
+ "type":"application/atom+xml",
56
+ "href":"https://gdata.youtube.com/feeds/api/videos/XXXXXXXXXXX/related"
57
+ },
58
+ {
59
+ "rel":"http://gdata.youtube.com/schemas/2007#mobile",
60
+ "type":"text/html",
61
+ "href":"https://m.youtube.com/details?v=XXXXXXXXXXX"
62
+ },
63
+ {
64
+ "rel":"http://gdata.youtube.com/schemas/2007#uploader",
65
+ "type":"application/atom+xml",
66
+ "href":"https://gdata.youtube.com/feeds/api/users/XXX-XXXXXXXXXXXXXXXXXX"
67
+ },
68
+ {
69
+ "rel":"self",
70
+ "type":"application/atom+xml",
71
+ "href":"https://gdata.youtube.com/feeds/api/videos/XXXXXXXXXXX"
72
+ }
73
+ ],
74
+ "author":[
75
+ {
76
+ "name":{
77
+ "$t":"pogobat"
78
+ },
79
+ "uri":{
80
+ "$t":"https://gdata.youtube.com/feeds/api/users/Author"
81
+ },
82
+ "yt$userId":{
83
+ "$t":"XXX-XXXXXXXXXXXXXXXXXX"
84
+ }
85
+ }
86
+ ],
87
+ "yt$accessControl":[
88
+ {
89
+ "action":"comment",
90
+ "permission":"allowed"
91
+ },
92
+ {
93
+ "action":"commentVote",
94
+ "permission":"allowed"
95
+ },
96
+ {
97
+ "action":"videoRespond",
98
+ "permission":"allowed"
99
+ },
100
+ {
101
+ "action":"rate",
102
+ "permission":"allowed"
103
+ },
104
+ {
105
+ "action":"embed",
106
+ "permission":"allowed"
107
+ },
108
+ {
109
+ "action":"list",
110
+ "permission":"allowed"
111
+ },
112
+ {
113
+ "action":"autoPlay",
114
+ "permission":"allowed"
115
+ },
116
+ {
117
+ "action":"syndicate",
118
+ "permission":"allowed"
119
+ }
120
+ ],
121
+ "gd$comments":{
122
+ "gd$feedLink":{
123
+ "rel":"http://gdata.youtube.com/schemas/2007#comments",
124
+ "href":"https://gdata.youtube.com/feeds/api/videos/XXXXXXXXXXX/comments",
125
+ "countHint":11111
126
+ }
127
+ },
128
+ "media$group":{
129
+ "media$category":[
130
+ {
131
+ "$t":"Music",
132
+ "label":"Music",
133
+ "scheme":"http://gdata.youtube.com/schemas/2007/categories.cat"
134
+ }
135
+ ],
136
+ "media$content":[
137
+ {
138
+ "url":"https://www.youtube.com/v/XXXXXXXXXXX?version=3&f=videos&app=youtube_gdata",
139
+ "type":"application/x-shockwave-flash",
140
+ "medium":"video",
141
+ "isDefault":"true",
142
+ "expression":"full",
143
+ "duration":111,
144
+ "yt$format":5
145
+ },
146
+ {
147
+ "url":"rtsp://v8.cache6.c.youtube.com/CiILENy73wIaGQkzQ5_8oAjEHhMYDSANFEgGUgZ2aWRlb3MM/0/0/0/video.3gp",
148
+ "type":"video/3gpp",
149
+ "medium":"video",
150
+ "expression":"full",
151
+ "duration":111,
152
+ "yt$format":1
153
+ },
154
+ {
155
+ "url":"rtsp://v4.cache4.c.youtube.com/CiILENy73wIaGQkzQ5_8oAjEHhMYESARFEgGUgZ2aWRlb3MM/0/0/0/video.3gp",
156
+ "type":"video/3gpp",
157
+ "medium":"video",
158
+ "expression":"full",
159
+ "duration":111,
160
+ "yt$format":6
161
+ }
162
+ ],
163
+ "media$credit":[
164
+ {
165
+ "$t":"Author",
166
+ "role":"uploader",
167
+ "scheme":"urn:youtube",
168
+ "yt$display":"Author",
169
+ "yt$type":"partner"
170
+ }
171
+ ],
172
+ "media$description":{
173
+ "$t":"This is a description.",
174
+ "type":"plain"
175
+ },
176
+ "media$keywords":{
177
+
178
+ },
179
+ "media$license":{
180
+ "$t":"youtube",
181
+ "type":"text/html",
182
+ "href":"http://www.youtube.com/t/terms"
183
+ },
184
+ "media$player":{
185
+ "url":"https://www.youtube.com/watch?v=XXXXXXXXXXX&feature=youtube_gdata_player"
186
+ },
187
+ "media$thumbnail":[
188
+ {
189
+ "url":"http://i.ytimg.com/vi/XXXXXXXXXXX/default.jpg",
190
+ "height":90,
191
+ "width":120,
192
+ "time":"00:03:16",
193
+ "yt$name":"default"
194
+ },
195
+ {
196
+ "url":"http://i.ytimg.com/vi/XXXXXXXXXXX/mqdefault.jpg",
197
+ "height":180,
198
+ "width":320,
199
+ "yt$name":"mqdefault"
200
+ },
201
+ {
202
+ "url":"http://i.ytimg.com/vi/XXXXXXXXXXX/hqdefault.jpg",
203
+ "height":360,
204
+ "width":480,
205
+ "yt$name":"hqdefault"
206
+ },
207
+ {
208
+ "url":"http://i.ytimg.com/vi/XXXXXXXXXXX/1.jpg",
209
+ "height":90,
210
+ "width":120,
211
+ "time":"00:01:11",
212
+ "yt$name":"start"
213
+ },
214
+ {
215
+ "url":"http://i.ytimg.com/vi/XXXXXXXXXXX/2.jpg",
216
+ "height":90,
217
+ "width":120,
218
+ "time":"00:01:11",
219
+ "yt$name":"middle"
220
+ },
221
+ {
222
+ "url":"http://i.ytimg.com/vi/XXXXXXXXXXX/3.jpg",
223
+ "height":90,
224
+ "width":120,
225
+ "time":"00:01:11",
226
+ "yt$name":"end"
227
+ }
228
+ ],
229
+ "media$title":{
230
+ "$t":"Title",
231
+ "type":"plain"
232
+ },
233
+ "yt$duration":{
234
+ "seconds":"111"
235
+ },
236
+ "yt$uploaded":{
237
+ "$t":"2012-01-01T00:00:00.000Z"
238
+ },
239
+ "yt$uploaderId":{
240
+ "$t":"XXXXX-XXXXXXXXXXXXXXXXXX"
241
+ },
242
+ "yt$videoid":{
243
+ "$t":"XXXXXXXXXXX"
244
+ }
245
+ },
246
+ "gd$rating":{
247
+ "average":5.0000000,
248
+ "max":5,
249
+ "min":1,
250
+ "numRaters":11111,
251
+ "rel":"http://schemas.google.com/g/2005#overall"
252
+ },
253
+ "yt$statistics":{
254
+ "favoriteCount":"0",
255
+ "viewCount":"11111111"
256
+ },
257
+ "yt$rating":{
258
+ "numDislikes":"1111",
259
+ "numLikes":"11111"
260
+ }
261
+ }
262
+ }
data/spec/spec_helper.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'minitest/autorun'
2
+ require 'minitest/pride'
2
3
  require 'bremen'
3
4
 
4
5
  def fixture path
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bremen
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-11-19 00:00:00.000000000 Z
12
+ date: 2012-12-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: guard-minitest
@@ -43,7 +43,23 @@ dependencies:
43
43
  - - ! '>='
44
44
  - !ruby/object:Gem::Version
45
45
  version: '0'
46
- description: integrated searcher of audio track on music sites
46
+ - !ruby/object:Gem::Dependency
47
+ name: terminal-notifier-guard
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: integrated searcher of audio tracks on music sites
47
63
  email:
48
64
  - itzki.h@gmail.com
49
65
  executables: []
@@ -70,10 +86,14 @@ files:
70
86
  - spec/bremen/nicovideo_spec.rb
71
87
  - spec/bremen/soundcloud_spec.rb
72
88
  - spec/bremen/youtube_spec.rb
73
- - spec/fixtures/mixcloud.json
74
- - spec/fixtures/nicovideo.html
75
- - spec/fixtures/soundcloud.json
76
- - spec/fixtures/youtube.json
89
+ - spec/fixtures/mixcloud_multi.json
90
+ - spec/fixtures/mixcloud_single.json
91
+ - spec/fixtures/nicovideo_multi.html
92
+ - spec/fixtures/nicovideo_single.html
93
+ - spec/fixtures/soundcloud_multi.json
94
+ - spec/fixtures/soundcloud_single.json
95
+ - spec/fixtures/youtube_multi.json
96
+ - spec/fixtures/youtube_single.json
77
97
  - spec/spec_helper.rb
78
98
  homepage: https://github.com/itzki/bremen
79
99
  licenses: []
@@ -98,14 +118,19 @@ rubyforge_project:
98
118
  rubygems_version: 1.8.23
99
119
  signing_key:
100
120
  specification_version: 3
101
- summary: integrated searcher of audio track on music sites
121
+ summary: Bremen provides common search interface for some music websites. it supports
122
+ YouTube, SoundCloud, MixCloud and Nicovideo
102
123
  test_files:
103
124
  - spec/bremen/mixcloud_spec.rb
104
125
  - spec/bremen/nicovideo_spec.rb
105
126
  - spec/bremen/soundcloud_spec.rb
106
127
  - spec/bremen/youtube_spec.rb
107
- - spec/fixtures/mixcloud.json
108
- - spec/fixtures/nicovideo.html
109
- - spec/fixtures/soundcloud.json
110
- - spec/fixtures/youtube.json
128
+ - spec/fixtures/mixcloud_multi.json
129
+ - spec/fixtures/mixcloud_single.json
130
+ - spec/fixtures/nicovideo_multi.html
131
+ - spec/fixtures/nicovideo_single.html
132
+ - spec/fixtures/soundcloud_multi.json
133
+ - spec/fixtures/soundcloud_single.json
134
+ - spec/fixtures/youtube_multi.json
135
+ - spec/fixtures/youtube_single.json
111
136
  - spec/spec_helper.rb