simple_pvr 0.0.2 → 0.0.3

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/Gemfile.lock CHANGED
@@ -1,17 +1,18 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- simple_pvr (0.0.2)
4
+ simple_pvr (0.0.3)
5
5
  activesupport (~> 3.2)
6
6
  data_mapper (~> 1.2)
7
7
  dm-sqlite-adapter (~> 1.2)
8
8
  nokogiri (~> 1.5)
9
+ puma (~> 1.6)
9
10
  sinatra (~> 1.3)
10
11
 
11
12
  GEM
12
13
  remote: http://rubygems.org/
13
14
  specs:
14
- activesupport (3.2.8)
15
+ activesupport (3.2.12)
15
16
  i18n (~> 0.6)
16
17
  multi_json (~> 1.0)
17
18
  addressable (2.2.8)
@@ -41,7 +42,7 @@ GEM
41
42
  dm-transactions (~> 1.2.0)
42
43
  dm-types (~> 1.2.0)
43
44
  dm-validations (~> 1.2.0)
44
- data_objects (0.10.8)
45
+ data_objects (0.10.12)
45
46
  addressable (~> 2.1)
46
47
  diff-lcs (1.1.3)
47
48
  dm-aggregates (1.2.0)
@@ -78,22 +79,24 @@ GEM
78
79
  uuidtools (~> 2.1)
79
80
  dm-validations (1.2.0)
80
81
  dm-core (~> 1.2.0)
81
- do_sqlite3 (0.10.8)
82
- data_objects (= 0.10.8)
82
+ do_sqlite3 (0.10.12)
83
+ data_objects (= 0.10.12)
83
84
  fastercsv (1.5.5)
84
85
  ffi (1.1.5)
85
86
  gherkin (2.11.2)
86
87
  json (>= 1.4.6)
87
- i18n (0.6.1)
88
+ i18n (0.6.4)
88
89
  json (1.7.5)
89
- json_pure (1.7.5)
90
+ json_pure (1.7.7)
90
91
  libwebsocket (0.1.5)
91
92
  addressable
92
93
  mime-types (1.19)
93
94
  multi_json (1.3.6)
94
95
  nokogiri (1.5.5)
96
+ puma (1.6.3)
97
+ rack (~> 1.2)
95
98
  rack (1.4.1)
96
- rack-protection (1.4.0)
99
+ rack-protection (1.5.0)
97
100
  rack
98
101
  rack-test (0.6.1)
99
102
  rack (>= 1.0)
@@ -112,12 +115,12 @@ GEM
112
115
  libwebsocket (~> 0.1.3)
113
116
  multi_json (~> 1.0)
114
117
  rubyzip
115
- sinatra (1.3.3)
116
- rack (~> 1.3, >= 1.3.6)
117
- rack-protection (~> 1.2)
118
+ sinatra (1.3.6)
119
+ rack (~> 1.4)
120
+ rack-protection (~> 1.3)
118
121
  tilt (~> 1.3, >= 1.3.3)
119
- stringex (1.4.0)
120
- tilt (1.3.3)
122
+ stringex (1.5.1)
123
+ tilt (1.3.5)
121
124
  uuidtools (2.1.3)
122
125
  xpath (0.1.4)
123
126
  nokogiri (~> 1.3)
data/README.md CHANGED
@@ -61,7 +61,7 @@ First you must specify in a YAML file how the channel IDs in your XMLTV file rel
61
61
  that the HDHomeRun has found for you. Create a file called e.g. "channel_mappings.yaml", with lines like this:
62
62
 
63
63
  www.ontv.dk/tv/1: DR 1
64
- www.ontv.dk/tv/2: DR 2
64
+ www.ontv.dk/tv/2: DR 2
65
65
 
66
66
  Then read your XMLTV file and the mappings file:
67
67
 
@@ -108,14 +108,16 @@ Future?
108
108
  This projects needs to be a nice, readable, hackable, tested system. No pull requests are
109
109
  accepted that violate this.
110
110
 
111
- For version 1 of SimplePVR, I'd like to finish the following:
111
+ For version 1 of SimplePVR, there are no more features planned. Instead, there'll be a little clean-up:
112
112
 
113
- * More schedule editing, e.g.:
114
- * "Start early" and "end late" (currently 2 and 5 minutes).
115
- * Which time of day the schedule should be active (e.g. only the afternoon, ignoring all the
116
- re-runs earlier in the day).
117
- * Removal of outdated schedules (the "Record single programme" and "Don't record this specific
118
- programme").
113
+ * Updating dependencies:
114
+ * Twitter Bootstrap.
115
+ * AngularJS.
116
+ * JQuery (should be part of the project, instead of fetched through CDN).
117
+ * Testacular is now called Karma.
118
+ * Various code clean-ups (no grand plan).
119
+ * Various GUI clean-ups (no grand plan).
120
+ * Various bug fixes (no known issues at this point).
119
121
 
120
122
  There is lots of stuff I'd like to do after that, but I have no deadline - which means that pull
121
123
  requests are the only means you have for speeding things up. This includes:
data/bin/pvr_server CHANGED
@@ -5,6 +5,6 @@ require 'simple_pvr'
5
5
 
6
6
  Rack::Server.start(
7
7
  :config => SimplePvr::PvrInitializer.rackup_file_path,
8
- :Port => 4567
9
- #:server => 'sinatra'
8
+ :Port => 4567,
9
+ :server => 'puma'
10
10
  )
@@ -6,6 +6,7 @@ Feature: Scheduling
6
6
  Background:
7
7
  Given the following programmes:
8
8
  | title | subtitle | channel | day |
9
+ | Old News | Just the old news... | Channel 1 | -1 |
9
10
  | News right now | Just the news... | Channel 1 | 0 |
10
11
  | Bonderøven | Danish documentary | Channel 1 | 1 |
11
12
  | Bonderøven | Danish documentary | Channel 2 | 1 |
@@ -16,6 +17,10 @@ Scenario: Nothing is scheduled by default
16
17
  Given I am on the schedules page
17
18
  Then there should be 0 upcoming recordings
18
19
 
20
+ Scenario: I cannot record past programmes
21
+ Given I have navigated to the programme page for yesterday's "Old News" on channel "Channel 1"
22
+ Then I should not see the button "Record just this programme"
23
+
19
24
  Scenario: Schedule by title for a single channel
20
25
  Given I have navigated to the programme page for "Bonderøven" on channel "Channel 1"
21
26
  And I choose to record the programme on this channel
@@ -109,4 +114,56 @@ Scenario: Editing a schedule so that only some weekdays are allowed
109
114
  And I check "Record Wednesdays"
110
115
  And I check "Record Sundays"
111
116
  And I press "Update"
112
- Then I should see "(Mondays, Wednesdays, and Sundays)"
117
+ Then I should see "(Mondays, Wednesdays, and Sundays)"
118
+
119
+ Scenario: Setting "Start early" and "End late"
120
+ Given I have navigated to the programme page for "Bonderøven" on channel "Channel 1"
121
+ And I choose to record the programme on any channel
122
+ And I am on the schedules page
123
+ And I follow "Edit"
124
+ And I fill in "Start early" with "4"
125
+ And I fill in "End late" with "10"
126
+ And I press "Update"
127
+ Then I should see "(starts 4 minutes early, ends 10 minutes late)"
128
+
129
+ Scenario: Start and end times of day
130
+ Given I have navigated to the programme page for "Bonderøven" on channel "Channel 1"
131
+ And I choose to record the programme on any channel
132
+ And I am on the schedules page
133
+ And I follow "Edit"
134
+ And I check "Filter by time of day"
135
+ And I fill in "From" with "17:00"
136
+ And I fill in "To" with "19:00"
137
+ And I press "Update"
138
+ Then I should see "(between 17:00 and 19:00)"
139
+
140
+ Scenario: Start and end times of day, crossing midnight
141
+ Given I have navigated to the programme page for "Bonderøven" on channel "Channel 1"
142
+ And I choose to record the programme on any channel
143
+ And I am on the schedules page
144
+ And I follow "Edit"
145
+ And I check "Filter by time of day"
146
+ And I fill in "From" with "19:00"
147
+ And I fill in "To" with "3:00"
148
+ And I press "Update"
149
+ Then I should see "(between 19:00 and 3:00)"
150
+
151
+ Scenario: Start time of day
152
+ Given I have navigated to the programme page for "Bonderøven" on channel "Channel 1"
153
+ And I choose to record the programme on any channel
154
+ And I am on the schedules page
155
+ And I follow "Edit"
156
+ And I check "Filter by time of day"
157
+ And I fill in "From" with "17:00"
158
+ And I press "Update"
159
+ Then I should see "(after 17:00)"
160
+
161
+ Scenario: End time of day
162
+ Given I have navigated to the programme page for "Bonderøven" on channel "Channel 1"
163
+ And I choose to record the programme on any channel
164
+ And I am on the schedules page
165
+ And I follow "Edit"
166
+ And I check "Filter by time of day"
167
+ And I fill in "To" with "7:00"
168
+ And I press "Update"
169
+ Then I should see "(before 7:00)"
@@ -28,6 +28,14 @@ Given /I have navigated to the programme page for "(.*)" on channel "(.*)"/ do |
28
28
  click_link(title)
29
29
  end
30
30
 
31
+ Given /I have navigated to the programme page for yesterday's "(.*)" on channel "(.*)"/ do |title, channel|
32
+ visit path_to('the channel overview page')
33
+ fill_in('channel_filter', :with => channel)
34
+ click_link('...')
35
+ click_link('<<')
36
+ click_link(title)
37
+ end
38
+
31
39
  Given /I choose to record just this programme/ do
32
40
  choose_to_record('Record just this programme')
33
41
  end
@@ -77,6 +85,10 @@ Then /I should not see the schedule "(.*)"/ do |text|
77
85
  end
78
86
  end
79
87
 
88
+ Then /I should not see the button "(.*)"/ do |text|
89
+ page.wait_until { page.has_no_button?(text) }
90
+ end
91
+
80
92
  Then /there should be (\d*) upcoming recordings?/ do |upcoming_recordings|
81
93
  page.wait_until { find('#upcoming_recordings').all('h2').length == upcoming_recordings.to_i }
82
94
  end
@@ -6,7 +6,7 @@ require 'rspec'
6
6
  require File.join(File.dirname(__FILE__), '../../lib/simple_pvr')
7
7
 
8
8
  SimplePvr::PvrInitializer.setup_for_integration_test
9
- SimplePvr::RecordingPlanner.read
9
+ SimplePvr::RecordingPlanner.reload
10
10
 
11
11
  Capybara.app = eval "Rack::Builder.new {( " + SimplePvr::PvrInitializer.rack_maps_file + ")}"
12
12
  Capybara.default_driver = :selenium
@@ -97,7 +97,7 @@ module SimplePvr
97
97
  end
98
98
 
99
99
  def tuner_control_file(tuner)
100
- File.dirname(__FILE__) + "/tuner#{tuner}.lock"
100
+ "tuner#{tuner}.lock"
101
101
  end
102
102
  end
103
103
  end
@@ -14,6 +14,14 @@ module SimplePvr
14
14
 
15
15
  belongs_to :channel
16
16
 
17
+ def end_time
18
+ @start_time.advance(seconds: duration)
19
+ end
20
+
21
+ def outdated?
22
+ end_time < Time.now
23
+ end
24
+
17
25
  def self.clear
18
26
  Programme.destroy
19
27
  end
@@ -3,13 +3,36 @@ module SimplePvr
3
3
  class Schedule
4
4
  include DataMapper::Resource
5
5
  storage_names[:default] = 'schedules'
6
+
7
+ def self.cleanup
8
+ Schedule.all(:end_time.lt => Time.now).each {|s| s.destroy }
9
+ end
10
+
11
+ def self.add_specification(options)
12
+ Schedule.create(
13
+ type: :specification,
14
+ title: options[:title],
15
+ channel: options[:channel],
16
+ start_time: options[:start_time],
17
+ end_time: options[:end_time])
18
+ end
6
19
 
7
20
  property :id, Serial
8
21
  property :type, Enum[:specification, :exception]
9
- property :title, String, :length => 255
22
+ property :title, String, length: 255
23
+
10
24
  # If specified (and channel is specified too), this schedule is for a specific
11
25
  # programme at a specific channel at a specific time
12
26
  property :start_time, DateTime
27
+ property :end_time, DateTime
28
+
29
+ property :custom_start_early_minutes, Integer
30
+ property :custom_end_late_minutes, Integer
31
+
32
+ property :filter_by_time_of_day, Boolean
33
+ property :from_time_of_day, String, length: 5
34
+ property :to_time_of_day, String, length: 5
35
+
13
36
  property :filter_by_weekday, Boolean
14
37
  property :monday, Boolean
15
38
  property :tuesday, Boolean
@@ -21,12 +44,12 @@ module SimplePvr
21
44
 
22
45
  belongs_to :channel, required: false
23
46
 
24
- def self.add_specification(options)
25
- Schedule.create(
26
- type: :specification,
27
- title: options[:title],
28
- channel: options[:channel],
29
- start_time: options[:start_time])
47
+ def start_early_minutes
48
+ custom_start_early_minutes || 2
49
+ end
50
+
51
+ def end_late_minutes
52
+ custom_end_late_minutes || 5
30
53
  end
31
54
  end
32
55
  end
@@ -1,6 +1,8 @@
1
1
  module SimplePvr
2
2
  class RecordingPlanner
3
- def self.read
3
+ def self.reload
4
+ Model::Schedule.cleanup
5
+
4
6
  planner = self.new
5
7
  planner.read
6
8
  end
@@ -15,24 +17,28 @@ module SimplePvr
15
17
  exceptions = schedules.find_all {|s| s.type == :exception }
16
18
 
17
19
  specifications.each do |specification|
18
- title = specification.title
19
- if specification.channel && specification.start_time
20
- programmes = Model::Programme.on_channel_with_title_and_start_time(specification.channel, specification.title, specification.start_time)
21
- elsif specification.channel
22
- programmes = Model::Programme.on_channel_with_title(specification.channel, specification.title)
23
- else
24
- programmes = Model::Programme.with_title(specification.title)
25
- end
26
-
20
+ programmes = programmes_matching(specification)
27
21
  programmes_with_exceptions_removed = programmes.find_all {|programme| !matches_exception(programme, exceptions) }
28
22
  programmes_filtered_by_weekdays = programmes_with_exceptions_removed.find_all {|programme| on_allowed_weekday(programme, specification) }
29
- add_programmes(title, programmes_filtered_by_weekdays)
23
+ programmes_filtered_by_time_of_day = programmes_filtered_by_weekdays.find_all {|programme| at_allowed_time_of_day(programme, specification) }
24
+
25
+ add_programmes(specification, programmes_filtered_by_time_of_day)
30
26
  end
31
27
 
32
28
  PvrInitializer.scheduler.recordings = @recordings
33
29
  end
34
30
 
35
31
  private
32
+ def programmes_matching(specification)
33
+ if specification.channel && specification.start_time
34
+ Model::Programme.on_channel_with_title_and_start_time(specification.channel, specification.title, specification.start_time)
35
+ elsif specification.channel
36
+ Model::Programme.on_channel_with_title(specification.channel, specification.title)
37
+ else
38
+ Model::Programme.with_title(specification.title)
39
+ end
40
+ end
41
+
36
42
  def matches_exception(programme, exceptions)
37
43
  exceptions.any? do |exception|
38
44
  programme.title == exception.title &&
@@ -56,17 +62,58 @@ module SimplePvr
56
62
  else false
57
63
  end
58
64
  end
65
+
66
+ def at_allowed_time_of_day(programme, specification)
67
+ return true unless specification.filter_by_time_of_day
68
+
69
+ # When comparing times of day below, we convert all timestamps into an integer so that we can easily compare them.
70
+ # We do this by converting e.g. "10:35" to the integer 1035.
71
+ programme_pseudo_start_time = pseudo_time_of_day_from_datetime(programme.start_time)
72
+
73
+ if specification.from_time_of_day && specification.to_time_of_day
74
+ pseudo_from_time = pseudo_time_of_day_from_string(specification.from_time_of_day)
75
+ pseudo_to_time = pseudo_time_of_day_from_string(specification.to_time_of_day)
76
+ if pseudo_from_time < pseudo_to_time
77
+ # Both times of day are at the same day
78
+ programme_pseudo_start_time >= pseudo_time_of_day_from_string(specification.from_time_of_day) &&
79
+ programme_pseudo_start_time <= pseudo_time_of_day_from_string(specification.to_time_of_day)
80
+ else
81
+ # Stretching across midnight
82
+ programme_pseudo_start_time >= pseudo_time_of_day_from_string(specification.from_time_of_day) ||
83
+ programme_pseudo_start_time <= pseudo_time_of_day_from_string(specification.to_time_of_day)
84
+ end
85
+ elsif specification.from_time_of_day
86
+ programme_pseudo_start_time >= pseudo_time_of_day_from_string(specification.from_time_of_day)
87
+ elsif specification.to_time_of_day
88
+ programme_pseudo_start_time <= pseudo_time_of_day_from_string(specification.to_time_of_day)
89
+ else
90
+ true
91
+ end
92
+ end
59
93
 
60
- def add_programmes(title, programmes)
94
+ def add_programmes(schedule, programmes)
61
95
  programmes.each do |programme|
62
- start_time = programme.start_time.advance(minutes: -2)
63
- duration = programme.duration + 7.minutes
64
- add_recording(title, programme.channel, start_time, duration, programme)
96
+ start_time = programme.start_time.advance(minutes: -schedule.start_early_minutes)
97
+ duration = programme.duration + (schedule.start_early_minutes + schedule.end_late_minutes).minutes
98
+ add_recording(schedule.title, programme.channel, start_time, duration, programme)
65
99
  end
66
100
  end
67
101
 
68
102
  def add_recording(title, channel, start_time, duration, programme=nil)
69
103
  @recordings << SimplePvr::Model::Recording.new(channel, title, start_time, duration, programme)
70
104
  end
105
+
106
+ # Given a time of day as string, e.g. "10:35", returns an integer which can be used to compare with other
107
+ # times of day, e.g. "1035"
108
+ def pseudo_time_of_day_from_string(s)
109
+ components = s.split(':')
110
+ components[0].to_i * 100 + components[1].to_i
111
+ end
112
+
113
+ # Given a datetime, representing e.g. "10:35", returns an integer which can be used to compare with other
114
+ # times of day, e.g. "1035"
115
+ def pseudo_time_of_day_from_datetime(datetime)
116
+ datetime.hour * 100 + datetime.min
117
+ end
71
118
  end
72
119
  end
@@ -29,11 +29,11 @@ module SimplePvr
29
29
  end
30
30
  end
31
31
 
32
- def is_scheduled?(programme)
32
+ def scheduled?(programme)
33
33
  @scheduled_programmes[programme.id] != nil
34
34
  end
35
35
 
36
- def is_conflicting?(programme)
36
+ def conflicting?(programme)
37
37
  @conflicting_programmes[programme.id] != nil
38
38
  end
39
39
 
@@ -24,11 +24,10 @@ module SimplePvr
24
24
  end
25
25
 
26
26
  def reload_schedules
27
- RecordingPlanner.read
27
+ RecordingPlanner.reload
28
28
  end
29
29
 
30
30
  def programme_hash(programme)
31
- is_scheduled = PvrInitializer.scheduler.is_scheduled?(programme)
32
31
  {
33
32
  id: programme.id,
34
33
  channel: { id: programme.channel.id, name: programme.channel.name },
@@ -36,8 +35,9 @@ module SimplePvr
36
35
  subtitle: programme.subtitle,
37
36
  description: programme.description,
38
37
  start_time: programme.start_time,
39
- is_scheduled: is_scheduled,
40
- episode_num: programme.episode_num
38
+ is_scheduled: PvrInitializer.scheduler.scheduled?(programme),
39
+ episode_num: programme.episode_num,
40
+ is_outdated: programme.outdated?
41
41
  }
42
42
  end
43
43
 
@@ -85,8 +85,8 @@ module SimplePvr
85
85
  id: programme.id,
86
86
  title: programme.title,
87
87
  start_time: programme.start_time,
88
- is_scheduled: PvrInitializer.scheduler.is_scheduled?(programme),
89
- is_conflicting: PvrInitializer.scheduler.is_conflicting?(programme)
88
+ is_scheduled: PvrInitializer.scheduler.scheduled?(programme),
89
+ is_conflicting: PvrInitializer.scheduler.conflicting?(programme)
90
90
  }
91
91
  end
92
92
  end
@@ -1,5 +1,5 @@
1
1
  SimplePvr::PvrInitializer.setup
2
- SimplePvr::RecordingPlanner.read
2
+ SimplePvr::RecordingPlanner.reload
3
3
 
4
4
  # Due to a lazy initialization bug in ActiveSupport:
5
5
  # http://stackoverflow.com/questions/5267700/undefined-method-encode-for-activesupportjsonmodule
@@ -30,14 +30,14 @@ module SimplePvr
30
30
 
31
31
  post '/:id/record_just_this_programme' do |id|
32
32
  programme = Model::Programme.get(id.to_i)
33
- Model::Schedule.add_specification(title: programme.title, channel: programme.channel, start_time: programme.start_time)
33
+ Model::Schedule.add_specification(title: programme.title, channel: programme.channel, start_time: programme.start_time, end_time: programme.end_time)
34
34
  reload_schedules
35
35
  programme_hash(programme).to_json
36
36
  end
37
37
 
38
38
  post '/:id/exclude' do |id|
39
39
  programme = Model::Programme.get(id.to_i)
40
- Model::Schedule.create(type: :exception, title: programme.title, channel: programme.channel, start_time: programme.start_time)
40
+ Model::Schedule.create(type: :exception, title: programme.title, channel: programme.channel, start_time: programme.start_time, end_time: programme.end_time)
41
41
  reload_schedules
42
42
  programme_hash(programme).to_json
43
43
  end
@@ -29,6 +29,14 @@ module SimplePvr
29
29
  schedule = Model::Schedule.get(id)
30
30
  schedule.title = parameters['title']
31
31
  schedule.channel = channel_id > 0 ? Model::Channel.get(channel_id) : nil
32
+
33
+ schedule.custom_start_early_minutes = parameters['custom_start_early_minutes'].present? ? parameters['custom_start_early_minutes'].to_i : nil
34
+ schedule.custom_end_late_minutes = parameters['custom_end_late_minutes'].present? ? parameters['custom_end_late_minutes'].to_i : nil
35
+
36
+ schedule.filter_by_time_of_day = parameters['filter_by_time_of_day']
37
+ schedule.from_time_of_day = parameters['from_time_of_day']
38
+ schedule.to_time_of_day = parameters['to_time_of_day']
39
+
32
40
  schedule.filter_by_weekday = parameters['filter_by_weekday'] ? true : nil
33
41
  schedule.monday = parameters['monday']
34
42
  schedule.tuesday = parameters['tuesday']
@@ -56,6 +64,16 @@ module SimplePvr
56
64
  channel: schedule.channel ? { id: schedule.channel.id, name: schedule.channel.name } : nil,
57
65
  start_time: schedule.start_time,
58
66
  is_exception: schedule.type == :exception,
67
+
68
+ custom_start_early_minutes: schedule.custom_start_early_minutes,
69
+ custom_end_late_minutes: schedule.custom_end_late_minutes,
70
+ start_early_minutes: schedule.start_early_minutes,
71
+ end_late_minutes: schedule.end_late_minutes,
72
+
73
+ filter_by_time_of_day: schedule.filter_by_time_of_day,
74
+ from_time_of_day: schedule.from_time_of_day,
75
+ to_time_of_day: schedule.to_time_of_day,
76
+
59
77
  filter_by_weekday: schedule.filter_by_weekday,
60
78
  monday: schedule.monday,
61
79
  tuesday: schedule.tuesday,
@@ -9,7 +9,7 @@ module SimplePvr
9
9
  start_time: recording.start_time,
10
10
  channel: { id: recording.channel.id, name: recording.channel.name },
11
11
  subtitle: recording.programme.subtitle,
12
- is_conflicting: PvrInitializer.scheduler.is_conflicting?(recording.programme)
12
+ is_conflicting: PvrInitializer.scheduler.conflicting?(recording.programme)
13
13
  }
14
14
  end.to_json
15
15
  end
@@ -1,3 +1,3 @@
1
1
  module SimplePvr
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
data/public/index.html CHANGED
@@ -20,6 +20,7 @@
20
20
 
21
21
  <script src="app/js/controllers.js"></script>
22
22
  <script src="app/js/services.js"></script>
23
+ <script src="app/js/filters.js"></script>
23
24
  <script src="app/js/app.js"></script>
24
25
  </head>
25
26
 
@@ -40,10 +41,7 @@
40
41
  <navbar-item route="/shows">Recordings</navbar-item>
41
42
  <navbar-item route="/status">Status</navbar-item>
42
43
  </ul>
43
- <form class="navbar-form pull-right" ng-controller="SearchProgrammesCtrl" ng-submit="search()">
44
- <input pvr-autocomplete class="span2" id="programme-search-query" type="text" placeholder="Search programmes...">
45
- <button type="submit" class="btn">Search</button>
46
- </form>
44
+ <title-search></title-search>
47
45
  </div>
48
46
  </div>
49
47
  </div>