nehm 1.6.1 → 2.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.
- 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
|