irecorder 0.0.4-linux → 0.0.5-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/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)" ),"")
|