groove-dl 0.1.0

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.
@@ -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