rmd 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +7 -0
- data/Gemfile +1 -0
- data/README.md +7 -2
- data/Rakefile +8 -0
- data/fixtures/vcr_cassettes/nhaccuatui_playlist.yml +124306 -0
- data/fixtures/vcr_cassettes/nhaccuatui_song.yml +32531 -0
- data/fixtures/vcr_cassettes/utils_correct_url_correct.yml +40 -0
- data/fixtures/vcr_cassettes/utils_correct_url_redirect.yml +41 -0
- data/fixtures/vcr_cassettes/zing_playlist.yml +69275 -0
- data/fixtures/vcr_cassettes/zing_song.yml +33334 -0
- data/lib/rmd/base/playlist.rb +52 -0
- data/lib/rmd/base/song.rb +17 -0
- data/lib/rmd/downloader.rb +10 -1
- data/lib/rmd/factory.rb +11 -0
- data/lib/rmd/nct/getter/key_from_page.rb +5 -1
- data/lib/rmd/nct/playlist.rb +9 -46
- data/lib/rmd/nct/song.rb +2 -10
- data/lib/rmd/version.rb +1 -1
- data/lib/rmd/zing/playlist.rb +21 -0
- data/lib/rmd/zing/song.rb +45 -0
- data/lib/rmd/zing/utils/correct_url.rb +43 -0
- data/rmd.gemspec +1 -0
- data/spec/acceptants/main_spec.rb +37 -0
- data/spec/rmd/downloader_spec.rb +16 -10
- data/spec/rmd/factory_spec.rb +37 -4
- data/spec/rmd/nct/playlist_spec.rb +5 -59
- data/spec/rmd/nct/song_spec.rb +1 -1
- data/spec/rmd/zing/playlist_spec.rb +44 -0
- data/spec/rmd/zing/song_spec.rb +92 -0
- data/spec/rmd/zing/utils/correct_url_spec.rb +28 -0
- data/spec/spec_helper.rb +22 -0
- data/spec/support/download_share_examples.rb +9 -0
- data/spec/support/playlist_share_examples.rb +58 -0
- metadata +40 -2
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'mechanize'
|
2
|
+
|
3
|
+
module RMD
|
4
|
+
module Base
|
5
|
+
class Playlist
|
6
|
+
attr_reader :errors, :link, :songs
|
7
|
+
|
8
|
+
def initialize(link)
|
9
|
+
@link = link
|
10
|
+
@errors = []
|
11
|
+
@songs = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def success?
|
15
|
+
!!songs && songs.count > 0
|
16
|
+
end
|
17
|
+
|
18
|
+
def fetch; end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def agent
|
23
|
+
agent ||= Mechanize.new
|
24
|
+
end
|
25
|
+
|
26
|
+
def page
|
27
|
+
@page ||= agent.get(link)
|
28
|
+
end
|
29
|
+
|
30
|
+
def song_elements
|
31
|
+
@song_element ||= page.search(song_css)
|
32
|
+
end
|
33
|
+
|
34
|
+
def calculate_progress
|
35
|
+
if song_elements.count > 0
|
36
|
+
progress_bar = ProgressBar.create(
|
37
|
+
starting_at: 0,
|
38
|
+
total: song_elements.count,
|
39
|
+
format: '%c / %C Songs %B %p%%'
|
40
|
+
)
|
41
|
+
|
42
|
+
song_elements.each do |element|
|
43
|
+
yield element.attr('href')
|
44
|
+
progress_bar.increment
|
45
|
+
end
|
46
|
+
else
|
47
|
+
@errors << 'Can not get song lists from this playlist page.'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/rmd/downloader.rb
CHANGED
@@ -44,8 +44,17 @@ module RMD
|
|
44
44
|
private
|
45
45
|
|
46
46
|
def file_name
|
47
|
+
@file_name ||= uncached_file_name
|
48
|
+
end
|
49
|
+
|
50
|
+
def uncached_file_name
|
47
51
|
uri = URI.parse(link)
|
48
|
-
|
52
|
+
name = CGI::parse(uri.query.to_s)['filename'].first
|
53
|
+
if name
|
54
|
+
name
|
55
|
+
else
|
56
|
+
File.basename(uri.path)
|
57
|
+
end
|
49
58
|
end
|
50
59
|
end
|
51
60
|
end
|
data/lib/rmd/factory.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'rmd/song_playlist_adapter'
|
2
2
|
require 'rmd/nct/song'
|
3
3
|
require 'rmd/nct/playlist'
|
4
|
+
require 'rmd/zing/song'
|
5
|
+
require 'rmd/zing/playlist'
|
4
6
|
|
5
7
|
module RMD
|
6
8
|
class Factory
|
@@ -19,6 +21,15 @@ module RMD
|
|
19
21
|
when /playlist/
|
20
22
|
RMD::NCT::Playlist.new(link)
|
21
23
|
end
|
24
|
+
when /mp3\.zing\.vn/
|
25
|
+
case link
|
26
|
+
when /bai-hat/
|
27
|
+
RMD::SongPlaylistAdapter.new(RMD::Zing::Song.new(link))
|
28
|
+
when /album|playlist/
|
29
|
+
RMD::Zing::Playlist.new(link)
|
30
|
+
end
|
31
|
+
else
|
32
|
+
raise 'Your url is not valid. Please check again.'
|
22
33
|
end
|
23
34
|
end
|
24
35
|
|
@@ -17,7 +17,7 @@ module RMD
|
|
17
17
|
|
18
18
|
def uncached_key
|
19
19
|
page.search('script').each do |element|
|
20
|
-
if match_data =
|
20
|
+
if match_data = regex.match(element.text)
|
21
21
|
return match_data.to_a.last
|
22
22
|
end
|
23
23
|
end
|
@@ -44,6 +44,10 @@ module RMD
|
|
44
44
|
def element
|
45
45
|
@element ||= response.at_xpath('.//tracklist//location')
|
46
46
|
end
|
47
|
+
|
48
|
+
def regex
|
49
|
+
/NCTNowPlaying.intFlashPlayer\("flashPlayer", "song", "(.+)"\)\;/
|
50
|
+
end
|
47
51
|
end
|
48
52
|
end
|
49
53
|
end
|
data/lib/rmd/nct/playlist.rb
CHANGED
@@ -1,63 +1,26 @@
|
|
1
|
-
require '
|
1
|
+
require 'rmd/base/playlist'
|
2
2
|
|
3
3
|
module RMD
|
4
4
|
module NCT
|
5
|
-
class Playlist
|
6
|
-
attr_reader :errors, :link, :songs
|
7
|
-
|
8
|
-
def initialize(link)
|
9
|
-
@link = link
|
10
|
-
end
|
5
|
+
class Playlist < RMD::Base::Playlist
|
11
6
|
|
12
7
|
def fetch
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
@songs = song_elements.inject([]) do |result, element|
|
22
|
-
link = element.attr('href')
|
23
|
-
song = RMD::NCT::Song.new(link)
|
24
|
-
song.fetch
|
25
|
-
if song.success?
|
26
|
-
result << song.data_link
|
27
|
-
else
|
28
|
-
@errors << song.errors
|
29
|
-
end
|
30
|
-
|
31
|
-
progress_bar.increment
|
32
|
-
result
|
8
|
+
calculate_progress do |link|
|
9
|
+
song = RMD::NCT::Song.new(link)
|
10
|
+
song.fetch
|
11
|
+
if song.success?
|
12
|
+
@songs << song.data_link
|
13
|
+
else
|
14
|
+
@errors << song.errors
|
33
15
|
end
|
34
|
-
else
|
35
|
-
@songs = []
|
36
|
-
@errors = ['Can not get song lists from this playlist page.']
|
37
16
|
end
|
38
17
|
end
|
39
18
|
|
40
|
-
def success?
|
41
|
-
!!songs && songs.count > 0
|
42
|
-
end
|
43
|
-
|
44
19
|
private
|
45
20
|
|
46
21
|
def song_css
|
47
22
|
'.item_content .name_song'
|
48
23
|
end
|
49
|
-
|
50
|
-
def song_elements
|
51
|
-
@song_element ||= page.search(song_css)
|
52
|
-
end
|
53
|
-
|
54
|
-
def page
|
55
|
-
@page ||= agent.get(link)
|
56
|
-
end
|
57
|
-
|
58
|
-
def agent
|
59
|
-
agent ||= Mechanize.new
|
60
|
-
end
|
61
24
|
end
|
62
25
|
end
|
63
26
|
end
|
data/lib/rmd/nct/song.rb
CHANGED
@@ -1,14 +1,10 @@
|
|
1
|
+
require 'rmd/base/song'
|
1
2
|
require 'rmd/nct/getter/key_from_page'
|
2
3
|
require 'rmd/nct/getter/key_from_url'
|
3
4
|
|
4
5
|
module RMD
|
5
6
|
module NCT
|
6
|
-
class Song
|
7
|
-
attr_reader :errors, :link, :data_link
|
8
|
-
|
9
|
-
def initialize(link)
|
10
|
-
@link = link
|
11
|
-
end
|
7
|
+
class Song < RMD::Base::Song
|
12
8
|
|
13
9
|
def fetch
|
14
10
|
getters.each do |getter|
|
@@ -19,10 +15,6 @@ module RMD
|
|
19
15
|
end
|
20
16
|
end
|
21
17
|
|
22
|
-
def success?
|
23
|
-
!!data_link
|
24
|
-
end
|
25
|
-
|
26
18
|
private
|
27
19
|
|
28
20
|
def getters
|
data/lib/rmd/version.rb
CHANGED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rmd/base/playlist'
|
2
|
+
require 'rmd/zing/utils/correct_url'
|
3
|
+
|
4
|
+
module RMD
|
5
|
+
module Zing
|
6
|
+
class Playlist < RMD::Base::Playlist
|
7
|
+
|
8
|
+
def fetch
|
9
|
+
calculate_progress do |link|
|
10
|
+
@songs << RMD::Zing::Utils::CorrectUrl.correct(link)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def song_css
|
17
|
+
'._btnDownload'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'mechanize'
|
2
|
+
require 'rmd/zing/utils/correct_url'
|
3
|
+
|
4
|
+
module RMD
|
5
|
+
module Zing
|
6
|
+
class Song < RMD::Base::Song
|
7
|
+
|
8
|
+
def fetch
|
9
|
+
if new_link
|
10
|
+
@data_link = RMD::Zing::Utils::CorrectUrl.correct(new_link)
|
11
|
+
else
|
12
|
+
@errors = 'Can not get song from this link!'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def agent
|
19
|
+
@agent ||= Mechanize.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def page
|
23
|
+
@page ||= agent.get(link)
|
24
|
+
end
|
25
|
+
|
26
|
+
def regex
|
27
|
+
/http\:\/\/mp3.zing.vn\/download\/song\/\S+\/\w+/
|
28
|
+
end
|
29
|
+
|
30
|
+
def new_link
|
31
|
+
@new_link ||= uncached_new_link
|
32
|
+
end
|
33
|
+
|
34
|
+
def uncached_new_link
|
35
|
+
page.search('.detail-function script').each do |element|
|
36
|
+
if match_data = regex.match(element.text)
|
37
|
+
return match_data.to_s
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
nil
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module RMD
|
2
|
+
module Zing
|
3
|
+
module Utils
|
4
|
+
class CorrectUrl
|
5
|
+
attr_reader :url
|
6
|
+
|
7
|
+
def initialize(url)
|
8
|
+
@url = url
|
9
|
+
end
|
10
|
+
|
11
|
+
def correct
|
12
|
+
if redirect_location
|
13
|
+
URI.escape(redirect_location)
|
14
|
+
else
|
15
|
+
url
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.correct(url)
|
20
|
+
new(url).correct
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def uri
|
26
|
+
@uri ||= URI.parse(url)
|
27
|
+
end
|
28
|
+
|
29
|
+
def http_client
|
30
|
+
@http_client ||= Net::HTTP.start(uri.host)
|
31
|
+
end
|
32
|
+
|
33
|
+
def header_response
|
34
|
+
@header_response ||= http_client.head(uri.path)
|
35
|
+
end
|
36
|
+
|
37
|
+
def redirect_location
|
38
|
+
header_response['location']
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/rmd.gemspec
CHANGED
@@ -24,6 +24,7 @@ Gem::Specification.new do |spec|
|
|
24
24
|
spec.add_dependency 'colorize', '~> 0.7'
|
25
25
|
|
26
26
|
spec.add_development_dependency "bundler", "~> 1.6"
|
27
|
+
spec.add_development_dependency "rake", "~> 10.1"
|
27
28
|
spec.add_development_dependency "rspec", '~> 3.1'
|
28
29
|
spec.add_development_dependency "webmock", '~> 1.20'
|
29
30
|
spec.add_development_dependency "vcr", '~> 2.9'
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RMD::Main do
|
4
|
+
describe '#download' do
|
5
|
+
let(:run_method) { RMD::Processor.process(link) }
|
6
|
+
let(:file_path) { File.expand_path("../../../#{file_name}", __FILE__) }
|
7
|
+
|
8
|
+
context 'when downloads song from nhaccuatui' do
|
9
|
+
let(:link) { 'http://www.nhaccuatui.com/bai-hat/honjitsu-mijukumono-juken-no-kamisama-ost-tv-version-tokio.tFBwsJKDGQX9.html' }
|
10
|
+
let(:file_name) { 'HonjitsuMijukumonoJukenNoKamisamaOSTTVVersion-TOKIO-3164566.mp3' }
|
11
|
+
let(:scenario) { 'nhaccuatui song'}
|
12
|
+
it_behaves_like 'download'
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'when downloads playlist from nhaccuatui' do
|
16
|
+
let(:link) { 'http://www.nhaccuatui.com/playlist/dev-playlist-dang-cap-nhat.jn0g1fg4Z6UO.html' }
|
17
|
+
let(:file_name) { 'BlazeTvSize-KajiuraYuki_35ax5_hq.mp3' }
|
18
|
+
let(:file_path) { File.expand_path("../../../#{file_name}", __FILE__) }
|
19
|
+
let(:scenario) { 'nhaccuatui playlist' }
|
20
|
+
it_behaves_like 'download'
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'when downloads song from zing mp3' do
|
24
|
+
let(:link) { 'http://mp3.zing.vn/bai-hat/Bird-TV-Size-Yuya-Matsushita/ZWZCO98B.html' }
|
25
|
+
let(:file_name) { 'Bird TV Size - Yuya Matsushita.mp3' }
|
26
|
+
let(:scenario) { 'zing song' }
|
27
|
+
it_behaves_like 'download'
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'when downloads playlist from zing mp3' do
|
31
|
+
let(:link) { 'http://mp3.zing.vn/playlist/dev-playlist-zid-sincepast/IO0E698Z.html' }
|
32
|
+
let(:file_name) { 'sharp TV Size - Negoto.mp3' }
|
33
|
+
let(:scenario) { 'zing playlist' }
|
34
|
+
it_behaves_like 'download'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/spec/rmd/downloader_spec.rb
CHANGED
@@ -14,20 +14,26 @@ describe RMD::Downloader do
|
|
14
14
|
|
15
15
|
describe '#download' do
|
16
16
|
let(:downloader) { described_class.new(link) }
|
17
|
+
let(:run_method) { downloader.download }
|
18
|
+
let(:scenario) { 'song download' }
|
17
19
|
let(:link) { 'http://db.gamefaqs.com/portable/3ds/file/fire_emblem_awakening_shop.txt' }
|
18
20
|
let(:file_name) { 'fire_emblem_awakening_shop.txt' }
|
19
|
-
let(:content_length) { body.length }
|
20
21
|
let(:file_path) { File.expand_path("../../../#{file_name}", __FILE__) }
|
21
|
-
|
22
|
+
it_behaves_like 'download'
|
23
|
+
end
|
22
24
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
25
|
+
describe '#file_name' do
|
26
|
+
let(:downloader) { described_class.new(link) }
|
27
|
+
subject { downloader.send(:file_name) }
|
28
|
+
|
29
|
+
context 'when link does not have file name' do
|
30
|
+
let(:link) { 'www.example.com/playlist/abc.mp3' }
|
31
|
+
it { is_expected.to eq 'abc.mp3' }
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'when link have file name' do
|
35
|
+
let(:link) { 'www.example.com/playlist/abc.mp3?filename=abc%20xyz.mp3' }
|
36
|
+
it { is_expected.to eq 'abc xyz.mp3' }
|
31
37
|
end
|
32
38
|
end
|
33
39
|
end
|