irecorder 0.0.4-linux
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 +37 -0
- data/Rakefile +67 -0
- data/bin/irecorder +9 -0
- data/bin/irecorder.rb +994 -0
- data/lib/bbcnet.rb +244 -0
- data/lib/download.rb +325 -0
- data/lib/logwin.rb +119 -0
- data/lib/mylibs.rb +279 -0
- data/lib/settings.rb +386 -0
- data/lib/taskwin.rb +354 -0
- data/resources/bbcstyle.qss +424 -0
- metadata +105 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2009 ruby.twiddler@gmail.com
|
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,37 @@
|
|
1
|
+
BBC iPlayer like audio recorder with KDE GUI.
|
2
|
+
You can browse BBC Radio programmes and click to download stream file.
|
3
|
+
file will be converted mp3 files automatically.
|
4
|
+
iplayer allow to play without any other browser or play on your prefered browser.
|
5
|
+
|
6
|
+
Installation
|
7
|
+
============
|
8
|
+
install most important package kdebindings4.
|
9
|
+
on Mandriva Linux use urpmi command.
|
10
|
+
|
11
|
+
# sudo urpmi ruby-kde4 ruby-qt4
|
12
|
+
|
13
|
+
install mplayer ffmpeg exiftool packages if necessary
|
14
|
+
|
15
|
+
# sudo urpmi mplayer ffmpeg perl-Image-ExifTool
|
16
|
+
|
17
|
+
install nokogiri gem.
|
18
|
+
# sudo gem install nokogiri
|
19
|
+
|
20
|
+
Finally you can install irecorder.
|
21
|
+
|
22
|
+
# sudo gem install irecorder
|
23
|
+
or directly specify your downloaded gem file.
|
24
|
+
# sudo gem install -l irecorder-0.0.x.gem
|
25
|
+
|
26
|
+
launch irecorder just type irecorder.rb
|
27
|
+
|
28
|
+
# irecorder.rb
|
29
|
+
|
30
|
+
|
31
|
+
Build Gem
|
32
|
+
============
|
33
|
+
if you want to gem package from source, use rake command.
|
34
|
+
|
35
|
+
# rake gem
|
36
|
+
|
37
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,67 @@
|
|
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.4"
|
10
|
+
s.author = "ruby.twiddler"
|
11
|
+
s.email = "ruby.twiddler at gmail.com"
|
12
|
+
s.platform = "linux"
|
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.license = "MIT-LICENSE"
|
18
|
+
s.require_path = "lib"
|
19
|
+
s.requirements = %w{ korundum4 qtwebkit kio }
|
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
|
+
iplayer allow to play without any other browser or on your prefered media player
|
26
|
+
like mplayer.
|
27
|
+
irecorder require kdebindings.
|
28
|
+
svn://anonsvn.kde.org/home/kde/branches/KDE/4.4/kdebindings
|
29
|
+
http://websvn.kde.org/branches/KDE/4.4/kdebindings/
|
30
|
+
please check your distro package to install it.
|
31
|
+
EOF
|
32
|
+
s.has_rdoc = false
|
33
|
+
s.extra_rdoc_files = ["README"]
|
34
|
+
end
|
35
|
+
|
36
|
+
package = Rake::GemPackageTask.new(spec) do |pkg|
|
37
|
+
pkg.need_tar = true
|
38
|
+
end
|
39
|
+
|
40
|
+
desc "install as gem package"
|
41
|
+
task :installgem => :gem do
|
42
|
+
system("gem install -r pkg/" + package.gem_file )
|
43
|
+
end
|
44
|
+
|
45
|
+
desc "install for rpm"
|
46
|
+
task :install4rpm do
|
47
|
+
def installToDir(file, dir, options={})
|
48
|
+
# puts "copy #{file} => #{dir}"
|
49
|
+
FileUtils.mkdir_p(File.join(dir, File.dirname(file)))
|
50
|
+
FileUtils.install(file, File.join(dir, File.dirname(file)), options)
|
51
|
+
end
|
52
|
+
|
53
|
+
prefix = ENV['prefix']
|
54
|
+
conf = Config::CONFIG
|
55
|
+
destDir = conf['sitelibdir'].sub(/#{conf['prefix']}/, prefix)
|
56
|
+
destDir = File.join(destDir, spec.name)
|
57
|
+
|
58
|
+
files = FileList["{bin,lib}/**/*"].to_a
|
59
|
+
files += %w{ resources/bbcstyle.qss }
|
60
|
+
files.each do |f|
|
61
|
+
# install files.
|
62
|
+
installToDir(f, destDir)
|
63
|
+
end
|
64
|
+
|
65
|
+
installToDir('bin/irecorder', prefix, :mode => 0755)
|
66
|
+
end
|
67
|
+
|
data/bin/irecorder
ADDED
data/bin/irecorder.rb
ADDED
@@ -0,0 +1,994 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
#
|
3
|
+
# 2010 by ruby.twiddler@gmail.com
|
4
|
+
#
|
5
|
+
# IPlayer interface
|
6
|
+
# record real/wma (rtsp/mms) audio/video 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.3"
|
16
|
+
|
17
|
+
# standard libs
|
18
|
+
require 'rubygems'
|
19
|
+
require 'uri'
|
20
|
+
require 'net/http'
|
21
|
+
require 'open-uri'
|
22
|
+
require 'rss'
|
23
|
+
require 'shellwords'
|
24
|
+
require 'fileutils'
|
25
|
+
require 'singleton'
|
26
|
+
|
27
|
+
# additional libs
|
28
|
+
require 'korundum4'
|
29
|
+
require 'qtwebkit'
|
30
|
+
|
31
|
+
#
|
32
|
+
# my libraries and programs
|
33
|
+
#
|
34
|
+
$:.unshift(LIB_DIR)
|
35
|
+
require "bbcnet"
|
36
|
+
require "mylibs"
|
37
|
+
require "logwin"
|
38
|
+
require "taskwin"
|
39
|
+
require "download"
|
40
|
+
require "settings"
|
41
|
+
|
42
|
+
|
43
|
+
|
44
|
+
|
45
|
+
|
46
|
+
#---------------------------------------------------------------------------------------------
|
47
|
+
#---------------------------------------------------------------------------------------------
|
48
|
+
|
49
|
+
|
50
|
+
|
51
|
+
|
52
|
+
|
53
|
+
#---------------------------------------------------------------------------------------------
|
54
|
+
#
|
55
|
+
#
|
56
|
+
class ProgrammeTableWidget < Qt::TableWidget
|
57
|
+
slots 'filterChanged(const QString &)'
|
58
|
+
|
59
|
+
#
|
60
|
+
#
|
61
|
+
class Programme
|
62
|
+
attr_reader :titleItem, :categoriesItem, :updatedItem
|
63
|
+
attr_reader :content, :link
|
64
|
+
|
65
|
+
def initialize(title, categories, updated, content, link)
|
66
|
+
@titleItem = Item.new(title)
|
67
|
+
@categoriesItem = Item.new(categories)
|
68
|
+
@updatedItem = Item.new(updated)
|
69
|
+
@content = content
|
70
|
+
@link = link
|
71
|
+
end
|
72
|
+
|
73
|
+
def title
|
74
|
+
@titleItem.text
|
75
|
+
end
|
76
|
+
|
77
|
+
def categories
|
78
|
+
@categoriesItem.text
|
79
|
+
end
|
80
|
+
|
81
|
+
def updated
|
82
|
+
@updatedItem.text
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
#
|
87
|
+
#
|
88
|
+
class Item < Qt::TableWidgetItem
|
89
|
+
def initialize(text)
|
90
|
+
super(text)
|
91
|
+
self.flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled
|
92
|
+
self.toolTip = text
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
#------------------------------------------------------------------------
|
98
|
+
#
|
99
|
+
#
|
100
|
+
attr_accessor :mediaFilter
|
101
|
+
|
102
|
+
def initialize()
|
103
|
+
super(0, 3)
|
104
|
+
|
105
|
+
setHorizontalHeaderLabels(['Title', 'Category', 'Updated'])
|
106
|
+
self.horizontalHeader.stretchLastSection = true
|
107
|
+
self.selectionBehavior = Qt::AbstractItemView::SelectRows
|
108
|
+
self.alternatingRowColors = true
|
109
|
+
self.sortingEnabled = true
|
110
|
+
sortByColumn(2, Qt::DescendingOrder )
|
111
|
+
|
112
|
+
@mediaFilter = ''
|
113
|
+
|
114
|
+
# Hash table : key column_0_item => Programme entry.
|
115
|
+
@table = Hash.new
|
116
|
+
end
|
117
|
+
|
118
|
+
def addEntry( row, title, categories, updated, content, link )
|
119
|
+
entry = Programme.new(title, categories, updated, content, link)
|
120
|
+
setItem( row, 0, entry.titleItem )
|
121
|
+
setItem( row, 1, entry.categoriesItem )
|
122
|
+
setItem( row, 2, entry.updatedItem )
|
123
|
+
@table[entry.titleItem] = entry
|
124
|
+
end
|
125
|
+
|
126
|
+
# return Programme object.
|
127
|
+
def [](row)
|
128
|
+
@table[item(row,0)]
|
129
|
+
end
|
130
|
+
|
131
|
+
|
132
|
+
#
|
133
|
+
# slot : called when filterLineEdit text is changed.
|
134
|
+
#
|
135
|
+
public
|
136
|
+
|
137
|
+
def filterChanged(text)
|
138
|
+
return unless text
|
139
|
+
|
140
|
+
text += ' ' + @mediaFilter unless @mediaFilter.empty?
|
141
|
+
|
142
|
+
regxs = text.split(/[,\s]+/).map do |w|
|
143
|
+
/#{Regexp.escape(w.strip)}/i
|
144
|
+
end
|
145
|
+
rowCount.times do |r|
|
146
|
+
i0 = item(r,0)
|
147
|
+
i1 = item(r,1)
|
148
|
+
i2 = item(r,2)
|
149
|
+
txt = ((i0 && i0.text) || '') + ((i1 && i1.text) || '') + ((i2 && i2.text) || '')
|
150
|
+
if regxs.all? do |rx| rx =~ txt end then
|
151
|
+
showRow(r)
|
152
|
+
else
|
153
|
+
hideRow(r)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
GroupName = "ProgrammeTable"
|
159
|
+
def writeSettings
|
160
|
+
config = $config.group(GroupName)
|
161
|
+
config.writeEntry('Header', horizontalHeader.saveState)
|
162
|
+
end
|
163
|
+
|
164
|
+
def readSettings
|
165
|
+
config = $config.group(GroupName)
|
166
|
+
horizontalHeader.restoreState(config.readEntry('Header', horizontalHeader.saveState))
|
167
|
+
end
|
168
|
+
|
169
|
+
protected
|
170
|
+
def contextMenuEvent(e)
|
171
|
+
item = itemAt(e.pos)
|
172
|
+
menu = createPopup
|
173
|
+
execPopup(menu, e.globalPos, item)
|
174
|
+
end
|
175
|
+
|
176
|
+
def createPopup()
|
177
|
+
menu = Qt::Menu.new
|
178
|
+
insertPlayerActions(menu)
|
179
|
+
menu
|
180
|
+
end
|
181
|
+
|
182
|
+
def execPopup(menu, pos, item)
|
183
|
+
action = menu.exec(pos)
|
184
|
+
if action then
|
185
|
+
action.data
|
186
|
+
# $log.code { "execute : '#{action.vData}'" }
|
187
|
+
cmd, exe = action.vData.split(/@/, 2)
|
188
|
+
# $log.code { "cmd(#{cmd}), exe(#{exe})" }
|
189
|
+
case cmd
|
190
|
+
when 'play'
|
191
|
+
playMedia(exe, item)
|
192
|
+
else
|
193
|
+
# self.method(cmd).call(item)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
menu.deleteLater
|
197
|
+
end
|
198
|
+
|
199
|
+
def insertPlayerActions(menu)
|
200
|
+
Mime::services('.wma').each do |s|
|
201
|
+
if s.exec then
|
202
|
+
exeName = s.exec[/\w+/]
|
203
|
+
a = menu.addAction(KDE::Icon.new(exeName), 'Play with ' + exeName)
|
204
|
+
a.setVData('play@' + s.exec)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def playMedia(exe, item)
|
210
|
+
begin
|
211
|
+
prog = self[item.row]
|
212
|
+
url = prog.content[UrlRegexp] # String[] method extract only 1st one.
|
213
|
+
|
214
|
+
$log.info { "episode Url : #{url}" }
|
215
|
+
minfo = BBCNet::MetaInfo.get(url).update
|
216
|
+
url = minfo.wma.url
|
217
|
+
|
218
|
+
cmd, args = exe.split(/\s+/, 2)
|
219
|
+
args = args.split(/\s+/).map do |a|
|
220
|
+
a.gsub(/%\w/, url)
|
221
|
+
end
|
222
|
+
# $log.debug { "execute cmd '#{cmd}', args '#{args.inspect}'" }
|
223
|
+
proc = Qt::Process.new(self)
|
224
|
+
proc.start(cmd, args)
|
225
|
+
|
226
|
+
rescue => e
|
227
|
+
$log.error { e }
|
228
|
+
KDE::MessageBox::information(self, i18n("There is not direct stream for this programme."))
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
|
234
|
+
|
235
|
+
|
236
|
+
#---------------------------------------------------------------------------------------------
|
237
|
+
#---------------------------------------------------------------------------------------------
|
238
|
+
#
|
239
|
+
# Main Window Class
|
240
|
+
#
|
241
|
+
class MainWindow < KDE::MainWindow
|
242
|
+
slots :startDownload, :updateTask, :getList, :reloadStyleSheet, :clearStyleSheet
|
243
|
+
slots :mediaFilterChanged, :playProgramme
|
244
|
+
slots 'programmeCellClicked(int,int)'
|
245
|
+
|
246
|
+
GroupName = "MainWindow"
|
247
|
+
|
248
|
+
#
|
249
|
+
#
|
250
|
+
#
|
251
|
+
def initialize
|
252
|
+
super(nil)
|
253
|
+
setCaption(APP_NAME)
|
254
|
+
|
255
|
+
|
256
|
+
$app.styleSheet = IO.read(APP_DIR + '/resources/bbcstyle.qss')
|
257
|
+
|
258
|
+
createWidgets
|
259
|
+
createMenu
|
260
|
+
createDlg
|
261
|
+
|
262
|
+
# default values
|
263
|
+
# BBCNet.setProxy('http://194.36.10.154:3127')
|
264
|
+
# initialize values
|
265
|
+
$log = MyLogger.new(@logWin)
|
266
|
+
$log.level = MyLogger::INFO
|
267
|
+
$log.info { 'Log Start.' }
|
268
|
+
|
269
|
+
# assign from config file.
|
270
|
+
readSettings
|
271
|
+
setAutoSaveSettings(GroupName)
|
272
|
+
|
273
|
+
initializeTaskTimer
|
274
|
+
end
|
275
|
+
|
276
|
+
|
277
|
+
|
278
|
+
protected
|
279
|
+
def initializeTaskTimer
|
280
|
+
# Task Timer
|
281
|
+
@timer = Qt::Timer.new(self)
|
282
|
+
connect( @timer, SIGNAL(:timeout), self, SLOT(:updateTask) )
|
283
|
+
@timer.start(1000) # 1000 msec = 1 sec
|
284
|
+
end
|
285
|
+
|
286
|
+
|
287
|
+
#
|
288
|
+
# make menus for MainWindow
|
289
|
+
#
|
290
|
+
def createMenu
|
291
|
+
|
292
|
+
# File menu
|
293
|
+
recordAction = KDE::Action.new(KDE::Icon.new('arrow-down'), i18n('Start &Download'), self)
|
294
|
+
reloadStyleAction = KDE::Action.new(KDE::Icon.new('view-refresh'), i18n('&Reload StyleSheet'), self)
|
295
|
+
reloadStyleAction.setShortcut(KDE::Shortcut.new('Ctrl+R'))
|
296
|
+
clearStyleAction = KDE::Action.new(KDE::Icon.new('list-remove'), i18n('&Clear StyleSheet'), self)
|
297
|
+
clearStyleAction.setShortcut(KDE::Shortcut.new('Ctrl+L'))
|
298
|
+
quitAction = KDE::Action.new(KDE::Icon.new('exit'), i18n('&Quit'), self)
|
299
|
+
quitAction.setShortcut(KDE::Shortcut.new('Ctrl+Q'))
|
300
|
+
fileMenu = KDE::Menu.new('&File', self)
|
301
|
+
fileMenu.addAction(recordAction)
|
302
|
+
fileMenu.addAction(reloadStyleAction)
|
303
|
+
fileMenu.addAction(clearStyleAction)
|
304
|
+
fileMenu.addAction(quitAction)
|
305
|
+
|
306
|
+
# connect actions
|
307
|
+
connect(recordAction, SIGNAL(:triggered), self, SLOT(:startDownload))
|
308
|
+
connect(reloadStyleAction, SIGNAL(:triggered), self, SLOT(:reloadStyleSheet))
|
309
|
+
connect(clearStyleAction, SIGNAL(:triggered), self, SLOT(:clearStyleSheet))
|
310
|
+
connect(quitAction, SIGNAL(:triggered), self, SLOT(:close))
|
311
|
+
|
312
|
+
# settings menu
|
313
|
+
playerDockAction = @playerDock.toggleViewAction
|
314
|
+
playerDockAction.text = i18n('Show Player')
|
315
|
+
configureAppAction = KDE::Action.new(KDE::Icon.new('configure'),
|
316
|
+
i18n("Configure #{APP_NAME}"), self)
|
317
|
+
settingsMenu = KDE::Menu.new(i18n('&Settings'), self)
|
318
|
+
settingsMenu.addAction(playerDockAction)
|
319
|
+
settingsMenu.addSeparator
|
320
|
+
settingsMenu.addAction(configureAppAction)
|
321
|
+
# connect actions
|
322
|
+
connect(configureAppAction, SIGNAL(:triggered), self, SLOT(:configureApp))
|
323
|
+
|
324
|
+
|
325
|
+
# Help menu
|
326
|
+
about = i18n(<<-ABOUT
|
327
|
+
#{APP_NAME} #{APP_VERSION}
|
328
|
+
|
329
|
+
BBC iPlayer like audio (mms/rtsp) stream recorder.
|
330
|
+
ABOUT
|
331
|
+
)
|
332
|
+
helpMenu = KDE::HelpMenu.new(self, about)
|
333
|
+
|
334
|
+
# insert menus in MenuBar
|
335
|
+
menu = KDE::MenuBar.new
|
336
|
+
menu.addMenu( fileMenu )
|
337
|
+
menu.addMenu( settingsMenu )
|
338
|
+
menu.addSeparator
|
339
|
+
menu.addMenu( helpMenu.menu )
|
340
|
+
setMenuBar(menu)
|
341
|
+
end
|
342
|
+
|
343
|
+
|
344
|
+
|
345
|
+
|
346
|
+
#-------------------------------------------------------------
|
347
|
+
#
|
348
|
+
# create Widgets for MainWindow
|
349
|
+
#
|
350
|
+
def createWidgets
|
351
|
+
@topTab = KDE::TabWidget.new
|
352
|
+
|
353
|
+
@mainTabPage = Qt::Splitter.new
|
354
|
+
@topTab.addTab(@mainTabPage, 'Channels')
|
355
|
+
|
356
|
+
@mainTabPage.addWidget(createChannelAreaWidget)
|
357
|
+
|
358
|
+
# Main Tab page. programme table area
|
359
|
+
@progTableFrame = Qt::Splitter.new(Qt::Vertical)
|
360
|
+
@progTableFrame.addWidget(createProgrammeAreaWidget)
|
361
|
+
@progTableFrame.addWidget(createProgrammeSummaryWidget)
|
362
|
+
@mainTabPage.addWidget(@progTableFrame)
|
363
|
+
|
364
|
+
# parameter : Qt::Splitter.setStretchFactor( int index, int stretch )
|
365
|
+
@mainTabPage.setStretchFactor( 0, 0 )
|
366
|
+
@mainTabPage.setStretchFactor( 1, 1 )
|
367
|
+
|
368
|
+
# dock
|
369
|
+
createPlayerDock
|
370
|
+
|
371
|
+
|
372
|
+
# Top Tab - Task Page
|
373
|
+
@taskWin = TaskWindow.new
|
374
|
+
@topTab.addTab(@taskWin, 'Task')
|
375
|
+
|
376
|
+
# Top Tab - Log Page
|
377
|
+
@logWin = LogWindow.new
|
378
|
+
@topTab.addTab(@logWin, 'Log')
|
379
|
+
|
380
|
+
|
381
|
+
# set Top Widget & Layout
|
382
|
+
setCentralWidget(@topTab)
|
383
|
+
end
|
384
|
+
|
385
|
+
|
386
|
+
#-------------------------------------------------------------
|
387
|
+
#
|
388
|
+
TVChannelRssTbl = [
|
389
|
+
['BBC One', 'bbc_one' ],
|
390
|
+
['BBC Two', 'bbc_two' ],
|
391
|
+
['BBC Three', 'bbc_three' ],
|
392
|
+
['BBC Four', 'bbc_four' ],
|
393
|
+
['CBBC', 'cbbc'],
|
394
|
+
['CBeebies', 'cbeebies'],
|
395
|
+
['BBC News Channel', 'bbc_news24'],
|
396
|
+
['BBC Parliament', 'bbc_parliament'],
|
397
|
+
['BBC HD', 'bbc_hd'],
|
398
|
+
['BBC ALBA', 'bbc_alba'] ]
|
399
|
+
|
400
|
+
RadioChannelRssTbl = [
|
401
|
+
['BBC Radio 1', 'bbc_radio_one'],
|
402
|
+
['BBC 1Xtra', 'bbc_1xtra'],
|
403
|
+
['BBC Radio 2', 'bbc_radio_two'],
|
404
|
+
['BBC Radio 3', 'bbc_radio_three'],
|
405
|
+
['BBC Radio 4', 'bbc_radio_four'],
|
406
|
+
['BBC Radio 5 live', 'bbc_radio_five_live'],
|
407
|
+
['BBC Radio 5 live sports extra', 'bbc_radio_five_live_sports_extra'],
|
408
|
+
['BBC 6 Music', 'bbc_6music'],
|
409
|
+
['BBC Radio 7', 'bbc_7'],
|
410
|
+
['BBC Asian Network', 'bbc_asian_network'],
|
411
|
+
['BBC World service', 'bbc_world_service'],
|
412
|
+
['BBC Radio Scotland', 'bbc_alba/scotland'],
|
413
|
+
['BBC Radio Nan Gàidheal', 'bbc_radio_nan_gaidheal'],
|
414
|
+
['BBC Radio Ulster', 'bbc_radio_ulster'],
|
415
|
+
['BBC Radio Foyle', 'bbc_radio_foyle'],
|
416
|
+
['BBC Radio Wales', 'bbc_radio_wales'],
|
417
|
+
['BBC Radio Cymru', 'bbc_radio_cymru'] ]
|
418
|
+
|
419
|
+
CategoryRssTbl = [
|
420
|
+
['Children\'s', 'childrens'],
|
421
|
+
['Comedy', 'comedy'],
|
422
|
+
['Drama', 'drama'],
|
423
|
+
['Entertainment', 'entertainment'],
|
424
|
+
['Factual', 'factual'],
|
425
|
+
['Films', 'films'],
|
426
|
+
['Music', 'music'],
|
427
|
+
['News', 'news'],
|
428
|
+
['Learning', 'learning'],
|
429
|
+
['Religion & Ethics', 'religion_and_ethics'],
|
430
|
+
['Sport', 'sport'],
|
431
|
+
['Sign Zone', 'signed'],
|
432
|
+
['Audio Described', 'audiodescribed'],
|
433
|
+
['Northern Ireland', 'northern_ireland'],
|
434
|
+
['Scotland', 'scotland'],
|
435
|
+
['Wales', 'wales'] ]
|
436
|
+
|
437
|
+
CategoryNameTbl = CategoryRssTbl.map do |c|
|
438
|
+
c[0][/[\w\s\'&]+/].gsub(/\'/, '').gsub(/&/, ' and ')
|
439
|
+
end
|
440
|
+
#
|
441
|
+
def createChannelListToolBox
|
442
|
+
toolBox = Qt::ToolBox.new do |w|
|
443
|
+
w.objectName = 'channelToolBox'
|
444
|
+
end
|
445
|
+
|
446
|
+
# TV & Radio Channels selector
|
447
|
+
@tvChannelListBox = KDE::ListWidget.new
|
448
|
+
# TV Channels
|
449
|
+
@tvChannelListBox.addItems( TVChannelRssTbl.map do |w| w[0] end )
|
450
|
+
toolBox.addItem( @tvChannelListBox, 'TV Channels' )
|
451
|
+
|
452
|
+
# Radio Channels
|
453
|
+
@radioChannelListBox = KDE::ListWidget.new
|
454
|
+
@radioChannelListBox.addItems( RadioChannelRssTbl.map do |w| w[0] end )
|
455
|
+
toolBox.addItem( @radioChannelListBox, 'Radio Channels' )
|
456
|
+
|
457
|
+
# Category selector
|
458
|
+
@categoryListBox = KDE::ListWidget.new
|
459
|
+
@categoryListBox.addItems( CategoryRssTbl.map do |w| w[0] end )
|
460
|
+
toolBox.addItem( @categoryListBox, 'Categories' )
|
461
|
+
|
462
|
+
toolBox
|
463
|
+
end
|
464
|
+
|
465
|
+
#-------------------------------------------------------------
|
466
|
+
#
|
467
|
+
# [ All / Highlights / Most Popular ] selector
|
468
|
+
#
|
469
|
+
def createListTypeButtons
|
470
|
+
@listTypeGroup = Qt::ButtonGroup.new
|
471
|
+
allBtn = KDE::PushButton.new('All') do |w|
|
472
|
+
w.objectName = 'switchButton'
|
473
|
+
w.checkable = true
|
474
|
+
w.autoExclusive = true
|
475
|
+
connect(w, SIGNAL(:clicked), self, SLOT(:getList))
|
476
|
+
end
|
477
|
+
|
478
|
+
highlightsBtn = KDE::PushButton.new('Highlights') do |w|
|
479
|
+
w.objectName = 'switchButton'
|
480
|
+
w.setMinimumWidth(80)
|
481
|
+
w.checkable = true
|
482
|
+
w.autoExclusive = true
|
483
|
+
connect(w, SIGNAL(:clicked), self, SLOT(:getList))
|
484
|
+
end
|
485
|
+
|
486
|
+
mostBtn = KDE::PushButton.new('Most Popular') do |w|
|
487
|
+
w.objectName = 'switchButton'
|
488
|
+
w.checkable = true
|
489
|
+
w.autoExclusive = true
|
490
|
+
connect(w, SIGNAL(:clicked), self, SLOT(:getList))
|
491
|
+
end
|
492
|
+
listTypeHLayout = Qt::HBoxLayout.new
|
493
|
+
listTypeHLayout.addWidget(allBtn, 54) # 2nd parameter is stretch.
|
494
|
+
listTypeHLayout.addWidget(highlightsBtn, 180)
|
495
|
+
listTypeHLayout.addWidget(mostBtn,235)
|
496
|
+
|
497
|
+
@listTypeGroup.addButton(allBtn, 0)
|
498
|
+
@listTypeGroup.addButton(highlightsBtn, 1)
|
499
|
+
@listTypeGroup.addButton(mostBtn, 2)
|
500
|
+
@listTypeGroup.exclusive = true
|
501
|
+
|
502
|
+
listTypeHLayout
|
503
|
+
end
|
504
|
+
|
505
|
+
|
506
|
+
#-------------------------------------------------------------
|
507
|
+
#
|
508
|
+
# Left Side Channel ToolBox & ListType Buttons
|
509
|
+
def createChannelAreaWidget
|
510
|
+
VBoxLayoutWidget.new do |vb|
|
511
|
+
@channelTypeToolBox = createChannelListToolBox
|
512
|
+
vb.addWidget(@channelTypeToolBox)
|
513
|
+
vb.addLayout(createListTypeButtons)
|
514
|
+
end
|
515
|
+
end
|
516
|
+
|
517
|
+
#-------------------------------------------------------------
|
518
|
+
#
|
519
|
+
#
|
520
|
+
def createProgrammeAreaWidget
|
521
|
+
VBoxLayoutWidget.new do |vbxw|
|
522
|
+
@programmeTable = ProgrammeTableWidget.new do |w|
|
523
|
+
connect(w, SIGNAL('cellClicked(int,int)'),
|
524
|
+
self, SLOT('programmeCellClicked(int,int)'))
|
525
|
+
end
|
526
|
+
vbxw.addWidget(HBoxLayoutWidget.new do |hw|
|
527
|
+
hw.addWidget(Qt::Label.new(i18n('Look for:')))
|
528
|
+
hw.addWidget(
|
529
|
+
@filterLineEdit = KDE::LineEdit.new do |w|
|
530
|
+
connect(w,SIGNAL('textChanged(const QString &)'),
|
531
|
+
@programmeTable, SLOT('filterChanged(const QString &)'))
|
532
|
+
w.setClearButtonShown(true)
|
533
|
+
end
|
534
|
+
)
|
535
|
+
end
|
536
|
+
)
|
537
|
+
vbxw.addWidget(@programmeTable)
|
538
|
+
|
539
|
+
# 'Start Download' Button
|
540
|
+
@tvFilterBtn = KDE::PushButton.new(i18n("TV")) do |w|
|
541
|
+
w.objectName = 'mediaButton'
|
542
|
+
w.checkable = true
|
543
|
+
w.autoExclusive = true
|
544
|
+
connect( w, SIGNAL(:clicked), self, SLOT(:mediaFilterChanged) )
|
545
|
+
end
|
546
|
+
|
547
|
+
@radioFilterBtn = KDE::PushButton.new(i18n("Radio")) do |w|
|
548
|
+
w.objectName = 'mediaButton'
|
549
|
+
w.checkable = true
|
550
|
+
w.autoExclusive = true
|
551
|
+
w.checked = true
|
552
|
+
connect( w, SIGNAL(:clicked), self, SLOT(:mediaFilterChanged) )
|
553
|
+
end
|
554
|
+
|
555
|
+
playBtn = KDE::PushButton.new( KDE::Icon.new('media-playback-start'), i18n("Play")) do |w|
|
556
|
+
w.objectName = 'playButton'
|
557
|
+
connect( w, SIGNAL(:clicked), self, SLOT(:playProgramme) )
|
558
|
+
end
|
559
|
+
|
560
|
+
downloadBtn = KDE::PushButton.new( KDE::Icon.new('arrow-down'), i18n("Download")) do |w|
|
561
|
+
w.objectName = 'downloadButton'
|
562
|
+
connect( w, SIGNAL(:clicked), self, SLOT(:startDownload) )
|
563
|
+
end
|
564
|
+
|
565
|
+
vbxw.addWidgets( @tvFilterBtn, @radioFilterBtn, nil, playBtn, nil, downloadBtn, nil )
|
566
|
+
end
|
567
|
+
end
|
568
|
+
|
569
|
+
#-------------------------------------------------------------
|
570
|
+
#
|
571
|
+
#
|
572
|
+
def createProgrammeSummaryWidget
|
573
|
+
@programmeSummaryWebView = Qt::WebView.new do |w|
|
574
|
+
w.page.linkDelegationPolicy = Qt::WebPage::DelegateAllLinks
|
575
|
+
end
|
576
|
+
end
|
577
|
+
|
578
|
+
#-------------------------------------------------------------
|
579
|
+
#
|
580
|
+
#
|
581
|
+
def createPlayerDock
|
582
|
+
@playerDock = Qt::DockWidget.new(self) do |w|
|
583
|
+
w.objectName = 'playerDock'
|
584
|
+
w.windowTitle = i18n('Player')
|
585
|
+
w.allowedAreas = Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::BottomDockWidgetArea
|
586
|
+
w.floating = true
|
587
|
+
w.hide
|
588
|
+
end
|
589
|
+
@playerWevView = Qt::WebView.new do |w|
|
590
|
+
w.page.linkDelegationPolicy = Qt::WebPage::DelegateAllLinks
|
591
|
+
end
|
592
|
+
|
593
|
+
webSettings = Qt::WebSettings::globalSettings
|
594
|
+
webSettings.setAttribute(Qt::WebSettings::PluginsEnabled, true)
|
595
|
+
|
596
|
+
|
597
|
+
@playerDock.setWidget(@playerWevView)
|
598
|
+
self.addDockWidget(Qt::RightDockWidgetArea, @playerDock)
|
599
|
+
|
600
|
+
@playerDock
|
601
|
+
end
|
602
|
+
|
603
|
+
#-------------------------------------------------------------
|
604
|
+
#
|
605
|
+
#
|
606
|
+
def createDlg
|
607
|
+
@settingsDlg = SettingsDlg.new(self)
|
608
|
+
end
|
609
|
+
|
610
|
+
|
611
|
+
slots :configureApp
|
612
|
+
# slot
|
613
|
+
def configureApp
|
614
|
+
@settingsDlg.exec
|
615
|
+
end
|
616
|
+
|
617
|
+
|
618
|
+
#-------------------------------------------------------------
|
619
|
+
#
|
620
|
+
# virtual function slot
|
621
|
+
def closeEvent(event)
|
622
|
+
writeSettings
|
623
|
+
super(event)
|
624
|
+
end
|
625
|
+
|
626
|
+
def readSettings
|
627
|
+
config = $config.group(GroupName)
|
628
|
+
@mainTabPage.restoreState(config.readEntry('MainTabPageState', @mainTabPage.saveState))
|
629
|
+
@progTableFrame.restoreState(config.readEntry('ProgTableFrame',
|
630
|
+
@progTableFrame.saveState))
|
631
|
+
|
632
|
+
@programmeTable.readSettings
|
633
|
+
@taskWin.readSettings
|
634
|
+
end
|
635
|
+
|
636
|
+
def writeSettings
|
637
|
+
config = $config.group(GroupName)
|
638
|
+
config.writeEntry('MainTabPageState', @mainTabPage.saveState)
|
639
|
+
config.writeEntry('ProgTableFrame', @progTableFrame.saveState)
|
640
|
+
|
641
|
+
@programmeTable.writeSettings
|
642
|
+
@taskWin.writeSettings
|
643
|
+
end
|
644
|
+
|
645
|
+
# ------------------------------------------------------------------------
|
646
|
+
# slot :
|
647
|
+
def reloadStyleSheet
|
648
|
+
styleStr = IO.read(APP_DIR + '/resources/bbcstyle.qss')
|
649
|
+
$app.styleSheet = styleStr
|
650
|
+
$app.styleSheet = styleStr
|
651
|
+
$log.info { 'Reloaded StyleSheet.' }
|
652
|
+
end
|
653
|
+
|
654
|
+
# slot :
|
655
|
+
def clearStyleSheet
|
656
|
+
$app.styleSheet = nil
|
657
|
+
$log.info { 'Cleared StyleSheet.' }
|
658
|
+
end
|
659
|
+
|
660
|
+
|
661
|
+
# slot :
|
662
|
+
def programmeCellClicked(row, column)
|
663
|
+
prog = @programmeTable[row]
|
664
|
+
color = "#%06x" % (@programmeSummaryWebView.palette.color(Qt::Palette::Text).rgb & 0xffffff)
|
665
|
+
|
666
|
+
html = <<-EOF
|
667
|
+
<font color="#{color}">
|
668
|
+
#{prog.content}
|
669
|
+
</font>
|
670
|
+
EOF
|
671
|
+
|
672
|
+
@programmeSummaryWebView.setHtml(html)
|
673
|
+
end
|
674
|
+
|
675
|
+
# slot :
|
676
|
+
def mediaFilterChanged
|
677
|
+
setMediaFilter
|
678
|
+
@programmeTable.filterChanged(@filterLineEdit.text)
|
679
|
+
end
|
680
|
+
|
681
|
+
|
682
|
+
# slot
|
683
|
+
def playProgramme
|
684
|
+
items = @programmeTable.selectedItems
|
685
|
+
return unless items.size > 0
|
686
|
+
|
687
|
+
def makeProcCommand(command, url)
|
688
|
+
cmd, args = command.split(/\s+/, 2)
|
689
|
+
args = args.split(/\s+/).map do |a|
|
690
|
+
a.gsub(/%\w/, url)
|
691
|
+
end
|
692
|
+
[ cmd, args ]
|
693
|
+
end
|
694
|
+
|
695
|
+
def getIplayerUrl(prog)
|
696
|
+
# big type console
|
697
|
+
url = prog.link
|
698
|
+
$log.info { "big console Url : #{url}" }
|
699
|
+
|
700
|
+
# old type console
|
701
|
+
url = prog.content[UrlRegexp] # String[] method extract only 1st one.
|
702
|
+
$log.info { "episode Url : #{url}" }
|
703
|
+
url = BBCNet.getPlayerConsoleUrl(url)
|
704
|
+
$log.info { "old console Url : #{url}" }
|
705
|
+
|
706
|
+
if IRecSettings.playerTypeBeta then
|
707
|
+
url.sub!(%r{www}, 'beta')
|
708
|
+
$log.info { "new console Url : #{url}" }
|
709
|
+
end
|
710
|
+
url
|
711
|
+
end
|
712
|
+
|
713
|
+
prog = @programmeTable[items[0].row]
|
714
|
+
webPlayerCommand = IRecSettings.webPlayerCommand
|
715
|
+
directPlayerCommand = IRecSettings.directPlayerCommand
|
716
|
+
|
717
|
+
begin
|
718
|
+
if IRecSettings.useInnerPlayer then
|
719
|
+
url = getIplayerUrl(prog)
|
720
|
+
|
721
|
+
@playerDock.show
|
722
|
+
@playerWevView.setUrl(Qt::Url.new(url))
|
723
|
+
elsif IRecSettings.useWebPlayer and webPlayerCommand then
|
724
|
+
$log.info { "Play on web browser" }
|
725
|
+
url = getIplayerUrl(prog)
|
726
|
+
cmd, args = makeProcCommand(webPlayerCommand, url)
|
727
|
+
$log.debug { "execute cmd '#{cmd}', args '#{args.inspect}'" }
|
728
|
+
proc = Qt::Process.new(self)
|
729
|
+
proc.start(cmd, args)
|
730
|
+
|
731
|
+
elsif IRecSettings.useDirectPlayer and directPlayerCommand then
|
732
|
+
$log.info { "Play direct" }
|
733
|
+
url = prog.content[UrlRegexp] # String[] method extract only 1st one.
|
734
|
+
|
735
|
+
$log.info { "episode Url : #{url}" }
|
736
|
+
minfo = BBCNet::MetaInfo.get(url).update
|
737
|
+
$log.debug { "#{minfo.inspect}" }
|
738
|
+
url = minfo.wma.url
|
739
|
+
|
740
|
+
cmd, args = makeProcCommand(directPlayerCommand, url)
|
741
|
+
|
742
|
+
$log.debug { "execute cmd '#{cmd}', args '#{args.inspect}'" }
|
743
|
+
proc = Qt::Process.new(self)
|
744
|
+
proc.start(cmd, args)
|
745
|
+
end
|
746
|
+
rescue => e
|
747
|
+
$log.error { e }
|
748
|
+
KDE::MessageBox::information(self, i18n("There is not direct stream for this programme."))
|
749
|
+
end
|
750
|
+
end
|
751
|
+
|
752
|
+
|
753
|
+
# ------------------------------------------------------------------------
|
754
|
+
#
|
755
|
+
# slot: called when 'Get List' Button clicked signal invoked.
|
756
|
+
#
|
757
|
+
public
|
758
|
+
def getList
|
759
|
+
feedAdr = getFeedAdr
|
760
|
+
return if feedAdr.nil?
|
761
|
+
|
762
|
+
$log.info{ "feeding from '#{feedAdr}'" }
|
763
|
+
|
764
|
+
begin
|
765
|
+
makeTablefromRss( BBCNet.read(feedAdr) )
|
766
|
+
rescue IOError, OpenURI::HTTPError => e
|
767
|
+
$log.error { e }
|
768
|
+
end
|
769
|
+
mediaFilterChanged
|
770
|
+
end
|
771
|
+
|
772
|
+
#
|
773
|
+
# get feed address
|
774
|
+
#
|
775
|
+
protected
|
776
|
+
def getFeedAdr
|
777
|
+
@channelType = @channelTypeToolBox.currentIndex
|
778
|
+
|
779
|
+
channelStr = nil
|
780
|
+
case @channelType
|
781
|
+
when 0
|
782
|
+
# get TV channel
|
783
|
+
@channelIndex = @tvChannelListBox.currentRow
|
784
|
+
channelStr = TVChannelRssTbl[ @channelIndex ][1]
|
785
|
+
when 1
|
786
|
+
# get Radio channel
|
787
|
+
@channelIndex = @radioChannelListBox.currentRow
|
788
|
+
channelStr = RadioChannelRssTbl[ @channelIndex ][1]
|
789
|
+
when 2
|
790
|
+
# get Category
|
791
|
+
@channelIndex = @categoryListBox.currentRow
|
792
|
+
channelStr = 'categories/' + CategoryRssTbl[ @channelIndex ][1]
|
793
|
+
end
|
794
|
+
|
795
|
+
return nil if channelStr.nil?
|
796
|
+
|
797
|
+
list = %w[ list highlights popular ][@listTypeGroup.checkedId]
|
798
|
+
|
799
|
+
"http://feeds.bbc.co.uk/iplayer/#{channelStr}/#{list}"
|
800
|
+
end
|
801
|
+
|
802
|
+
|
803
|
+
protected
|
804
|
+
def makeTablefromRss(rssRaw)
|
805
|
+
rss = RSS::Parser.parse(rssRaw)
|
806
|
+
sortFlag = @programmeTable.sortingEnabled
|
807
|
+
@programmeTable.sortingEnabled = false
|
808
|
+
@programmeTable.hide
|
809
|
+
@programmeTable.clearContents
|
810
|
+
@filterLineEdit.clear
|
811
|
+
@programmeTable.rowCount = rss.entries.size
|
812
|
+
setMediaFilter
|
813
|
+
|
814
|
+
# ['Title', 'Category', 'Updated' ]
|
815
|
+
rss.entries.each_with_index do |i, r|
|
816
|
+
title = i.title.content.to_s
|
817
|
+
updated = i.updated.content.to_s
|
818
|
+
contents = i.content.content
|
819
|
+
link = i.links.find do |l| l.rel == 'self' end.href
|
820
|
+
categories = i.categories.map do |c| c.term end.join(',')
|
821
|
+
$log.misc { title }
|
822
|
+
@programmeTable.addEntry( r, title, categories, updated, contents, link )
|
823
|
+
end
|
824
|
+
|
825
|
+
@programmeTable.sortingEnabled = sortFlag
|
826
|
+
@programmeTable.show
|
827
|
+
end
|
828
|
+
|
829
|
+
def setMediaFilter
|
830
|
+
@programmeTable.mediaFilter =
|
831
|
+
case @channelType
|
832
|
+
when 2
|
833
|
+
@tvFilterBtn.enabled = true
|
834
|
+
@radioFilterBtn.enabled = true
|
835
|
+
@tvFilterBtn.checked ? 'tv' : 'radio'
|
836
|
+
else
|
837
|
+
@tvFilterBtn.enabled = false
|
838
|
+
@radioFilterBtn.enabled = false
|
839
|
+
''
|
840
|
+
end
|
841
|
+
end
|
842
|
+
|
843
|
+
|
844
|
+
# ------------------------------------------------------------------------
|
845
|
+
#
|
846
|
+
# slot : when 'Download' Button pressed.
|
847
|
+
#
|
848
|
+
# Start Downloading
|
849
|
+
#
|
850
|
+
public
|
851
|
+
def startDownload
|
852
|
+
rowsSet = {} # use Hash as Set.
|
853
|
+
@programmeTable.selectedItems.each do |i| rowsSet[i.row] = true end
|
854
|
+
|
855
|
+
rowsSet.keys.sort.map do |r|
|
856
|
+
begin
|
857
|
+
prog = @programmeTable[r]
|
858
|
+
url = prog.content[UrlRegexp] # String[] method extract only 1st one.
|
859
|
+
|
860
|
+
$log.info { "episode Url : #{url}" }
|
861
|
+
minfo = BBCNet::MetaInfo.get(url).update
|
862
|
+
url = minfo.wma.url
|
863
|
+
|
864
|
+
fName = getSaveName(prog, 'wma')
|
865
|
+
$log.info { "save name : #{fName}" }
|
866
|
+
|
867
|
+
startDownOneFile(minfo, fName)
|
868
|
+
rescue Timeout::Error, StandardError => e
|
869
|
+
$log.error { e }
|
870
|
+
KDE::MessageBox::information(self, i18n("There is not direct stream for programme '%s'.") % [prog.title])
|
871
|
+
end
|
872
|
+
end
|
873
|
+
end
|
874
|
+
|
875
|
+
|
876
|
+
private
|
877
|
+
#
|
878
|
+
def getSaveName(prog, ext='wma')
|
879
|
+
tags = prog.categories.split(/,/)
|
880
|
+
dir = getSaveSubDirName(tags)
|
881
|
+
$log.debug { "save dir : #{dir}" }
|
882
|
+
|
883
|
+
dir + '/' + getSaveBaseName(prog.title, tags, ext)
|
884
|
+
end
|
885
|
+
|
886
|
+
def getSaveBaseName(title, tags, ext)
|
887
|
+
s = IRecSettings
|
888
|
+
head = s.fileAddHeadStr
|
889
|
+
head += getMediaName(tags) + ' ' if s.fileAddMediaName
|
890
|
+
head += getChannelName + ' ' if s.fileAddChannelName and getChannelName
|
891
|
+
head += getGenreName(tags) + ' ' if s.fileAddGenreName and getGenreName(tags)
|
892
|
+
head += "- " unless head.empty?
|
893
|
+
baseName = head + title + '.' + ext
|
894
|
+
baseName.gsub(%r{[\/]}, '-')
|
895
|
+
end
|
896
|
+
|
897
|
+
#
|
898
|
+
def getSaveSubDirName(tags)
|
899
|
+
s = IRecSettings
|
900
|
+
dir = []
|
901
|
+
dir << getMediaName(tags) if s.dirAddMediaName
|
902
|
+
dir << getChannelName if s.dirAddChannelName and getChannelName
|
903
|
+
dir << getGenreName(tags) if s.dirAddGenreName and getGenreName(tags)
|
904
|
+
File.join(dir.compact)
|
905
|
+
end
|
906
|
+
|
907
|
+
# media [TV,Radio,iPod]
|
908
|
+
def getMediaName(tags)
|
909
|
+
tags.find do |t|
|
910
|
+
%w(radio tv ipod).include?(t.downcase)
|
911
|
+
end
|
912
|
+
end
|
913
|
+
|
914
|
+
# channel [BBC Radio 4, ..]
|
915
|
+
def getChannelName
|
916
|
+
title = getChannelTitle
|
917
|
+
end
|
918
|
+
|
919
|
+
def getChannelTitle
|
920
|
+
case @channelType
|
921
|
+
when 0
|
922
|
+
# get TV channel
|
923
|
+
TVChannelRssTbl[ @channelIndex ][0]
|
924
|
+
when 1
|
925
|
+
# get Radio channel
|
926
|
+
RadioChannelRssTbl[ @channelIndex ][0]
|
927
|
+
else
|
928
|
+
nil
|
929
|
+
end
|
930
|
+
end
|
931
|
+
|
932
|
+
# Main Genre [Drama, Comedy, ..]
|
933
|
+
def getGenreName(tags)
|
934
|
+
CategoryNameTbl.find do |cat|
|
935
|
+
tags.find do |t|
|
936
|
+
cat =~ /#{t}/i
|
937
|
+
end
|
938
|
+
end
|
939
|
+
end
|
940
|
+
|
941
|
+
|
942
|
+
# other genre [Sitcom, SF, etc]
|
943
|
+
def getSubGenreName(tags)
|
944
|
+
end
|
945
|
+
|
946
|
+
|
947
|
+
|
948
|
+
|
949
|
+
|
950
|
+
#-------------------------------------------------------------------
|
951
|
+
# parameter
|
952
|
+
# metaInfo : source stream MetaInfo of download file.
|
953
|
+
# fName : save file name.
|
954
|
+
#
|
955
|
+
# start Dwnload One file.
|
956
|
+
protected
|
957
|
+
def startDownOneFile(metaInfo, fName)
|
958
|
+
process = DownloadProcess.new(self, metaInfo, fName)
|
959
|
+
process.taskItem = @taskWin.addTask(process)
|
960
|
+
process.beginTask
|
961
|
+
end
|
962
|
+
|
963
|
+
|
964
|
+
|
965
|
+
|
966
|
+
#
|
967
|
+
# slot : periodically called to update task view.
|
968
|
+
#
|
969
|
+
protected
|
970
|
+
def updateTask
|
971
|
+
@taskWin.each do |task|
|
972
|
+
task.process.updateView
|
973
|
+
end
|
974
|
+
end
|
975
|
+
end
|
976
|
+
|
977
|
+
|
978
|
+
#
|
979
|
+
# main start
|
980
|
+
#
|
981
|
+
|
982
|
+
about = KDE::AboutData.new(APP_NAME, APP_NAME, KDE::ki18n(APP_NAME), APP_VERSION)
|
983
|
+
KDE::CmdLineArgs.init(ARGV, about)
|
984
|
+
# options = KDE::CmdLineOptions.new()
|
985
|
+
# options.add( "+url", KDE::ki18n( "The url to record)" ),"")
|
986
|
+
|
987
|
+
$app = KDE::Application.new
|
988
|
+
args = KDE::CmdLineArgs.parsedArgs()
|
989
|
+
$config = KDE::Global::config
|
990
|
+
win = MainWindow.new
|
991
|
+
$app.setTopWidget(win)
|
992
|
+
|
993
|
+
win.show
|
994
|
+
$app.exec
|