rmd 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.
- 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
|