nehm 1.6.1 → 2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +52 -35
- data/Rakefile +63 -13
- data/bin/nehm +0 -1
- data/lib/nehm.rb +33 -11
- data/lib/nehm/cfg.rb +19 -6
- data/lib/nehm/client.rb +30 -33
- data/lib/nehm/command.rb +19 -34
- data/lib/nehm/command_manager.rb +8 -18
- data/lib/nehm/commands/configure_command.rb +17 -14
- data/lib/nehm/commands/dl_command.rb +13 -11
- data/lib/nehm/commands/get_command.rb +36 -12
- data/lib/nehm/commands/help_command.rb +5 -5
- data/lib/nehm/commands/search_command.rb +41 -0
- data/lib/nehm/commands/select_command.rb +56 -0
- data/lib/nehm/http_client.rb +66 -0
- data/lib/nehm/menu.rb +96 -0
- data/lib/nehm/option_parser.rb +0 -2
- data/lib/nehm/os.rb +2 -2
- data/lib/nehm/path_manager.rb +5 -24
- data/lib/nehm/playlist.rb +2 -2
- data/lib/nehm/playlist_manager.rb +3 -5
- data/lib/nehm/track.rb +4 -2
- data/lib/nehm/track_manager.rb +135 -0
- data/lib/nehm/tracks_view_command.rb +123 -0
- data/lib/nehm/ui.rb +18 -2
- data/lib/nehm/user_manager.rb +5 -4
- data/lib/nehm/version.rb +1 -1
- data/nehm.gemspec +4 -7
- metadata +13 -64
- data/lib/nehm/tracks.rb +0 -153
@@ -0,0 +1,123 @@
|
|
1
|
+
module Nehm
|
2
|
+
class TracksViewCommand < Command
|
3
|
+
|
4
|
+
DEFAULT_LIMIT = 10
|
5
|
+
|
6
|
+
DEFAULT_OFFSET = 0
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
super
|
10
|
+
|
11
|
+
add_option(:to, 'to PATH',
|
12
|
+
'Download track(s) to PATH')
|
13
|
+
|
14
|
+
add_option(:pl, 'pl PLAYLIST',
|
15
|
+
'Add track(s) to iTunes playlist with PLAYLIST name')
|
16
|
+
|
17
|
+
add_option(:limit, 'limit NUMBER',
|
18
|
+
'Show NUMBER tracks on each page')
|
19
|
+
|
20
|
+
add_option(:offset, 'offset NUMBER',
|
21
|
+
'Show from NUMBER track')
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
def execute
|
26
|
+
tracks = []
|
27
|
+
old_offset = -1
|
28
|
+
|
29
|
+
@queue = []
|
30
|
+
@track_manager = TrackManager.new(@options)
|
31
|
+
|
32
|
+
setup_environment
|
33
|
+
|
34
|
+
loop do
|
35
|
+
# If offset changed
|
36
|
+
unless old_offset == @offset
|
37
|
+
tracks = get_tracks
|
38
|
+
old_offset = @offset
|
39
|
+
end
|
40
|
+
|
41
|
+
# If tracks == nil, then there is a last page or there aren't tracks
|
42
|
+
if tracks.nil?
|
43
|
+
@msg = 'There are no more tracks'.red
|
44
|
+
prev_page
|
45
|
+
next
|
46
|
+
end
|
47
|
+
|
48
|
+
show_menu(tracks)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
protected
|
53
|
+
|
54
|
+
def get_tracks; end
|
55
|
+
|
56
|
+
def show_menu(tracks)
|
57
|
+
UI.menu do |menu|
|
58
|
+
menu.header = 'Enter the number of track to add it to download queue'.green
|
59
|
+
|
60
|
+
menu.msg_bar = @msg
|
61
|
+
|
62
|
+
tracks.each do |track|
|
63
|
+
ids = @queue.map(&:id) # Get ids of tracks in queue
|
64
|
+
if ids.include? track.id
|
65
|
+
menu.choice(:added, track.full_name) { already_added(track) }
|
66
|
+
else
|
67
|
+
menu.choice(:inc, track.full_name) { add_track_to_queue(track) }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
menu.newline
|
72
|
+
|
73
|
+
menu.choice('d', 'Download tracks from queue'.green.freeze) { download_tracks_from_queue; UI.term }
|
74
|
+
menu.choice('n', 'Next page'.magenta.freeze) { next_page }
|
75
|
+
menu.choice('p', 'Prev page'.magenta.freeze) { prev_page }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def setup_environment
|
80
|
+
limit = @options[:limit]
|
81
|
+
@limit =
|
82
|
+
if limit
|
83
|
+
limit = limit.to_i
|
84
|
+
UI.term "Invalid limit value\nIt should be more than 0" if limit <= 0
|
85
|
+
limit
|
86
|
+
else
|
87
|
+
DEFAULT_LIMIT
|
88
|
+
end
|
89
|
+
|
90
|
+
offset = @options[:offset]
|
91
|
+
@offset =
|
92
|
+
if offset
|
93
|
+
offset = offset.to_i
|
94
|
+
UI.term "Invalid offset value\nIt should be more or equal 0" if offset < 0
|
95
|
+
offset
|
96
|
+
else
|
97
|
+
DEFAULT_OFFSET
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def add_track_to_queue(track)
|
102
|
+
@queue << track
|
103
|
+
@msg = "'#{track.full_name}' added".green
|
104
|
+
end
|
105
|
+
|
106
|
+
def already_added(track)
|
107
|
+
@msg = "'#{track.full_name}' was already added".yellow
|
108
|
+
end
|
109
|
+
|
110
|
+
def download_tracks_from_queue
|
111
|
+
@track_manager.process_tracks(@queue)
|
112
|
+
end
|
113
|
+
|
114
|
+
def next_page
|
115
|
+
@offset += @limit
|
116
|
+
end
|
117
|
+
|
118
|
+
def prev_page
|
119
|
+
@offset -= @limit if @offset >= @limit
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
end
|
data/lib/nehm/ui.rb
CHANGED
@@ -1,14 +1,26 @@
|
|
1
|
+
require 'nehm/menu'
|
2
|
+
|
1
3
|
module Nehm
|
2
4
|
module UI
|
3
5
|
|
4
|
-
|
6
|
+
##
|
7
|
+
# This constant used to set delay between user operation
|
8
|
+
# Because it's more comfortable to have a small delay
|
9
|
+
# between interactions
|
10
|
+
|
11
|
+
SLEEP_PERIOD = 0.7
|
12
|
+
|
13
|
+
def self.ask(arg)
|
14
|
+
say arg
|
15
|
+
$stdin.gets.chomp
|
16
|
+
end
|
5
17
|
|
6
18
|
def self.error(msg)
|
7
19
|
puts "#{msg}\n".red
|
8
20
|
end
|
9
21
|
|
10
22
|
def self.newline
|
11
|
-
puts
|
23
|
+
puts
|
12
24
|
end
|
13
25
|
|
14
26
|
def self.say(msg)
|
@@ -19,6 +31,10 @@ module Nehm
|
|
19
31
|
puts msg.green
|
20
32
|
end
|
21
33
|
|
34
|
+
def self.menu(&block)
|
35
|
+
Menu.new(&block)
|
36
|
+
end
|
37
|
+
|
22
38
|
def self.term(msg = nil)
|
23
39
|
if msg
|
24
40
|
abort msg.red
|
data/lib/nehm/user_manager.rb
CHANGED
@@ -5,8 +5,9 @@ module Nehm
|
|
5
5
|
|
6
6
|
module UserManager
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
def self.default_permalink
|
9
|
+
Cfg[:permalink]
|
10
|
+
end
|
10
11
|
|
11
12
|
def self.default_uid
|
12
13
|
Cfg[:default_id]
|
@@ -21,10 +22,10 @@ module Nehm
|
|
21
22
|
|
22
23
|
def self.set_uid
|
23
24
|
loop do
|
24
|
-
permalink =
|
25
|
+
permalink = UI.ask('Please enter your permalink (last word in your profile url): ')
|
25
26
|
user = Client.user(permalink)
|
26
27
|
if user
|
27
|
-
Cfg[:default_id] = user
|
28
|
+
Cfg[:default_id] = user['id']
|
28
29
|
Cfg[:permalink] = permalink
|
29
30
|
UI.success 'Successfully logged in!'
|
30
31
|
break
|
data/lib/nehm/version.rb
CHANGED
data/nehm.gemspec
CHANGED
@@ -9,22 +9,19 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ['Albert Nigmatzianov']
|
10
10
|
spec.email = ['albertnigma@gmail.com']
|
11
11
|
|
12
|
-
spec.summary =
|
13
|
-
spec.description =
|
12
|
+
spec.summary = 'Convenient way to download tracks from SoundCloud via terminal'
|
13
|
+
spec.description = 'nehm is a console tool, which downloads, sets IDv3 tags and adds to your iTunes library your SoundCloud posts or likes in convenient way. See homepage for instructions'
|
14
14
|
spec.homepage = 'http://www.github.com/bogem/nehm'
|
15
15
|
spec.license = 'MIT'
|
16
16
|
|
17
|
-
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(Pictures|Rakefile)/}) }
|
18
18
|
spec.bindir = 'bin'
|
19
19
|
spec.executables = 'nehm'
|
20
20
|
spec.require_paths = ['lib']
|
21
21
|
spec.required_ruby_version = '>= 1.9.3'
|
22
|
+
spec.post_install_message = "Don't forget to install Taglib from OS' package manager!"
|
22
23
|
|
23
|
-
spec.add_dependency 'bogy'
|
24
24
|
spec.add_dependency 'certifi'
|
25
25
|
spec.add_dependency 'colored'
|
26
|
-
spec.add_dependency 'faraday', '>= 0.9.1'
|
27
|
-
spec.add_dependency 'highline', '>= 1.7.2'
|
28
|
-
spec.add_dependency 'soundcloud', '>= 0.3.2'
|
29
26
|
spec.add_dependency 'taglib-ruby', '>= 0.7.0'
|
30
27
|
end
|
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nehm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Albert Nigmatzianov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-11-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: bogy
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ">="
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - ">="
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
27
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: certifi
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,48 +38,6 @@ dependencies:
|
|
52
38
|
- - ">="
|
53
39
|
- !ruby/object:Gem::Version
|
54
40
|
version: '0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: faraday
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: 0.9.1
|
62
|
-
type: :runtime
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: 0.9.1
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: highline
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - ">="
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: 1.7.2
|
76
|
-
type: :runtime
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - ">="
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: 1.7.2
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: soundcloud
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - ">="
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: 0.3.2
|
90
|
-
type: :runtime
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - ">="
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: 0.3.2
|
97
41
|
- !ruby/object:Gem::Dependency
|
98
42
|
name: taglib-ruby
|
99
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,9 +52,9 @@ dependencies:
|
|
108
52
|
- - ">="
|
109
53
|
- !ruby/object:Gem::Version
|
110
54
|
version: 0.7.0
|
111
|
-
description:
|
112
|
-
|
113
|
-
|
55
|
+
description: nehm is a console tool, which downloads, sets IDv3 tags and adds to your
|
56
|
+
iTunes library your SoundCloud posts or likes in convenient way. See homepage for
|
57
|
+
instructions
|
114
58
|
email:
|
115
59
|
- albertnigma@gmail.com
|
116
60
|
executables:
|
@@ -139,14 +83,19 @@ files:
|
|
139
83
|
- lib/nehm/commands/dl_command.rb
|
140
84
|
- lib/nehm/commands/get_command.rb
|
141
85
|
- lib/nehm/commands/help_command.rb
|
86
|
+
- lib/nehm/commands/search_command.rb
|
87
|
+
- lib/nehm/commands/select_command.rb
|
142
88
|
- lib/nehm/commands/version_command.rb
|
89
|
+
- lib/nehm/http_client.rb
|
90
|
+
- lib/nehm/menu.rb
|
143
91
|
- lib/nehm/option_parser.rb
|
144
92
|
- lib/nehm/os.rb
|
145
93
|
- lib/nehm/path_manager.rb
|
146
94
|
- lib/nehm/playlist.rb
|
147
95
|
- lib/nehm/playlist_manager.rb
|
148
96
|
- lib/nehm/track.rb
|
149
|
-
- lib/nehm/
|
97
|
+
- lib/nehm/track_manager.rb
|
98
|
+
- lib/nehm/tracks_view_command.rb
|
150
99
|
- lib/nehm/ui.rb
|
151
100
|
- lib/nehm/user_manager.rb
|
152
101
|
- lib/nehm/version.rb
|
@@ -155,7 +104,7 @@ homepage: http://www.github.com/bogem/nehm
|
|
155
104
|
licenses:
|
156
105
|
- MIT
|
157
106
|
metadata: {}
|
158
|
-
post_install_message:
|
107
|
+
post_install_message: Don't forget to install Taglib from OS' package manager!
|
159
108
|
rdoc_options: []
|
160
109
|
require_paths:
|
161
110
|
- lib
|
@@ -171,7 +120,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
171
120
|
version: '0'
|
172
121
|
requirements: []
|
173
122
|
rubyforge_project:
|
174
|
-
rubygems_version: 2.
|
123
|
+
rubygems_version: 2.5.0
|
175
124
|
signing_key:
|
176
125
|
specification_version: 4
|
177
126
|
summary: Convenient way to download tracks from SoundCloud via terminal
|
data/lib/nehm/tracks.rb
DELETED
@@ -1,153 +0,0 @@
|
|
1
|
-
require 'taglib'
|
2
|
-
|
3
|
-
require 'nehm/applescript'
|
4
|
-
require 'nehm/os'
|
5
|
-
require 'nehm/track'
|
6
|
-
|
7
|
-
module Nehm
|
8
|
-
|
9
|
-
##
|
10
|
-
# Tracks contains logic, that need to 'nehm get/dl ...' commands.
|
11
|
-
#
|
12
|
-
# It used in 'get_command.rb' and 'dl_command.rb'.
|
13
|
-
|
14
|
-
module Tracks
|
15
|
-
|
16
|
-
##
|
17
|
-
# Main method.
|
18
|
-
|
19
|
-
def self.[](type, options)
|
20
|
-
# Setting up user id
|
21
|
-
permalink = options[:from]
|
22
|
-
uid = permalink ? UserManager.get_uid(permalink) : UserManager.default_uid
|
23
|
-
unless uid
|
24
|
-
UI.error "You didn't logged in"
|
25
|
-
UI.say "Login from #{'nehm configure'.yellow} or use #{'[from PERMALINK]'.yellow} option"
|
26
|
-
UI.term
|
27
|
-
end
|
28
|
-
|
29
|
-
# Setting up iTunes playlist
|
30
|
-
if type == :get && !OS.linux?
|
31
|
-
playlist_name = options[:playlist]
|
32
|
-
playlist = playlist_name ? PlaylistManager.get_playlist(playlist_name) : PlaylistManager.default_playlist
|
33
|
-
itunes_playlist_ready = true if playlist
|
34
|
-
else
|
35
|
-
itunes_playlist_ready = false
|
36
|
-
end
|
37
|
-
|
38
|
-
# Setting up download path
|
39
|
-
temp_path = options[:to]
|
40
|
-
dl_path = temp_path ? PathManager.get_path(temp_path) : PathManager.default_dl_path
|
41
|
-
if dl_path
|
42
|
-
ENV['dl_path'] = dl_path
|
43
|
-
else
|
44
|
-
UI.error "You don't set up download path!"
|
45
|
-
UI.say "Set it up from #{'nehm configure'.yellow} or use #{'[to PATH_TO_DIRECTORY]'.yellow} option"
|
46
|
-
UI.term
|
47
|
-
end
|
48
|
-
|
49
|
-
UI.say 'Getting information about track(s)'
|
50
|
-
arg = options[:args].pop
|
51
|
-
tracks = []
|
52
|
-
tracks +=
|
53
|
-
case arg
|
54
|
-
when 'like'
|
55
|
-
likes(1, uid)
|
56
|
-
when 'post'
|
57
|
-
posts(1, uid)
|
58
|
-
when 'likes'
|
59
|
-
count = options[:args].pop.to_i
|
60
|
-
likes(count, uid)
|
61
|
-
when 'posts'
|
62
|
-
count = options[:args].pop.to_i
|
63
|
-
posts(count, uid)
|
64
|
-
when %r{https:\/\/soundcloud.com\/}
|
65
|
-
track(arg)
|
66
|
-
when nil
|
67
|
-
UI.error 'You must provide argument'
|
68
|
-
UI.say "Use #{'nehm help'.yellow} for help"
|
69
|
-
UI.term
|
70
|
-
else
|
71
|
-
UI.error "Invalid argument/option #{arg}"
|
72
|
-
UI.say "Use #{'nehm help'.yellow} for help"
|
73
|
-
UI.term
|
74
|
-
end
|
75
|
-
|
76
|
-
tracks.each do |track|
|
77
|
-
UI.newline
|
78
|
-
dl(track)
|
79
|
-
tag(track)
|
80
|
-
track.artwork.suicide
|
81
|
-
playlist.add_track(track.file_path) if itunes_playlist_ready
|
82
|
-
UI.newline
|
83
|
-
end
|
84
|
-
UI.success 'Done!'
|
85
|
-
end
|
86
|
-
|
87
|
-
module_function
|
88
|
-
|
89
|
-
def dl(track)
|
90
|
-
# Downloading track
|
91
|
-
UI.say 'Downloading ' + track.full_name
|
92
|
-
`curl -# -o \"#{track.file_path}\" -L #{track.url}`
|
93
|
-
|
94
|
-
# Downloading artwork
|
95
|
-
UI.say 'Downloading artwork'
|
96
|
-
artwork = track.artwork
|
97
|
-
`curl -# -o \"#{artwork.file_path}\" -L #{artwork.url}`
|
98
|
-
end
|
99
|
-
|
100
|
-
def tag(track)
|
101
|
-
UI.say 'Setting tags'
|
102
|
-
path = track.file_path
|
103
|
-
TagLib::MPEG::File.open(path) do |file|
|
104
|
-
tag = file.id3v2_tag
|
105
|
-
tag.artist = track.artist
|
106
|
-
tag.title = track.title
|
107
|
-
tag.year = track.year
|
108
|
-
|
109
|
-
# Adding artwork
|
110
|
-
apic = TagLib::ID3v2::AttachedPictureFrame.new
|
111
|
-
apic.mime_type = 'image/jpeg'
|
112
|
-
apic.description = 'Cover'
|
113
|
-
apic.type = TagLib::ID3v2::AttachedPictureFrame::FrontCover
|
114
|
-
apic.picture = File.open(track.artwork.file_path, 'rb') { |f| f.read }
|
115
|
-
tag.add_frame(apic)
|
116
|
-
|
117
|
-
file.save
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
def likes(count, uid)
|
122
|
-
likes = Client.tracks(count, :likes, uid)
|
123
|
-
UI.term 'There are no likes yet' if likes.empty?
|
124
|
-
|
125
|
-
# Removing playlists and unstreamable tracks
|
126
|
-
unstreamable_tracks = likes.reject! { |hash| hash['streamable'] == false }
|
127
|
-
UI.warning "Was skipped #{unstreamable_tracks.length} undownloadable track(s)" if unstreamable_tracks
|
128
|
-
|
129
|
-
likes.map! { |hash| Track.new(hash) }
|
130
|
-
end
|
131
|
-
|
132
|
-
def posts(count, uid)
|
133
|
-
posts = Client.tracks(count, :posts, uid)
|
134
|
-
UI.term 'There are no posts yet' if posts.empty?
|
135
|
-
|
136
|
-
# Removing playlists and unstreamable tracks
|
137
|
-
first_count = posts.length
|
138
|
-
playlists = posts.reject! { |hash| hash['type'] == 'playlist' }
|
139
|
-
unstreamable_tracks = posts.reject! { |hash| hash['track']['streamable'] == false }
|
140
|
-
if playlists || unstreamable_tracks
|
141
|
-
UI.warning "Was skipped #{first_count - posts.length} undownloadable track(s) or playlist(s)"
|
142
|
-
end
|
143
|
-
|
144
|
-
posts.map! { |hash| Track.new(hash['track']) }
|
145
|
-
end
|
146
|
-
|
147
|
-
def track(url)
|
148
|
-
hash = Client.track(url)
|
149
|
-
[*Track.new(hash)]
|
150
|
-
end
|
151
|
-
|
152
|
-
end
|
153
|
-
end
|