simple_pvr 0.0.1
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/.rspec +1 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +133 -0
- data/LICENSE.txt +13 -0
- data/README.md +169 -0
- data/Rakefile +16 -0
- data/bin/pvr_server +10 -0
- data/bin/pvr_xmltv +18 -0
- data/features/channel_overview.feature +48 -0
- data/features/programme_search.feature +20 -0
- data/features/scheduling.feature +112 -0
- data/features/step_definitions/pvr_steps.rb +104 -0
- data/features/step_definitions/web_steps.rb +219 -0
- data/features/support/env.rb +28 -0
- data/features/support/paths.rb +17 -0
- data/features/week_overview.feature +39 -0
- data/lib/simple_pvr/ffmpeg.rb +22 -0
- data/lib/simple_pvr/hdhomerun.rb +103 -0
- data/lib/simple_pvr/hdhomerun_save.sh +10 -0
- data/lib/simple_pvr/model/channel.rb +72 -0
- data/lib/simple_pvr/model/database_initializer.rb +36 -0
- data/lib/simple_pvr/model/programme.rb +58 -0
- data/lib/simple_pvr/model/recording.rb +45 -0
- data/lib/simple_pvr/model/schedule.rb +33 -0
- data/lib/simple_pvr/pvr_initializer.rb +47 -0
- data/lib/simple_pvr/pvr_logger.rb +14 -0
- data/lib/simple_pvr/recorder.rb +25 -0
- data/lib/simple_pvr/recording_manager.rb +101 -0
- data/lib/simple_pvr/recording_planner.rb +72 -0
- data/lib/simple_pvr/scheduler.rb +124 -0
- data/lib/simple_pvr/server/app_controller.rb +13 -0
- data/lib/simple_pvr/server/base_controller.rb +94 -0
- data/lib/simple_pvr/server/channels_controller.rb +68 -0
- data/lib/simple_pvr/server/config.ru +8 -0
- data/lib/simple_pvr/server/programmes_controller.rb +46 -0
- data/lib/simple_pvr/server/rack_maps.rb +7 -0
- data/lib/simple_pvr/server/schedules_controller.rb +71 -0
- data/lib/simple_pvr/server/shows_controller.rb +63 -0
- data/lib/simple_pvr/server/status_controller.rb +11 -0
- data/lib/simple_pvr/server/upcoming_recordings_controller.rb +18 -0
- data/lib/simple_pvr/version.rb +3 -0
- data/lib/simple_pvr/xmltv_reader.rb +83 -0
- data/lib/simple_pvr.rb +22 -0
- data/public/css/bootstrap-responsive.min.css +9 -0
- data/public/css/bootstrap.min.css +9 -0
- data/public/css/simplepvr.css +11 -0
- data/public/img/glyphicons-halflings-white.png +0 -0
- data/public/img/glyphicons-halflings.png +0 -0
- data/public/index.html +55 -0
- data/public/js/angular/angular-resource.min.js +10 -0
- data/public/js/angular/angular.min.js +157 -0
- data/public/js/app.js +145 -0
- data/public/js/bootstrap/bootstrap.min.js +6 -0
- data/public/js/controllers.js +156 -0
- data/public/js/services.js +27 -0
- data/public/partials/about.html +5 -0
- data/public/partials/channels.html +41 -0
- data/public/partials/programme.html +20 -0
- data/public/partials/programmeListing.html +18 -0
- data/public/partials/schedule.html +80 -0
- data/public/partials/schedules.html +44 -0
- data/public/partials/search.html +17 -0
- data/public/partials/show.html +21 -0
- data/public/partials/shows.html +7 -0
- data/public/partials/status.html +6 -0
- data/simple_pvr.gemspec +30 -0
- data/spec/resources/channels.txt +11 -0
- data/spec/resources/programs-without-icon.xmltv +95 -0
- data/spec/resources/programs.xmltv +98 -0
- data/spec/simple_pvr/ffmpeg_spec.rb +26 -0
- data/spec/simple_pvr/hdhomerun_spec.rb +82 -0
- data/spec/simple_pvr/model/channel_spec.rb +114 -0
- data/spec/simple_pvr/model/programme_spec.rb +110 -0
- data/spec/simple_pvr/model/schedule_spec.rb +47 -0
- data/spec/simple_pvr/pvr_initializer_spec.rb +50 -0
- data/spec/simple_pvr/recorder_spec.rb +32 -0
- data/spec/simple_pvr/recording_manager_spec.rb +158 -0
- data/spec/simple_pvr/recording_planner_spec.rb +104 -0
- data/spec/simple_pvr/scheduler_spec.rb +201 -0
- data/spec/simple_pvr/xmltv_reader_spec.rb +49 -0
- data/test/config/jsTestDriver-scenario.conf +10 -0
- data/test/config/jsTestDriver.conf +12 -0
- data/test/config/jstd-scenario-adapter-config.js +6 -0
- data/test/filtersSpec.js +97 -0
- data/test/lib/angular/angular-mocks.js +1719 -0
- data/test/lib/angular/angular-scenario.js +25937 -0
- data/test/lib/angular/jstd-scenario-adapter.js +185 -0
- data/test/lib/angular/version.txt +1 -0
- data/test/lib/jasmine/MIT.LICENSE +20 -0
- data/test/lib/jasmine/index.js +180 -0
- data/test/lib/jasmine/jasmine-html.js +190 -0
- data/test/lib/jasmine/jasmine.css +166 -0
- data/test/lib/jasmine/jasmine.js +2476 -0
- data/test/lib/jasmine/jasmine_favicon.png +0 -0
- data/test/lib/jasmine/version.txt +1 -0
- data/test/lib/jasmine-jstd-adapter/JasmineAdapter.js +196 -0
- data/test/lib/jasmine-jstd-adapter/version.txt +1 -0
- data/test/lib/jstestdriver/JsTestDriver.jar +0 -0
- data/test/lib/jstestdriver/version.txt +1 -0
- data/test/scripts/test-server.sh +14 -0
- data/test/scripts/test.sh +8 -0
- metadata +342 -0
data/.rspec
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
--colour --format documentation
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
simple_pvr (0.0.1)
|
|
5
|
+
activesupport (~> 3.2)
|
|
6
|
+
data_mapper (~> 1.2)
|
|
7
|
+
dm-sqlite-adapter (~> 1.2)
|
|
8
|
+
nokogiri (~> 1.5)
|
|
9
|
+
sinatra (~> 1.3)
|
|
10
|
+
|
|
11
|
+
GEM
|
|
12
|
+
remote: http://rubygems.org/
|
|
13
|
+
specs:
|
|
14
|
+
activesupport (3.2.8)
|
|
15
|
+
i18n (~> 0.6)
|
|
16
|
+
multi_json (~> 1.0)
|
|
17
|
+
addressable (2.2.8)
|
|
18
|
+
bcrypt-ruby (3.0.1)
|
|
19
|
+
builder (3.1.0)
|
|
20
|
+
capybara (1.1.2)
|
|
21
|
+
mime-types (>= 1.16)
|
|
22
|
+
nokogiri (>= 1.3.3)
|
|
23
|
+
rack (>= 1.0.0)
|
|
24
|
+
rack-test (>= 0.5.4)
|
|
25
|
+
selenium-webdriver (~> 2.0)
|
|
26
|
+
xpath (~> 0.1.4)
|
|
27
|
+
childprocess (0.3.5)
|
|
28
|
+
ffi (~> 1.0, >= 1.0.6)
|
|
29
|
+
cucumber (1.2.1)
|
|
30
|
+
builder (>= 2.1.2)
|
|
31
|
+
diff-lcs (>= 1.1.3)
|
|
32
|
+
gherkin (~> 2.11.0)
|
|
33
|
+
json (>= 1.4.6)
|
|
34
|
+
data_mapper (1.2.0)
|
|
35
|
+
dm-aggregates (~> 1.2.0)
|
|
36
|
+
dm-constraints (~> 1.2.0)
|
|
37
|
+
dm-core (~> 1.2.0)
|
|
38
|
+
dm-migrations (~> 1.2.0)
|
|
39
|
+
dm-serializer (~> 1.2.0)
|
|
40
|
+
dm-timestamps (~> 1.2.0)
|
|
41
|
+
dm-transactions (~> 1.2.0)
|
|
42
|
+
dm-types (~> 1.2.0)
|
|
43
|
+
dm-validations (~> 1.2.0)
|
|
44
|
+
data_objects (0.10.8)
|
|
45
|
+
addressable (~> 2.1)
|
|
46
|
+
diff-lcs (1.1.3)
|
|
47
|
+
dm-aggregates (1.2.0)
|
|
48
|
+
dm-core (~> 1.2.0)
|
|
49
|
+
dm-constraints (1.2.0)
|
|
50
|
+
dm-core (~> 1.2.0)
|
|
51
|
+
dm-core (1.2.0)
|
|
52
|
+
addressable (~> 2.2.6)
|
|
53
|
+
dm-do-adapter (1.2.0)
|
|
54
|
+
data_objects (~> 0.10.6)
|
|
55
|
+
dm-core (~> 1.2.0)
|
|
56
|
+
dm-migrations (1.2.0)
|
|
57
|
+
dm-core (~> 1.2.0)
|
|
58
|
+
dm-serializer (1.2.2)
|
|
59
|
+
dm-core (~> 1.2.0)
|
|
60
|
+
fastercsv (~> 1.5)
|
|
61
|
+
json (~> 1.6)
|
|
62
|
+
json_pure (~> 1.6)
|
|
63
|
+
multi_json (~> 1.0)
|
|
64
|
+
dm-sqlite-adapter (1.2.0)
|
|
65
|
+
dm-do-adapter (~> 1.2.0)
|
|
66
|
+
do_sqlite3 (~> 0.10.6)
|
|
67
|
+
dm-timestamps (1.2.0)
|
|
68
|
+
dm-core (~> 1.2.0)
|
|
69
|
+
dm-transactions (1.2.0)
|
|
70
|
+
dm-core (~> 1.2.0)
|
|
71
|
+
dm-types (1.2.2)
|
|
72
|
+
bcrypt-ruby (~> 3.0)
|
|
73
|
+
dm-core (~> 1.2.0)
|
|
74
|
+
fastercsv (~> 1.5)
|
|
75
|
+
json (~> 1.6)
|
|
76
|
+
multi_json (~> 1.0)
|
|
77
|
+
stringex (~> 1.4)
|
|
78
|
+
uuidtools (~> 2.1)
|
|
79
|
+
dm-validations (1.2.0)
|
|
80
|
+
dm-core (~> 1.2.0)
|
|
81
|
+
do_sqlite3 (0.10.8)
|
|
82
|
+
data_objects (= 0.10.8)
|
|
83
|
+
fastercsv (1.5.5)
|
|
84
|
+
ffi (1.1.5)
|
|
85
|
+
gherkin (2.11.2)
|
|
86
|
+
json (>= 1.4.6)
|
|
87
|
+
i18n (0.6.1)
|
|
88
|
+
json (1.7.5)
|
|
89
|
+
json_pure (1.7.5)
|
|
90
|
+
libwebsocket (0.1.5)
|
|
91
|
+
addressable
|
|
92
|
+
mime-types (1.19)
|
|
93
|
+
multi_json (1.3.6)
|
|
94
|
+
nokogiri (1.5.5)
|
|
95
|
+
rack (1.4.1)
|
|
96
|
+
rack-protection (1.2.0)
|
|
97
|
+
rack
|
|
98
|
+
rack-test (0.6.1)
|
|
99
|
+
rack (>= 1.0)
|
|
100
|
+
rake (10.0.3)
|
|
101
|
+
rspec (2.11.0)
|
|
102
|
+
rspec-core (~> 2.11.0)
|
|
103
|
+
rspec-expectations (~> 2.11.0)
|
|
104
|
+
rspec-mocks (~> 2.11.0)
|
|
105
|
+
rspec-core (2.11.1)
|
|
106
|
+
rspec-expectations (2.11.3)
|
|
107
|
+
diff-lcs (~> 1.1.3)
|
|
108
|
+
rspec-mocks (2.11.2)
|
|
109
|
+
rubyzip (0.9.9)
|
|
110
|
+
selenium-webdriver (2.25.0)
|
|
111
|
+
childprocess (>= 0.2.5)
|
|
112
|
+
libwebsocket (~> 0.1.3)
|
|
113
|
+
multi_json (~> 1.0)
|
|
114
|
+
rubyzip
|
|
115
|
+
sinatra (1.3.3)
|
|
116
|
+
rack (~> 1.3, >= 1.3.6)
|
|
117
|
+
rack-protection (~> 1.2)
|
|
118
|
+
tilt (~> 1.3, >= 1.3.3)
|
|
119
|
+
stringex (1.4.0)
|
|
120
|
+
tilt (1.3.3)
|
|
121
|
+
uuidtools (2.1.3)
|
|
122
|
+
xpath (0.1.4)
|
|
123
|
+
nokogiri (~> 1.3)
|
|
124
|
+
|
|
125
|
+
PLATFORMS
|
|
126
|
+
ruby
|
|
127
|
+
|
|
128
|
+
DEPENDENCIES
|
|
129
|
+
capybara (~> 1.1)
|
|
130
|
+
cucumber (~> 1.2)
|
|
131
|
+
rake (>= 10.0.0)
|
|
132
|
+
rspec (~> 2.11)
|
|
133
|
+
simple_pvr!
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
|
2
|
+
Version 2, December 2004
|
|
3
|
+
|
|
4
|
+
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
|
5
|
+
|
|
6
|
+
Everyone is permitted to copy and distribute verbatim or modified
|
|
7
|
+
copies of this license document, and changing it is allowed as long
|
|
8
|
+
as the name is changed.
|
|
9
|
+
|
|
10
|
+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
|
11
|
+
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
|
12
|
+
|
|
13
|
+
0. You just DO WHAT THE FUCK YOU WANT TO.
|
data/README.md
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
What?
|
|
2
|
+
=====
|
|
3
|
+
A really, really simple PVR (Personal Video Recorder) system which only supports the
|
|
4
|
+
[HDHomeRun network tuners](http://www.silicondust.com/). It's written in Ruby and is highly hackable. If
|
|
5
|
+
you don't want to hack it, but just want a solid PVR system, no worries: It's dead-simple to use.
|
|
6
|
+
|
|
7
|
+
SimplePVR does not contain its own player, but currently provides an XBMC plug-in and some half-hearted
|
|
8
|
+
browser playback. Apart from that, all recordings are stored in a simple directory structure (see below
|
|
9
|
+
for an explanation), so that you can just point your favorite player to the recordings.
|
|
10
|
+
|
|
11
|
+
Why?
|
|
12
|
+
====
|
|
13
|
+
MythTV stopped working for me and my HDHomeRun box in the 0.25 release. And even though MythTV has loads
|
|
14
|
+
of merits, I just have no idea what to do when it stops working - I am not in control of my media center.
|
|
15
|
+
|
|
16
|
+
During the last couple of years, I have spent a substantial amount of time on bugs that suddenly appeared
|
|
17
|
+
in MythTV and suddenly went away. I really don't like using systems this brittle.
|
|
18
|
+
|
|
19
|
+
So I wanted to create a really simple PVR in Ruby, making it possible for others to hack away and have
|
|
20
|
+
fun while recording TV shows for the rest of the family.
|
|
21
|
+
|
|
22
|
+
It's based on the HDHomeRun command-line utility, which means it's:
|
|
23
|
+
|
|
24
|
+
* built on something that's officially supported by SiliconDust (the makers of HDHomeRun).
|
|
25
|
+
* really simple.
|
|
26
|
+
* limited to supporting HDHomeRun tuners.
|
|
27
|
+
|
|
28
|
+
Installation
|
|
29
|
+
============
|
|
30
|
+
First of all, you need a computer and an HDHomeRun tuner box. On your computer, you need to have the
|
|
31
|
+
"hdhomerun_config" tool on the path.
|
|
32
|
+
|
|
33
|
+
You need Ruby 1.9.2 or newer (1.9.0 or newer is probably enough).
|
|
34
|
+
|
|
35
|
+
gem install simple_pvr
|
|
36
|
+
|
|
37
|
+
It might not always be completely straightforward... simple_pvr uses DataMapper, which in turn relies on
|
|
38
|
+
bcrypt-ruby, which compiles some native stuff. So on MacOS, you need to install XCode and its command-line
|
|
39
|
+
utilities, or get "make" in some other way. On Linux, it should just work. Don't know about Windows.
|
|
40
|
+
|
|
41
|
+
If you'd like thumbnails for the recorded shows and ability to transcode recordings to WebM (so you can view
|
|
42
|
+
them directly in your browser), you need FFMPEG on the command-line. Install it using MacPorts, Homebrew,
|
|
43
|
+
"apt-get", or whatever.
|
|
44
|
+
|
|
45
|
+
Starting the server
|
|
46
|
+
===================
|
|
47
|
+
Run
|
|
48
|
+
|
|
49
|
+
pvr_server
|
|
50
|
+
|
|
51
|
+
...and go to [http://localhost:4567](http://localhost:4567). If you want to expose this URL to the outside
|
|
52
|
+
world, you'd better supply a username and password:
|
|
53
|
+
|
|
54
|
+
username=me password=secret pvr_server
|
|
55
|
+
|
|
56
|
+
This will secure the application with Basic HTTP Authentication.
|
|
57
|
+
|
|
58
|
+
XMLTV
|
|
59
|
+
=====
|
|
60
|
+
First you must specify in a YAML file how the channel IDs in your XMLTV file relates to the channel names
|
|
61
|
+
that the HDHomeRun has found for you. Create a file called e.g. "channel_mappings.yaml", with lines like this:
|
|
62
|
+
|
|
63
|
+
www.ontv.dk/tv/1: DR 1
|
|
64
|
+
www.ontv.dk/tv/2: DR 2
|
|
65
|
+
|
|
66
|
+
Then read your XMLTV file and the mappings file:
|
|
67
|
+
|
|
68
|
+
pvr_xmltv programmes.xmltv channel_mappings.yaml
|
|
69
|
+
|
|
70
|
+
...and wait a little. You can tell the webserver to update its schedules without restarting the server. This is
|
|
71
|
+
done by POST'ing to /api/schedules/reload on the server, e.g.:
|
|
72
|
+
|
|
73
|
+
curl -d "" localhost:4567/api/schedules/reload
|
|
74
|
+
|
|
75
|
+
Or, if you've secured your web server with Basic HTTP Authentication like I told you to, specify username and password:
|
|
76
|
+
|
|
77
|
+
curl -d "" -u me:secret localhost:4567/api/schedules/reload
|
|
78
|
+
|
|
79
|
+
Recordings
|
|
80
|
+
==========
|
|
81
|
+
The recordings are laid out like this, from the directory where you ran pvr_server:
|
|
82
|
+
|
|
83
|
+
* recordings/
|
|
84
|
+
* Borgias/
|
|
85
|
+
* 1/
|
|
86
|
+
* 2/
|
|
87
|
+
* Sports news/
|
|
88
|
+
* 1/
|
|
89
|
+
* 2/
|
|
90
|
+
* 3/
|
|
91
|
+
* ...
|
|
92
|
+
|
|
93
|
+
Inside the numbered directories are these files:
|
|
94
|
+
|
|
95
|
+
* stream.ts: The actual stream. Let VLC or another media player show these for you.
|
|
96
|
+
* hdhomerun_save.log: The output from the actual recording command.
|
|
97
|
+
* metadata.yml: Recording time, title, channel, etc.
|
|
98
|
+
|
|
99
|
+
...and a few other files (thumbnails, transcoded version of the recording, etc.).
|
|
100
|
+
|
|
101
|
+
XBMC Plug-In
|
|
102
|
+
============
|
|
103
|
+
There's a very simple XBMC plug-in for SimplePVR. See [the home page](https://github.com/olefriis/simplepvr)
|
|
104
|
+
for more information.
|
|
105
|
+
|
|
106
|
+
Future?
|
|
107
|
+
=======
|
|
108
|
+
This projects needs to be a nice, readable, hackable, tested system. No pull requests are
|
|
109
|
+
accepted that violate this.
|
|
110
|
+
|
|
111
|
+
For version 1 of SimplePVR, I'd like to finish the following:
|
|
112
|
+
|
|
113
|
+
* "Gemify" the stuff, so installation becomes a breeze.
|
|
114
|
+
* More schedule editing, e.g.:
|
|
115
|
+
* "Start early" and "end late" (currently 2 and 5 minutes).
|
|
116
|
+
* Which time of day the schedule should be active (e.g. only the afternoon, ignoring all the
|
|
117
|
+
re-runs earlier in the day).
|
|
118
|
+
* Removal of outdated schedules (the "Record single programme" and "Don't record this specific
|
|
119
|
+
programme").
|
|
120
|
+
|
|
121
|
+
There is lots of stuff I'd like to do after that, but I have no deadline - which means that pull
|
|
122
|
+
requests are the only means you have for speeding things up. This includes:
|
|
123
|
+
|
|
124
|
+
* Web interface:
|
|
125
|
+
* "Dashboard" giving "the big picture" of the status of the system (next 5 upcoming recordings,
|
|
126
|
+
last 5 recorded programmes, current status, last couple of errors, whether there are any
|
|
127
|
+
upcoming conflicts, etc.).
|
|
128
|
+
* Better overview of recordings (a flat view).
|
|
129
|
+
* Better overview pages, e.g. "all children programmes", "all movies this week", "tonight's
|
|
130
|
+
programmes", ...
|
|
131
|
+
* Setting up schedules defined by a channel, a start time, and a duration (and a name,
|
|
132
|
+
probably), so that the web GUI is usable even without XMLTV.
|
|
133
|
+
* Schedule editing: Show which programmes match the edited schedule, to make it easier to create
|
|
134
|
+
a schedule which exactly matches your needs.
|
|
135
|
+
* XMLTV import:
|
|
136
|
+
* Let SimplePVR itself fetch XMLTV URLs at specified times of day.
|
|
137
|
+
* Set-up of matching XMLTV IDs to channels could make good use of a GUI.
|
|
138
|
+
* Parse and make use of programme icons etc.
|
|
139
|
+
* Searching for tuners and scanning for channels would be nice through a GUI.
|
|
140
|
+
* Saving with the hdhomerun_config command is done through a shell script, so we can shut it down properly. I'd
|
|
141
|
+
like a simpler solution, but haven't found anything that works both on OS X and Linux.
|
|
142
|
+
[Bluepill](https://github.com/arya/bluepill) seems to do the job, but seems like too big a hammer...
|
|
143
|
+
|
|
144
|
+
Some features would be cool to have, but I don't have a personal need for them, so they will only
|
|
145
|
+
happen if *you* implement them and send me a pull request. Besides, some of them I have no clue how
|
|
146
|
+
to implement...
|
|
147
|
+
|
|
148
|
+
* Some kind of live TV.
|
|
149
|
+
* Create metadata for XBMC and Serviio.
|
|
150
|
+
* Duplication detection.
|
|
151
|
+
* Commercial detection.
|
|
152
|
+
* Record multiple programmes on same multiplex, so we are not restricted to only recording two
|
|
153
|
+
programmes at once.
|
|
154
|
+
|
|
155
|
+
Development
|
|
156
|
+
===========
|
|
157
|
+
Run the specs and features like this:
|
|
158
|
+
|
|
159
|
+
rake test
|
|
160
|
+
|
|
161
|
+
Run the JavaScript tests by first calling
|
|
162
|
+
|
|
163
|
+
test/scripts/test-server.sh
|
|
164
|
+
|
|
165
|
+
then opening a browser on the shown URL. Capture the browser in strict mode. After this, you can run
|
|
166
|
+
|
|
167
|
+
test/scripts/test.sh
|
|
168
|
+
|
|
169
|
+
any number of times. However, the test-server needs to be restarted from time to time.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require 'bundler/setup'
|
|
2
|
+
require 'bundler/gem_tasks'
|
|
3
|
+
require 'rspec/core/rake_task'
|
|
4
|
+
require 'cucumber/rake/task'
|
|
5
|
+
|
|
6
|
+
directory 'output'
|
|
7
|
+
|
|
8
|
+
namespace :test do
|
|
9
|
+
RSpec::Core::RakeTask.new(:spec)
|
|
10
|
+
Cucumber::Rake::Task.new(:features)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
desc 'Run specs and features'
|
|
14
|
+
task :test => ['test:spec', 'test:features']
|
|
15
|
+
|
|
16
|
+
task :default => ['test']
|
data/bin/pvr_server
ADDED
data/bin/pvr_xmltv
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'simple_pvr'
|
|
4
|
+
require 'yaml'
|
|
5
|
+
require 'open-uri'
|
|
6
|
+
|
|
7
|
+
if ARGV.length != 2
|
|
8
|
+
puts "Requires two arguments: The XMLTV file name, and the channel mapping file name"
|
|
9
|
+
exit 1
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
SimplePvr::PvrInitializer.setup
|
|
13
|
+
|
|
14
|
+
xmltv_file = File.new(ARGV[0])
|
|
15
|
+
mapping_to_channels = YAML.load_file(ARGV[1])
|
|
16
|
+
|
|
17
|
+
reader = SimplePvr::XmltvReader.new(mapping_to_channels)
|
|
18
|
+
reader.read(xmltv_file)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
Feature: Channel overview
|
|
2
|
+
In order to find what's on TV
|
|
3
|
+
As a user
|
|
4
|
+
I want a good channel overview
|
|
5
|
+
|
|
6
|
+
Background:
|
|
7
|
+
Given the following channels:
|
|
8
|
+
| name |
|
|
9
|
+
| Channel 1 |
|
|
10
|
+
| Channel 2 |
|
|
11
|
+
| Animals |
|
|
12
|
+
And the following programmes:
|
|
13
|
+
| title | subtitle | channel | day |
|
|
14
|
+
| Blast from past | Prehistoric documentary | Channel 1 | -1 |
|
|
15
|
+
| Bonderøven | Danish documentary | Channel 1 | 0 |
|
|
16
|
+
| Blood and Bone | American action movie from 2009 | Channel 1 | 0 |
|
|
17
|
+
| Noddy | Children's programme | Channel 2 | 0 |
|
|
18
|
+
|
|
19
|
+
Scenario: Channel overview shows channel names
|
|
20
|
+
Given I am on the channel overview page
|
|
21
|
+
Then I should see "Channel 1"
|
|
22
|
+
And I should see "Channel 2"
|
|
23
|
+
And I should see "Animals"
|
|
24
|
+
|
|
25
|
+
Scenario: Channel overview shows upcoming programmes
|
|
26
|
+
Given I am on the channel overview page
|
|
27
|
+
Then I should see "Bonderøven"
|
|
28
|
+
But I should not see "Blast from past"
|
|
29
|
+
|
|
30
|
+
Scenario: Clicking on an upcoming programme reveals more programme information
|
|
31
|
+
Given I am on the channel overview page
|
|
32
|
+
And I follow "Bonderøven"
|
|
33
|
+
Then I should see "Danish documentary"
|
|
34
|
+
|
|
35
|
+
Scenario: Channel filtering
|
|
36
|
+
Given I am on the channel overview page
|
|
37
|
+
And I fill in "channel_filter" with "channel"
|
|
38
|
+
Then I should see "Channel 1"
|
|
39
|
+
And I should see "Channel 2"
|
|
40
|
+
But I should not see "Animals"
|
|
41
|
+
|
|
42
|
+
Scenario: I can go to a week overview for a given channel
|
|
43
|
+
Given I am on the channel overview page
|
|
44
|
+
And I fill in "channel_filter" with "Channel 1"
|
|
45
|
+
And I follow "..."
|
|
46
|
+
Then I should see "Bonderøven"
|
|
47
|
+
And I should see "Blood and Bone"
|
|
48
|
+
But I should not see "Noddy"
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Feature: Programme search
|
|
2
|
+
In order to find interesting programmes
|
|
3
|
+
As a user
|
|
4
|
+
I want to search through all programmes
|
|
5
|
+
|
|
6
|
+
Background:
|
|
7
|
+
Given the following programmes:
|
|
8
|
+
| title | subtitle |
|
|
9
|
+
| Bonderøven | Danish documentary |
|
|
10
|
+
| Blood and Bone | American action movie from 2009 |
|
|
11
|
+
| Noddy | Children's programme |
|
|
12
|
+
And I am on the schedules page
|
|
13
|
+
|
|
14
|
+
Scenario: Autocomplete in programme search
|
|
15
|
+
Given I enter "Bon" in the programme search field
|
|
16
|
+
Then I should see the programme title suggestion "Bonderøven"
|
|
17
|
+
|
|
18
|
+
Scenario: Searching for a text reveals summary of programmes with matching titles
|
|
19
|
+
Given I search for programmes with title "Bon"
|
|
20
|
+
Then I should see "Danish documentary" in the page contents
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
Feature: Scheduling
|
|
2
|
+
In order to record programmes
|
|
3
|
+
As a user
|
|
4
|
+
I want to set up recording schedules
|
|
5
|
+
|
|
6
|
+
Background:
|
|
7
|
+
Given the following programmes:
|
|
8
|
+
| title | subtitle | channel | day |
|
|
9
|
+
| News right now | Just the news... | Channel 1 | 0 |
|
|
10
|
+
| Bonderøven | Danish documentary | Channel 1 | 1 |
|
|
11
|
+
| Bonderøven | Danish documentary | Channel 2 | 1 |
|
|
12
|
+
| Bonderøven | Danish documentary | Channel 1 | 3 |
|
|
13
|
+
| Noddy | Children's programme | Channel 1 | 1 |
|
|
14
|
+
|
|
15
|
+
Scenario: Nothing is scheduled by default
|
|
16
|
+
Given I am on the schedules page
|
|
17
|
+
Then there should be 0 upcoming recordings
|
|
18
|
+
|
|
19
|
+
Scenario: Schedule by title for a single channel
|
|
20
|
+
Given I have navigated to the programme page for "Bonderøven" on channel "Channel 1"
|
|
21
|
+
And I choose to record the programme on this channel
|
|
22
|
+
And I am on the schedules page
|
|
23
|
+
Then I should see the schedule "Bonderøven on Channel 1"
|
|
24
|
+
And there should be 2 upcoming recordings
|
|
25
|
+
|
|
26
|
+
Scenario: Schedule by title for all channels
|
|
27
|
+
Given I have navigated to the programme page for "Bonderøven" on channel "Channel 1"
|
|
28
|
+
And I choose to record the programme on any channel
|
|
29
|
+
And I am on the schedules page
|
|
30
|
+
Then I should see the schedule "Bonderøven"
|
|
31
|
+
But I should not see the schedule "Bonderøven on Channel 1"
|
|
32
|
+
And there should be 3 upcoming recordings
|
|
33
|
+
|
|
34
|
+
Scenario: Schedule a specific programme
|
|
35
|
+
Given I have navigated to the programme page for "Bonderøven" on channel "Channel 1"
|
|
36
|
+
And I choose to record just this programme
|
|
37
|
+
And I am on the schedules page
|
|
38
|
+
Then I should see the timed schedule "Bonderøven on Channel 1"
|
|
39
|
+
And there should be 1 upcoming recordings
|
|
40
|
+
|
|
41
|
+
Scenario: Set up schedule manually
|
|
42
|
+
Given I am on the schedules page
|
|
43
|
+
And I fill in "Name" with "Bonderøven"
|
|
44
|
+
And I select "Channel 1" from "Channel"
|
|
45
|
+
And I press "Create schedule"
|
|
46
|
+
Then I should see the schedule "Bonderøven on Channel 1"
|
|
47
|
+
And there should be 2 upcoming recordings
|
|
48
|
+
|
|
49
|
+
Scenario: Scheduling the current programme starts recording immediately
|
|
50
|
+
Given I am on the status page
|
|
51
|
+
Then I should see "Idle"
|
|
52
|
+
When I have navigated to the programme page for "News right now" on channel "Channel 1"
|
|
53
|
+
And I choose to record the programme on this channel
|
|
54
|
+
And I wait 2 seconds
|
|
55
|
+
When I am on the status page
|
|
56
|
+
Then I should see "Recording 'News right now' on channel 'Channel 1'"
|
|
57
|
+
|
|
58
|
+
Scenario: Remove schedule
|
|
59
|
+
Given I have navigated to the programme page for "Bonderøven" on channel "Channel 1"
|
|
60
|
+
And I choose to record the programme on this channel
|
|
61
|
+
And I am on the schedules page
|
|
62
|
+
And I follow "Delete"
|
|
63
|
+
Then I should not see the schedule "Bonderøven on Channel 1"
|
|
64
|
+
And there should be 0 upcoming recordings
|
|
65
|
+
|
|
66
|
+
Scenario: Defining conflicting schedules
|
|
67
|
+
Given I have navigated to the programme page for "Bonderøven" on channel "Channel 1"
|
|
68
|
+
And I choose to record the programme on any channel
|
|
69
|
+
And I have navigated to the programme page for "Noddy" on channel "Channel 1"
|
|
70
|
+
And I choose to record the programme on this channel
|
|
71
|
+
When I am on the schedules page
|
|
72
|
+
Then there should be a conflict
|
|
73
|
+
|
|
74
|
+
Scenario: Fixing conflicts by removing a schedule
|
|
75
|
+
Given I have navigated to the programme page for "Bonderøven" on channel "Channel 1"
|
|
76
|
+
And I choose to record the programme on any channel
|
|
77
|
+
And I have navigated to the programme page for "Noddy" on channel "Channel 1"
|
|
78
|
+
And I choose to record the programme on this channel
|
|
79
|
+
When I am on the schedules page
|
|
80
|
+
And I follow "Delete"
|
|
81
|
+
Then there should be no conflicts
|
|
82
|
+
|
|
83
|
+
Scenario: Removing a specific recording from a schedule
|
|
84
|
+
Given I have navigated to the programme page for "Bonderøven" on channel "Channel 1"
|
|
85
|
+
And I choose to record the programme on any channel
|
|
86
|
+
And I am on the schedules page
|
|
87
|
+
Then there should be 3 upcoming recordings
|
|
88
|
+
When I follow "Do not record this specific show"
|
|
89
|
+
Then there should be 2 upcoming recordings
|
|
90
|
+
And I should see "Exception: Bonderøven"
|
|
91
|
+
|
|
92
|
+
Scenario: Editing a schedule
|
|
93
|
+
Given I have navigated to the programme page for "Bonderøven" on channel "Channel 1"
|
|
94
|
+
And I choose to record the programme on any channel
|
|
95
|
+
And I am on the schedules page
|
|
96
|
+
And I follow "Edit"
|
|
97
|
+
And I fill in "Name of show" with "Noddy"
|
|
98
|
+
And I press "Update"
|
|
99
|
+
Then there should be 1 upcoming recording
|
|
100
|
+
And I should not see "Bonderøven"
|
|
101
|
+
|
|
102
|
+
Scenario: Editing a schedule so that only some weekdays are allowed
|
|
103
|
+
Given I have navigated to the programme page for "Bonderøven" on channel "Channel 1"
|
|
104
|
+
And I choose to record the programme on any channel
|
|
105
|
+
And I am on the schedules page
|
|
106
|
+
And I follow "Edit"
|
|
107
|
+
And I check "Filter by weekday"
|
|
108
|
+
And I check "Record Mondays"
|
|
109
|
+
And I check "Record Wednesdays"
|
|
110
|
+
And I check "Record Sundays"
|
|
111
|
+
And I press "Update"
|
|
112
|
+
Then I should see "(Mondays, Wednesdays, and Sundays)"
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
require 'timeout'
|
|
2
|
+
|
|
3
|
+
Given /the following programmes\:/ do |programme_table|
|
|
4
|
+
programme_table.hashes.each do |programme|
|
|
5
|
+
channel = find_or_create_channel_with_name(programme['channel'] || 'Channel 1')
|
|
6
|
+
air_time = Time.now.advance(days: (programme['day'] || '0').to_i)
|
|
7
|
+
SimplePvr::Model::Programme.add(channel, programme['title'] || '', programme['subtitle'] || '',
|
|
8
|
+
programme['description'] || '', air_time, 60.minutes, ' .23/40. ')
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
Given /the following channels\:/ do |channel_table|
|
|
13
|
+
channel_table.hashes.each do |channel|
|
|
14
|
+
find_or_create_channel_with_name(channel['name'])
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
Given /I have navigated to the week overview for channel "(.*)"/ do |channel|
|
|
19
|
+
visit path_to('the channel overview page')
|
|
20
|
+
fill_in('channel_filter', :with => channel)
|
|
21
|
+
click_link('...')
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
Given /I have navigated to the programme page for "(.*)" on channel "(.*)"/ do |title, channel|
|
|
25
|
+
visit path_to('the channel overview page')
|
|
26
|
+
fill_in('channel_filter', :with => channel)
|
|
27
|
+
click_link('...')
|
|
28
|
+
click_link(title)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
Given /I choose to record just this programme/ do
|
|
32
|
+
choose_to_record('Record just this programme')
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
Given /I choose to record the programme on this channel/ do
|
|
36
|
+
choose_to_record('Record on this channel')
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
Given /I choose to record the programme on any channel/ do
|
|
40
|
+
choose_to_record('Record on any channel')
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
When /I enter "(.*)" in the programme search field/ do |query|
|
|
44
|
+
fill_in('programme-search-query', :with => query)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
When /I search for programmes with title "(.*)"/ do |query|
|
|
48
|
+
fill_in('programme-search-query', :with => query)
|
|
49
|
+
click_button('Search')
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
Then /I should see the programme title suggestion "(.*)"/ do |suggestion|
|
|
53
|
+
page.wait_until { page.text.include? suggestion }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
Then /I should see "(.*)" in the page contents/ do |text|
|
|
57
|
+
within('#contents') do
|
|
58
|
+
page.wait_until { page.text.include? text }
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
Then /I should see the schedule "(.*)"/ do |text|
|
|
63
|
+
within('#schedules') do
|
|
64
|
+
page.wait_until { page.text.include? text }
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
Then /I should see the timed schedule "(.*)"/ do |text|
|
|
69
|
+
within('#schedules') do
|
|
70
|
+
page.wait_until { page.text =~ /#{text} .* \d+, \d{4} at \d?\d:\d\d/ }
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
Then /I should not see the schedule "(.*)"/ do |text|
|
|
75
|
+
within('#schedules') do
|
|
76
|
+
page.wait_until { !(page.text.include? text) }
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
Then /there should be (\d*) upcoming recordings?/ do |upcoming_recordings|
|
|
81
|
+
page.wait_until { find('#upcoming_recordings').all('h2').length == upcoming_recordings.to_i }
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
Then /^there should be a conflict$/ do
|
|
85
|
+
page.wait_until { page.text.include? '(Conflicting)' }
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
Then /^there should be no conflicts$/ do
|
|
89
|
+
page.wait_until { !(page.text.include? '(Conflicting)') }
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
Then /I wait (\d*) seconds/ do |seconds|
|
|
93
|
+
sleep seconds.to_i
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def find_or_create_channel_with_name(name)
|
|
97
|
+
channel = SimplePvr::Model::Channel.first(name: name)
|
|
98
|
+
channel ? channel : SimplePvr::Model::Channel.add(name, 0, 0)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def choose_to_record(button_text)
|
|
102
|
+
click_button(button_text)
|
|
103
|
+
page.wait_until { page.text.include? 'This programme is being recorded' }
|
|
104
|
+
end
|