nehm 1.5.6.2 → 1.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/CHANGELOG.md +8 -0
- data/README.md +6 -7
- data/bin/nehm +6 -1
- data/lib/nehm.rb +31 -48
- data/lib/nehm/applescript.rb +7 -2
- data/lib/nehm/artwork.rb +6 -6
- data/lib/nehm/cfg.rb +5 -1
- data/lib/nehm/client.rb +78 -6
- data/lib/nehm/command.rb +123 -0
- data/lib/nehm/command_manager.rb +66 -0
- data/lib/nehm/commands/configure_command.rb +44 -0
- data/lib/nehm/commands/dl_command.rb +41 -0
- data/lib/nehm/commands/get_command.rb +44 -0
- data/lib/nehm/commands/help_command.rb +85 -0
- data/lib/nehm/commands/version_command.rb +23 -0
- data/lib/nehm/option_parser.rb +31 -0
- data/lib/nehm/os.rb +5 -0
- data/lib/nehm/path_manager.rb +28 -31
- data/lib/nehm/playlist.rb +7 -1
- data/lib/nehm/playlist_manager.rb +31 -14
- data/lib/nehm/track.rb +23 -21
- data/lib/nehm/tracks.rb +153 -0
- data/lib/nehm/ui.rb +35 -0
- data/lib/nehm/user_manager.rb +19 -42
- data/lib/nehm/version.rb +1 -1
- data/nehm.gemspec +2 -2
- metadata +24 -18
- data/lib/nehm/configure.rb +0 -24
- data/lib/nehm/get.rb +0 -100
- data/lib/nehm/help.rb +0 -93
- data/lib/nehm/user.rb +0 -81
@@ -1,38 +1,51 @@
|
|
1
|
+
require 'nehm/playlist'
|
2
|
+
|
1
3
|
module Nehm
|
4
|
+
|
5
|
+
##
|
6
|
+
# Playlist manager works with iTunes playlists
|
7
|
+
|
2
8
|
module PlaylistManager
|
3
|
-
|
4
|
-
|
9
|
+
|
10
|
+
##
|
11
|
+
# Returns default iTunes playlist (contains in ~/.nehmconfig)
|
12
|
+
|
13
|
+
def self.default_playlist
|
14
|
+
default_user_playlist || music_master_library unless OS.linux?
|
15
|
+
end
|
16
|
+
|
17
|
+
##
|
18
|
+
# Checks path for existence and returns it if exists
|
19
|
+
|
20
|
+
def self.get_playlist(playlist_name)
|
21
|
+
if AppleScript.list_of_playlists.include? playlist_name
|
22
|
+
Playlist.new(playlist_name)
|
23
|
+
else
|
24
|
+
UI.term 'Invalid playlist name. Please enter correct name'
|
25
|
+
end
|
5
26
|
end
|
6
27
|
|
7
28
|
def self.set_playlist
|
8
29
|
loop do
|
9
|
-
playlist = HighLine.new.ask('Enter name of default iTunes playlist to
|
30
|
+
playlist = HighLine.new.ask('Enter name of default iTunes playlist to that you want add tracks (press Enter to set it to default iTunes Music library):')
|
10
31
|
|
11
32
|
# If entered nothing, unset iTunes playlist
|
12
33
|
if playlist == ''
|
13
34
|
Cfg[:playlist] = nil
|
14
|
-
|
35
|
+
UI.success 'Default iTunes playlist unset'
|
15
36
|
break
|
16
37
|
end
|
17
38
|
|
18
39
|
if AppleScript.list_of_playlists.include? playlist
|
19
40
|
Cfg[:playlist] = playlist
|
20
|
-
|
41
|
+
UI.say "#{'Default iTunes playlist set up to'.green} #{playlist.magenta}"
|
21
42
|
break
|
22
43
|
else
|
23
|
-
|
44
|
+
UI.error 'Invalid playlist name. Please enter correct name'
|
24
45
|
end
|
25
46
|
end
|
26
47
|
end
|
27
48
|
|
28
|
-
def self.temp_playlist=(playlist)
|
29
|
-
if AppleScript.list_of_playlists.include? playlist
|
30
|
-
@temp_playlist = Playlist.new(playlist)
|
31
|
-
else
|
32
|
-
puts Paint['Invalid playlist name. Please enter correct name', :red]
|
33
|
-
exit
|
34
|
-
end
|
35
|
-
end
|
36
49
|
|
37
50
|
module_function
|
38
51
|
|
@@ -40,8 +53,12 @@ module Nehm
|
|
40
53
|
Playlist.new(Cfg[:playlist]) unless Cfg[:playlist].nil?
|
41
54
|
end
|
42
55
|
|
56
|
+
##
|
57
|
+
# Music master library is main iTunes music library
|
58
|
+
|
43
59
|
def music_master_library
|
44
60
|
Playlist.new(AppleScript.music_master_library)
|
45
61
|
end
|
62
|
+
|
46
63
|
end
|
47
64
|
end
|
data/lib/nehm/track.rb
CHANGED
@@ -1,5 +1,11 @@
|
|
1
|
+
require 'nehm/artwork'
|
2
|
+
|
1
3
|
module Nehm
|
4
|
+
|
5
|
+
# Primitive for SoundCloud track
|
6
|
+
|
2
7
|
class Track
|
8
|
+
|
3
9
|
attr_reader :hash
|
4
10
|
|
5
11
|
def initialize(hash)
|
@@ -7,13 +13,7 @@ module Nehm
|
|
7
13
|
end
|
8
14
|
|
9
15
|
def artist
|
10
|
-
|
11
|
-
|
12
|
-
if title.include? ' - '
|
13
|
-
title.split(' - ')[0]
|
14
|
-
else
|
15
|
-
@hash['user']['username']
|
16
|
-
end
|
16
|
+
name[0]
|
17
17
|
end
|
18
18
|
|
19
19
|
def artwork
|
@@ -21,34 +21,35 @@ module Nehm
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def file_name
|
24
|
-
"#{
|
24
|
+
"#{full_name.tr(',./\\\'$%"', '')}.mp3"
|
25
25
|
end
|
26
26
|
|
27
27
|
def file_path
|
28
|
-
File.join(
|
28
|
+
File.join(ENV['dl_path'], file_name)
|
29
|
+
end
|
30
|
+
|
31
|
+
def full_name
|
32
|
+
"#{artist} - #{title}"
|
29
33
|
end
|
30
34
|
|
31
35
|
def id
|
32
36
|
@hash['id']
|
33
37
|
end
|
34
38
|
|
35
|
-
#
|
39
|
+
# Returns artist and title in array
|
36
40
|
def name
|
37
|
-
|
38
|
-
|
41
|
+
title = @hash['title']
|
42
|
+
|
43
|
+
separators = [' - ', ' ~ ']
|
44
|
+
separators.each do |sep|
|
45
|
+
return title.split(sep) if title.include? sep
|
46
|
+
end
|
39
47
|
|
40
|
-
|
41
|
-
@hash['streamable']
|
48
|
+
[@hash['user']['username'], title]
|
42
49
|
end
|
43
50
|
|
44
51
|
def title
|
45
|
-
|
46
|
-
|
47
|
-
if title.include? ' - '
|
48
|
-
title.split(' - ')[1]
|
49
|
-
else
|
50
|
-
title
|
51
|
-
end
|
52
|
+
name[1]
|
52
53
|
end
|
53
54
|
|
54
55
|
def url
|
@@ -58,5 +59,6 @@ module Nehm
|
|
58
59
|
def year
|
59
60
|
@hash['created_at'][0..3].to_i
|
60
61
|
end
|
62
|
+
|
61
63
|
end
|
62
64
|
end
|
data/lib/nehm/tracks.rb
ADDED
@@ -0,0 +1,153 @@
|
|
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
|
data/lib/nehm/ui.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
module Nehm
|
2
|
+
module UI
|
3
|
+
|
4
|
+
# TODO: add Highline features to UI module
|
5
|
+
|
6
|
+
def self.error(msg)
|
7
|
+
puts "#{msg}\n".red
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.newline
|
11
|
+
puts "\n"
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.say(msg)
|
15
|
+
puts msg
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.success(msg)
|
19
|
+
puts msg.green
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.term(msg = nil)
|
23
|
+
if msg
|
24
|
+
abort msg.red
|
25
|
+
else
|
26
|
+
exit
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.warning(msg)
|
31
|
+
puts "#{msg}".yellow
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
data/lib/nehm/user_manager.rb
CHANGED
@@ -1,61 +1,38 @@
|
|
1
1
|
module Nehm
|
2
|
+
|
3
|
+
##
|
4
|
+
# User manager works with SoundCloud users' id
|
5
|
+
|
2
6
|
module UserManager
|
3
|
-
|
4
|
-
|
7
|
+
|
8
|
+
##
|
9
|
+
# Returns default user id (contains in ~/.nehmconfig)
|
10
|
+
|
11
|
+
def self.default_uid
|
12
|
+
Cfg[:default_id]
|
5
13
|
end
|
6
14
|
|
7
|
-
def self.
|
8
|
-
|
15
|
+
def self.get_uid(permalink)
|
16
|
+
user = Client.user(permalink)
|
17
|
+
UI.term 'Invalid permalink. Please enter correct permalink' if user.nil?
|
18
|
+
|
19
|
+
user['id']
|
9
20
|
end
|
10
21
|
|
11
|
-
def self.
|
22
|
+
def self.set_uid
|
12
23
|
loop do
|
13
24
|
permalink = HighLine.new.ask('Please enter your permalink (last word in your profile url): ')
|
14
|
-
user =
|
25
|
+
user = Client.user(permalink)
|
15
26
|
if user
|
16
27
|
Cfg[:default_id] = user.id
|
17
28
|
Cfg[:permalink] = permalink
|
18
|
-
|
29
|
+
UI.success 'Successfully logged in!'
|
19
30
|
break
|
20
31
|
else
|
21
|
-
|
32
|
+
UI.error 'Invalid permalink. Please enter correct permalink'
|
22
33
|
end
|
23
34
|
end
|
24
35
|
end
|
25
36
|
|
26
|
-
def self.temp_user=(permalink)
|
27
|
-
user = get_user(permalink)
|
28
|
-
if user
|
29
|
-
@temp_user = User.new(user.id)
|
30
|
-
else
|
31
|
-
puts Paint['Invalid permalink. Please enter correct permalink', :red]
|
32
|
-
exit
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
module_function
|
37
|
-
|
38
|
-
def default_user
|
39
|
-
if UserManager.logged_in?
|
40
|
-
User.new(Cfg[:default_id])
|
41
|
-
else
|
42
|
-
puts Paint["You didn't logged in", :red]
|
43
|
-
puts "Login from #{Paint['nehm configure', :yellow]} or use #{Paint['[from PERMALINK]', :yellow]} option"
|
44
|
-
exit
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def get_user(permalink)
|
49
|
-
begin
|
50
|
-
user = Client.get('/resolve', url: "https://soundcloud.com/#{permalink}")
|
51
|
-
rescue SoundCloud::ResponseError => e
|
52
|
-
if e.message =~ /404/
|
53
|
-
user = nil
|
54
|
-
else
|
55
|
-
raise e
|
56
|
-
end
|
57
|
-
end
|
58
|
-
user
|
59
|
-
end
|
60
37
|
end
|
61
38
|
end
|
data/lib/nehm/version.rb
CHANGED
data/nehm.gemspec
CHANGED
@@ -20,11 +20,11 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.require_paths = ['lib']
|
21
21
|
spec.required_ruby_version = '>= 1.9.3'
|
22
22
|
|
23
|
-
spec.add_dependency 'bogy'
|
23
|
+
spec.add_dependency 'bogy'
|
24
24
|
spec.add_dependency 'certifi'
|
25
|
+
spec.add_dependency 'colored'
|
25
26
|
spec.add_dependency 'faraday', '>= 0.9.1'
|
26
27
|
spec.add_dependency 'highline', '>= 1.7.2'
|
27
|
-
spec.add_dependency 'paint'
|
28
28
|
spec.add_dependency 'soundcloud', '>= 0.3.2'
|
29
29
|
spec.add_dependency 'taglib-ruby', '>= 0.7.0'
|
30
30
|
end
|