irecorder 0.0.7
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.
- data/MIT-LICENSE +19 -0
- data/README +45 -0
- data/Rakefile +72 -0
- data/bin/irecorder +9 -0
- data/bin/irecorder.rb +885 -0
- data/ext/Rakefile +27 -0
- data/lib/bbcnet.rb +271 -0
- data/lib/cache.rb +121 -0
- data/lib/download.rb +441 -0
- data/lib/irecorder_resource.rb +264 -0
- data/lib/logwin.rb +119 -0
- data/lib/mylibs.rb +462 -0
- data/lib/programmewin.rb +185 -0
- data/lib/settings.rb +376 -0
- data/lib/taskwin.rb +363 -0
- data/resources/bbcstyle.qss +443 -0
- metadata +107 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2010 ruby.twiddler
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "irecorder"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
BBC iPlayer like audio recorder with KDE GUI.
|
2
|
+
You can browse BBC Radio programmes and click to download stream file.
|
3
|
+
files will be converted to mp3 files automatically.
|
4
|
+
irecorder allow to play without any other browser or play on your prefered browser.
|
5
|
+
|
6
|
+
KDE ruby
|
7
|
+
==============
|
8
|
+
irecorder require kdebindings.
|
9
|
+
Please check your distro package to install it.
|
10
|
+
or you can compile from source.
|
11
|
+
http://download.kde.org/download.php?url=stable/4.5.0/src/kdebindings-4.5.0.tar.bz2
|
12
|
+
|
13
|
+
|
14
|
+
Installation
|
15
|
+
==================
|
16
|
+
Install most important package kdebindings4.
|
17
|
+
on Mandriva Linux use urpmi command.
|
18
|
+
|
19
|
+
# sudo urpmi ruby-kde4 ruby-qt4
|
20
|
+
|
21
|
+
Install mplayer ffmpeg exiftool packages if necessary
|
22
|
+
|
23
|
+
# sudo urpmi mplayer ffmpeg perl-Image-ExifTool
|
24
|
+
|
25
|
+
Install nokogiri gem.
|
26
|
+
# sudo gem install nokogiri
|
27
|
+
|
28
|
+
Finally you can install irecorder.
|
29
|
+
|
30
|
+
# sudo gem install irecorder
|
31
|
+
or directly specify your downloaded gem file.
|
32
|
+
# sudo gem install -l irecorder-0.0.x.gem
|
33
|
+
|
34
|
+
To launch irecorder just type irecorder.rb
|
35
|
+
|
36
|
+
# irecorder.rb
|
37
|
+
|
38
|
+
|
39
|
+
Build Gem
|
40
|
+
=================
|
41
|
+
If you want to gem package from source, use rake command.
|
42
|
+
|
43
|
+
# rake gem
|
44
|
+
|
45
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
require 'rbconfig'
|
4
|
+
require 'rubygems'
|
5
|
+
require 'rake/gempackagetask'
|
6
|
+
|
7
|
+
spec = Gem::Specification.new do |s|
|
8
|
+
s.name = "irecorder"
|
9
|
+
s.version = "0.0.7"
|
10
|
+
s.author = "ruby.twiddler"
|
11
|
+
s.email = "ruby.twiddler at gmail.com"
|
12
|
+
s.homepage = "http://github.com/rubytwiddler/irecorder/wiki"
|
13
|
+
s.summary = "BBC iPlayer like audio recorder with KDE GUI."
|
14
|
+
s.files = FileList["{bin,lib}/**/*"].to_a
|
15
|
+
s.files += %w{ README MIT-LICENSE Rakefile resources/bbcstyle.qss }
|
16
|
+
s.executables = [ 'irecorder.rb' ]
|
17
|
+
s.require_path = "lib"
|
18
|
+
s.extensions = [ 'ext/Rakefile' ]
|
19
|
+
s.requirements = %w{ korundum4 qtwebkit kio ktexteditor }
|
20
|
+
s.add_runtime_dependency( 'nokogiri', '>= 1.4.0' )
|
21
|
+
s.description = <<-EOF
|
22
|
+
BBC iPlayer like audio recorder with KDE GUI.
|
23
|
+
You can browse BBC Radio programmes and click to download stream file.
|
24
|
+
files will be converted to mp3 files automatically.
|
25
|
+
irecorder allow to play without any other browser or play on your prefered browser.
|
26
|
+
like mplayer.
|
27
|
+
irecorder require kdebindings.
|
28
|
+
EOF
|
29
|
+
s.has_rdoc = false
|
30
|
+
s.extra_rdoc_files = ["README"]
|
31
|
+
end
|
32
|
+
|
33
|
+
package = Rake::GemPackageTask.new(spec) do |pkg|
|
34
|
+
pkg.need_tar = true
|
35
|
+
end
|
36
|
+
|
37
|
+
desc "install as gem package"
|
38
|
+
task :installgem => :gem do
|
39
|
+
system("gem install -r pkg/" + package.gem_file )
|
40
|
+
end
|
41
|
+
|
42
|
+
desc "install for rpm"
|
43
|
+
task :install4rpm do
|
44
|
+
def installToDir(file, dir, options={})
|
45
|
+
# puts "copy #{file} => #{dir}"
|
46
|
+
FileUtils.mkdir_p(File.join(dir, File.dirname(file)))
|
47
|
+
FileUtils.install(file, File.join(dir, File.dirname(file)), options)
|
48
|
+
end
|
49
|
+
|
50
|
+
prefix = ENV['prefix']
|
51
|
+
conf = Config::CONFIG
|
52
|
+
destDir = conf['sitelibdir'].sub(/#{conf['prefix']}/, prefix)
|
53
|
+
destDir = File.join(destDir, spec.name)
|
54
|
+
|
55
|
+
files = FileList["{bin,lib}/**/*"].to_a
|
56
|
+
files += %w{ resources/bbcstyle.qss }
|
57
|
+
files.each do |f|
|
58
|
+
# install files.
|
59
|
+
installToDir(f, destDir)
|
60
|
+
end
|
61
|
+
|
62
|
+
installToDir('bin/irecorder', prefix, :mode => 0755)
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
resouce_files = [ 'resources/irecorder.qrc' ] + FileList['resources/images/*.png']
|
67
|
+
desc "package resources"
|
68
|
+
file 'lib/irecorder_resource.rb' => resouce_files do
|
69
|
+
%x{ rbrcc resources/irecorder.qrc >lib/irecorder_resource.rb }
|
70
|
+
end
|
71
|
+
|
72
|
+
task :resource => 'lib/irecorder_resource.rb'
|
data/bin/irecorder
ADDED
data/bin/irecorder.rb
ADDED
@@ -0,0 +1,885 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
#
|
3
|
+
# 2010 by ruby.twiddler@gmail.com
|
4
|
+
#
|
5
|
+
# iPlayer like stream recorder
|
6
|
+
# record real/wma (rtsp/mms) audio stream
|
7
|
+
#
|
8
|
+
|
9
|
+
$KCODE = 'UTF8'
|
10
|
+
require 'ftools'
|
11
|
+
|
12
|
+
APP_NAME = File.basename(__FILE__).sub(/\.rb/, '')
|
13
|
+
APP_DIR = File::dirname(File.expand_path(File.dirname(__FILE__)))
|
14
|
+
LIB_DIR = File::join(APP_DIR, "lib")
|
15
|
+
APP_VERSION = "0.0.7"
|
16
|
+
|
17
|
+
# standard libs
|
18
|
+
require 'rubygems'
|
19
|
+
require 'uri'
|
20
|
+
require 'net/http'
|
21
|
+
require 'open-uri'
|
22
|
+
require 'shellwords'
|
23
|
+
require 'fileutils'
|
24
|
+
require 'singleton'
|
25
|
+
|
26
|
+
# additional libs
|
27
|
+
require 'korundum4'
|
28
|
+
require 'qtwebkit'
|
29
|
+
|
30
|
+
#
|
31
|
+
# my libraries and programs
|
32
|
+
#
|
33
|
+
$:.unshift(LIB_DIR)
|
34
|
+
require "irecorder_resource"
|
35
|
+
require "bbcnet"
|
36
|
+
require "mylibs"
|
37
|
+
require "logwin"
|
38
|
+
require "taskwin"
|
39
|
+
require "download"
|
40
|
+
require "programmewin"
|
41
|
+
require "settings"
|
42
|
+
|
43
|
+
|
44
|
+
#---------------------------------------------------------------------------------------------
|
45
|
+
#---------------------------------------------------------------------------------------------
|
46
|
+
#
|
47
|
+
# Main Window Class
|
48
|
+
#
|
49
|
+
class MainWindow < KDE::MainWindow
|
50
|
+
|
51
|
+
GroupName = "MainWindow"
|
52
|
+
|
53
|
+
#
|
54
|
+
#
|
55
|
+
#
|
56
|
+
def initialize
|
57
|
+
super(nil)
|
58
|
+
setCaption(APP_NAME)
|
59
|
+
|
60
|
+
|
61
|
+
$app.styleSheet = IO.read(APP_DIR + '/resources/bbcstyle.qss')
|
62
|
+
@actions = KDE::ActionCollection.new(self)
|
63
|
+
|
64
|
+
createWidgets
|
65
|
+
createMenu
|
66
|
+
createDlg
|
67
|
+
|
68
|
+
# default values
|
69
|
+
# BBCNet.setProxy('http://194.36.10.154:3127')
|
70
|
+
# initialize values
|
71
|
+
$log = MyLogger.new(@logWin)
|
72
|
+
$log.level = MyLogger::DEBUG
|
73
|
+
$log.info { 'Log Start.' }
|
74
|
+
|
75
|
+
# assign from config file.
|
76
|
+
readSettings
|
77
|
+
@actions.readSettings
|
78
|
+
setAutoSaveSettings(GroupName)
|
79
|
+
|
80
|
+
initializeTaskTimer
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
|
85
|
+
protected
|
86
|
+
def initializeTaskTimer
|
87
|
+
# Task Timer
|
88
|
+
@timer = Qt::Timer.new(self)
|
89
|
+
connect( @timer, SIGNAL(:timeout), self, SLOT(:updateTask) )
|
90
|
+
@timer.start(1000) # 1000 msec = 1 sec
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
#
|
95
|
+
# make menus for MainWindow
|
96
|
+
#
|
97
|
+
def createMenu
|
98
|
+
|
99
|
+
# File menu
|
100
|
+
recordAction = @actions.addNew(i18n('Start Download'), self, \
|
101
|
+
{ :icon => 'arrow-down', :triggered => :startDownload })
|
102
|
+
reloadStyleAction = @actions.addNew(i18n('&Reload StyleSheet'), self, \
|
103
|
+
{ :icon => 'view-refresh', :shortCut => 'Ctrl+R', :triggered => :reloadStyleSheet })
|
104
|
+
clearStyleAction = @actions.addNew(i18n('&Clear StyleSheet'), self, \
|
105
|
+
{ :icon => 'list-remove', :shortCut => 'Ctrl+L', :triggered => :clearStyleSheet })
|
106
|
+
quitAction = @actions.addNew(i18n('&Quit'), self, \
|
107
|
+
{ :icon => 'application-exit', :shortCut => 'Ctrl+Q', :triggered => :close })
|
108
|
+
|
109
|
+
fileMenu = KDE::Menu.new('&File', self)
|
110
|
+
fileMenu.addAction(recordAction)
|
111
|
+
fileMenu.addAction(reloadStyleAction)
|
112
|
+
fileMenu.addAction(clearStyleAction)
|
113
|
+
fileMenu.addAction(quitAction)
|
114
|
+
|
115
|
+
|
116
|
+
# settings menu
|
117
|
+
playerDockAction = @playerDock.toggleViewAction
|
118
|
+
playerDockAction.text = i18n('Show Player')
|
119
|
+
configureAppAction = @actions.addNew(i18n('Configure %s') % APP_NAME, self, \
|
120
|
+
{ :icon => 'configure', :shortCut => 'F2', :triggered => :configureApp })
|
121
|
+
|
122
|
+
settingsMenu = KDE::Menu.new(i18n('&Settings'), self)
|
123
|
+
settingsMenu.addAction(playerDockAction)
|
124
|
+
settingsMenu.addSeparator
|
125
|
+
settingsMenu.addAction(configureAppAction)
|
126
|
+
|
127
|
+
|
128
|
+
# Help menu
|
129
|
+
aboutDlg = KDE::AboutApplicationDialog.new($about)
|
130
|
+
openAboutAction = @actions.addNew(i18n('About %s') % APP_NAME, self, \
|
131
|
+
{ :icon => 'irecorder', :triggered =>[aboutDlg, :exec] })
|
132
|
+
openDocUrlAction = @actions.addNew(i18n('Open Document Wiki'), self, \
|
133
|
+
{ :icon => 'help-contents', :triggered =>:openDocUrl})
|
134
|
+
openReportIssueUrlAction = @actions.addNew(i18n('Report Bug'), self, \
|
135
|
+
{ :icon => 'tools-report-bug', :triggered =>:openReportIssueUrl })
|
136
|
+
openRdocAction = @actions.addNew(i18n('Open Rdoc'), self, \
|
137
|
+
{ :icon => 'help-contents', :triggered =>:openRdoc })
|
138
|
+
openSourceAction = @actions.addNew(i18n('Open Source Folder'), self, \
|
139
|
+
{ :icon => 'document-open-folder', :triggered =>:openSource })
|
140
|
+
|
141
|
+
|
142
|
+
helpMenu = KDE::Menu.new(i18n('&Help'), self)
|
143
|
+
helpMenu.addAction(openDocUrlAction)
|
144
|
+
helpMenu.addAction(openReportIssueUrlAction)
|
145
|
+
helpMenu.addAction(openRdocAction)
|
146
|
+
helpMenu.addAction(openSourceAction)
|
147
|
+
helpMenu.addSeparator
|
148
|
+
helpMenu.addAction(openAboutAction)
|
149
|
+
|
150
|
+
# insert menus in MenuBar
|
151
|
+
menu = KDE::MenuBar.new
|
152
|
+
menu.addMenu( fileMenu )
|
153
|
+
menu.addMenu( settingsMenu )
|
154
|
+
menu.addSeparator
|
155
|
+
menu.addMenu( helpMenu )
|
156
|
+
setMenuBar(menu)
|
157
|
+
end
|
158
|
+
|
159
|
+
|
160
|
+
|
161
|
+
|
162
|
+
#-------------------------------------------------------------
|
163
|
+
#
|
164
|
+
# create Widgets for MainWindow
|
165
|
+
#
|
166
|
+
def createWidgets
|
167
|
+
@topTab = KDE::TabWidget.new
|
168
|
+
|
169
|
+
@mainTabPage = Qt::Splitter.new
|
170
|
+
@topTab.addTab(@mainTabPage, 'Channels')
|
171
|
+
|
172
|
+
@mainTabPage.addWidget(createChannelAreaWidget)
|
173
|
+
|
174
|
+
# Main Tab page. programme table area
|
175
|
+
@progTableFrame = Qt::Splitter.new(Qt::Vertical)
|
176
|
+
@progTableFrame.addWidget(createProgrammeAreaWidget)
|
177
|
+
@progTableFrame.addWidget(createProgrammeSummaryWidget)
|
178
|
+
@mainTabPage.addWidget(@progTableFrame)
|
179
|
+
|
180
|
+
# parameter : Qt::Splitter.setStretchFactor( int index, int stretch )
|
181
|
+
@mainTabPage.setStretchFactor( 0, 0 )
|
182
|
+
@mainTabPage.setStretchFactor( 1, 1 )
|
183
|
+
|
184
|
+
# dock
|
185
|
+
createPlayerDock
|
186
|
+
|
187
|
+
|
188
|
+
# Top Tab - Task Page
|
189
|
+
@taskWin = TaskWindow.new
|
190
|
+
@topTab.addTab(@taskWin, 'Task')
|
191
|
+
|
192
|
+
# Top Tab - Log Page
|
193
|
+
@logWin = LogWindow.new
|
194
|
+
@topTab.addTab(@logWin, 'Log')
|
195
|
+
|
196
|
+
|
197
|
+
# set Top Widget & Layout
|
198
|
+
setCentralWidget(@topTab)
|
199
|
+
end
|
200
|
+
|
201
|
+
|
202
|
+
#-------------------------------------------------------------
|
203
|
+
#
|
204
|
+
TvType, RadioType, RadioCategoryType = [-1,0,1] # TvType = -1 (hide)
|
205
|
+
TVChannelRssTbl = [
|
206
|
+
['BBC One', 'bbc_one' ],
|
207
|
+
['BBC Two', 'bbc_two' ],
|
208
|
+
['BBC Three', 'bbc_three' ],
|
209
|
+
['BBC Four', 'bbc_four' ],
|
210
|
+
['CBBC', 'cbbc'],
|
211
|
+
['CBeebies', 'cbeebies'],
|
212
|
+
['BBC News Channel', 'bbc_news24'],
|
213
|
+
['BBC Parliament', 'bbc_parliament'],
|
214
|
+
['BBC HD', 'bbc_hd'],
|
215
|
+
['BBC ALBA', 'bbc_alba'] ]
|
216
|
+
|
217
|
+
RadioChannelRssTbl = [
|
218
|
+
['BBC Radio 1', 'bbc_radio_one'],
|
219
|
+
['BBC 1Xtra', 'bbc_1xtra'],
|
220
|
+
['BBC Radio 2', 'bbc_radio_two'],
|
221
|
+
['BBC Radio 3', 'bbc_radio_three'],
|
222
|
+
['BBC Radio 4', 'bbc_radio_four'],
|
223
|
+
['BBC Radio 5 live', 'bbc_radio_five_live'],
|
224
|
+
['BBC Radio 5 live sports extra', 'bbc_radio_five_live_sports_extra'],
|
225
|
+
['BBC 6 Music', 'bbc_6music'],
|
226
|
+
['BBC Radio 7', 'bbc_7'],
|
227
|
+
['BBC Asian Network', 'bbc_asian_network'],
|
228
|
+
['BBC World service', 'bbc_world_service'],
|
229
|
+
['BBC Radio Scotland', 'bbc_alba/scotland'],
|
230
|
+
['BBC Radio Nan Gàidheal', 'bbc_radio_nan_gaidheal'],
|
231
|
+
['BBC Radio Ulster', 'bbc_radio_ulster'],
|
232
|
+
['BBC Radio Foyle', 'bbc_radio_foyle'],
|
233
|
+
['BBC Radio Wales', 'bbc_radio_wales'],
|
234
|
+
['BBC Radio Cymru', 'bbc_radio_cymru'] ]
|
235
|
+
|
236
|
+
CategoryRssTbl = [
|
237
|
+
['Children\'s', 'childrens'],
|
238
|
+
['Comedy', 'comedy'],
|
239
|
+
['Drama', 'drama'],
|
240
|
+
['Entertainment', 'entertainment'],
|
241
|
+
['Factual', 'factual'],
|
242
|
+
['Films', 'films'],
|
243
|
+
['Music', 'music'],
|
244
|
+
['News', 'news'],
|
245
|
+
['Learning', 'learning'],
|
246
|
+
['Religion & Ethics', 'religion_and_ethics'],
|
247
|
+
['Sport', 'sport'],
|
248
|
+
['Sign Zone', 'signed'],
|
249
|
+
['Audio Described', 'audiodescribed'],
|
250
|
+
['Northern Ireland', 'northern_ireland'],
|
251
|
+
['Scotland', 'scotland'],
|
252
|
+
['Wales', 'wales'] ]
|
253
|
+
|
254
|
+
CategoryNameTbl = CategoryRssTbl.map do |c|
|
255
|
+
c[0][/[\w\s\'&]+/].gsub(/\'/, '').gsub(/&/, ' and ')
|
256
|
+
end
|
257
|
+
#
|
258
|
+
def createChannelListToolBox
|
259
|
+
toolBox = Qt::ToolBox.new do |w|
|
260
|
+
w.objectName = 'channelToolBox'
|
261
|
+
end
|
262
|
+
|
263
|
+
# default value
|
264
|
+
toolBox.currentIndex = 2
|
265
|
+
|
266
|
+
# TV & Radio Channels selector
|
267
|
+
# @tvChannelListBox = KDE::ListWidget.new
|
268
|
+
# # TV Channels
|
269
|
+
# @tvChannelListBox.addItems( TVChannelRssTbl.map do |w| w[0] end )
|
270
|
+
# toolBox.addItem( @tvChannelListBox, 'TV Channels' )
|
271
|
+
|
272
|
+
|
273
|
+
# Radio Channels
|
274
|
+
@radioChannelListBox = KDE::ListWidget.new
|
275
|
+
@radioChannelListBox.addItems( RadioChannelRssTbl.map do |w| w[0] end )
|
276
|
+
toolBox.addItem( @radioChannelListBox, 'Radio Channels' )
|
277
|
+
|
278
|
+
# Category selector
|
279
|
+
@categoryListBox = KDE::ListWidget.new
|
280
|
+
@categoryListBox.addItems( CategoryRssTbl.map do |w| w[0] end )
|
281
|
+
toolBox.addItem( @categoryListBox, 'Radio Categories' )
|
282
|
+
|
283
|
+
toolBox
|
284
|
+
end
|
285
|
+
|
286
|
+
#-------------------------------------------------------------
|
287
|
+
#
|
288
|
+
# [ All / Highlights / Most Popular ] selector
|
289
|
+
#
|
290
|
+
def createListTypeButtons
|
291
|
+
@listTypeGroup = Qt::ButtonGroup.new
|
292
|
+
allBtn = KDE::PushButton.new('All') do |w|
|
293
|
+
w.objectName = 'switchButton'
|
294
|
+
w.checkable = true
|
295
|
+
w.autoExclusive = true
|
296
|
+
connect(w, SIGNAL(:clicked), self, SLOT(:getList))
|
297
|
+
end
|
298
|
+
|
299
|
+
highlightsBtn = KDE::PushButton.new('Highlights') do |w|
|
300
|
+
w.objectName = 'switchButton'
|
301
|
+
w.setMinimumWidth(80)
|
302
|
+
w.checkable = true
|
303
|
+
w.autoExclusive = true
|
304
|
+
connect(w, SIGNAL(:clicked), self, SLOT(:getList))
|
305
|
+
end
|
306
|
+
|
307
|
+
mostBtn = KDE::PushButton.new('Most Popular') do |w|
|
308
|
+
w.objectName = 'switchButton'
|
309
|
+
w.checkable = true
|
310
|
+
w.autoExclusive = true
|
311
|
+
connect(w, SIGNAL(:clicked), self, SLOT(:getList))
|
312
|
+
end
|
313
|
+
listTypeHLayout = Qt::HBoxLayout.new
|
314
|
+
listTypeHLayout.addWidget(allBtn, 54) # 2nd parameter is stretch.
|
315
|
+
listTypeHLayout.addWidget(highlightsBtn, 180)
|
316
|
+
listTypeHLayout.addWidget(mostBtn,235)
|
317
|
+
|
318
|
+
@listTypeGroup.addButton(allBtn, 0)
|
319
|
+
@listTypeGroup.addButton(highlightsBtn, 1)
|
320
|
+
@listTypeGroup.addButton(mostBtn, 2)
|
321
|
+
@listTypeGroup.exclusive = true
|
322
|
+
|
323
|
+
listTypeHLayout
|
324
|
+
end
|
325
|
+
|
326
|
+
|
327
|
+
#-------------------------------------------------------------
|
328
|
+
#
|
329
|
+
# Left Side Channel ToolBox & ListType Buttons
|
330
|
+
def createChannelAreaWidget
|
331
|
+
VBoxLayoutWidget.new do |vb|
|
332
|
+
@channelTypeToolBox = createChannelListToolBox
|
333
|
+
vb.addWidget(@channelTypeToolBox)
|
334
|
+
vb.addLayout(createListTypeButtons)
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
#-------------------------------------------------------------
|
339
|
+
#
|
340
|
+
#
|
341
|
+
def createProgrammeAreaWidget
|
342
|
+
VBoxLayoutWidget.new do |vbxw|
|
343
|
+
@programmeTable = ProgrammeTableWidget.new do |w|
|
344
|
+
connect(w, SIGNAL('cellClicked(int,int)'),
|
345
|
+
self, SLOT('programmeCellClicked(int,int)'))
|
346
|
+
end
|
347
|
+
vbxw.addWidget(HBoxLayoutWidget.new do |hw|
|
348
|
+
hw.addWidget(Qt::Label.new(i18n('Look for:')))
|
349
|
+
hw.addWidget(
|
350
|
+
@filterLineEdit = KDE::LineEdit.new do |w|
|
351
|
+
connect(w,SIGNAL('textChanged(const QString &)'),
|
352
|
+
@programmeTable, SLOT('filterChanged(const QString &)'))
|
353
|
+
w.setClearButtonShown(true)
|
354
|
+
connect(@programmeTable, SIGNAL('filterRequest(const QString &)'),
|
355
|
+
w, SLOT('setText(const QString &)'))
|
356
|
+
end
|
357
|
+
)
|
358
|
+
end
|
359
|
+
)
|
360
|
+
vbxw.addWidget( @listTitleLabel = Qt::Label.new('') )
|
361
|
+
vbxw.addWidget(@programmeTable)
|
362
|
+
|
363
|
+
playIcon = KDE::Icon.new(':images/play-22.png')
|
364
|
+
playBtn = KDE::PushButton.new( playIcon, i18n("Play")) do |w|
|
365
|
+
w.objectName = 'playButton'
|
366
|
+
connect( w, SIGNAL(:clicked), self, SLOT(:playProgramme) )
|
367
|
+
end
|
368
|
+
|
369
|
+
# 'Start Download' Button
|
370
|
+
downloadIcon = KDE::Icon.new(':images/download-22.png')
|
371
|
+
downloadBtn = KDE::PushButton.new( downloadIcon, i18n("Download")) do |w|
|
372
|
+
w.objectName = 'downloadButton'
|
373
|
+
connect( w, SIGNAL(:clicked), self, SLOT(:startDownload) )
|
374
|
+
end
|
375
|
+
|
376
|
+
vbxw.addWidgets( nil, playBtn, nil, downloadBtn, nil )
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
#-------------------------------------------------------------
|
381
|
+
#
|
382
|
+
#
|
383
|
+
def createProgrammeSummaryWidget
|
384
|
+
@programmeSummaryWebView = Qt::WebView.new do |w|
|
385
|
+
w.page.linkDelegationPolicy = Qt::WebPage::DelegateAllLinks
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
#-------------------------------------------------------------
|
390
|
+
#
|
391
|
+
#
|
392
|
+
def createPlayerDock
|
393
|
+
@playerDock = Qt::DockWidget.new(self) do |w|
|
394
|
+
w.objectName = 'playerDock'
|
395
|
+
w.windowTitle = i18n('Player')
|
396
|
+
w.allowedAreas = Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::BottomDockWidgetArea
|
397
|
+
w.floating = true
|
398
|
+
w.hide
|
399
|
+
end
|
400
|
+
@playerWevView = Qt::WebView.new do |w|
|
401
|
+
w.page.linkDelegationPolicy = Qt::WebPage::DelegateAllLinks
|
402
|
+
end
|
403
|
+
|
404
|
+
webSettings = Qt::WebSettings::globalSettings
|
405
|
+
webSettings.setAttribute(Qt::WebSettings::PluginsEnabled, true)
|
406
|
+
|
407
|
+
|
408
|
+
@playerDock.setWidget(@playerWevView)
|
409
|
+
self.addDockWidget(Qt::RightDockWidgetArea, @playerDock)
|
410
|
+
|
411
|
+
@playerDock
|
412
|
+
end
|
413
|
+
|
414
|
+
#-------------------------------------------------------------
|
415
|
+
#
|
416
|
+
#
|
417
|
+
def createDlg
|
418
|
+
@settingsDlg = SettingsDlg.new(self)
|
419
|
+
end
|
420
|
+
|
421
|
+
|
422
|
+
slots :configureApp
|
423
|
+
# slot
|
424
|
+
def configureApp
|
425
|
+
@settingsDlg.exec
|
426
|
+
end
|
427
|
+
|
428
|
+
|
429
|
+
#-------------------------------------------------------------
|
430
|
+
#
|
431
|
+
# virtual function slot
|
432
|
+
def closeEvent(event)
|
433
|
+
writeSettings
|
434
|
+
super(event)
|
435
|
+
$config.sync # important! qtruby can't invoke destructor properly.
|
436
|
+
end
|
437
|
+
|
438
|
+
def readSettings
|
439
|
+
config = $config.group(GroupName)
|
440
|
+
@mainTabPage.restoreState(config.readEntry('MainTabPageState', @mainTabPage.saveState))
|
441
|
+
@progTableFrame.restoreState(config.readEntry('ProgTableFrame',
|
442
|
+
@progTableFrame.saveState))
|
443
|
+
@channelTypeToolBox.currentIndex = config.readEntry('ChannelType', @channelTypeToolBox.currentIndex)
|
444
|
+
|
445
|
+
@programmeTable.readSettings
|
446
|
+
@taskWin.readSettings
|
447
|
+
end
|
448
|
+
|
449
|
+
def writeSettings
|
450
|
+
config = $config.group(GroupName)
|
451
|
+
config.writeEntry('MainTabPageState', @mainTabPage.saveState)
|
452
|
+
config.writeEntry('ProgTableFrame', @progTableFrame.saveState)
|
453
|
+
config.writeEntry('ChannelType', @channelTypeToolBox.currentIndex)
|
454
|
+
|
455
|
+
@programmeTable.writeSettings
|
456
|
+
@taskWin.writeSettings
|
457
|
+
# dumpConfig(GroupName)
|
458
|
+
end
|
459
|
+
|
460
|
+
def dumpConfig(group)
|
461
|
+
puts "dump #{group} config"
|
462
|
+
entries = KDE::Global.config.entryMap(group)
|
463
|
+
confGroup = KDE::Global.config.group(group)
|
464
|
+
entries.each do |key, val|
|
465
|
+
puts " key(#{key}) = #{val.inspect}"
|
466
|
+
end
|
467
|
+
end
|
468
|
+
|
469
|
+
# ------------------------------------------------------------------------
|
470
|
+
slots :reloadStyleSheet
|
471
|
+
def reloadStyleSheet
|
472
|
+
styleStr = IO.read(APP_DIR + '/resources/bbcstyle.qss')
|
473
|
+
$app.styleSheet = styleStr
|
474
|
+
$app.styleSheet = styleStr
|
475
|
+
$log.info { 'Reloaded StyleSheet.' }
|
476
|
+
end
|
477
|
+
|
478
|
+
slots :clearStyleSheet
|
479
|
+
def clearStyleSheet
|
480
|
+
$app.styleSheet = nil
|
481
|
+
$log.info { 'Cleared StyleSheet.' }
|
482
|
+
end
|
483
|
+
|
484
|
+
|
485
|
+
# slot :
|
486
|
+
slots 'programmeCellClicked(int,int)'
|
487
|
+
def programmeCellClicked(row, column)
|
488
|
+
prog = @programmeTable[row]
|
489
|
+
color = "#%06x" % (@programmeSummaryWebView.palette.color(Qt::Palette::Text).rgb & 0xffffff)
|
490
|
+
|
491
|
+
html = <<-EOF
|
492
|
+
<style type="text/css">
|
493
|
+
img { float: left; margin: 4px; }
|
494
|
+
</style>
|
495
|
+
<font color="#{color}">
|
496
|
+
#{prog.content}
|
497
|
+
</font>
|
498
|
+
EOF
|
499
|
+
|
500
|
+
@programmeSummaryWebView.setHtml(html)
|
501
|
+
end
|
502
|
+
|
503
|
+
|
504
|
+
|
505
|
+
def makeProcCommand(command, url)
|
506
|
+
cmd, args = command.split(/\s+/, 2)
|
507
|
+
args = args.split(/\s+/).map do |a|
|
508
|
+
a.gsub(/%\w/, url)
|
509
|
+
end
|
510
|
+
[ cmd, args ]
|
511
|
+
end
|
512
|
+
|
513
|
+
slots :playProgramme
|
514
|
+
def playProgramme
|
515
|
+
items = @programmeTable.selectedItems
|
516
|
+
return unless items.size > 0
|
517
|
+
|
518
|
+
|
519
|
+
def getIplayerUrl(prog)
|
520
|
+
# big type console
|
521
|
+
url = prog.link
|
522
|
+
$log.info { "big console Url : #{url}" }
|
523
|
+
|
524
|
+
# old type console
|
525
|
+
url = prog.content[UrlRegexp] # String[] method extract only 1st one.
|
526
|
+
$log.info { "episode Url : #{url}" }
|
527
|
+
url = BBCNet.getPlayerConsoleUrl(url)
|
528
|
+
$log.info { "old console Url : #{url}" }
|
529
|
+
|
530
|
+
if IRecSettings.playerTypeBeta then
|
531
|
+
url.sub!(%r{www}, 'beta')
|
532
|
+
$log.info { "new console Url : #{url}" }
|
533
|
+
end
|
534
|
+
url
|
535
|
+
end
|
536
|
+
|
537
|
+
prog = @programmeTable[items[0].row]
|
538
|
+
webPlayerCommand = IRecSettings.webPlayerCommand
|
539
|
+
directPlayerCommand = IRecSettings.directPlayerCommand
|
540
|
+
|
541
|
+
begin
|
542
|
+
if IRecSettings.useInnerPlayer then
|
543
|
+
url = getIplayerUrl(prog)
|
544
|
+
|
545
|
+
@playerDock.show
|
546
|
+
@playerWevView.setUrl(Qt::Url.new(url))
|
547
|
+
elsif IRecSettings.useWebPlayer and webPlayerCommand then
|
548
|
+
$log.info { "Play on web browser" }
|
549
|
+
url = getIplayerUrl(prog)
|
550
|
+
cmd, args = makeProcCommand(webPlayerCommand, url)
|
551
|
+
$log.debug { "execute cmd '#{cmd}', args '#{args.inspect}'" }
|
552
|
+
proc = Qt::Process.new(self)
|
553
|
+
proc.start(cmd, args)
|
554
|
+
|
555
|
+
elsif IRecSettings.useDirectPlayer and directPlayerCommand then
|
556
|
+
$log.info { "Play direct" }
|
557
|
+
url = prog.content[UrlRegexp] # String[] method extract only 1st one.
|
558
|
+
|
559
|
+
$log.info { "episode Url : #{url}" }
|
560
|
+
minfo = BBCNet::CacheMetaInfoDevice.read(url)
|
561
|
+
$log.debug { "#{minfo.inspect}" }
|
562
|
+
raise "No stream Url" unless minfo.wma
|
563
|
+
url = minfo.wma.url
|
564
|
+
|
565
|
+
cmd, args = makeProcCommand(directPlayerCommand, url)
|
566
|
+
|
567
|
+
$log.debug { "execute cmd '#{cmd}', args '#{args.inspect}'" }
|
568
|
+
proc = Qt::Process.new(self)
|
569
|
+
proc.start(cmd, args)
|
570
|
+
end
|
571
|
+
rescue => e
|
572
|
+
if e.kind_of? RuntimeError
|
573
|
+
$log.info { e.message }
|
574
|
+
else
|
575
|
+
$log.error { e }
|
576
|
+
end
|
577
|
+
# some messages must be treated.
|
578
|
+
# already expired.
|
579
|
+
# some xml error.
|
580
|
+
# no url
|
581
|
+
passiveMessage(i18n("There is no direct stream for this programme.\n %s" %[prog.title]))
|
582
|
+
end
|
583
|
+
end
|
584
|
+
|
585
|
+
slots :openDocUrl
|
586
|
+
def openDocUrl
|
587
|
+
openUrlDocument('http://github.com/rubytwiddler/irecorder/wiki')
|
588
|
+
end
|
589
|
+
|
590
|
+
slots :openReportIssueUrl
|
591
|
+
def openReportIssueUrl
|
592
|
+
openUrlDocument('http://github.com/rubytwiddler/irecorder/issues')
|
593
|
+
end
|
594
|
+
|
595
|
+
slots :openRdoc
|
596
|
+
def openRdoc
|
597
|
+
@@gemPath ||= %x{ gem environment gempath }.split(/:/)
|
598
|
+
relPath = '/doc/' + APP_NAME + '-' + APP_VERSION + '/rdoc/index.html'
|
599
|
+
topPath = @@gemPath.find do |p|
|
600
|
+
File.exist?(p + relPath)
|
601
|
+
end
|
602
|
+
return unless topPath
|
603
|
+
openUrlDocument(topPath + relPath)
|
604
|
+
end
|
605
|
+
|
606
|
+
slots :openSource
|
607
|
+
def openSource
|
608
|
+
openDirectory(APP_DIR)
|
609
|
+
end
|
610
|
+
|
611
|
+
def openUrlDocument(url)
|
612
|
+
webPlayerCommand = IRecSettings.webPlayerCommand
|
613
|
+
cmd, args = makeProcCommand(webPlayerCommand, url)
|
614
|
+
$log.debug { "execute cmd '#{cmd}', args '#{args.inspect}'" }
|
615
|
+
proc = Qt::Process.new(self)
|
616
|
+
proc.start(cmd, args)
|
617
|
+
end
|
618
|
+
|
619
|
+
# ------------------------------------------------------------------------
|
620
|
+
#
|
621
|
+
# slot: called when 'Get List' Button clicked signal invoked.
|
622
|
+
#
|
623
|
+
public
|
624
|
+
slots :getList
|
625
|
+
def getList
|
626
|
+
feedAdr = getFeedAdr
|
627
|
+
return if feedAdr.nil?
|
628
|
+
|
629
|
+
$log.info{ "feeding from '#{feedAdr}'" }
|
630
|
+
|
631
|
+
begin
|
632
|
+
makeTablefromRss( CacheRssDevice.read(feedAdr) )
|
633
|
+
rescue => e
|
634
|
+
$log.error { e }
|
635
|
+
end
|
636
|
+
setListTitle
|
637
|
+
end
|
638
|
+
|
639
|
+
|
640
|
+
#
|
641
|
+
# get feed address
|
642
|
+
#
|
643
|
+
protected
|
644
|
+
def getFeedAdr
|
645
|
+
@channelType = @channelTypeToolBox.currentIndex
|
646
|
+
|
647
|
+
channelStr = nil
|
648
|
+
case @channelType
|
649
|
+
when TvType
|
650
|
+
# get TV channel
|
651
|
+
@channelIndex = @tvChannelListBox.currentRow
|
652
|
+
channelStr = TVChannelRssTbl[ @channelIndex ][1]
|
653
|
+
when RadioType
|
654
|
+
# get Radio channel
|
655
|
+
@channelIndex = @radioChannelListBox.currentRow
|
656
|
+
channelStr = RadioChannelRssTbl[ @channelIndex ][1]
|
657
|
+
when RadioCategoryType
|
658
|
+
# get Category
|
659
|
+
@channelIndex = @categoryListBox.currentRow
|
660
|
+
channelStr = 'categories/' + CategoryRssTbl[ @channelIndex ][1] + '/radio'
|
661
|
+
end
|
662
|
+
|
663
|
+
return nil if channelStr.nil?
|
664
|
+
|
665
|
+
@listType = @listTypeGroup.checkedId
|
666
|
+
list = %w[ list highlights popular ][@listType]
|
667
|
+
|
668
|
+
"http://feeds.bbc.co.uk/iplayer/#{channelStr}/#{list}"
|
669
|
+
end
|
670
|
+
|
671
|
+
|
672
|
+
def getCategoryTitle
|
673
|
+
CategoryRssTbl[ @channelIndex ][0]
|
674
|
+
end
|
675
|
+
|
676
|
+
def setListTitle
|
677
|
+
names = []
|
678
|
+
if getChannelTitle
|
679
|
+
names << getChannelTitle
|
680
|
+
else
|
681
|
+
names << CategoryRssTbl[ @channelIndex ][0]
|
682
|
+
end
|
683
|
+
names << %w[ All Highlights Popular ][@listType]
|
684
|
+
@listTitleLabel.text = names.join(' / ')
|
685
|
+
end
|
686
|
+
|
687
|
+
protected
|
688
|
+
def makeTablefromRss(rss)
|
689
|
+
@programmeTable.clearContents
|
690
|
+
@programmeTable.rowCount = 0
|
691
|
+
@filterLineEdit.clear
|
692
|
+
entries = rss.css('entry')
|
693
|
+
return unless rss and entries and entries.size
|
694
|
+
|
695
|
+
sortFlag = @programmeTable.sortingEnabled
|
696
|
+
@programmeTable.sortingEnabled = false
|
697
|
+
@programmeTable.hide
|
698
|
+
@programmeTable.rowCount = entries.size
|
699
|
+
|
700
|
+
# ['Title', 'Category', 'Updated' ]
|
701
|
+
entries.each_with_index do |i, r|
|
702
|
+
title = i.at_css('title').content
|
703
|
+
updated = i.at_css('updated').content
|
704
|
+
contents = i.at_css('content').content
|
705
|
+
linkItem = i.css('link').find do |l| l['rel'] == 'self' end
|
706
|
+
link = linkItem ? linkItem['href'] : nil
|
707
|
+
categories = i.css('category').map do |c| c['term'] end.join(',')
|
708
|
+
$log.misc { title }
|
709
|
+
@programmeTable.addEntry( r, title, categories, updated, contents, link )
|
710
|
+
end
|
711
|
+
|
712
|
+
@programmeTable.sortingEnabled = sortFlag
|
713
|
+
@programmeTable.show
|
714
|
+
end
|
715
|
+
|
716
|
+
|
717
|
+
|
718
|
+
# ------------------------------------------------------------------------
|
719
|
+
#
|
720
|
+
# slot : when 'Download' Button pressed.
|
721
|
+
#
|
722
|
+
# Start Downloading
|
723
|
+
#
|
724
|
+
public
|
725
|
+
slots :startDownload
|
726
|
+
def startDownload
|
727
|
+
rowsSet = {} # use Hash as Set.
|
728
|
+
@programmeTable.selectedItems.each do |i| rowsSet[i.row] = true end
|
729
|
+
|
730
|
+
titles = {}
|
731
|
+
rowsSet.keys.map do |r|
|
732
|
+
@programmeTable[r]
|
733
|
+
end .each do |p| titles[p.title] = p end
|
734
|
+
|
735
|
+
titles.each_value do |prog|
|
736
|
+
begin
|
737
|
+
url = prog.content[UrlRegexp] # String[] method extract only 1st one.
|
738
|
+
|
739
|
+
$log.info { "episode Url : #{url}" }
|
740
|
+
minfo = BBCNet::CacheMetaInfoDevice.read(url)
|
741
|
+
url = minfo.wma.url
|
742
|
+
|
743
|
+
fName = getSaveName(prog, 'wma')
|
744
|
+
$log.info { "save name : #{fName}" }
|
745
|
+
|
746
|
+
startDownOneFile(minfo, fName)
|
747
|
+
|
748
|
+
passiveMessage(i18n("Start Download programme '%s'") % [prog.title])
|
749
|
+
|
750
|
+
rescue Timeout::Error, StandardError => e
|
751
|
+
if e.kind_of? RuntimeError
|
752
|
+
$log.info { e.message }
|
753
|
+
else
|
754
|
+
$log.error { e }
|
755
|
+
end
|
756
|
+
passiveMessage(i18n("There is no direct stream for this programme.\n%s" %[prog.title]))
|
757
|
+
end
|
758
|
+
end
|
759
|
+
end
|
760
|
+
|
761
|
+
|
762
|
+
protected
|
763
|
+
#
|
764
|
+
def getSaveName(prog, ext='wma')
|
765
|
+
tags = prog.categories.split(/,/)
|
766
|
+
dir = getSaveSubDirName(tags)
|
767
|
+
$log.debug { "save dir : #{dir}" }
|
768
|
+
|
769
|
+
dir + '/' + getSaveBaseName(prog.title, tags, ext)
|
770
|
+
end
|
771
|
+
|
772
|
+
def getSaveBaseName(title, tags, ext)
|
773
|
+
s = IRecSettings
|
774
|
+
head = s.fileAddHeadStr
|
775
|
+
head += getMediaName(tags) + ' ' if s.fileAddMediaName
|
776
|
+
head += getChannelName + ' ' if s.fileAddChannelName and getChannelName
|
777
|
+
head += getGenreName(tags) + ' ' if s.fileAddGenreName and getGenreName(tags)
|
778
|
+
head += "- " unless head.empty?
|
779
|
+
baseName = head + title + '.' + ext
|
780
|
+
baseName.gsub(%r{[\/]}, '-')
|
781
|
+
end
|
782
|
+
|
783
|
+
#
|
784
|
+
def getSaveSubDirName(tags)
|
785
|
+
s = IRecSettings
|
786
|
+
dir = []
|
787
|
+
dir << getMediaName(tags) if s.dirAddMediaName
|
788
|
+
dir << getChannelName if s.dirAddChannelName and getChannelName
|
789
|
+
dir << getGenreName(tags) if s.dirAddGenreName and getGenreName(tags)
|
790
|
+
File.join(dir.compact)
|
791
|
+
end
|
792
|
+
|
793
|
+
# media [TV,Radio,iPod]
|
794
|
+
def getMediaName(tags)
|
795
|
+
tags.find do |t|
|
796
|
+
%w(radio tv ipod).include?(t.downcase)
|
797
|
+
end
|
798
|
+
end
|
799
|
+
|
800
|
+
# channel [BBC Radio 4, ..]
|
801
|
+
def getChannelName
|
802
|
+
getChannelTitle
|
803
|
+
end
|
804
|
+
|
805
|
+
def getChannelTitle
|
806
|
+
case @channelType
|
807
|
+
when TvType
|
808
|
+
# get TV channel
|
809
|
+
TVChannelRssTbl[ @channelIndex ][0]
|
810
|
+
when RadioType
|
811
|
+
# get Radio channel
|
812
|
+
RadioChannelRssTbl[ @channelIndex ][0]
|
813
|
+
else
|
814
|
+
nil
|
815
|
+
end
|
816
|
+
end
|
817
|
+
|
818
|
+
# Main Genre [Drama, Comedy, ..]
|
819
|
+
def getGenreName(tags)
|
820
|
+
CategoryNameTbl.find do |cat|
|
821
|
+
tags.find do |t|
|
822
|
+
cat =~ /#{t}/i
|
823
|
+
end
|
824
|
+
end
|
825
|
+
end
|
826
|
+
|
827
|
+
|
828
|
+
# other genre [Sitcom, SF, etc]
|
829
|
+
def getSubGenreName(tags)
|
830
|
+
end
|
831
|
+
|
832
|
+
|
833
|
+
|
834
|
+
|
835
|
+
|
836
|
+
#-------------------------------------------------------------------
|
837
|
+
# parameter
|
838
|
+
# metaInfo : source stream MetaInfo of download file.
|
839
|
+
# fName : save file name.
|
840
|
+
#
|
841
|
+
# start Dwnload One file.
|
842
|
+
protected
|
843
|
+
def startDownOneFile(metaInfo, fName)
|
844
|
+
process = DownloadProcess.new(self, metaInfo, fName)
|
845
|
+
process.taskItem = @taskWin.addTask(process)
|
846
|
+
process.beginTask
|
847
|
+
end
|
848
|
+
|
849
|
+
|
850
|
+
|
851
|
+
|
852
|
+
#
|
853
|
+
# slot : periodically called to update task view.
|
854
|
+
#
|
855
|
+
protected
|
856
|
+
slots :updateTask
|
857
|
+
def updateTask
|
858
|
+
@taskWin.each do |task|
|
859
|
+
task.process.updateView
|
860
|
+
end
|
861
|
+
end
|
862
|
+
end
|
863
|
+
|
864
|
+
|
865
|
+
#
|
866
|
+
# main start
|
867
|
+
#
|
868
|
+
|
869
|
+
$about = KDE::AboutData.new(APP_NAME, APP_NAME, KDE::ki18n(APP_NAME), APP_VERSION,
|
870
|
+
KDE::ki18n('BBC iRecorder KDE')
|
871
|
+
)
|
872
|
+
$about.setProgramIconName(':images/irecorder-22.png')
|
873
|
+
$about.addLicenseTextFile(APP_DIR + '/MIT-LICENSE')
|
874
|
+
KDE::CmdLineArgs.init(ARGV, $about)
|
875
|
+
# options = KDE::CmdLineOptions.new()
|
876
|
+
# options.add( "+url", KDE::ki18n( "The url to record)" ),"")
|
877
|
+
|
878
|
+
$app = KDE::Application.new
|
879
|
+
args = KDE::CmdLineArgs.parsedArgs()
|
880
|
+
$config = KDE::Global::config
|
881
|
+
win = MainWindow.new
|
882
|
+
$app.setTopWidget(win)
|
883
|
+
|
884
|
+
win.show
|
885
|
+
$app.exec
|