irecorder 0.0.4-linux → 0.0.5-linux
Sign up to get free protection for your applications and to get access to all the features.
- data/README +14 -6
- data/Rakefile +11 -5
- data/bin/irecorder.rb +55 -207
- data/lib/bbcnet.rb +34 -7
- data/lib/cache.rb +115 -0
- data/lib/download.rb +32 -19
- data/lib/irecorder_resource.rb +264 -0
- data/lib/mylibs.rb +11 -11
- data/lib/programmewin.rb +182 -0
- data/lib/settings.rb +0 -3
- data/lib/taskwin.rb +72 -78
- data/resources/bbcstyle.qss +14 -0
- metadata +9 -9
data/README
CHANGED
@@ -1,10 +1,18 @@
|
|
1
1
|
BBC iPlayer like audio recorder with KDE GUI.
|
2
2
|
You can browse BBC Radio programmes and click to download stream file.
|
3
|
-
|
4
|
-
|
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
5
|
|
6
|
-
|
7
|
-
|
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
|
+
==================
|
8
16
|
install most important package kdebindings4.
|
9
17
|
on Mandriva Linux use urpmi command.
|
10
18
|
|
@@ -28,8 +36,8 @@ launch irecorder just type irecorder.rb
|
|
28
36
|
# irecorder.rb
|
29
37
|
|
30
38
|
|
31
|
-
Build Gem
|
32
|
-
|
39
|
+
== Build Gem
|
40
|
+
=================
|
33
41
|
if you want to gem package from source, use rake command.
|
34
42
|
|
35
43
|
# rake gem
|
data/Rakefile
CHANGED
@@ -6,9 +6,10 @@ require 'rake/gempackagetask'
|
|
6
6
|
|
7
7
|
spec = Gem::Specification.new do |s|
|
8
8
|
s.name = "irecorder"
|
9
|
-
s.version = "0.0.
|
9
|
+
s.version = "0.0.5"
|
10
10
|
s.author = "ruby.twiddler"
|
11
11
|
s.email = "ruby.twiddler at gmail.com"
|
12
|
+
s.homepage = "http://wiki.github.com/rubytwiddler/irecorder/"
|
12
13
|
s.platform = "linux"
|
13
14
|
s.summary = "BBC iPlayer like audio recorder with KDE GUI."
|
14
15
|
s.files = FileList["{bin,lib}/**/*"].to_a
|
@@ -22,12 +23,9 @@ spec = Gem::Specification.new do |s|
|
|
22
23
|
BBC iPlayer like audio recorder with KDE GUI.
|
23
24
|
You can browse BBC Radio programmes and click to download stream file.
|
24
25
|
files will be converted to mp3 files automatically.
|
25
|
-
|
26
|
+
irecorder allow to play without any other browser or play on your prefered browser.
|
26
27
|
like mplayer.
|
27
28
|
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
29
|
EOF
|
32
30
|
s.has_rdoc = false
|
33
31
|
s.extra_rdoc_files = ["README"]
|
@@ -65,3 +63,11 @@ task :install4rpm do
|
|
65
63
|
installToDir('bin/irecorder', prefix, :mode => 0755)
|
66
64
|
end
|
67
65
|
|
66
|
+
|
67
|
+
resouce_files = [ 'resources/irecorder.qrc' ] + FileList['resources/images/*.png']
|
68
|
+
desc "package resources"
|
69
|
+
file 'lib/irecorder_resource.rb' => resouce_files do
|
70
|
+
%x{ rbrcc resources/irecorder.qrc >lib/irecorder_resource.rb }
|
71
|
+
end
|
72
|
+
|
73
|
+
task :resource => 'lib/irecorder_resource.rb'
|
data/bin/irecorder.rb
CHANGED
@@ -2,8 +2,8 @@
|
|
2
2
|
#
|
3
3
|
# 2010 by ruby.twiddler@gmail.com
|
4
4
|
#
|
5
|
-
#
|
6
|
-
# record real/wma (rtsp/mms) audio
|
5
|
+
# iPlayer interface
|
6
|
+
# record real/wma (rtsp/mms) audio stream
|
7
7
|
#
|
8
8
|
|
9
9
|
$KCODE = 'UTF8'
|
@@ -12,7 +12,7 @@ require 'ftools'
|
|
12
12
|
APP_NAME = File.basename(__FILE__).sub(/\.rb/, '')
|
13
13
|
APP_DIR = File::dirname(File.expand_path(File.dirname(__FILE__)))
|
14
14
|
LIB_DIR = File::join(APP_DIR, "lib")
|
15
|
-
APP_VERSION = "0.0.
|
15
|
+
APP_VERSION = "0.0.5"
|
16
16
|
|
17
17
|
# standard libs
|
18
18
|
require 'rubygems'
|
@@ -32,207 +32,16 @@ require 'qtwebkit'
|
|
32
32
|
# my libraries and programs
|
33
33
|
#
|
34
34
|
$:.unshift(LIB_DIR)
|
35
|
+
require "irecorder_resource"
|
35
36
|
require "bbcnet"
|
36
37
|
require "mylibs"
|
37
38
|
require "logwin"
|
38
39
|
require "taskwin"
|
39
40
|
require "download"
|
41
|
+
require "programmewin"
|
40
42
|
require "settings"
|
41
43
|
|
42
44
|
|
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
45
|
#---------------------------------------------------------------------------------------------
|
237
46
|
#---------------------------------------------------------------------------------------------
|
238
47
|
#
|
@@ -295,7 +104,7 @@ class MainWindow < KDE::MainWindow
|
|
295
104
|
reloadStyleAction.setShortcut(KDE::Shortcut.new('Ctrl+R'))
|
296
105
|
clearStyleAction = KDE::Action.new(KDE::Icon.new('list-remove'), i18n('&Clear StyleSheet'), self)
|
297
106
|
clearStyleAction.setShortcut(KDE::Shortcut.new('Ctrl+L'))
|
298
|
-
quitAction = KDE::Action.new(KDE::Icon.new('exit'), i18n('&Quit'), self)
|
107
|
+
quitAction = KDE::Action.new(KDE::Icon.new('application-exit'), i18n('&Quit'), self)
|
299
108
|
quitAction.setShortcut(KDE::Shortcut.new('Ctrl+Q'))
|
300
109
|
fileMenu = KDE::Menu.new('&File', self)
|
301
110
|
fileMenu.addAction(recordAction)
|
@@ -534,6 +343,7 @@ BBC iPlayer like audio (mms/rtsp) stream recorder.
|
|
534
343
|
)
|
535
344
|
end
|
536
345
|
)
|
346
|
+
vbxw.addWidget( @listTitleLabel = Qt::Label.new('') )
|
537
347
|
vbxw.addWidget(@programmeTable)
|
538
348
|
|
539
349
|
# 'Start Download' Button
|
@@ -552,12 +362,14 @@ BBC iPlayer like audio (mms/rtsp) stream recorder.
|
|
552
362
|
connect( w, SIGNAL(:clicked), self, SLOT(:mediaFilterChanged) )
|
553
363
|
end
|
554
364
|
|
555
|
-
|
365
|
+
playIcon = KDE::Icon.new(':images/play-22.png')
|
366
|
+
playBtn = KDE::PushButton.new( playIcon, i18n("Play")) do |w|
|
556
367
|
w.objectName = 'playButton'
|
557
368
|
connect( w, SIGNAL(:clicked), self, SLOT(:playProgramme) )
|
558
369
|
end
|
559
370
|
|
560
|
-
|
371
|
+
downloadIcon = KDE::Icon.new(':images/download-22.png')
|
372
|
+
downloadBtn = KDE::PushButton.new( downloadIcon, i18n("Download")) do |w|
|
561
373
|
w.objectName = 'downloadButton'
|
562
374
|
connect( w, SIGNAL(:clicked), self, SLOT(:startDownload) )
|
563
375
|
end
|
@@ -621,6 +433,7 @@ BBC iPlayer like audio (mms/rtsp) stream recorder.
|
|
621
433
|
def closeEvent(event)
|
622
434
|
writeSettings
|
623
435
|
super(event)
|
436
|
+
$config.sync # important! qtruby can't invoke destructor properly.
|
624
437
|
end
|
625
438
|
|
626
439
|
def readSettings
|
@@ -628,6 +441,7 @@ BBC iPlayer like audio (mms/rtsp) stream recorder.
|
|
628
441
|
@mainTabPage.restoreState(config.readEntry('MainTabPageState', @mainTabPage.saveState))
|
629
442
|
@progTableFrame.restoreState(config.readEntry('ProgTableFrame',
|
630
443
|
@progTableFrame.saveState))
|
444
|
+
@channelTypeToolBox.currentIndex = config.readEntry('ChannelType', @channelTypeToolBox.currentIndex)
|
631
445
|
|
632
446
|
@programmeTable.readSettings
|
633
447
|
@taskWin.readSettings
|
@@ -637,9 +451,20 @@ BBC iPlayer like audio (mms/rtsp) stream recorder.
|
|
637
451
|
config = $config.group(GroupName)
|
638
452
|
config.writeEntry('MainTabPageState', @mainTabPage.saveState)
|
639
453
|
config.writeEntry('ProgTableFrame', @progTableFrame.saveState)
|
454
|
+
config.writeEntry('ChannelType', @channelTypeToolBox.currentIndex)
|
640
455
|
|
641
456
|
@programmeTable.writeSettings
|
642
457
|
@taskWin.writeSettings
|
458
|
+
# dumpConfig(GroupName)
|
459
|
+
end
|
460
|
+
|
461
|
+
def dumpConfig(group)
|
462
|
+
puts "dump #{group} config"
|
463
|
+
entries = KDE::Global.config.entryMap(group)
|
464
|
+
confGroup = KDE::Global.config.group(group)
|
465
|
+
entries.each do |key, val|
|
466
|
+
puts " key(#{key}) = #{val.inspect}"
|
467
|
+
end
|
643
468
|
end
|
644
469
|
|
645
470
|
# ------------------------------------------------------------------------
|
@@ -664,6 +489,9 @@ BBC iPlayer like audio (mms/rtsp) stream recorder.
|
|
664
489
|
color = "#%06x" % (@programmeSummaryWebView.palette.color(Qt::Palette::Text).rgb & 0xffffff)
|
665
490
|
|
666
491
|
html = <<-EOF
|
492
|
+
<style type="text/css">
|
493
|
+
img { float: left; margin: 4px; }
|
494
|
+
</style>
|
667
495
|
<font color="#{color}">
|
668
496
|
#{prog.content}
|
669
497
|
</font>
|
@@ -733,7 +561,7 @@ BBC iPlayer like audio (mms/rtsp) stream recorder.
|
|
733
561
|
url = prog.content[UrlRegexp] # String[] method extract only 1st one.
|
734
562
|
|
735
563
|
$log.info { "episode Url : #{url}" }
|
736
|
-
minfo = BBCNet::
|
564
|
+
minfo = BBCNet::CacheMetaInfoDevice.read(url)
|
737
565
|
$log.debug { "#{minfo.inspect}" }
|
738
566
|
url = minfo.wma.url
|
739
567
|
|
@@ -762,13 +590,15 @@ BBC iPlayer like audio (mms/rtsp) stream recorder.
|
|
762
590
|
$log.info{ "feeding from '#{feedAdr}'" }
|
763
591
|
|
764
592
|
begin
|
765
|
-
makeTablefromRss(
|
593
|
+
makeTablefromRss( CacheRssDevice.read(feedAdr) )
|
766
594
|
rescue IOError, OpenURI::HTTPError => e
|
767
595
|
$log.error { e }
|
768
596
|
end
|
769
597
|
mediaFilterChanged
|
598
|
+
setListTitle
|
770
599
|
end
|
771
600
|
|
601
|
+
|
772
602
|
#
|
773
603
|
# get feed address
|
774
604
|
#
|
@@ -794,15 +624,31 @@ BBC iPlayer like audio (mms/rtsp) stream recorder.
|
|
794
624
|
|
795
625
|
return nil if channelStr.nil?
|
796
626
|
|
797
|
-
|
627
|
+
@listType = @listTypeGroup.checkedId
|
628
|
+
list = %w[ list highlights popular ][@listType]
|
798
629
|
|
799
630
|
"http://feeds.bbc.co.uk/iplayer/#{channelStr}/#{list}"
|
800
631
|
end
|
801
632
|
|
802
633
|
|
634
|
+
def getCategoryTitle
|
635
|
+
CategoryRssTbl[ @channelIndex ][0]
|
636
|
+
end
|
637
|
+
|
638
|
+
def setListTitle
|
639
|
+
names = []
|
640
|
+
if getChannelTitle
|
641
|
+
names << getChannelTitle
|
642
|
+
else
|
643
|
+
names << CategoryRssTbl[ @channelIndex ][0]
|
644
|
+
end
|
645
|
+
names << %w[ All Highlights Popular ][@listType]
|
646
|
+
@listTitleLabel.text = names.join(' / ')
|
647
|
+
end
|
648
|
+
|
803
649
|
protected
|
804
|
-
def makeTablefromRss(
|
805
|
-
|
650
|
+
def makeTablefromRss(rss)
|
651
|
+
# rss = RSS::Parser.parse(rssRaw)
|
806
652
|
sortFlag = @programmeTable.sortingEnabled
|
807
653
|
@programmeTable.sortingEnabled = false
|
808
654
|
@programmeTable.hide
|
@@ -816,7 +662,8 @@ BBC iPlayer like audio (mms/rtsp) stream recorder.
|
|
816
662
|
title = i.title.content.to_s
|
817
663
|
updated = i.updated.content.to_s
|
818
664
|
contents = i.content.content
|
819
|
-
|
665
|
+
linkItem = i.links.find do |l| l.rel == 'self' end
|
666
|
+
link = linkItem ? linkItem.href : nil
|
820
667
|
categories = i.categories.map do |c| c.term end.join(',')
|
821
668
|
$log.misc { title }
|
822
669
|
@programmeTable.addEntry( r, title, categories, updated, contents, link )
|
@@ -858,7 +705,7 @@ BBC iPlayer like audio (mms/rtsp) stream recorder.
|
|
858
705
|
url = prog.content[UrlRegexp] # String[] method extract only 1st one.
|
859
706
|
|
860
707
|
$log.info { "episode Url : #{url}" }
|
861
|
-
minfo = BBCNet::
|
708
|
+
minfo = BBCNet::CacheMetaInfoDevice.read(url)
|
862
709
|
url = minfo.wma.url
|
863
710
|
|
864
711
|
fName = getSaveName(prog, 'wma')
|
@@ -913,7 +760,7 @@ BBC iPlayer like audio (mms/rtsp) stream recorder.
|
|
913
760
|
|
914
761
|
# channel [BBC Radio 4, ..]
|
915
762
|
def getChannelName
|
916
|
-
|
763
|
+
getChannelTitle
|
917
764
|
end
|
918
765
|
|
919
766
|
def getChannelTitle
|
@@ -980,6 +827,7 @@ end
|
|
980
827
|
#
|
981
828
|
|
982
829
|
about = KDE::AboutData.new(APP_NAME, APP_NAME, KDE::ki18n(APP_NAME), APP_VERSION)
|
830
|
+
about.setProgramIconName(':images/irecorder-22.png')
|
983
831
|
KDE::CmdLineArgs.init(ARGV, about)
|
984
832
|
# options = KDE::CmdLineOptions.new()
|
985
833
|
# options.add( "+url", KDE::ki18n( "The url to record)" ),"")
|