simple_pvr 1.0.0 → 1.1.0
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.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +1 -4
- data/Gemfile.lock +72 -61
- data/README.md +51 -33
- data/bin/pvr_server +14 -6
- data/changelog.txt +11 -0
- data/development_server +14 -6
- data/features/channel_overview.feature +1 -1
- data/features/recordings.feature +30 -0
- data/features/step_definitions/pvr_steps.rb +34 -0
- data/features/support/env.rb +1 -2
- data/features/support/paths.rb +2 -0
- data/lib/simple_pvr.rb +2 -0
- data/lib/simple_pvr/model/database_initializer.rb +8 -0
- data/lib/simple_pvr/model/programme.rb +12 -2
- data/lib/simple_pvr/model/programme_actor.rb +14 -0
- data/lib/simple_pvr/model/programme_category.rb +14 -0
- data/lib/simple_pvr/model/programme_director.rb +13 -0
- data/lib/simple_pvr/model/programme_presenter.rb +13 -0
- data/lib/simple_pvr/model/recording.rb +12 -0
- data/lib/simple_pvr/programme_icon_fetcher.rb +15 -0
- data/lib/simple_pvr/pvr_initializer.rb +4 -4
- data/lib/simple_pvr/recorder.rb +4 -3
- data/lib/simple_pvr/recording_manager.rb +44 -24
- data/lib/simple_pvr/recording_planner.rb +3 -3
- data/lib/simple_pvr/scheduler.rb +12 -4
- data/lib/simple_pvr/server/base_controller.rb +12 -13
- data/lib/simple_pvr/server/channels_controller.rb +5 -5
- data/lib/simple_pvr/server/programmes_controller.rb +2 -2
- data/lib/simple_pvr/server/schedules_controller.rb +4 -4
- data/lib/simple_pvr/server/secured_controller.rb +71 -0
- data/lib/simple_pvr/server/shows_controller.rb +13 -8
- data/lib/simple_pvr/server/status_controller.rb +1 -1
- data/lib/simple_pvr/server/upcoming_recordings_controller.rb +1 -1
- data/lib/simple_pvr/version.rb +1 -1
- data/lib/simple_pvr/xmltv_reader.rb +37 -4
- data/public/css/typeahead.js-bootstrap.css +83 -0
- data/public/index.html +45 -37
- data/public/js/angular/http-auth-interceptor.js +122 -0
- data/public/js/app.js +4 -37
- data/public/js/controllers.js +22 -14
- data/public/js/directives.js +102 -0
- data/public/js/filters.js +0 -31
- data/public/js/services.js +64 -0
- data/public/js/typeahead/typeahead.min.js +7 -0
- data/public/partials/about.html +15 -13
- data/public/partials/channels.html +41 -36
- data/public/partials/programme.html +20 -4
- data/public/partials/programmeListing.html +14 -13
- data/public/partials/schedule.html +91 -86
- data/public/partials/schedules.html +28 -16
- data/public/partials/search.html +10 -11
- data/public/partials/show.html +26 -9
- data/public/partials/shows.html +5 -6
- data/public/partials/status.html +1 -1
- data/public/templates/loginDialog.html +30 -0
- data/public/templates/logoutLink.html +1 -0
- data/public/templates/titleSearch.html +5 -3
- data/simple_pvr.gemspec +6 -4
- data/spec/resources/dummyImage.png +1 -0
- data/spec/resources/programmes-with-categories.xmltv +27 -0
- data/spec/resources/programmes-with-credits.xmltv +24 -0
- data/spec/resources/programmes-with-icons.xmltv +25 -0
- data/spec/resources/programmes-with-presenters.xmltv +19 -0
- data/spec/resources/{programs-without-icon.xmltv → programmes-without-icon.xmltv} +0 -0
- data/spec/resources/{programs.xmltv → programmes.xmltv} +0 -4
- data/spec/simple_pvr/ffmpeg_spec.rb +24 -22
- data/spec/simple_pvr/hdhomerun_spec.rb +69 -67
- data/spec/simple_pvr/model/channel_spec.rb +101 -101
- data/spec/simple_pvr/model/programme_spec.rb +104 -104
- data/spec/simple_pvr/model/schedule_spec.rb +74 -74
- data/spec/simple_pvr/programme_icon_fetcher_spec.rb +25 -0
- data/spec/simple_pvr/pvr_initializer_spec.rb +40 -38
- data/spec/simple_pvr/recorder_spec.rb +37 -26
- data/spec/simple_pvr/recording_manager_spec.rb +160 -133
- data/spec/simple_pvr/recording_planner_spec.rb +213 -211
- data/spec/simple_pvr/scheduler_spec.rb +189 -172
- data/spec/simple_pvr/server/secured_controller_spec.rb +118 -0
- data/spec/simple_pvr/xmltv_reader_spec.rb +89 -41
- data/test/karma.conf.js +7 -4
- data/test/unit/filtersSpec.js +0 -36
- metadata +79 -63
- data/public/css/bootstrap-responsive.min.css +0 -9
- data/public/css/bootstrap.min.css +0 -9
- data/public/img/glyphicons-halflings-white.png +0 -0
- data/public/img/glyphicons-halflings.png +0 -0
- data/public/js/angular/angular-resource.min.js +0 -10
- data/public/js/angular/angular.min.js +0 -162
- data/public/js/bootstrap/bootstrap.min.js +0 -6
- data/public/js/jquery/jquery.min.js +0 -5
- data/test/lib/angular/angular-mocks.js +0 -1768
|
@@ -11,7 +11,7 @@ Background:
|
|
|
11
11
|
| Animals |
|
|
12
12
|
And the following programmes:
|
|
13
13
|
| title | subtitle | channel | day |
|
|
14
|
-
|
|
14
|
+
| Blast from past | Prehistoric documentary | Channel 1 | -1 |
|
|
15
15
|
| Bonderøven | Danish documentary | Channel 1 | 0 |
|
|
16
16
|
| Blood and Bone | American action movie from 2009 | Channel 1 | 0 |
|
|
17
17
|
| Noddy | Children's programme | Channel 2 | 0 |
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
Feature: Channel overview
|
|
2
|
+
In order to actually use the system for anything
|
|
3
|
+
As a user
|
|
4
|
+
I need to be able to view and administer recorded shows
|
|
5
|
+
|
|
6
|
+
Background:
|
|
7
|
+
Given the following recorded shows:
|
|
8
|
+
| name |
|
|
9
|
+
| Bonderøven |
|
|
10
|
+
| Noddy |
|
|
11
|
+
| Star Trek |
|
|
12
|
+
And the following recordings:
|
|
13
|
+
| name | id |
|
|
14
|
+
| Bonderøven | 1234567 |
|
|
15
|
+
| Bonderøven | 1234567-1 |
|
|
16
|
+
| Bonderøven | 1234678 |
|
|
17
|
+
| Star Trek | 2345678 |
|
|
18
|
+
|
|
19
|
+
Scenario: Shows overview shows all recorded shows
|
|
20
|
+
Given I am on the shows page
|
|
21
|
+
Then I should see "Bonderøven"
|
|
22
|
+
And I should see "Noddy"
|
|
23
|
+
And I should see "Star Trek"
|
|
24
|
+
|
|
25
|
+
Scenario: Show details shows all recordings of show
|
|
26
|
+
Given I am on the shows page
|
|
27
|
+
# The following does not work with Poltergeist/PhantomJS - prints infinitely many
|
|
28
|
+
# AngularJS errors :-(
|
|
29
|
+
#And I see the details for show "Bonderøven"
|
|
30
|
+
#Then I should see 3 recordings
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require 'timeout'
|
|
2
|
+
require 'pry'
|
|
2
3
|
|
|
3
4
|
RSpec::Matchers.define :become do |expected|
|
|
4
5
|
match do |block|
|
|
@@ -40,6 +41,24 @@ Given /the following channels\:/ do |channel_table|
|
|
|
40
41
|
end
|
|
41
42
|
end
|
|
42
43
|
|
|
44
|
+
Given /the following recorded shows:/ do |shows_table|
|
|
45
|
+
recordings_directory = Dir.pwd + '/features/recordings'
|
|
46
|
+
FileUtils.rm_rf(recordings_directory)
|
|
47
|
+
FileUtils.makedirs(recordings_directory)
|
|
48
|
+
|
|
49
|
+
shows_table.hashes.each do |show|
|
|
50
|
+
FileUtils.makedirs(recordings_directory + '/' + show['name'])
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
Given /the following recordings:/ do |recordings_table|
|
|
55
|
+
recordings_directory = Dir.pwd + '/features/recordings'
|
|
56
|
+
|
|
57
|
+
recordings_table.hashes.each do |recording|
|
|
58
|
+
FileUtils.makedirs(recordings_directory + '/' + recording['name'] + '/' + recording['id'])
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
43
62
|
Given /I have navigated to the week overview for channel "(.*)"/ do |channel|
|
|
44
63
|
visit path_to('the channel overview page')
|
|
45
64
|
fill_in('channel_filter', :with => channel)
|
|
@@ -97,6 +116,17 @@ Then /I should see the programme title suggestion "(.*)"/ do |suggestion|
|
|
|
97
116
|
page.should have_text(text)
|
|
98
117
|
end
|
|
99
118
|
|
|
119
|
+
When /I see the details for show "(.*)"/ do |show_name|
|
|
120
|
+
div = find(:xpath, "//h2[text()='#{show_name}']").find(:xpath, '..')
|
|
121
|
+
within(div) do
|
|
122
|
+
click_on('Episodes')
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
Then /I should see (\d*) recordings/ do |number_of_recordings|
|
|
127
|
+
expect { page.all(:xpath, "//button[text()='Delete recording']").length }.to become(number_of_recordings.to_i)
|
|
128
|
+
end
|
|
129
|
+
|
|
100
130
|
Then /I should see "(.*)" in the page contents/ do |text|
|
|
101
131
|
within('#contents') do
|
|
102
132
|
page.should have_text(text)
|
|
@@ -141,6 +171,10 @@ Then /I wait (\d*) seconds/ do |seconds|
|
|
|
141
171
|
sleep seconds.to_i
|
|
142
172
|
end
|
|
143
173
|
|
|
174
|
+
Then /I start the debugger/ do
|
|
175
|
+
binding.pry
|
|
176
|
+
end
|
|
177
|
+
|
|
144
178
|
def find_or_create_channel_with_name(name)
|
|
145
179
|
channel = SimplePvr::Model::Channel.first(name: name)
|
|
146
180
|
channel ? channel : SimplePvr::Model::Channel.add(name, 0, 0)
|
data/features/support/env.rb
CHANGED
|
@@ -10,9 +10,8 @@ SimplePvr::PvrInitializer.setup_for_integration_test
|
|
|
10
10
|
SimplePvr::RecordingPlanner.reload
|
|
11
11
|
|
|
12
12
|
Capybara.app = eval "Rack::Builder.new {( " + SimplePvr::PvrInitializer.rack_maps_file + ")}"
|
|
13
|
-
Capybara.default_driver = (ENV['capybara_driver'] || '
|
|
13
|
+
Capybara.default_driver = (ENV['capybara_driver'] || 'poltergeist').to_sym # 'selenium' can be nice too
|
|
14
14
|
Capybara.default_wait_time = 30
|
|
15
|
-
Capybara.ignore_hidden_elements = true # AngularJS shows and hides elements all the time, so this is important
|
|
16
15
|
|
|
17
16
|
class SimplePvrWorld
|
|
18
17
|
include Capybara::DSL
|
data/features/support/paths.rb
CHANGED
data/lib/simple_pvr.rb
CHANGED
|
@@ -9,10 +9,12 @@ require File.dirname(__FILE__) + '/simple_pvr/recording_planner'
|
|
|
9
9
|
require File.dirname(__FILE__) + '/simple_pvr/recorder'
|
|
10
10
|
require File.dirname(__FILE__) + '/simple_pvr/scheduler'
|
|
11
11
|
require File.dirname(__FILE__) + '/simple_pvr/recording_manager'
|
|
12
|
+
require File.dirname(__FILE__) + '/simple_pvr/programme_icon_fetcher'
|
|
12
13
|
require File.dirname(__FILE__) + '/simple_pvr/ffmpeg'
|
|
13
14
|
require File.dirname(__FILE__) + '/simple_pvr/xmltv_reader'
|
|
14
15
|
|
|
15
16
|
require File.dirname(__FILE__) + '/simple_pvr/server/base_controller'
|
|
17
|
+
require File.dirname(__FILE__) + '/simple_pvr/server/secured_controller'
|
|
16
18
|
require File.dirname(__FILE__) + '/simple_pvr/server/app_controller'
|
|
17
19
|
require File.dirname(__FILE__) + '/simple_pvr/server/channels_controller'
|
|
18
20
|
require File.dirname(__FILE__) + '/simple_pvr/server/programmes_controller'
|
|
@@ -3,6 +3,10 @@ require 'dm-migrations'
|
|
|
3
3
|
require 'active_support/time_with_zone'
|
|
4
4
|
require File.dirname(__FILE__) + '/channel'
|
|
5
5
|
require File.dirname(__FILE__) + '/programme'
|
|
6
|
+
require File.dirname(__FILE__) + '/programme_category'
|
|
7
|
+
require File.dirname(__FILE__) + '/programme_director'
|
|
8
|
+
require File.dirname(__FILE__) + '/programme_presenter'
|
|
9
|
+
require File.dirname(__FILE__) + '/programme_actor'
|
|
6
10
|
require File.dirname(__FILE__) + '/schedule'
|
|
7
11
|
require File.dirname(__FILE__) + '/recording'
|
|
8
12
|
|
|
@@ -19,6 +23,10 @@ module SimplePvr
|
|
|
19
23
|
|
|
20
24
|
def self.clear
|
|
21
25
|
Schedule.destroy
|
|
26
|
+
ProgrammeCategory.destroy
|
|
27
|
+
ProgrammePresenter.destroy
|
|
28
|
+
ProgrammeDirector.destroy
|
|
29
|
+
ProgrammeActor.destroy
|
|
22
30
|
Programme.destroy
|
|
23
31
|
Channel.destroy
|
|
24
32
|
end
|
|
@@ -11,8 +11,13 @@ module SimplePvr
|
|
|
11
11
|
property :start_time, DateTime
|
|
12
12
|
property :duration, Integer
|
|
13
13
|
property :episode_num, String, index: true
|
|
14
|
+
property :icon_url, String, :length => 255
|
|
14
15
|
|
|
15
16
|
belongs_to :channel
|
|
17
|
+
has n, :categories, 'ProgrammeCategory'
|
|
18
|
+
has n, :directors, 'ProgrammeDirector'
|
|
19
|
+
has n, :presenters, 'ProgrammePresenter'
|
|
20
|
+
has n, :actors, 'ProgrammeActor'
|
|
16
21
|
|
|
17
22
|
def end_time
|
|
18
23
|
@start_time.advance(seconds: duration)
|
|
@@ -23,10 +28,14 @@ module SimplePvr
|
|
|
23
28
|
end
|
|
24
29
|
|
|
25
30
|
def self.clear
|
|
31
|
+
ProgrammeCategory.destroy
|
|
32
|
+
ProgrammeDirector.destroy
|
|
33
|
+
ProgrammePresenter.destroy
|
|
34
|
+
ProgrammeActor.destroy
|
|
26
35
|
Programme.destroy
|
|
27
36
|
end
|
|
28
37
|
|
|
29
|
-
def self.add(channel, title, subtitle, description, start_time, duration, episode_num)
|
|
38
|
+
def self.add(channel, title, subtitle, description, start_time, duration, episode_num, icon_url=nil)
|
|
30
39
|
channel.programmes.create(
|
|
31
40
|
channel: channel,
|
|
32
41
|
title: title,
|
|
@@ -34,7 +43,8 @@ module SimplePvr
|
|
|
34
43
|
description: description,
|
|
35
44
|
start_time: start_time,
|
|
36
45
|
duration: duration.to_i,
|
|
37
|
-
episode_num: episode_num
|
|
46
|
+
episode_num: episode_num,
|
|
47
|
+
icon_url: icon_url)
|
|
38
48
|
end
|
|
39
49
|
|
|
40
50
|
def self.with_title(title)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module SimplePvr
|
|
2
|
+
module Model
|
|
3
|
+
class ProgrammeActor
|
|
4
|
+
include DataMapper::Resource
|
|
5
|
+
storage_names[:default] = 'programme_actors'
|
|
6
|
+
|
|
7
|
+
property :id, Serial
|
|
8
|
+
property :role_name, String, :length => 255
|
|
9
|
+
property :actor_name, String, :length => 255
|
|
10
|
+
|
|
11
|
+
belongs_to :programme
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module SimplePvr
|
|
2
|
+
module Model
|
|
3
|
+
class ProgrammeCategory
|
|
4
|
+
include DataMapper::Resource
|
|
5
|
+
storage_names[:default] = 'programme_categories'
|
|
6
|
+
|
|
7
|
+
property :id, Serial
|
|
8
|
+
property :language, String, :length => 4
|
|
9
|
+
property :name, String, :length => 255
|
|
10
|
+
|
|
11
|
+
belongs_to :programme
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -26,6 +26,18 @@ module SimplePvr
|
|
|
26
26
|
def inspect
|
|
27
27
|
"'#{@show_name}' from '#{@channel.name}' at '#{@start_time}' with duration #{@duration} and programme #{@programme}"
|
|
28
28
|
end
|
|
29
|
+
|
|
30
|
+
def similar_to(other)
|
|
31
|
+
other != nil &&
|
|
32
|
+
other.channel == @channel &&
|
|
33
|
+
other.show_name == @show_name &&
|
|
34
|
+
other.start_time == @start_time
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def update_with(other)
|
|
38
|
+
@duration = other.duration
|
|
39
|
+
@programme = other.programme
|
|
40
|
+
end
|
|
29
41
|
|
|
30
42
|
def ==(other)
|
|
31
43
|
other != nil &&
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'open-uri'
|
|
2
|
+
|
|
3
|
+
module SimplePvr
|
|
4
|
+
class ProgrammeIconFetcher
|
|
5
|
+
def self.fetch(url, destination_file)
|
|
6
|
+
Thread.new do
|
|
7
|
+
File.open(destination_file, "wb") do |saved_file|
|
|
8
|
+
open(url, 'rb') do |read_file|
|
|
9
|
+
saved_file.write(read_file.read)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -2,13 +2,13 @@ module SimplePvr
|
|
|
2
2
|
class PvrInitializer
|
|
3
3
|
def self.setup
|
|
4
4
|
Model::DatabaseInitializer.setup
|
|
5
|
-
|
|
5
|
+
setup_with_hdhomerun_and_recording_directory(HDHomeRun.new, Dir.pwd + '/recordings')
|
|
6
6
|
@hdhomerun.scan_for_channels if Model::Channel.all.empty?
|
|
7
7
|
end
|
|
8
8
|
|
|
9
9
|
def self.setup_for_integration_test
|
|
10
10
|
Model::DatabaseInitializer.prepare_for_test
|
|
11
|
-
|
|
11
|
+
setup_with_hdhomerun_and_recording_directory(HDHomeRunFake.new, Dir.pwd + '/features/recordings')
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def self.hdhomerun
|
|
@@ -37,9 +37,9 @@ module SimplePvr
|
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
private
|
|
40
|
-
def self.
|
|
40
|
+
def self.setup_with_hdhomerun_and_recording_directory(hdhomerun, recording_directory)
|
|
41
41
|
@hdhomerun = hdhomerun
|
|
42
|
-
@recording_manager = RecordingManager.new
|
|
42
|
+
@recording_manager = RecordingManager.new(recording_directory)
|
|
43
43
|
@scheduler = Scheduler.new
|
|
44
44
|
@scheduler.start
|
|
45
45
|
end
|
data/lib/simple_pvr/recorder.rb
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
require 'fileutils'
|
|
2
|
-
require File.dirname(__FILE__) + '/hdhomerun'
|
|
3
|
-
require File.dirname(__FILE__) + '/pvr_logger'
|
|
4
2
|
|
|
5
3
|
module SimplePvr
|
|
6
4
|
class Recorder
|
|
@@ -11,7 +9,10 @@ module SimplePvr
|
|
|
11
9
|
def start!
|
|
12
10
|
@directory = PvrInitializer.recording_manager.create_directory_for_recording(@recording)
|
|
13
11
|
PvrInitializer.hdhomerun.start_recording(@tuner, @recording.channel.frequency, @recording.channel.channel_id, @directory)
|
|
14
|
-
|
|
12
|
+
|
|
13
|
+
icon_url = @recording.programme.icon_url
|
|
14
|
+
ProgrammeIconFetcher.fetch(icon_url, "#{@directory}/icon") if icon_url
|
|
15
|
+
|
|
15
16
|
PvrLogger.info "Started recording #{@recording.show_name} in #{@directory}"
|
|
16
17
|
end
|
|
17
18
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
module SimplePvr
|
|
2
|
-
RecordingMetadata = Struct.new(:has_thumbnail, :has_webm, :show_name, :
|
|
2
|
+
RecordingMetadata = Struct.new(:id, :has_icon, :has_thumbnail, :has_webm, :show_name, :channel, :subtitle, :description, :categories, :directors, :presenters, :actors, :start_time, :duration)
|
|
3
3
|
|
|
4
4
|
class RecordingManager
|
|
5
|
-
def initialize(recordings_directory
|
|
6
|
-
@recordings_directory = recordings_directory
|
|
5
|
+
def initialize(recordings_directory)
|
|
6
|
+
@recordings_directory = recordings_directory
|
|
7
7
|
end
|
|
8
8
|
|
|
9
9
|
def shows
|
|
@@ -14,45 +14,53 @@ module SimplePvr
|
|
|
14
14
|
FileUtils.rm_rf(directory_for_show(show_name))
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
-
def
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
metadata_for(show_name,
|
|
17
|
+
def recordings_of(show_name)
|
|
18
|
+
recordings = Dir.new(directory_for_show(show_name)).entries - ['.', '..']
|
|
19
|
+
recordings.sort.map do |recording_id|
|
|
20
|
+
metadata_for(show_name, recording_id)
|
|
21
21
|
end
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
-
def metadata_for(show_name,
|
|
25
|
-
metadata_file_name =
|
|
24
|
+
def metadata_for(show_name, recording_id)
|
|
25
|
+
metadata_file_name = directory_for_show_and_recording(show_name, recording_id) + '/metadata.yml'
|
|
26
26
|
metadata = File.exists?(metadata_file_name) ? YAML.load_file(metadata_file_name) : {}
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
icon_file_name = directory_for_show_and_recording(show_name, recording_id) + '/icon'
|
|
29
|
+
has_icon = File.exists?(icon_file_name)
|
|
30
|
+
|
|
31
|
+
thumbnail_file_name = directory_for_show_and_recording(show_name, recording_id) + '/thumbnail.png'
|
|
29
32
|
has_thumbnail = File.exists?(thumbnail_file_name)
|
|
30
33
|
|
|
31
|
-
webm_file_name =
|
|
34
|
+
webm_file_name = directory_for_show_and_recording(show_name, recording_id) + '/stream.webm'
|
|
32
35
|
has_webm = File.exists?(webm_file_name)
|
|
33
36
|
|
|
34
37
|
RecordingMetadata.new(
|
|
38
|
+
recording_id,
|
|
39
|
+
has_icon,
|
|
35
40
|
has_thumbnail,
|
|
36
41
|
has_webm,
|
|
37
42
|
show_name,
|
|
38
|
-
episode,
|
|
39
43
|
metadata[:channel],
|
|
40
44
|
metadata[:subtitle],
|
|
41
45
|
metadata[:description],
|
|
46
|
+
metadata[:categories] || [],
|
|
47
|
+
metadata[:directors] || [],
|
|
48
|
+
metadata[:presenters] || [],
|
|
49
|
+
metadata[:actors] || [],
|
|
42
50
|
metadata[:start_time],
|
|
43
51
|
metadata[:duration])
|
|
44
52
|
end
|
|
45
53
|
|
|
46
|
-
def
|
|
47
|
-
FileUtils.rm_rf(@recordings_directory + '/' + show_name + '/' +
|
|
54
|
+
def delete_show_recording(show_name, recording_id)
|
|
55
|
+
FileUtils.rm_rf(@recordings_directory + '/' + show_name + '/' + recording_id)
|
|
48
56
|
end
|
|
49
57
|
|
|
50
58
|
def create_directory_for_recording(recording)
|
|
51
59
|
show_directory = directory_for_show(recording.show_name)
|
|
52
60
|
ensure_directory_exists(show_directory)
|
|
53
61
|
|
|
54
|
-
|
|
55
|
-
recording_directory = "#{show_directory}/#{
|
|
62
|
+
recording_subdirectory = subdirectory_for_recording(recording, show_directory)
|
|
63
|
+
recording_directory = "#{show_directory}/#{recording_subdirectory}"
|
|
56
64
|
ensure_directory_exists(recording_directory)
|
|
57
65
|
|
|
58
66
|
create_metadata(recording_directory, recording)
|
|
@@ -60,8 +68,8 @@ module SimplePvr
|
|
|
60
68
|
recording_directory
|
|
61
69
|
end
|
|
62
70
|
|
|
63
|
-
def
|
|
64
|
-
directory_for_show(show_name) + '/' +
|
|
71
|
+
def directory_for_show_and_recording(show_name, recording_id)
|
|
72
|
+
directory_for_show(show_name) + '/' + recording_id
|
|
65
73
|
end
|
|
66
74
|
|
|
67
75
|
private
|
|
@@ -75,9 +83,16 @@ module SimplePvr
|
|
|
75
83
|
FileUtils.makedirs(directory) unless File.exists?(directory)
|
|
76
84
|
end
|
|
77
85
|
|
|
78
|
-
def
|
|
79
|
-
|
|
80
|
-
|
|
86
|
+
def subdirectory_for_recording(recording, base_directory)
|
|
87
|
+
start_time_millis = recording.start_time.to_i
|
|
88
|
+
path = "#{base_directory}/#{start_time_millis}"
|
|
89
|
+
return "#{start_time_millis}" unless File.exists?(path)
|
|
90
|
+
|
|
91
|
+
sequence_number = 1
|
|
92
|
+
while File.exists?("#{path}-#{sequence_number}")
|
|
93
|
+
sequence_number += 1
|
|
94
|
+
end
|
|
95
|
+
"#{start_time_millis}-#{sequence_number}"
|
|
81
96
|
end
|
|
82
97
|
|
|
83
98
|
def create_metadata(directory, recording)
|
|
@@ -88,10 +103,15 @@ module SimplePvr
|
|
|
88
103
|
duration: recording.duration
|
|
89
104
|
}
|
|
90
105
|
|
|
91
|
-
|
|
106
|
+
programme = recording.programme
|
|
107
|
+
if programme
|
|
92
108
|
metadata.merge!({
|
|
93
|
-
subtitle:
|
|
94
|
-
description:
|
|
109
|
+
subtitle: programme.subtitle,
|
|
110
|
+
description: programme.description,
|
|
111
|
+
categories: programme.categories.map { |category| category.name },
|
|
112
|
+
directors: programme.directors.map { |director| director.name },
|
|
113
|
+
presenters: programme.presenters.map { |presenter| presenter.name },
|
|
114
|
+
actors: programme.actors.map { |actor| { role_name: actor.role_name, actor_name: actor.actor_name } }
|
|
95
115
|
})
|
|
96
116
|
end
|
|
97
117
|
|