groove-dl 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,8 @@
1
+ # -*- coding: utf-8 -*-
2
+ module GrooveDl
3
+ # Errors module
4
+ module Errors
5
+ class AlreadyDownloaded < StandardError
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ # -*- coding: utf-8 -*-
2
+ # GrooveDl version
3
+ module GrooveDl
4
+ VERSION = '0.1.0'
5
+ end
@@ -0,0 +1,87 @@
1
+ # -*- coding: utf-8 -*-
2
+ module GrooveDl
3
+ # Widgets components
4
+ module Widgets
5
+ # Download section
6
+ module Download
7
+ # Download bar
8
+ class Bar < Gtk::Box
9
+ attr_reader :type, :query
10
+
11
+ ##
12
+ # Initialize widgets
13
+ #
14
+ # @param [Grooveshark::Client] client Grooveshark client
15
+ # @param [Gtk::Window] window Gtk app
16
+ #
17
+ def load(_client, window)
18
+ set_name('download_bar')
19
+
20
+ download_box = Gtk::Box.new(:horizontal, 6)
21
+
22
+ add_button = Gtk::Button.new(label: 'Add to queue',
23
+ stock_id: Gtk::Stock::SAVE)
24
+
25
+ add_button.signal_connect('released') do
26
+ l = window.find_by_name('download_list')
27
+ l.store.clear
28
+ l.create_model(window.find_by_name('search_list').selection)
29
+ end
30
+
31
+ download_box.pack_start(add_button,
32
+ expand: false,
33
+ fill: true,
34
+ padding: 5)
35
+
36
+ directory_chooser =
37
+ Gtk::FileChooserButton.new('Select directory',
38
+ Gtk::FileChooser::Action::SELECT_FOLDER)
39
+ directory_chooser.filename = Dir.tmpdir
40
+ directory_chooser.set_name('directory_chooser')
41
+ download_box.pack_start(directory_chooser,
42
+ expand: true,
43
+ fill: true,
44
+ padding: 5)
45
+
46
+ concurrency_entry = Gtk::Entry.new
47
+ concurrency_entry.set_name('concurrency_entry')
48
+ concurrency_entry.text = '5'
49
+
50
+ concurrency_label = Gtk::Label.new('Concurrency', true)
51
+ concurrency_label.mnemonic_widget = concurrency_entry
52
+
53
+ download_box.pack_start(concurrency_label,
54
+ expand: false,
55
+ fill: false,
56
+ padding: 5)
57
+ download_box.pack_start(concurrency_entry,
58
+ expand: false,
59
+ fill: false,
60
+ padding: 5)
61
+
62
+ concurrency_entry.signal_connect('changed') do
63
+ value = concurrency_entry.text.to_i
64
+ concurrency_entry.text = value.to_s unless value == 0
65
+ end
66
+
67
+ download_button = Gtk::Button.new(label: 'Download',
68
+ stock_id: Gtk::Stock::SAVE)
69
+
70
+ download_button.signal_connect('released') do
71
+ download_button.sensitive = false
72
+ window.find_by_name('download_list').download
73
+ end
74
+
75
+ download_box.pack_start(download_button,
76
+ expand: false,
77
+ fill: true,
78
+ padding: 5)
79
+
80
+ pack_start(download_box,
81
+ expand: false,
82
+ padding: 10)
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,73 @@
1
+ # -*- coding: utf-8 -*-
2
+ module GrooveDl
3
+ # Widgets components
4
+ module Widgets
5
+ # Download section
6
+ module Download
7
+ # Download book
8
+ class Book < Gtk::Notebook
9
+ attr_reader :window
10
+
11
+ QUEUE = 'Queue (%d)'
12
+ SUCCESS = 'Success (%d)'
13
+ FAILED = 'Failed (%d)'
14
+
15
+ ##
16
+ # Initialize widgets
17
+ #
18
+ # @param [Grooveshark::Client] client Grooveshark client
19
+ # @param [Gtk::Window] window Gtk app
20
+ #
21
+ def load(client, window)
22
+ @window = window
23
+ set_name('download_book')
24
+ set_tab_pos(Gtk::PositionType::TOP)
25
+
26
+ # Download list
27
+ download_list = Widgets::Download::List::Queue.new(:vertical, 6)
28
+ download_list.set_name('download_list')
29
+ download_list.load(client, window)
30
+
31
+ @download_label = Gtk::Label.new(QUEUE % 0)
32
+ @download_label.set_name('download_label')
33
+ append_page(download_list, @download_label)
34
+
35
+ # Success list
36
+ download_success_list =
37
+ Widgets::Download::List::Success.new(:vertical, 6)
38
+ download_success_list.set_name('download_success_list')
39
+ download_success_list.load(client, window)
40
+
41
+ @download_success_label = Gtk::Label.new(SUCCESS % 0)
42
+ @download_success_label.set_name('download_success_label')
43
+ append_page(download_success_list, @download_success_label)
44
+
45
+ # Failed list
46
+ download_failed_list =
47
+ Widgets::Download::List::Failed.new(:vertical, 6)
48
+ download_failed_list.set_name('download_failed_list')
49
+ download_failed_list.load(client, window)
50
+
51
+ @download_failed_label = Gtk::Label.new(FAILED % 0)
52
+ @download_failed_label.set_name('download_failed_label')
53
+ append_page(download_failed_list, @download_failed_label)
54
+ end
55
+
56
+ ##
57
+ # Set label for page in notebook element
58
+ #
59
+ # @param [String] type Page type
60
+ # @param [Integer] nb Number of element in this page
61
+ #
62
+ def set_label(type, nb)
63
+ element = @download_label if type == 'QUEUE'
64
+ element = @download_success_label if type == 'SUCCESS'
65
+ element = @download_failed_label if type == 'FAILED'
66
+
67
+ return if element.nil?
68
+ element.set_text(Book.const_get(type.upcase) % nb)
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,75 @@
1
+ # -*- coding: utf-8 -*-
2
+ module GrooveDl
3
+ # Widgets components
4
+ module Widgets
5
+ # Download section
6
+ module Download
7
+ # List page
8
+ module List
9
+ # Failed tree
10
+ class Failed < Gtk::Box
11
+ attr_reader :store, :data
12
+
13
+ COLUMN_PATH,
14
+ COLUMN_REASON = *(0..2).to_a
15
+
16
+ ##
17
+ # Initialize widgets
18
+ #
19
+ # @param [Grooveshark::Client] client Grooveshark client
20
+ # @param [Gtk::Window] window Gtk app
21
+ #
22
+ def load(_client, _window)
23
+ @data = {}
24
+ sw = Gtk::ScrolledWindow.new
25
+ sw.shadow_type = Gtk::ShadowType::ETCHED_IN
26
+ sw.set_policy(Gtk::PolicyType::AUTOMATIC,
27
+ Gtk::PolicyType::AUTOMATIC)
28
+ pack_start(sw, expand: true, fill: true, padding: 0)
29
+
30
+ @store = Gtk::ListStore.new(String, String)
31
+ treeview = Gtk::TreeView.new(@store)
32
+ treeview.rules_hint = true
33
+
34
+ sw.add(treeview)
35
+
36
+ add_columns(treeview)
37
+ end
38
+
39
+ ##
40
+ # Append row in list store
41
+ #
42
+ # @param [Gtk::TreeIter] i Iterable element
43
+ # @param [String] reason Why this download have failed
44
+ #
45
+ def create_model(i, reason)
46
+ iter = @store.append
47
+ path = i[COLUMN_PATH]
48
+ iter[COLUMN_PATH] = path
49
+ iter[COLUMN_REASON] = reason
50
+ end
51
+
52
+ ##
53
+ # Add columns on the treeview element
54
+ #
55
+ # @param [Gtk::Treeview] treeview Treeview
56
+ #
57
+ def add_columns(treeview)
58
+ renderer = Gtk::CellRendererText.new
59
+ column = Gtk::TreeViewColumn.new('Path',
60
+ renderer,
61
+ 'text' => COLUMN_PATH)
62
+ column.fixed_width = 650
63
+ treeview.append_column(column)
64
+
65
+ renderer = Gtk::CellRendererText.new
66
+ column = Gtk::TreeViewColumn.new('Reason',
67
+ renderer,
68
+ 'text' => COLUMN_REASON)
69
+ treeview.append_column(column)
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,171 @@
1
+ # -*- coding: utf-8 -*-
2
+ module GrooveDl
3
+ # Widgets components
4
+ module Widgets
5
+ # Download section
6
+ module Download
7
+ # List page
8
+ module List
9
+ # Queue tree
10
+ class Queue < Gtk::Box
11
+ attr_reader :store, :data
12
+ attr_writer :downloader, :client
13
+ attr_accessor :failed, :success, :queue
14
+
15
+ COLUMN_PATH,
16
+ COLUMN_PGBAR_VALUE,
17
+ COLUMN_PGBAR_TEXT = *(0..2).to_a
18
+
19
+ ##
20
+ # Initialize widgets
21
+ #
22
+ # @param [Grooveshark::Client] client Grooveshark client
23
+ # @param [Gtk::Window] window Gtk app
24
+ #
25
+ def load(client, window)
26
+ @success = 0
27
+ @failed = 0
28
+ @queue = 0
29
+ @client = client
30
+ @window = window
31
+ @data = {}
32
+ @downloader = GrooveDl::Downloader.new(@client)
33
+ @downloader.type = 'gui'
34
+
35
+ sw = Gtk::ScrolledWindow.new
36
+ sw.shadow_type = Gtk::ShadowType::ETCHED_IN
37
+ sw.set_policy(Gtk::PolicyType::AUTOMATIC,
38
+ Gtk::PolicyType::AUTOMATIC)
39
+ pack_start(sw, expand: true, fill: true, padding: 0)
40
+
41
+ @store = Gtk::ListStore.new(String, Integer, String)
42
+ create_model
43
+ treeview = Gtk::TreeView.new(@store)
44
+ treeview.rules_hint = true
45
+
46
+ sw.add(treeview)
47
+
48
+ add_columns(treeview)
49
+ end
50
+
51
+ def create_model(data = {})
52
+ data.each do |id, element|
53
+ if element.is_a?(Grooveshark::Song)
54
+ iter = @store.append
55
+ iter[COLUMN_PATH] =
56
+ @downloader.build_path(@window
57
+ .find_by_name('directory_chooser')
58
+ .filename,
59
+ element)
60
+ iter[COLUMN_PGBAR_VALUE] = 0
61
+ iter[COLUMN_PGBAR_TEXT] = nil
62
+ @data[element.id] = { iter: iter, song: element }
63
+ else
64
+ playlist = Grooveshark::Playlist.new(@client,
65
+ 'playlist_id' => id)
66
+ result = {}
67
+ playlist.load_songs.each do |song|
68
+ result[song.id] = song
69
+ end
70
+
71
+ create_model(result)
72
+ end
73
+ end
74
+
75
+ return if @data.empty?
76
+ @queue = @data.count
77
+ @window.find_by_name('download_book').set_label('QUEUE', @queue)
78
+ end
79
+
80
+ ##
81
+ # Add columns on the treeview element
82
+ #
83
+ # @param [Gtk::Treeview] treeview Treeview
84
+ #
85
+ def add_columns(treeview)
86
+ renderer = Gtk::CellRendererText.new
87
+ column = Gtk::TreeViewColumn.new('Path',
88
+ renderer,
89
+ 'text' => COLUMN_PATH)
90
+ column.fixed_width = 650
91
+ treeview.append_column(column)
92
+
93
+ renderer = Gtk::CellRendererProgress.new
94
+ column = Gtk::TreeViewColumn.new('Progress',
95
+ renderer,
96
+ value: COLUMN_PGBAR_VALUE,
97
+ text: COLUMN_PGBAR_TEXT)
98
+ column.fixed_width = 100
99
+ treeview.append_column(column)
100
+ end
101
+
102
+ ##
103
+ # Download files in queue
104
+ #
105
+ def download
106
+ concurrency = @window.find_by_name('concurrency_entry').text.to_i
107
+ concurrency = 5 if concurrency == 0
108
+ Thread.abort_on_exception = true
109
+ Thread.new do
110
+ nb = 0
111
+ @data.each do |_id, s|
112
+ nb += 1
113
+ Thread.new do
114
+ download_file(s)
115
+ nb -= 1
116
+ end
117
+ sleep(0.5) until nb < concurrency
118
+ end
119
+ end
120
+ end
121
+
122
+ ##
123
+ # Download song
124
+ #
125
+ # @param [Grooveshark::Song] song Song to download
126
+ #
127
+ def download_file(song)
128
+ begin
129
+ @downloader.download(song[:song], song[:iter])
130
+ notify_success(song)
131
+ rescue Errors::AlreadyDownloaded => e
132
+ GrooveDl.configuration.logger.info(e.message)
133
+ notify_success(song)
134
+ rescue Grooveshark::GeneralError => e
135
+ GrooveDl.configuration.logger.error(e)
136
+ notify_error(song, e)
137
+ end
138
+
139
+ @window.find_by_name('download_book')
140
+ .set_label('QUEUE', @queue -= 1)
141
+ @store.remove(song[:iter])
142
+ end
143
+
144
+ ##
145
+ # Notify success
146
+ #
147
+ # @param [Grooveshark::Song] song Song displayed in success page
148
+ #
149
+ def notify_success(song)
150
+ @window.find_by_name('download_success_list')
151
+ .create_model(song[:iter])
152
+ @window.find_by_name('download_book')
153
+ .set_label('SUCCESS', @success += 1)
154
+ end
155
+
156
+ ##
157
+ # Notify erro
158
+ #
159
+ # @param [Grooveshark::Song] song Song displayed in failed page
160
+ #
161
+ def notify_error(song, e)
162
+ @window.find_by_name('download_failed_list')
163
+ .create_model(song[:iter], e.message)
164
+ @window.find_by_name('download_book')
165
+ .set_label('FAILED', @failed += 1)
166
+ end
167
+ end
168
+ end
169
+ end
170
+ end
171
+ end
@@ -0,0 +1,76 @@
1
+ # -*- coding: utf-8 -*-
2
+ module GrooveDl
3
+ # Widgets components
4
+ module Widgets
5
+ # Download section
6
+ module Download
7
+ # List page
8
+ module List
9
+ # Success tree
10
+ class Success < Gtk::Box
11
+ attr_reader :store, :data
12
+
13
+ COLUMN_PATH,
14
+ COLUMN_SIZE = *(0..1).to_a
15
+
16
+ ##
17
+ # Initialize widgets
18
+ #
19
+ # @param [Grooveshark::Client] client Grooveshark client
20
+ # @param [Gtk::Window] window Gtk app
21
+ #
22
+ def load(_client, _window)
23
+ @data = {}
24
+ sw = Gtk::ScrolledWindow.new
25
+ sw.shadow_type = Gtk::ShadowType::ETCHED_IN
26
+ sw.set_policy(Gtk::PolicyType::AUTOMATIC,
27
+ Gtk::PolicyType::AUTOMATIC)
28
+ pack_start(sw, expand: true, fill: true, padding: 0)
29
+
30
+ @store = Gtk::ListStore.new(String, String)
31
+ treeview = Gtk::TreeView.new(@store)
32
+ treeview.rules_hint = true
33
+
34
+ sw.add(treeview)
35
+
36
+ add_columns(treeview)
37
+ end
38
+
39
+ ##
40
+ # Append row in the list store
41
+ #
42
+ # @param [Gtk::TreeIter] i Iterable element
43
+ #
44
+ def create_model(i)
45
+ iter = @store.append
46
+ path = i[COLUMN_PATH]
47
+ iter[COLUMN_PATH] = path
48
+ size = (File.size?(path).to_f / (1024 * 1024)).round(2)
49
+ iter[COLUMN_SIZE] = "#{size} MB"
50
+ end
51
+
52
+ ##
53
+ # Add columns on the treeview element
54
+ #
55
+ # @param [Gtk::Treeview] treeview Treeview
56
+ #
57
+ def add_columns(treeview)
58
+ renderer = Gtk::CellRendererText.new
59
+ column = Gtk::TreeViewColumn.new('Path',
60
+ renderer,
61
+ 'text' => COLUMN_PATH)
62
+ column.fixed_width = 650
63
+ treeview.append_column(column)
64
+
65
+ renderer = Gtk::CellRendererText.new
66
+ column = Gtk::TreeViewColumn.new('Size',
67
+ renderer,
68
+ 'text' => COLUMN_SIZE)
69
+ column.fixed_width = 100
70
+ treeview.append_column(column)
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end