jeeves-pvr 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/Bugs.rdoc +6 -0
- data/History.txt +49 -0
- data/LICENCE.rdoc +159 -0
- data/README.md +60 -0
- data/bin/jeeves +122 -0
- data/bin/jeeves-install +27 -0
- data/bin/jeeves-old +375 -0
- data/bin/jeeves.wrapper +26 -0
- data/etc/jerbil/jeeves.rb +46 -0
- data/lib/jeeves.rb +68 -0
- data/lib/jeeves/config.rb +141 -0
- data/lib/jeeves/errors.rb +70 -0
- data/lib/jeeves/listings.rb +116 -0
- data/lib/jeeves/parser/listings.rb +41 -0
- data/lib/jeeves/parser/store.rb +167 -0
- data/lib/jeeves/parser/videos.rb +136 -0
- data/lib/jeeves/partition.rb +174 -0
- data/lib/jeeves/scheduler/base.rb +209 -0
- data/lib/jeeves/scheduler/old_base.rb +148 -0
- data/lib/jeeves/store.rb +544 -0
- data/lib/jeeves/tags.rb +329 -0
- data/lib/jeeves/utils.rb +124 -0
- data/lib/jeeves/version.rb +13 -0
- data/lib/jeeves/video.rb +79 -0
- metadata +176 -0
data/bin/jeeves.wrapper
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/ruby18
|
2
|
+
#
|
3
|
+
# This file was generated by RubyGems.
|
4
|
+
#
|
5
|
+
# The application 'jeeves-pvr' is installed as part of a gem, and
|
6
|
+
# this file is here to facilitate running it.
|
7
|
+
#
|
8
|
+
|
9
|
+
require 'rubygems'
|
10
|
+
|
11
|
+
version = ">= 0"
|
12
|
+
|
13
|
+
if ARGV.first
|
14
|
+
str = ARGV.first
|
15
|
+
str = str.dup.force_encoding("BINARY") if str.respond_to? :force_encoding
|
16
|
+
if str =~ /\A_(.*)_\z/
|
17
|
+
version = $1
|
18
|
+
ARGV.shift
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
#gem 'jeeves-pvr', version
|
23
|
+
#require 'jeeves'
|
24
|
+
executable = Gem.bin_path('jeeves-pvr', 'jeeves', version)
|
25
|
+
puts executable
|
26
|
+
load executable
|
@@ -0,0 +1,46 @@
|
|
1
|
+
#
|
2
|
+
# Configuration Options for: Jeeves::Config
|
3
|
+
#
|
4
|
+
|
5
|
+
# Add a file partition for Jeeves. Must have the following parameters:
|
6
|
+
# :path - valid file path to the partition to be added (not a device path),
|
7
|
+
# :key - the key given to the partition when it was initialised,
|
8
|
+
# :mountable - true if the partition should be mounted directly,
|
9
|
+
# :mounted_on - path of mount point if the partition is not one itself
|
10
|
+
#
|
11
|
+
# Use :mountable=>true to enable the partition to be mounted - needs to be an entry in /etc/fstab
|
12
|
+
# If the partition is not directly mountable but is on a mountable device partition that you also want
|
13
|
+
# mounted then use :mounted_on=>/path/to/partition instead
|
14
|
+
#add_partition
|
15
|
+
add_partition :path=>'/home/jeeves', :key=>'d1520a02b294db739bddb2324482310116f39d07'
|
16
|
+
add_partition :path=>'/home/jeeves_2', :key=>'9227567edca1bb8018d2c7bda592dbb69a89af35'
|
17
|
+
|
18
|
+
# Specify what to do if a specified partition cannot be added, e.g. because it has not been mounted
|
19
|
+
# Can be one of the following:
|
20
|
+
# :ignore - log an info message and carry on
|
21
|
+
# :warn - let the user know but carry on
|
22
|
+
# :fatal - do not continue without the partition
|
23
|
+
#
|
24
|
+
# The default is to warn but carry on. Jeeves should still be able to allocate a file even if there are
|
25
|
+
# missing partitions in the store
|
26
|
+
store_errors :warn
|
27
|
+
|
28
|
+
# Specify the environment within which Jeeves services (Jetuner etc) are expected
|
29
|
+
# to be operating. Should be one of :dev, :test or :prod
|
30
|
+
#environment :dev
|
31
|
+
|
32
|
+
# URL to the Jeeves listing/TV application that has info on programme listings
|
33
|
+
jeeves_tv_url 'http://tv.jeeves.osburn-sharp.ath.cx'
|
34
|
+
|
35
|
+
# Set the base rate for estimating data storage in kbytes per second. Note
|
36
|
+
# for some tuners this may need to be scaled, which can be done at the time
|
37
|
+
# of allocation.
|
38
|
+
#base_data_rate 416
|
39
|
+
|
40
|
+
# Specify a directory where jeeves can put working files etc. If you are working
|
41
|
+
# across a network then this directory needs to be shared across the network too.
|
42
|
+
working_dir '/home/jeeves/.jeeves'
|
43
|
+
|
44
|
+
# URL to the Jeeves video application to which recorded videos are referred etc
|
45
|
+
jeeves_url 'http://jeeves.osburn-sharp.ath.cx'
|
46
|
+
|
data/lib/jeeves.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
#
|
2
|
+
# Author:: R.J.Sharp
|
3
|
+
# Email:: robert(a)osburn-sharp.ath.cx
|
4
|
+
# Copyright:: Copyright (c) 2011
|
5
|
+
# License:: Open Software Licence v3.0
|
6
|
+
#
|
7
|
+
# This software is licensed for use under the Open Software Licence v. 3.0
|
8
|
+
# The terms of this licence can be found at http://www.opensource.org/licenses/osl-3.0.php
|
9
|
+
# and in the file LICENCE. Under the terms of this licence, all derivative works
|
10
|
+
# must themselves be licensed under the Open Software Licence v. 3.0
|
11
|
+
#
|
12
|
+
#
|
13
|
+
require 'jerbil/jerbil_service/base'
|
14
|
+
require 'jerbil/jerbil_service/support'
|
15
|
+
require 'jerbil/support'
|
16
|
+
require 'jerbil/config'
|
17
|
+
|
18
|
+
# pull in things to do with jeeves
|
19
|
+
|
20
|
+
require 'jeeves/listings'
|
21
|
+
require 'jeeves/store'
|
22
|
+
require 'jeeves/tags'
|
23
|
+
require 'jeeves/config'
|
24
|
+
require 'jeeves/errors'
|
25
|
+
|
26
|
+
#
|
27
|
+
# == Jeeves Service
|
28
|
+
#
|
29
|
+
# Synopsis of the whole service
|
30
|
+
#
|
31
|
+
module Jeeves
|
32
|
+
|
33
|
+
# add generic class methods
|
34
|
+
extend JerbilService::Support
|
35
|
+
|
36
|
+
# === Jeeves Service class
|
37
|
+
#
|
38
|
+
# Description of how the service class works
|
39
|
+
#
|
40
|
+
# class Service < JerbilService::Base
|
41
|
+
#
|
42
|
+
# # Document the constructor as required.
|
43
|
+
# #
|
44
|
+
# # pkey:: string - private key that must be used for
|
45
|
+
# # supervision calls (e.g. stop_callback)
|
46
|
+
# # options:: hash of options, preferably as created by Jeckyl. See documentation
|
47
|
+
# # on JerbilService::Base for assumed options re logging etc
|
48
|
+
# #
|
49
|
+
# def initialize(pkey, options)
|
50
|
+
#
|
51
|
+
# # do things that cannot be done when $SAFE > 0
|
52
|
+
#
|
53
|
+
# # the symbol should be the app name and must correspond to a service in /etc/services
|
54
|
+
# super(:jeeves, pkey, options)
|
55
|
+
#
|
56
|
+
# # DRb is now working, this process may have daemonized and $SAFE = 1
|
57
|
+
#
|
58
|
+
# end
|
59
|
+
#
|
60
|
+
# #
|
61
|
+
# # define additional class methods to make things happen
|
62
|
+
# #
|
63
|
+
#
|
64
|
+
# # do not redefine the superclass methods unless you are absolutely sure you know
|
65
|
+
# # what you are doing.
|
66
|
+
#
|
67
|
+
# end
|
68
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
#
|
2
|
+
#
|
3
|
+
# = Configuration settings for Jeeves Applications etc
|
4
|
+
#
|
5
|
+
# == Jeckyl config
|
6
|
+
#
|
7
|
+
# Author:: Robert Sharp
|
8
|
+
# Copyright:: Copyright (c) 2013 Robert Sharp
|
9
|
+
# License:: Open Software Licence v3.0
|
10
|
+
#
|
11
|
+
# This software is licensed for use under the Open Software Licence v. 3.0
|
12
|
+
# The terms of this licence can be found at http://www.opensource.org/licenses/osl-3.0.php
|
13
|
+
# and in the file copyright.txt. Under the terms of this licence, all derivative works
|
14
|
+
# must themselves be licensed under the Open Software Licence v. 3.0
|
15
|
+
#
|
16
|
+
#
|
17
|
+
#
|
18
|
+
require 'jeckyl'
|
19
|
+
|
20
|
+
module Jeeves
|
21
|
+
|
22
|
+
# define all of the configuration settings for Jeeves. Derived from
|
23
|
+
# Jellog to provide logging options for store operations
|
24
|
+
#
|
25
|
+
class Config < Jeckyl::Config
|
26
|
+
|
27
|
+
def configure_add_partition(params={})
|
28
|
+
comment "Add a file partition for Jeeves. Must have the following parameters:",
|
29
|
+
" :path - valid file path to the partition to be added (not a device path),",
|
30
|
+
" :key - the key given to the partition when it was initialised,",
|
31
|
+
" :mountable - true if the partition should be mounted directly,",
|
32
|
+
" :mounted_on - path of mount point if the partition is not one itself",
|
33
|
+
" ",
|
34
|
+
"Use :mountable=>true to enable the partition to be mounted - needs to be an entry in /etc/fstab",
|
35
|
+
"If the partition is not directly mountable but is on a mountable device partition that you also want",
|
36
|
+
"mounted then use :mounted_on=>/path/to/partition instead"
|
37
|
+
|
38
|
+
# ignore calls to get a default, which will not have the right params
|
39
|
+
return unless params.kind_of?(Hash)
|
40
|
+
|
41
|
+
@stores ||= Hash.new
|
42
|
+
|
43
|
+
if @stores.has_key?(params[:path]) then
|
44
|
+
# should not have defined the store already...
|
45
|
+
raise Jeckyl::ConfigError, "Duplicate store: #{params[:path]}"
|
46
|
+
end
|
47
|
+
|
48
|
+
# make sure this is a writable directory
|
49
|
+
# but if its not mounted it may not be!
|
50
|
+
#a_writable_dir(params[:path])
|
51
|
+
|
52
|
+
# if Jeeves.store_key(params[:path]) != params[:key] then
|
53
|
+
# # store has not been initialised with this key
|
54
|
+
# raise Jeckyl::ConfigError, "Incorrect/missing key for store: #{params[:path]}"
|
55
|
+
# end
|
56
|
+
|
57
|
+
@stores[params[:path]] = {:key=>params[:key]}
|
58
|
+
|
59
|
+
# check that both mount options have not been provided
|
60
|
+
if params[:mountable] then
|
61
|
+
if params.has_key?(:mounted_on) then
|
62
|
+
raise Jeckyl::ConfigError, "Please provide :mountable or :mounted_on but not both"
|
63
|
+
end
|
64
|
+
@stores[params[:path]][:mount_point] = params[:path]
|
65
|
+
end
|
66
|
+
|
67
|
+
if params.has_key?(:mounted_on) then
|
68
|
+
a_readable_file(params[:mounted_on]) # the directory may not be writable!
|
69
|
+
@stores[params[:path]][:mount_point] = params[:mounted_on]
|
70
|
+
end
|
71
|
+
|
72
|
+
return @stores
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
def configure_base_data_rate(kbpm)
|
77
|
+
default 25000 / 60 # reasonable rate for dvb
|
78
|
+
comment "Set the base rate for estimating data storage in kbytes per second. Note",
|
79
|
+
"for some tuners this may need to be scaled, which can be done at the time",
|
80
|
+
"of allocation."
|
81
|
+
|
82
|
+
a_type_of(kbpm, Integer) && in_range(kbpm, 100, 10000)
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
def configure_jeeves_url(url)
|
87
|
+
comment "URL to the Jeeves video application to which recorded videos are referred etc"
|
88
|
+
|
89
|
+
a_matching_string(url, /https?:\/\/[\S]+/)
|
90
|
+
end
|
91
|
+
|
92
|
+
def configure_jeeves_tv_url(url)
|
93
|
+
comment "URL to the Jeeves listing/TV application that has info on programme listings"
|
94
|
+
|
95
|
+
a_matching_string(url, /https?:\/\/[\S]+/)
|
96
|
+
end
|
97
|
+
|
98
|
+
def configure_jeeves_uri_timeout(timeout)
|
99
|
+
default 2 * 60 # 2 minutes
|
100
|
+
comment "Set the timeout on updating Jeeves TV with the listings data. This can",
|
101
|
+
"take a long time so usually it exceeds the default. Needs to be in seconds.",
|
102
|
+
"To set an infinite timeout, use 0"
|
103
|
+
|
104
|
+
a_type_of(timeout, Integer) && in_range(timeout, 0, 10000) # some very high upper limit
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
def configure_store_errors(symb)
|
109
|
+
default :warn
|
110
|
+
comment "Specify what to do if a specified partition cannot be added, e.g. because it has not been mounted",
|
111
|
+
"Can be one of the following:",
|
112
|
+
" :ignore - log an info message and carry on",
|
113
|
+
" :warn - let the user know but carry on",
|
114
|
+
" :fatal - do not continue without the partition",
|
115
|
+
"",
|
116
|
+
"The default is to warn but carry on. Jeeves should still be able to allocate a file even if there are",
|
117
|
+
"missing partitions in the store"
|
118
|
+
|
119
|
+
a_member_of(symb, [:ignore, :warn, :fatal])
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
def configure_working_dir(dir)
|
124
|
+
default '/tmp'
|
125
|
+
comment "Specify a directory where jeeves can put working files etc. If you are working",
|
126
|
+
"across a network then this directory needs to be shared across the network too."
|
127
|
+
|
128
|
+
a_writable_dir(dir)
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
def configure_environment(env)
|
133
|
+
default :dev
|
134
|
+
comment "Specify the environment within which Jeeves services (Jetuner etc) are expected",
|
135
|
+
"to be operating. Should be one of :dev, :test or :prod"
|
136
|
+
a_member_of(env, [:dev, :test, :prod])
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
#
|
2
|
+
# Author:: R.J.Sharp
|
3
|
+
# Email:: robert(a)osburn-sharp.ath.cx
|
4
|
+
# Copyright:: Copyright (c) 2011
|
5
|
+
# License:: Open Software Licence v3.0
|
6
|
+
#
|
7
|
+
# This software is licensed for use under the Open Software Licence v. 3.0
|
8
|
+
# The terms of this licence can be found at http://www.opensource.org/licenses/osl-3.0.php
|
9
|
+
# and in the file LICENCE. Under the terms of this licence, all derivative works
|
10
|
+
# must themselves be licensed under the Open Software Licence v. 3.0
|
11
|
+
#
|
12
|
+
#
|
13
|
+
# This file groups together all the errors for jeeves.
|
14
|
+
# Preceed each class with a description of the error
|
15
|
+
|
16
|
+
module Jeeves
|
17
|
+
|
18
|
+
# A general class for all errors created by this project. All specific exceptions
|
19
|
+
# should be children of this class
|
20
|
+
class JeevesError < RuntimeError; end
|
21
|
+
|
22
|
+
class VersionError < JeevesError; end
|
23
|
+
|
24
|
+
# errors raised by the scheduler
|
25
|
+
class JscheduleError < JeevesError; end
|
26
|
+
|
27
|
+
#the tuner type for a scheduler is not valid
|
28
|
+
class InvalidTuner < JscheduleError; end
|
29
|
+
|
30
|
+
# the tuner does not have the given mode
|
31
|
+
class InvalidMode < JscheduleError; end
|
32
|
+
|
33
|
+
# a schedule request is missing a required parameter
|
34
|
+
class MissingParam < JscheduleError; end
|
35
|
+
|
36
|
+
# the tuner is busy
|
37
|
+
class TunerBusy < JscheduleError; end
|
38
|
+
|
39
|
+
# store related errors
|
40
|
+
class StoreError < JeevesError; end
|
41
|
+
|
42
|
+
class InvalidPartition < StoreError; end
|
43
|
+
|
44
|
+
class InvalidPartitionKey < StoreError; end
|
45
|
+
|
46
|
+
class DiskError < JeevesError; end
|
47
|
+
|
48
|
+
# listings related errors
|
49
|
+
class ListingError < JeevesError; end
|
50
|
+
class VideoError < JeevesError; end
|
51
|
+
|
52
|
+
|
53
|
+
class TaggerError < JeevesError; end
|
54
|
+
|
55
|
+
# A Jeckyl option that is needed has not been provided
|
56
|
+
class MissingOption < TaggerError; end
|
57
|
+
|
58
|
+
# the file provided cannot be read
|
59
|
+
class FileError < TaggerError; end
|
60
|
+
|
61
|
+
# the url does not work
|
62
|
+
class UrlError < TaggerError; end
|
63
|
+
|
64
|
+
# there was an error with the XML tags
|
65
|
+
class XMLError < TaggerError; end
|
66
|
+
|
67
|
+
# error creating matroska file
|
68
|
+
class MkvError < TaggerError; end
|
69
|
+
|
70
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
#
|
2
|
+
#
|
3
|
+
# = Xmltv
|
4
|
+
#
|
5
|
+
# == methods for interfacing xmltv with jeeves
|
6
|
+
#
|
7
|
+
# Author:: Robert Sharp
|
8
|
+
# Copyright:: Copyright (c) 2013 Robert Sharp
|
9
|
+
# License:: Open Software Licence v3.0
|
10
|
+
#
|
11
|
+
# This software is licensed for use under the Open Software Licence v. 3.0
|
12
|
+
# The terms of this licence can be found at http://www.opensource.org/licenses/osl-3.0.php
|
13
|
+
# and in the file copyright.txt. Under the terms of this licence, all derivative works
|
14
|
+
# must themselves be licensed under the Open Software Licence v. 3.0
|
15
|
+
#
|
16
|
+
#
|
17
|
+
#
|
18
|
+
require 'jeckyl/errors'
|
19
|
+
require 'jeeves/errors'
|
20
|
+
|
21
|
+
module Jeeves
|
22
|
+
|
23
|
+
# load the latest listings data into Jeeves
|
24
|
+
#
|
25
|
+
# jeeves will use existing listings data if it was downloaded
|
26
|
+
# less than 6 hours ago. This can be overriden with the :force option
|
27
|
+
#
|
28
|
+
# If the :reset option is set to true then the listings data will replace
|
29
|
+
# all existing data and not just append to it.
|
30
|
+
#
|
31
|
+
# @param [Hash] params to control the loading
|
32
|
+
# @option [String] :working_dir, see config
|
33
|
+
# @option [String] :jeeves_tv_url, see config
|
34
|
+
# @option [Boolean] :force - set to true to force new listings data
|
35
|
+
# @option [Boolean] :reset - set to true to reset all listings data
|
36
|
+
def Jeeves.update_listings(params={})
|
37
|
+
|
38
|
+
working_dir = params[:working_dir]
|
39
|
+
unless File.directory?(working_dir) && File.writable?(working_dir)
|
40
|
+
# if config file is used this should not be possible
|
41
|
+
raise Jeckyl::ConfigError, "Cannot write to #{working_dir}"
|
42
|
+
end
|
43
|
+
|
44
|
+
chan_txt_file = File.join(working_dir, 'channels.txt')
|
45
|
+
listings_file = File.join(working_dir, 'listings.xml')
|
46
|
+
|
47
|
+
age = 0
|
48
|
+
# see how old it is
|
49
|
+
age = Time.now - File.mtime(listings_file) if FileTest.exists?(listings_file)
|
50
|
+
|
51
|
+
age = 0 if params[:update_listings] == true
|
52
|
+
|
53
|
+
jeeves_tv_url = params[:jeeves_tv_url]
|
54
|
+
|
55
|
+
# check how old the listings file is
|
56
|
+
unless age > 0 && age < (60*60*6) then
|
57
|
+
# its more than 6 hours old, so renew it
|
58
|
+
# or you forced renewal!
|
59
|
+
|
60
|
+
# make sure it does not already exist
|
61
|
+
FileUtils.rm_f(chan_txt_file)
|
62
|
+
FileUtils.rm_f(listings_file)
|
63
|
+
|
64
|
+
|
65
|
+
# get the channels info from jeeves_tv
|
66
|
+
cmd = "/usr/bin/wget #{jeeves_tv_url}/bchannels.txt -O #{chan_txt_file}"
|
67
|
+
|
68
|
+
|
69
|
+
unless system(cmd)
|
70
|
+
raise ListingError, "#{cmd}\n failed with error #{$?}"
|
71
|
+
end
|
72
|
+
|
73
|
+
unless File.exists?(chan_txt_file)
|
74
|
+
raise ListingError, "Failed to create file: #{chan_txt_file}"
|
75
|
+
end
|
76
|
+
|
77
|
+
# now copy this file to where xmltv expects to find it.
|
78
|
+
# cheat with shell cos of ~
|
79
|
+
cmd = "cp #{chan_txt_file} ~/.xmltv/tv_grab_uk_rt.conf"
|
80
|
+
unless system(cmd)
|
81
|
+
raise ListingError, "Failed to copy file: #{cmd}"
|
82
|
+
end
|
83
|
+
|
84
|
+
cmd = "/usr/bin/tv_grab_uk_rt >#{listings_file}"
|
85
|
+
unless system(cmd)
|
86
|
+
raise ListingError, "Failed to grab listings: #{$?}\n #{cmd}"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
listings_url = URI.encode(listings_file) # ensure it is OK as url
|
91
|
+
|
92
|
+
# and now poke jeeves-tv to let it know there is something to process
|
93
|
+
#cmd = "/usr/bin/wget #{jeeves_tv_url}/load?file=#{listings_url}"
|
94
|
+
url = "#{jeeves_tv_url}/load?file=#{listings_url}"
|
95
|
+
url << "&reset=true" if params[:reset_listings]
|
96
|
+
|
97
|
+
# unless system(cmd)
|
98
|
+
# raise ListingError, "Failed to load programme info: #{$?}\n#{cmd}"
|
99
|
+
# end
|
100
|
+
|
101
|
+
rto = params[:jeeves_uri_timeout]
|
102
|
+
rto = nil if rto == 0 # makes it infinite
|
103
|
+
|
104
|
+
response = Array.new
|
105
|
+
open(url, read_timeout:rto) do |resp|
|
106
|
+
resp.each_line do |line|
|
107
|
+
response << line
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# test that the response was OK
|
112
|
+
|
113
|
+
return true
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|