vnehm 1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,85 @@
1
+ module Vnehm
2
+ class HelpCommand < Command
3
+
4
+ SPACES_BTWN_NAME_AND_DESC = 3
5
+
6
+ def execute
7
+ command_name = options[:args].pop
8
+ if command_name.nil?
9
+ UI.say HELP
10
+ UI.term
11
+ end
12
+
13
+ @cmd = CommandManager.find_command(command_name)
14
+
15
+ show_usage
16
+ show_summary
17
+ show_arguments unless @cmd.arguments.empty?
18
+ show_options unless @cmd.options.empty?
19
+ end
20
+
21
+ def arguments
22
+ { 'КОМАНДА' => 'имя команды (может быть сокращено), справку которой нужно показать' }
23
+ end
24
+
25
+ def program_name
26
+ 'vnehm help'
27
+ end
28
+
29
+ def summary
30
+ 'Показ справки для определенной команды'
31
+ end
32
+
33
+ def usage
34
+ "#{program_name} КОМАНДА"
35
+ end
36
+
37
+ private
38
+
39
+ def find_longest_name(names)
40
+ names.inject do |longest, word|
41
+ word.length > longest.length ? word : longest
42
+ end
43
+ end
44
+
45
+ def show_usage
46
+ UI.say "#{'Использование:'.yellow} #{@cmd.usage}"
47
+ end
48
+
49
+ def show_summary
50
+ UI.newline
51
+ UI.say "#{'Описание:'.yellow}"
52
+ UI.say " #{@cmd.summary}"
53
+ end
54
+
55
+ def show_arguments
56
+ UI.newline
57
+ UI.say "#{'Аргументы:'.yellow}"
58
+ show_info(@cmd.arguments)
59
+ end
60
+
61
+ def show_options
62
+ UI.newline
63
+ UI.say "#{'Опции:'.yellow}"
64
+ show_info(@cmd.options_descs)
65
+ end
66
+
67
+ def show_info(hash)
68
+ @longest ||= nil
69
+
70
+ unless @longest
71
+ names = []
72
+ names += @cmd.arguments.keys unless @cmd.arguments.empty?
73
+ names += @cmd.options_descs.keys unless @cmd.options_descs.empty?
74
+ @longest ||= find_longest_name(names).length
75
+ end
76
+
77
+ hash.each do |name, desc|
78
+ need_spaces = @longest - name.length
79
+
80
+ UI.say " #{name.green}#{' ' * (need_spaces + SPACES_BTWN_NAME_AND_DESC)}#{desc}"
81
+ end
82
+ end
83
+
84
+ end
85
+ end
@@ -0,0 +1,50 @@
1
+ require 'vnehm/tracks_view_command'
2
+
3
+ module Vnehm
4
+
5
+ ##
6
+ # This command gets likes/posts from user's account,
7
+ # Prints as menu, and downloads selected tracks
8
+
9
+ class ListCommand < TracksViewCommand
10
+
11
+ def initialize
12
+ super
13
+
14
+ add_option(:to, 'to ПУТЬ',
15
+ 'Скачивать аудиозапись(и) в ПУТЬ')
16
+
17
+ add_option(:pl, 'pl ПЛЕЙЛИСТ',
18
+ "Добавлять аудиозапись(и) в плейлист iTunes'a c именем" \
19
+ ' ПЛЕЙЛИСТ')
20
+
21
+ add_option(:limit, 'limit ЧИСЛО',
22
+ 'Показывать ЧИСЛО аудиозаписей на каждой страницe')
23
+
24
+ add_option(:offset, 'offset ЧИСЛО',
25
+ 'Показывать с ЧИСЛО+1 аудиозаписи')
26
+
27
+ add_option(:dl, 'dl yes',
28
+ 'Не добавлять аудиозапись(и) в iTunes. Просто скачать их')
29
+ end
30
+
31
+ def program_name
32
+ 'vnehm list'
33
+ end
34
+
35
+ def summary
36
+ 'Вывод списка ваших аудиозаписей из VK и загрузка выбранных треков'
37
+ end
38
+
39
+ def usage
40
+ "#{program_name} [ОПЦИИ]"
41
+ end
42
+
43
+ protected
44
+
45
+ def get_tracks
46
+ @track_manager.tracks(@limit, @offset)
47
+ end
48
+
49
+ end
50
+ end
@@ -0,0 +1,67 @@
1
+ require 'vnehm/tracks_view_command'
2
+
3
+ module Vnehm
4
+
5
+ class SearchCommand < TracksViewCommand
6
+
7
+ def initialize
8
+ super
9
+
10
+ add_option(:"-t", '-t ПУТЬ',
11
+ 'Скачивать аудиозапись(и) в ПУТЬ')
12
+
13
+ add_option(:"-pl", '-pl ПЛЕЙЛИСТ',
14
+ "Добавлять аудиозапись(и) в плейлист iTunes'a c именем" \
15
+ ' ПЛЕЙЛИСТ')
16
+
17
+ add_option(:"-lim", '-lim ЧИСЛО',
18
+ 'Показывать ЧИСЛО аудиозаписей на каждой страницe')
19
+
20
+ add_option(:"-dl", '-dl yes',
21
+ 'Не добавлять аудиозаписи в iTunes. Просто скачать их')
22
+
23
+ end
24
+
25
+ def execute
26
+ # Convert dash-options to normal options
27
+ options_to_convert = { :"-t" => :to,
28
+ :"-pl" => :pl,
29
+ :"-lim" => :limit,
30
+ :"-dl" => :dl }
31
+
32
+ options_to_convert.each do |k,v|
33
+ value = @options[k]
34
+ @options.delete(k)
35
+ @options[v] = value unless value.nil?
36
+ end
37
+
38
+ @query = @options[:args].join(' ')
39
+ super
40
+ end
41
+
42
+ def arguments
43
+ { 'ЗАПРОС' => 'Искать аудиозаписи по ЗАПРОСу' }
44
+ end
45
+
46
+ def program_name
47
+ 'vnehm search'
48
+ end
49
+
50
+ def summary
51
+ 'Поиск, вывод и загрузка определенных аудиозаписей по запросу'
52
+ end
53
+
54
+ def usage
55
+ "#{program_name} ЗАПРОС [ОПЦИИ]"
56
+ end
57
+
58
+ protected
59
+
60
+ def get_tracks
61
+ UI.term 'Вы должны ввести запрос' if @query.empty?
62
+
63
+ @track_manager.search(@query, @limit, @offset)
64
+ end
65
+
66
+ end
67
+ end
@@ -0,0 +1,23 @@
1
+ require 'vnehm/version'
2
+
3
+ module Vnehm
4
+ class VersionCommand < Command
5
+
6
+ def execute
7
+ UI.say VERSION
8
+ end
9
+
10
+ def program_name
11
+ 'vnehm version'
12
+ end
13
+
14
+ def summary
15
+ 'Вывод версии приложения'
16
+ end
17
+
18
+ def usage
19
+ program_name
20
+ end
21
+
22
+ end
23
+ end
data/lib/vnehm/menu.rb ADDED
@@ -0,0 +1,78 @@
1
+ module Vnehm
2
+ module UI
3
+ class Menu
4
+
5
+ def initialize
6
+ @choices = {}
7
+ @inc_index = 1
8
+ @items = []
9
+
10
+ yield self
11
+ select
12
+ end
13
+
14
+ def choice(index, desc, &block)
15
+ # Visual index - index that you see in menu
16
+ # Select index - index than can be selected
17
+ # For example, if you use ':added' index
18
+ # In menu you see 'A', but you can select it by number
19
+ # You receive a warning though
20
+
21
+ visual_index = select_index = index
22
+
23
+ if index == :inc
24
+ visual_index = select_index = @inc_index.to_s
25
+ @inc_index += 1
26
+ end
27
+
28
+ if index == :added
29
+ visual_index = 'A'.green
30
+ select_index = @inc_index.to_s
31
+ @inc_index += 1
32
+ end
33
+
34
+ @choices[select_index] = block
35
+ @items << "#{visual_index} #{desc}"
36
+ end
37
+
38
+ def header=(value)
39
+ @items.unshift(value)
40
+ end
41
+
42
+ def newline
43
+ @items << "\n"
44
+ end
45
+
46
+ def select
47
+ # Add exit option
48
+ newline
49
+ choice('e', 'Выйти'.red) { UI.term }
50
+
51
+ # Output items
52
+ @items.each do |item|
53
+ UI.say item
54
+ end
55
+
56
+ UI.newline
57
+
58
+ selected = UI.ask('Введите опцию:'.yellow.freeze)
59
+ call_selected_block(selected)
60
+
61
+ UI.newline
62
+ end
63
+
64
+ def call_selected_block(selected)
65
+ loop do
66
+ if @choices.keys.include? selected
67
+ block = @choices[selected]
68
+ block.call unless block.nil?
69
+ break
70
+ else
71
+ selected = UI.ask "Вы должны выбрать одно из [#{@choices.keys.join(', ')}]"
72
+ end
73
+ end
74
+ end
75
+
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,29 @@
1
+ module Vnehm
2
+
3
+ ##
4
+ # OptionParser parses options and add hash with options to specified command
5
+
6
+ class OptionParser
7
+
8
+ def initialize(args, command)
9
+ @args = args
10
+ @command = command
11
+ end
12
+
13
+ def parse
14
+ options = @command.options.keys.map(&:to_s)
15
+ options.each do |option|
16
+ if @args.include? option
17
+ index = @args.index(option)
18
+ value = @args[index + 1]
19
+ @args.delete_at(index + 1)
20
+ @args.delete_at(index)
21
+
22
+ @command.options[option.to_sym] = value
23
+ end
24
+ end
25
+ @command.options[:args] = @args
26
+ end
27
+
28
+ end
29
+ end
data/lib/vnehm/os.rb ADDED
@@ -0,0 +1,13 @@
1
+ require 'rbconfig'
2
+
3
+ module Vnehm
4
+
5
+ ##
6
+ # OS module returns information about OS on this computer
7
+
8
+ module OS
9
+ def self.mac?
10
+ RbConfig::CONFIG['host_os'] =~ /darwin|mac os/ ? true : false
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,49 @@
1
+ module Vnehm
2
+
3
+ ##
4
+ # Path manager works with download paths
5
+
6
+ module PathManager
7
+
8
+ def self.default_dl_path
9
+ Cfg[:dl_path]
10
+ end
11
+
12
+ ##
13
+ # Checks path for validation and returns it if valid
14
+
15
+ def self.get_path(path)
16
+ # Check path for existence
17
+ UI.term 'Такой папки не существует! Пожалуйста, введите корректный путь' unless Dir.exist?(path)
18
+
19
+ File.expand_path(path)
20
+ end
21
+
22
+ def self.set_dl_path
23
+ loop do
24
+ ask_sentence = 'Введите путь в желаемую директорию скачиваемых аудиозаписей'
25
+ default_path = File.join(ENV['HOME'], '/Music')
26
+
27
+ if Dir.exist?(default_path)
28
+ ask_sentence << " (нажмите Enter, чтобы установить #{default_path.magenta} в качестве этой директории)"
29
+ else
30
+ default_path = nil
31
+ end
32
+
33
+ path = UI.ask(ask_sentence + ':')
34
+
35
+ # If user press enter, set path to default
36
+ path = default_path if path == '' && default_path
37
+
38
+ if Dir.exist?(path)
39
+ Cfg[:dl_path] = File.expand_path(path)
40
+ UI.say "#{'Директория загружаемых аудиотреков установлена по пути'.green} #{path.magenta}"
41
+ break
42
+ else
43
+ UI.error 'Такой папки не существует! Пожалуйста, введите корректный путь'
44
+ end
45
+ end
46
+ end
47
+
48
+ end
49
+ end
@@ -0,0 +1,24 @@
1
+ module Vnehm
2
+
3
+ ##
4
+ # iTunes playlist primitive
5
+
6
+ class Playlist
7
+
8
+ attr_reader :name
9
+
10
+ def initialize(name)
11
+ @name = name.chomp
12
+ end
13
+
14
+ def add_track(track)
15
+ UI.say 'Adding to iTunes'
16
+ AppleScript.add_track_to_playlist(track.file_path, @name)
17
+ end
18
+
19
+ def to_s
20
+ @name
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,66 @@
1
+ require 'vnehm/applescript'
2
+ require 'vnehm/playlist'
3
+
4
+ module Vnehm
5
+
6
+ ##
7
+ # Playlist manager works with iTunes playlists
8
+
9
+ module PlaylistManager
10
+
11
+ def self.default_playlist
12
+ default_user_playlist || music_master_library if OS.mac?
13
+ end
14
+
15
+ ##
16
+ # Checks path for existence and returns it if exists
17
+
18
+ def self.get_playlist(playlist_name)
19
+ if AppleScript.list_of_playlists.include? playlist_name
20
+ Playlist.new(playlist_name)
21
+ else
22
+ UI.term 'Такого плейлиста не существует. Введите корректное название'
23
+ end
24
+ end
25
+
26
+ def self.set_playlist
27
+ loop do
28
+ playlist = UI.ask('Введите имя плейлиста iTunes, в который вы ' \
29
+ 'хотите добавлять треки (нажмите Enter, чтобы ' \
30
+ 'не добавлять аудиозаписи в плейлист, ' \
31
+ 'а в музыкальную медиатеку iTunes)')
32
+
33
+ # If entered nothing, unset iTunes playlist
34
+ if playlist == ''
35
+ Cfg[:playlist] = nil
36
+ UI.success 'Треки будут добавляться в музыкальную медиатеку iTunes'
37
+ break
38
+ end
39
+
40
+ if AppleScript.list_of_playlists.include? playlist
41
+ Cfg[:playlist] = playlist
42
+ UI.say 'Аудиозаписи будут добавляться в плейлист '.green +
43
+ playlist.magenta
44
+ break
45
+ else
46
+ UI.error 'Такого плейлиста не существует. Введите корректное название'
47
+ end
48
+ end
49
+ end
50
+
51
+
52
+ module_function
53
+
54
+ def default_user_playlist
55
+ Playlist.new(Cfg[:playlist]) unless Cfg[:playlist].nil?
56
+ end
57
+
58
+ ##
59
+ # Music master library is main iTunes music library
60
+
61
+ def music_master_library
62
+ Playlist.new(AppleScript.music_master_library)
63
+ end
64
+
65
+ end
66
+ end
@@ -0,0 +1,33 @@
1
+ require 'cgi'
2
+
3
+ module Vnehm
4
+
5
+ module TokenManager
6
+
7
+ def self.token
8
+ Cfg['token'] if Cfg.exist?
9
+ end
10
+
11
+ def self.authorize
12
+ auth_url = Client.authorization_url
13
+ UI.say "1. Переходите по этой ссылке с помощью вашего браузера: #{auth_url.magenta}"
14
+ UI.say "2. Жмите #{'Разрешить'.green}"
15
+ UI.say '3. Скопируйте ссылку из адресной строки вашего браузера сюда:'
16
+ uri = UI.ask
17
+
18
+ uri = URI(uri)
19
+ hash = CGI::parse(uri.fragment)
20
+
21
+ if hash['access_token']
22
+ Cfg['token'] = hash['access_token'].first
23
+ else
24
+ UI.term 'Вы ввели неверную ссылку! ' \
25
+ 'Пожалуйста, авторизируйтесь ещё раз и перепроверьте введеные данные'
26
+ end
27
+
28
+ UI.success 'Вы успешно авторизованы!'
29
+ end
30
+
31
+ end
32
+
33
+ end
@@ -0,0 +1,51 @@
1
+ module Vnehm
2
+
3
+ # Primitive for SoundCloud track
4
+
5
+ class Track
6
+
7
+ attr_reader :hash
8
+
9
+ def initialize(hash)
10
+ @hash = hash
11
+ end
12
+
13
+ def artist
14
+ CGI::unescapeHTML(@hash.artist)
15
+ end
16
+
17
+ def duration
18
+ seconds = @hash['duration']
19
+
20
+ time = Time.at(seconds)
21
+ time -= time.utc_offset
22
+
23
+ time.hour > 0 ? time.strftime("%H:%M:%S") : time.strftime("%M:%S")
24
+ end
25
+
26
+ def file_name
27
+ "#{full_name.tr(',./\\\'$%"', '')}.mp3"
28
+ end
29
+
30
+ def file_path
31
+ File.join(ENV['dl_path'], file_name)
32
+ end
33
+
34
+ def full_name
35
+ "#{artist} - #{title}"
36
+ end
37
+
38
+ def id
39
+ @hash.aid
40
+ end
41
+
42
+ def title
43
+ CGI::unescapeHTML(@hash.title)
44
+ end
45
+
46
+ def url
47
+ @hash.url
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,86 @@
1
+ require 'taglib'
2
+
3
+ require 'vnehm/track'
4
+
5
+ module Vnehm
6
+
7
+ class TrackManager
8
+
9
+ def initialize(options)
10
+ setup_environment(options)
11
+ end
12
+
13
+ def process_tracks(tracks)
14
+ tracks.reverse_each do |track|
15
+ UI.newline
16
+ dl(track)
17
+ tag(track)
18
+ @playlist.add_track(track) if @playlist
19
+ UI.newline
20
+ end
21
+ UI.success 'Done!'
22
+ end
23
+
24
+ def tracks(limit, offset)
25
+ UI.term "Неверное значение опции 'limit'\nОно должно быть больше 0" if limit <= 0
26
+ UI.term "Неверное значении опции 'offset'\nОно должно быть больше или равно 0" if offset < 0
27
+
28
+ tracks = Client.tracks(limit, offset)
29
+ return nil if tracks.empty?
30
+
31
+ tracks.map! { |hash| Track.new(hash) }
32
+ end
33
+
34
+ def search(query, limit, offset)
35
+ UI.term "Неверное значение опции 'limit'\nОно должно быть больше 0" if limit <= 0
36
+ UI.term "Неверное значении опции 'offset'\nОно должно быть больше или равно 0" if offset < 0
37
+
38
+ found = Client.search(query, limit, offset)
39
+ return nil if found.empty?
40
+
41
+ found.shift # Deleting first item - 'count'
42
+
43
+ found.map! { |hash| Track.new(hash) }
44
+ end
45
+
46
+ private
47
+
48
+ def dl(track)
49
+ # Downloading track
50
+ UI.say 'Загрузка ' + track.full_name
51
+ `curl -# -o \"#{track.file_path}\" -L \"#{track.url}\"`
52
+ end
53
+
54
+ def tag(track)
55
+ TagLib::MPEG::File.open(track.file_path) do |file|
56
+ tag = file.id3v2_tag
57
+ tag.artist = track.artist
58
+ tag.title = track.title
59
+
60
+ file.save
61
+ end
62
+ end
63
+
64
+ def setup_environment(options)
65
+ # Setting up download path
66
+ temp_path = options[:to]
67
+ dl_path = temp_path ? PathManager.get_path(temp_path) : PathManager.default_dl_path
68
+ if dl_path
69
+ ENV['dl_path'] = dl_path
70
+ else
71
+ UI.error "Вы не указали путь, куда должны скачиваться треки!"
72
+ UI.say "Укажите его через команду #{'vnehm configure'.yellow} " \
73
+ " или используйте опцию #{'to ПУТЬ'.yellow}"
74
+ UI.term
75
+ end
76
+
77
+ # Setting up iTunes playlist
78
+ @playlist = nil
79
+ if options[:dl] != 'yes' && OS.mac?
80
+ playlist_name = options[:pl]
81
+ @playlist = playlist_name ? PlaylistManager.get_playlist(playlist_name) : PlaylistManager.default_playlist
82
+ end
83
+ end
84
+
85
+ end
86
+ end