simple_pvr 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. data/.rspec +1 -0
  2. data/Gemfile +4 -0
  3. data/Gemfile.lock +133 -0
  4. data/LICENSE.txt +13 -0
  5. data/README.md +169 -0
  6. data/Rakefile +16 -0
  7. data/bin/pvr_server +10 -0
  8. data/bin/pvr_xmltv +18 -0
  9. data/features/channel_overview.feature +48 -0
  10. data/features/programme_search.feature +20 -0
  11. data/features/scheduling.feature +112 -0
  12. data/features/step_definitions/pvr_steps.rb +104 -0
  13. data/features/step_definitions/web_steps.rb +219 -0
  14. data/features/support/env.rb +28 -0
  15. data/features/support/paths.rb +17 -0
  16. data/features/week_overview.feature +39 -0
  17. data/lib/simple_pvr/ffmpeg.rb +22 -0
  18. data/lib/simple_pvr/hdhomerun.rb +103 -0
  19. data/lib/simple_pvr/hdhomerun_save.sh +10 -0
  20. data/lib/simple_pvr/model/channel.rb +72 -0
  21. data/lib/simple_pvr/model/database_initializer.rb +36 -0
  22. data/lib/simple_pvr/model/programme.rb +58 -0
  23. data/lib/simple_pvr/model/recording.rb +45 -0
  24. data/lib/simple_pvr/model/schedule.rb +33 -0
  25. data/lib/simple_pvr/pvr_initializer.rb +47 -0
  26. data/lib/simple_pvr/pvr_logger.rb +14 -0
  27. data/lib/simple_pvr/recorder.rb +25 -0
  28. data/lib/simple_pvr/recording_manager.rb +101 -0
  29. data/lib/simple_pvr/recording_planner.rb +72 -0
  30. data/lib/simple_pvr/scheduler.rb +124 -0
  31. data/lib/simple_pvr/server/app_controller.rb +13 -0
  32. data/lib/simple_pvr/server/base_controller.rb +94 -0
  33. data/lib/simple_pvr/server/channels_controller.rb +68 -0
  34. data/lib/simple_pvr/server/config.ru +8 -0
  35. data/lib/simple_pvr/server/programmes_controller.rb +46 -0
  36. data/lib/simple_pvr/server/rack_maps.rb +7 -0
  37. data/lib/simple_pvr/server/schedules_controller.rb +71 -0
  38. data/lib/simple_pvr/server/shows_controller.rb +63 -0
  39. data/lib/simple_pvr/server/status_controller.rb +11 -0
  40. data/lib/simple_pvr/server/upcoming_recordings_controller.rb +18 -0
  41. data/lib/simple_pvr/version.rb +3 -0
  42. data/lib/simple_pvr/xmltv_reader.rb +83 -0
  43. data/lib/simple_pvr.rb +22 -0
  44. data/public/css/bootstrap-responsive.min.css +9 -0
  45. data/public/css/bootstrap.min.css +9 -0
  46. data/public/css/simplepvr.css +11 -0
  47. data/public/img/glyphicons-halflings-white.png +0 -0
  48. data/public/img/glyphicons-halflings.png +0 -0
  49. data/public/index.html +55 -0
  50. data/public/js/angular/angular-resource.min.js +10 -0
  51. data/public/js/angular/angular.min.js +157 -0
  52. data/public/js/app.js +145 -0
  53. data/public/js/bootstrap/bootstrap.min.js +6 -0
  54. data/public/js/controllers.js +156 -0
  55. data/public/js/services.js +27 -0
  56. data/public/partials/about.html +5 -0
  57. data/public/partials/channels.html +41 -0
  58. data/public/partials/programme.html +20 -0
  59. data/public/partials/programmeListing.html +18 -0
  60. data/public/partials/schedule.html +80 -0
  61. data/public/partials/schedules.html +44 -0
  62. data/public/partials/search.html +17 -0
  63. data/public/partials/show.html +21 -0
  64. data/public/partials/shows.html +7 -0
  65. data/public/partials/status.html +6 -0
  66. data/simple_pvr.gemspec +30 -0
  67. data/spec/resources/channels.txt +11 -0
  68. data/spec/resources/programs-without-icon.xmltv +95 -0
  69. data/spec/resources/programs.xmltv +98 -0
  70. data/spec/simple_pvr/ffmpeg_spec.rb +26 -0
  71. data/spec/simple_pvr/hdhomerun_spec.rb +82 -0
  72. data/spec/simple_pvr/model/channel_spec.rb +114 -0
  73. data/spec/simple_pvr/model/programme_spec.rb +110 -0
  74. data/spec/simple_pvr/model/schedule_spec.rb +47 -0
  75. data/spec/simple_pvr/pvr_initializer_spec.rb +50 -0
  76. data/spec/simple_pvr/recorder_spec.rb +32 -0
  77. data/spec/simple_pvr/recording_manager_spec.rb +158 -0
  78. data/spec/simple_pvr/recording_planner_spec.rb +104 -0
  79. data/spec/simple_pvr/scheduler_spec.rb +201 -0
  80. data/spec/simple_pvr/xmltv_reader_spec.rb +49 -0
  81. data/test/config/jsTestDriver-scenario.conf +10 -0
  82. data/test/config/jsTestDriver.conf +12 -0
  83. data/test/config/jstd-scenario-adapter-config.js +6 -0
  84. data/test/filtersSpec.js +97 -0
  85. data/test/lib/angular/angular-mocks.js +1719 -0
  86. data/test/lib/angular/angular-scenario.js +25937 -0
  87. data/test/lib/angular/jstd-scenario-adapter.js +185 -0
  88. data/test/lib/angular/version.txt +1 -0
  89. data/test/lib/jasmine/MIT.LICENSE +20 -0
  90. data/test/lib/jasmine/index.js +180 -0
  91. data/test/lib/jasmine/jasmine-html.js +190 -0
  92. data/test/lib/jasmine/jasmine.css +166 -0
  93. data/test/lib/jasmine/jasmine.js +2476 -0
  94. data/test/lib/jasmine/jasmine_favicon.png +0 -0
  95. data/test/lib/jasmine/version.txt +1 -0
  96. data/test/lib/jasmine-jstd-adapter/JasmineAdapter.js +196 -0
  97. data/test/lib/jasmine-jstd-adapter/version.txt +1 -0
  98. data/test/lib/jstestdriver/JsTestDriver.jar +0 -0
  99. data/test/lib/jstestdriver/version.txt +1 -0
  100. data/test/scripts/test-server.sh +14 -0
  101. data/test/scripts/test.sh +8 -0
  102. metadata +342 -0
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour --format documentation
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in simple_pvr.gemspec
4
+ gemspec
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
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rack'
4
+ require 'simple_pvr'
5
+
6
+ Rack::Server.start(
7
+ :config => SimplePvr::PvrInitializer.rackup_file_path,
8
+ :Port => 4567
9
+ #:server => 'sinatra'
10
+ )
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