network_executive 0.0.4 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +53 -24
- data/app/assets/fonts/network_executive/league_gothic.css +13 -0
- data/app/assets/fonts/network_executive/league_gothic.svg +148 -0
- data/app/assets/fonts/network_executive/league_gothic.ttf +0 -0
- data/app/assets/fonts/network_executive/league_gothic.woff +0 -0
- data/app/assets/javascripts/network_executive/components/iframe_notifier.coffee +14 -0
- data/app/assets/javascripts/network_executive/components/namespace.coffee +1 -0
- data/app/assets/javascripts/network_executive/components/osd.coffee +65 -0
- data/app/assets/javascripts/network_executive/components/photo_player.coffee +55 -0
- data/app/assets/javascripts/network_executive/components/postman.coffee +23 -0
- data/app/assets/javascripts/network_executive/components/set_top_box.coffee +81 -0
- data/app/assets/javascripts/network_executive/components/tweet_player.coffee +95 -0
- data/app/assets/javascripts/network_executive/components/you_tube_player.coffee +85 -0
- data/app/assets/javascripts/network_executive/slideshow.coffee +6 -0
- data/app/assets/javascripts/network_executive/twitter.coffee +7 -0
- data/app/assets/javascripts/network_executive/you_tube.coffee +8 -0
- data/app/assets/javascripts/network_executive.coffee +10 -0
- data/app/assets/stylesheets/network_executive/{gui_components.css → components/gui_components.css} +0 -0
- data/app/assets/stylesheets/network_executive/{normalize.css → components/normalize.css} +0 -0
- data/app/assets/stylesheets/network_executive/{osd.css → components/osd.css} +6 -34
- data/app/assets/stylesheets/network_executive/components/osd_guide.css +43 -0
- data/app/assets/stylesheets/network_executive/components/photo_player.css +61 -0
- data/app/assets/stylesheets/network_executive/{smpte.css → components/smpte.css} +0 -0
- data/app/assets/stylesheets/network_executive/components/tweet_player.css +60 -0
- data/app/assets/stylesheets/network_executive/components/you_tube_player.css +12 -0
- data/app/assets/stylesheets/network_executive/off_air.css +5 -0
- data/app/assets/stylesheets/network_executive/slideshow.css +4 -0
- data/app/assets/stylesheets/network_executive/twitter.css +5 -0
- data/app/assets/stylesheets/network_executive/you_tube.css +3 -0
- data/app/assets/stylesheets/{network_executive/application.css → network_executive.css} +5 -5
- data/app/controllers/network_executive/components_controller.rb +4 -0
- data/app/controllers/network_executive/guide_controller.rb +41 -0
- data/app/controllers/network_executive/programs_controller.rb +9 -0
- data/app/helpers/network_executive/network_helper.rb +6 -0
- data/app/models/network_executive/channel.rb +15 -14
- data/app/models/network_executive/guide.rb +65 -0
- data/app/models/network_executive/program.rb +69 -5
- data/app/models/network_executive/viewer.rb +4 -0
- data/app/programs/network_executive/off_air.rb +18 -0
- data/app/views/network_executive/components/slideshow.html.erb +20 -0
- data/app/views/network_executive/components/twitter.html.erb +16 -0
- data/app/views/network_executive/components/you_tube.html.erb +13 -0
- data/app/views/network_executive/guide/index.html.erb +30 -0
- data/app/views/network_executive/network/index.html.erb +3 -3
- data/app/views/network_executive/programs/off_air.html.erb +13 -0
- data/config/routes.rb +7 -1
- data/lib/network_executive/channel_schedule.rb +65 -0
- data/lib/network_executive/components/photo_player.rb +48 -0
- data/lib/network_executive/components/tweet_player.rb +48 -0
- data/lib/network_executive/components/you_tube_player.rb +15 -0
- data/lib/network_executive/components.rb +3 -0
- data/lib/network_executive/engine.rb +29 -3
- data/lib/network_executive/off_air_schedule.rb +18 -0
- data/lib/network_executive/producer.rb +3 -3
- data/lib/network_executive/program_schedule.rb +96 -0
- data/lib/network_executive/program_schedule_proxy.rb +55 -0
- data/lib/network_executive/scheduled_program.rb +26 -0
- data/lib/network_executive/scheduling.rb +15 -21
- data/lib/network_executive/time_calculations.rb +10 -0
- data/lib/network_executive/version.rb +1 -1
- data/lib/network_executive.rb +2 -1
- data/network_executive.gemspec +5 -0
- data/spec/models/channel_spec.rb +30 -12
- data/spec/models/{lineup_spec.rb → guide_spec.rb} +28 -6
- data/spec/models/program_spec.rb +46 -3
- data/spec/models/viewer_spec.rb +9 -1
- data/spec/programs/off_air_spec.rb +9 -0
- data/spec/spec_helper.rb +3 -2
- data/spec/unit/channel_schedule_spec.rb +67 -0
- data/spec/unit/components/photo_player_spec.rb +76 -0
- data/spec/unit/components/tweet_player_spec.rb +68 -0
- data/spec/unit/components/you_tube_player_spec.rb +17 -0
- data/spec/unit/off_air_schedule_spec.rb +28 -0
- data/spec/unit/producer_spec.rb +2 -4
- data/spec/unit/program_schedule_proxy_spec.rb +102 -0
- data/spec/unit/program_schedule_spec.rb +191 -0
- data/spec/unit/scheduled_program_spec.rb +57 -0
- data/spec/unit/scheduling_spec.rb +61 -72
- data/vendor/assets/javascripts/bigtext.js +264 -0
- metadata +185 -44
- data/app/assets/javascripts/application.js +0 -13
- data/app/assets/javascripts/network_executive/osd.js +0 -62
- data/app/assets/javascripts/network_executive/set_top_box.js +0 -45
- data/app/controllers/network_executive/lineup_controller.rb +0 -11
- data/app/models/network_executive/channel_schedule.rb +0 -13
- data/app/models/network_executive/lineup.rb +0 -74
- data/app/models/network_executive/lineup_range.rb +0 -34
- data/app/models/network_executive/program_schedule.rb +0 -148
- data/app/views/network_executive/lineup/index.html.erb +0 -26
- data/spec/models/channel_schedule_spec.rb +0 -29
- data/spec/models/lineup_range_spec.rb +0 -65
- data/spec/models/program_schedule_spec.rb +0 -399
@@ -0,0 +1,18 @@
|
|
1
|
+
# Acts as a NullObject when there is nothing scheduled for a given channel
|
2
|
+
module NetworkExecutive
|
3
|
+
class OffAir < NetworkExecutive::Program
|
4
|
+
|
5
|
+
def display_name
|
6
|
+
'Off Air'
|
7
|
+
end
|
8
|
+
|
9
|
+
def url
|
10
|
+
NetworkExecutive::Engine.routes.url_helpers.program_path 'off_air'
|
11
|
+
end
|
12
|
+
|
13
|
+
def duration
|
14
|
+
Guide::Interval.minutes
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<%= stylesheet_link_tag 'network_executive/slideshow' %>
|
5
|
+
<link href='//fonts.googleapis.com/css?family=Lato:400,700' rel='stylesheet' type='text/css'>
|
6
|
+
</head>
|
7
|
+
<body>
|
8
|
+
<figure id="photo_player" class="photo-player">
|
9
|
+
<img id="current_photo" class="current-photo">
|
10
|
+
<figcaption id="caption" class="caption">
|
11
|
+
<div id="title" class="title"></div>
|
12
|
+
<div id="description" class="desc"></div>
|
13
|
+
<div id="photographer" class="photog"></div>
|
14
|
+
<div id="location" class="location"></div>
|
15
|
+
</figcaption>
|
16
|
+
</figure>
|
17
|
+
|
18
|
+
<%= javascript_include_tag 'network_executive/slideshow' %>
|
19
|
+
</body>
|
20
|
+
</html>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<%= stylesheet_link_tag 'network_executive/twitter' %>
|
5
|
+
</head>
|
6
|
+
<body>
|
7
|
+
<img id="background" class="background">
|
8
|
+
<div id="tweet" class="tweet">
|
9
|
+
<div class="tweet-text"></div>
|
10
|
+
<div id="author" class="author"></div>
|
11
|
+
</div>
|
12
|
+
|
13
|
+
<script src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
|
14
|
+
<%= javascript_include_tag 'network_executive/twitter' %>
|
15
|
+
</body>
|
16
|
+
</html>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<%= stylesheet_link_tag 'network_executive/you_tube' %>
|
5
|
+
<%= javascript_include_tag 'network_executive/you_tube' %>
|
6
|
+
<%= javascript_include_tag '//www.youtube.com/iframe_api' %>
|
7
|
+
<script>
|
8
|
+
</script>
|
9
|
+
</head>
|
10
|
+
<body>
|
11
|
+
<div id="player"></div>
|
12
|
+
</body>
|
13
|
+
</html>
|
@@ -0,0 +1,30 @@
|
|
1
|
+
<table>
|
2
|
+
<thead>
|
3
|
+
<tr>
|
4
|
+
<td style="width: <%= guide_header_width %>%;"> </td>
|
5
|
+
<% @guide.times.each do |t| %>
|
6
|
+
<th class="guide-time" style="width: <%= guide_header_width %>%;">
|
7
|
+
<%= t.strftime '%l:%M' %>
|
8
|
+
</th>
|
9
|
+
<% end %>
|
10
|
+
</tr>
|
11
|
+
</thead>
|
12
|
+
<tbody>
|
13
|
+
<% @guide[:channels].each do |ch| %>
|
14
|
+
<tr>
|
15
|
+
<th class="guide-channel">
|
16
|
+
<%= link_to ch[:channel].display_name, channel_path( ch[:channel] ) %>
|
17
|
+
</th>
|
18
|
+
<td colspan="<%= @guide.times.size %>">
|
19
|
+
<% ch[:programs].each do |program| %>
|
20
|
+
<div class="guide-program-ct" style="width: <%= '%.3f' % program.portion %>%;">
|
21
|
+
<span class="guide-program">
|
22
|
+
<%= program.display_name %>
|
23
|
+
</span>
|
24
|
+
</div>
|
25
|
+
<% end %>
|
26
|
+
</td>
|
27
|
+
</tr>
|
28
|
+
<% end %>
|
29
|
+
</tbody>
|
30
|
+
</table>
|
@@ -5,7 +5,7 @@
|
|
5
5
|
<meta name="viewport" content="width=device-width">
|
6
6
|
<title>Network Executive: <%= network_name %></title>
|
7
7
|
<link href='//fonts.googleapis.com/css?family=Lekton:400,700|Quicksand:300,400,700' rel='stylesheet' type='text/css'>
|
8
|
-
<%= stylesheet_link_tag 'network_executive
|
8
|
+
<%= stylesheet_link_tag 'network_executive', media:'all' %>
|
9
9
|
<base href="<%= network_executive.root_url %>"/>
|
10
10
|
</head>
|
11
11
|
<body>
|
@@ -28,9 +28,9 @@
|
|
28
28
|
</aside>
|
29
29
|
</h1>
|
30
30
|
</header>
|
31
|
-
<article id="
|
31
|
+
<article id="guide" class="guide"></article>
|
32
32
|
</div>
|
33
33
|
|
34
|
-
<%= javascript_include_tag '
|
34
|
+
<%= javascript_include_tag 'network_executive' %>
|
35
35
|
</body>
|
36
36
|
</html>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<%= stylesheet_link_tag 'network_executive/off_air', media:'all' %>
|
5
|
+
<link href='//fonts.googleapis.com/css?family=Lekton:400,700|Quicksand:300,400,700' rel='stylesheet' type='text/css'>
|
6
|
+
</head>
|
7
|
+
<body>
|
8
|
+
<div id="smpte">
|
9
|
+
<h1 id="smpte_message" class="msg">Off Air</h1>
|
10
|
+
<aside class="network-name"><%= network_name %></aside>
|
11
|
+
</div>
|
12
|
+
</body>
|
13
|
+
</html>
|
data/config/routes.rb
CHANGED
@@ -3,7 +3,13 @@ NetworkExecutive::Engine.routes.draw do
|
|
3
3
|
|
4
4
|
match 'channels/:channel_name' => 'network#index', as: :channel
|
5
5
|
|
6
|
-
match '
|
6
|
+
match 'you_tube' => 'components#you_tube', as: :you_tube
|
7
|
+
match 'twitter' => 'components#twitter', as: :twitter
|
8
|
+
match 'slideshow' => 'components#slideshow', as: :slideshow
|
9
|
+
|
10
|
+
match 'guide' => 'guide#index', as: :guide
|
11
|
+
|
12
|
+
match 'programs/:program_name' => 'programs#show', as: :program
|
7
13
|
|
8
14
|
root to:'network#index'
|
9
15
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'network_executive/program_schedule'
|
2
|
+
require 'network_executive/off_air_schedule'
|
3
|
+
require 'network_executive/scheduled_program'
|
4
|
+
|
5
|
+
module NetworkExecutive
|
6
|
+
class ChannelSchedule < Array
|
7
|
+
|
8
|
+
def add( program, options = {}, &block )
|
9
|
+
unshift ProgramSchedule.new( program, options, &block )
|
10
|
+
end
|
11
|
+
|
12
|
+
def whats_on_between?( start, stop, interval )
|
13
|
+
cursor = start.dup
|
14
|
+
programs = []
|
15
|
+
|
16
|
+
until cursor > stop do
|
17
|
+
program = find_program_occurring_at( cursor )
|
18
|
+
|
19
|
+
occurrence = program.occurrence_at cursor
|
20
|
+
|
21
|
+
if repeated_off_air?( programs, program )
|
22
|
+
program, occurrence, remainder = extend_off_air( programs, program, stop )
|
23
|
+
else
|
24
|
+
remainder = time_left( cursor, occurrence.end_time, stop )
|
25
|
+
end
|
26
|
+
|
27
|
+
portion = remainder / (stop - start) * 100
|
28
|
+
step = occurrence.end_time - cursor
|
29
|
+
|
30
|
+
programs << ScheduledProgram.new( program, occurrence, remainder, portion )
|
31
|
+
|
32
|
+
cursor += step + 1
|
33
|
+
end
|
34
|
+
|
35
|
+
programs
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def find_program_occurring_at( time )
|
41
|
+
find { |p| p.occurring_at? time } || OffAirSchedule.new( start_time:time )
|
42
|
+
end
|
43
|
+
|
44
|
+
def time_left( time, end_time, max = end_time )
|
45
|
+
[ max, end_time ].min - time
|
46
|
+
end
|
47
|
+
|
48
|
+
def repeated_off_air?( programs, program )
|
49
|
+
return unless last = programs.last
|
50
|
+
|
51
|
+
last.program.is_a?( OffAirSchedule ) && program.is_a?( OffAirSchedule )
|
52
|
+
end
|
53
|
+
|
54
|
+
# Extends the previous Off Air schedule
|
55
|
+
def extend_off_air( programs, program, stop )
|
56
|
+
prev = programs.pop + program
|
57
|
+
program = prev.program
|
58
|
+
occurrence = prev.occurrence
|
59
|
+
remainder = time_left( occurrence.start_time, occurrence.end_time, stop )
|
60
|
+
|
61
|
+
[ program, occurrence, remainder ]
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
module NetworkExecutive
|
4
|
+
module Components
|
5
|
+
module PhotoPlayer
|
6
|
+
|
7
|
+
def url
|
8
|
+
NetworkExecutive::Engine.routes.url_helpers.slideshow_path
|
9
|
+
end
|
10
|
+
|
11
|
+
def refresh
|
12
|
+
false
|
13
|
+
end
|
14
|
+
|
15
|
+
def onload
|
16
|
+
{
|
17
|
+
photos: photos
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
def feed_url
|
22
|
+
raise NotImplementedError
|
23
|
+
end
|
24
|
+
|
25
|
+
def photos
|
26
|
+
[]
|
27
|
+
end
|
28
|
+
|
29
|
+
def feed
|
30
|
+
_url = URI.parse( feed_url )
|
31
|
+
http = Net::HTTP.new( _url.host, _url.port )
|
32
|
+
|
33
|
+
if _url.scheme == 'https'
|
34
|
+
http.use_ssl = true
|
35
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
36
|
+
end
|
37
|
+
|
38
|
+
request = Net::HTTP::Get.new( _url.request_uri )
|
39
|
+
response = http.request( request )
|
40
|
+
|
41
|
+
JSON.parse response.body
|
42
|
+
rescue StandardError
|
43
|
+
{}
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
|
3
|
+
require 'twitter'
|
4
|
+
|
5
|
+
# TODO: Refactor this into a plugin. Might want to include a generator that
|
6
|
+
# creates an initializer.
|
7
|
+
module NetworkExecutive
|
8
|
+
module Components
|
9
|
+
module TweetPlayer
|
10
|
+
extend ActiveSupport::Concern
|
11
|
+
|
12
|
+
def url
|
13
|
+
NetworkExecutive::Engine.routes.url_helpers.twitter_path
|
14
|
+
end
|
15
|
+
|
16
|
+
def refresh
|
17
|
+
false
|
18
|
+
end
|
19
|
+
|
20
|
+
def onload
|
21
|
+
{
|
22
|
+
tweets: self.class.tweets[:statuses]
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
module ClassMethods
|
27
|
+
attr_accessor :client, :query
|
28
|
+
|
29
|
+
def client
|
30
|
+
@client ||= Twitter::Client.new
|
31
|
+
end
|
32
|
+
|
33
|
+
def configure
|
34
|
+
yield client
|
35
|
+
end
|
36
|
+
|
37
|
+
def search( *args )
|
38
|
+
@query = args
|
39
|
+
end
|
40
|
+
|
41
|
+
def tweets
|
42
|
+
client.search( *query )
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -1,5 +1,8 @@
|
|
1
1
|
# TODO: Only load when needed (enables asset pipeline)
|
2
2
|
require 'sass-rails'
|
3
|
+
require 'ice_cube'
|
4
|
+
|
5
|
+
require 'network_executive/time_calculations'
|
3
6
|
|
4
7
|
module NetworkExecutive
|
5
8
|
|
@@ -8,18 +11,41 @@ module NetworkExecutive
|
|
8
11
|
|
9
12
|
isolate_namespace NetworkExecutive
|
10
13
|
|
14
|
+
initializer 'network_executive.extend_time' do |app|
|
15
|
+
Time.send :include, TimeCalculations
|
16
|
+
end
|
17
|
+
|
18
|
+
initializer 'network_executive.eager_load_default_programs' do |app|
|
19
|
+
eager_load_models_in 'programs', self
|
20
|
+
end
|
21
|
+
|
22
|
+
initializer 'network_executive.eager_load_user_programs' do |app|
|
23
|
+
eager_load_models_in 'programs', app
|
24
|
+
end
|
25
|
+
|
11
26
|
initializer 'network_executive.eager_load_channels' do |app|
|
12
27
|
eager_load_models_in 'channels', app
|
13
28
|
end
|
14
29
|
|
15
|
-
initializer
|
16
|
-
|
30
|
+
initializer :assets do |app|
|
31
|
+
app.config.assets.paths << File.join( root, 'app', 'assets', 'fonts' )
|
32
|
+
|
33
|
+
app.config.assets.precompile += [
|
34
|
+
'network_executive.js',
|
35
|
+
'network_executive/you_tube.js',
|
36
|
+
'network_executive/twitter.js',
|
37
|
+
|
38
|
+
'network_executive.css',
|
39
|
+
'network_executive/off_air.css',
|
40
|
+
'network_executive/you_tube.css',
|
41
|
+
'network_executive/twitter.css',
|
42
|
+
]
|
17
43
|
end
|
18
44
|
|
19
45
|
private
|
20
46
|
|
21
47
|
def eager_load_models_in( sub_path, app )
|
22
|
-
Dir[ File.join(app.root, 'app', sub_path, '
|
48
|
+
Dir[ File.join(app.root, 'app', sub_path, '**', '*.rb') ].each do |c|
|
23
49
|
require c
|
24
50
|
end
|
25
51
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# Acts as a NullObject for ProgramSchedule
|
2
|
+
module NetworkExecutive
|
3
|
+
class OffAirSchedule < ProgramSchedule
|
4
|
+
|
5
|
+
def initialize( options = {} )
|
6
|
+
options[:duration] ||= 59.seconds
|
7
|
+
|
8
|
+
super 'off_air', options
|
9
|
+
end
|
10
|
+
|
11
|
+
def occurrence_at( time )
|
12
|
+
end_time = time + duration
|
13
|
+
|
14
|
+
ProgramSchedule::Occurrence.new time, duration, end_time
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -24,10 +24,10 @@ module NetworkExecutive
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def run_scheduled_programming
|
27
|
+
Rails.logger.info "\n\n"
|
28
|
+
|
27
29
|
Network.channels.each do |channel|
|
28
|
-
|
29
|
-
channel.show scheduled_program
|
30
|
-
end
|
30
|
+
channel.play channel.whats_on?
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'network_executive/program_schedule_proxy'
|
2
|
+
|
3
|
+
module NetworkExecutive
|
4
|
+
class ProgramSchedule
|
5
|
+
attr_accessor :program, :start_time, :duration, :proxy
|
6
|
+
|
7
|
+
Occurrence = Struct.new('Occurrence', :start_time, :duration, :end_time)
|
8
|
+
|
9
|
+
def initialize( program, options = {}, &block )
|
10
|
+
options.symbolize_keys!
|
11
|
+
|
12
|
+
options[:duration] ||= 24.hours
|
13
|
+
|
14
|
+
@start_time, @duration = options[:start_time], options[:duration]
|
15
|
+
|
16
|
+
@program = Program.find_by_name program
|
17
|
+
|
18
|
+
raise ProgramNameError, %Q{"#{program}" is not a registered Program} unless @program
|
19
|
+
|
20
|
+
@block = block
|
21
|
+
end
|
22
|
+
|
23
|
+
def proxy
|
24
|
+
@proxy ||= ProgramScheduleProxy.new( start_time, duration, &@block )
|
25
|
+
end
|
26
|
+
|
27
|
+
def start_time=( time )
|
28
|
+
@start_time = time
|
29
|
+
|
30
|
+
reset_proxy!
|
31
|
+
|
32
|
+
time
|
33
|
+
end
|
34
|
+
|
35
|
+
def duration=( d )
|
36
|
+
@duration = d
|
37
|
+
|
38
|
+
reset_proxy!
|
39
|
+
|
40
|
+
d
|
41
|
+
end
|
42
|
+
|
43
|
+
def whats_on?( time = Time.now )
|
44
|
+
proxy.occurring_at? time
|
45
|
+
end
|
46
|
+
|
47
|
+
def occurs_at?( time )
|
48
|
+
proxy.occurs_at? time
|
49
|
+
end
|
50
|
+
|
51
|
+
def play( &block )
|
52
|
+
program.play( &block )
|
53
|
+
end
|
54
|
+
|
55
|
+
def update( &block )
|
56
|
+
program.update( &block )
|
57
|
+
end
|
58
|
+
|
59
|
+
# Returns the scheduled occurrence that matches the specified time
|
60
|
+
def occurrence_at( time )
|
61
|
+
real_duration = duration - 1
|
62
|
+
|
63
|
+
range = [ time - real_duration, time ]
|
64
|
+
|
65
|
+
start_time = proxy.occurrences_between( range[0], range[1] ).first
|
66
|
+
end_time = start_time + real_duration
|
67
|
+
|
68
|
+
Occurrence.new start_time, real_duration, end_time
|
69
|
+
end
|
70
|
+
|
71
|
+
def respond_to_missing?( method_id, include_private = false )
|
72
|
+
proxy.respond_to?( method_id ) \
|
73
|
+
|| program.respond_to?( method_id ) \
|
74
|
+
|| super
|
75
|
+
end
|
76
|
+
|
77
|
+
def method_missing( method_id, *args )
|
78
|
+
if program.respond_to?( method_id )
|
79
|
+
program.send method_id, *args
|
80
|
+
elsif proxy.respond_to?( method_id )
|
81
|
+
proxy.send method_id, *args
|
82
|
+
else
|
83
|
+
super
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
def reset_proxy!
|
90
|
+
@proxy = nil
|
91
|
+
|
92
|
+
self.proxy
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'ice_cube'
|
2
|
+
|
3
|
+
# A proxy object to IceCube::Schedule
|
4
|
+
#
|
5
|
+
# Mainly, this allows some method missing magic during block evaluation
|
6
|
+
# that simplifies the `schedule` DSL by adding new recurrence rules for
|
7
|
+
# each Rule method that is called from within the block.
|
8
|
+
module NetworkExecutive
|
9
|
+
class ProgramScheduleProxy
|
10
|
+
|
11
|
+
attr_accessor :start_time, :duration
|
12
|
+
|
13
|
+
def initialize( start_time = nil, duration = nil, &block )
|
14
|
+
start_time ||= Time.now.beginning_of_day
|
15
|
+
duration ||= 24.hours
|
16
|
+
|
17
|
+
@start_time, @duration = start_time, duration
|
18
|
+
|
19
|
+
@schedule = IceCube::Schedule.new( start_time, duration:duration.to_i )
|
20
|
+
|
21
|
+
if block_given?
|
22
|
+
@parsing_schedule = true
|
23
|
+
|
24
|
+
instance_eval( &block )
|
25
|
+
|
26
|
+
@parsing_schedule = false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_schedule
|
31
|
+
@schedule
|
32
|
+
end
|
33
|
+
|
34
|
+
def respond_to_missing?( method_id, include_private = false )
|
35
|
+
if @parsing_schedule
|
36
|
+
IceCube::Rule.respond_to?( method_id ) || super
|
37
|
+
else
|
38
|
+
@schedule.respond_to?( method_id ) || super
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def method_missing( method_id, *args )
|
43
|
+
if @parsing_schedule && IceCube::Rule.respond_to?( method_id )
|
44
|
+
IceCube::Rule.send( method_id, *args ).tap do |rule|
|
45
|
+
@schedule.add_recurrence_rule rule
|
46
|
+
end
|
47
|
+
elsif @schedule.respond_to?( method_id )
|
48
|
+
@schedule.send( method_id, *args )
|
49
|
+
else
|
50
|
+
super
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module NetworkExecutive
|
2
|
+
class ScheduledProgram
|
3
|
+
attr_accessor :program, :occurrence, :remainder, :portion
|
4
|
+
|
5
|
+
def initialize( *args )
|
6
|
+
@program, @occurrence, @remainder, @portion = *args
|
7
|
+
end
|
8
|
+
|
9
|
+
def display_name
|
10
|
+
program.display_name
|
11
|
+
end
|
12
|
+
|
13
|
+
# Extends this scheduled program with another program of the same type.
|
14
|
+
def +( other_program )
|
15
|
+
raise ArgumentError if @program.class != other_program.class
|
16
|
+
|
17
|
+
additional_duration = other_program.duration + 1
|
18
|
+
|
19
|
+
program.duration += additional_duration
|
20
|
+
occurrence.duration += additional_duration
|
21
|
+
occurrence.end_time += additional_duration
|
22
|
+
|
23
|
+
self
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -1,29 +1,21 @@
|
|
1
1
|
require 'active_support/concern'
|
2
2
|
|
3
|
+
require 'network_executive/channel_schedule'
|
4
|
+
|
3
5
|
module NetworkExecutive
|
4
6
|
module Scheduling
|
5
7
|
extend ActiveSupport::Concern
|
6
8
|
|
7
|
-
def
|
8
|
-
|
9
|
-
|
10
|
-
if stop_time
|
11
|
-
with_showtimes_between( start_time, stop_time, options ) do |showtime, program|
|
12
|
-
program = (block_given? ? yield(program) : program)
|
13
|
-
|
14
|
-
{ time:showtime, program:program }
|
15
|
-
end
|
16
|
-
else
|
17
|
-
schedule.find_by_showtime start_time
|
18
|
-
end
|
9
|
+
def whats_on_at?( time )
|
10
|
+
schedule.find { |sch| sch.whats_on? time } || OffAirSchedule.new
|
19
11
|
end
|
20
12
|
|
21
|
-
def
|
22
|
-
|
23
|
-
|
13
|
+
def whats_on?
|
14
|
+
whats_on_at? Time.now.change(sec:0)
|
15
|
+
end
|
24
16
|
|
25
|
-
|
26
|
-
|
17
|
+
def whats_on_between?( start, stop, interval = nil )
|
18
|
+
schedule.whats_on_between? start, stop, interval
|
27
19
|
end
|
28
20
|
|
29
21
|
def schedule
|
@@ -31,12 +23,14 @@ module NetworkExecutive
|
|
31
23
|
end
|
32
24
|
|
33
25
|
module ClassMethods
|
34
|
-
def schedule
|
26
|
+
def schedule( program = nil, options = {}, &block )
|
35
27
|
@schedule ||= ChannelSchedule.new
|
36
|
-
end
|
37
28
|
|
38
|
-
|
39
|
-
|
29
|
+
if block_given?
|
30
|
+
@schedule.add program, options, &block
|
31
|
+
else
|
32
|
+
@schedule
|
33
|
+
end
|
40
34
|
end
|
41
35
|
end
|
42
36
|
|