rubyVDRconvert 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/rubyVDRconvert +4 -0
- data/lib/file_dir.rb +31 -0
- data/lib/processing_thread.rb +8 -0
- data/lib/recording.rb +76 -0
- data/lib/recording_ts.rb +22 -0
- data/lib/recording_vdr.rb +21 -0
- data/lib/recordings.rb +59 -0
- metadata +82 -0
data/bin/rubyVDRconvert
ADDED
data/lib/file_dir.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'find'
|
2
|
+
|
3
|
+
class FileDir
|
4
|
+
def self.delete!(filedir)
|
5
|
+
case Dir.exist?(filedir)
|
6
|
+
when true
|
7
|
+
begin
|
8
|
+
Dir.rmdir(filedir)
|
9
|
+
rescue
|
10
|
+
Dir.foreach(filedir) { | entry |
|
11
|
+
delete!(entry) unless (entry == ".") or (entry == "..")
|
12
|
+
}
|
13
|
+
retry
|
14
|
+
end
|
15
|
+
else
|
16
|
+
File.delete(filedir)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
def self.mkdirtree(directory)
|
20
|
+
begin
|
21
|
+
Dir.mkdir(directory)
|
22
|
+
rescue SystemCallError => ex
|
23
|
+
parent = File.dirname(directory)
|
24
|
+
# Prevent an endless loop
|
25
|
+
return true if Dir.exist?(directory)
|
26
|
+
raise ex if parent.length == '/'
|
27
|
+
self.mkdirtree(parent)
|
28
|
+
retry
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/recording.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
require 'recording_ts'
|
4
|
+
require 'recording_vdr'
|
5
|
+
require 'file_dir'
|
6
|
+
|
7
|
+
class Recording
|
8
|
+
attr_reader :directory, :target_dir, :processed, :friendly_name
|
9
|
+
def initialize(directory)
|
10
|
+
@mutex = Mutex.new
|
11
|
+
@directory = directory
|
12
|
+
@recording = nil
|
13
|
+
@title = nil
|
14
|
+
@subtitle = nil
|
15
|
+
@friendly_name = nil
|
16
|
+
@target_dir = nil
|
17
|
+
@processed = false
|
18
|
+
@timestamp = File.mtime(@directory + '/index')
|
19
|
+
load_info
|
20
|
+
update_target_dir
|
21
|
+
determine_stream_type
|
22
|
+
end
|
23
|
+
def delete!()
|
24
|
+
@mutex.synchronize {
|
25
|
+
@recording = nil
|
26
|
+
GC.start
|
27
|
+
FileDir.delete!(@target_dir)
|
28
|
+
}
|
29
|
+
end
|
30
|
+
def load_info()
|
31
|
+
#begin
|
32
|
+
info = File.read(@directory + '/info')
|
33
|
+
info.force_encoding('BINARY')
|
34
|
+
cd = CharDet.detect(info)
|
35
|
+
encoding = cd['encoding']
|
36
|
+
info.each_line { | line |
|
37
|
+
case line[0..1]
|
38
|
+
when 'T '
|
39
|
+
@title = line[2..256].chomp
|
40
|
+
@title.force_encoding(encoding)
|
41
|
+
p "Found title: #{@title}"
|
42
|
+
when 'S '
|
43
|
+
@subtitle = line[2..256].chomp
|
44
|
+
@subtitle.force_encoding(encoding)
|
45
|
+
p "Found subtitle: #{@subtitle}"
|
46
|
+
end
|
47
|
+
}
|
48
|
+
#rescue
|
49
|
+
#end
|
50
|
+
@title = 'Unknown' if not @title
|
51
|
+
@subtitle = 'Unknown' if not @subtitle
|
52
|
+
end
|
53
|
+
def determine_stream_type()
|
54
|
+
case
|
55
|
+
when File.file?(@directory + '/00001.ts')
|
56
|
+
@recording = RecordingTS.new(self)
|
57
|
+
when File.file?(@directory + '/00001.vdr')
|
58
|
+
@recording = RecordingVDR.new(self)
|
59
|
+
else
|
60
|
+
raise 'Unknown recording'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
def update_target_dir()
|
64
|
+
title = @title
|
65
|
+
subtitle = @subtitle
|
66
|
+
title.gsub!('/', '!')
|
67
|
+
subtitle.gsub!('/', '!')
|
68
|
+
@target_dir = "/video/#{title}/#{subtitle}"
|
69
|
+
@friendly_name = "#{title} - #{subtitle}"
|
70
|
+
end
|
71
|
+
def process!()
|
72
|
+
@mutex.synchronize{
|
73
|
+
@processed = true if @recording.process!
|
74
|
+
}
|
75
|
+
end
|
76
|
+
end
|
data/lib/recording_ts.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'file_dir'
|
2
|
+
|
3
|
+
class RecordingTS
|
4
|
+
def initialize(recording)
|
5
|
+
@parent = recording
|
6
|
+
end
|
7
|
+
def process!()
|
8
|
+
target_file = @parent.target_dir + "/#{@parent.friendly_name}.ts"
|
9
|
+
FileDir.mkdirtree(@parent.target_dir)
|
10
|
+
tf = File.new(target_file, 'wb:ascii-8bit')
|
11
|
+
source_files = Dir.glob("#{@parent.directory}/*.ts")
|
12
|
+
source_files.sort!
|
13
|
+
source_files.each { | source_file |
|
14
|
+
sf = File.new(source_file, 'rb:ascii-8bit')
|
15
|
+
while not sf.eof?
|
16
|
+
tf.write(sf.read(1*(2**20))) # Only read some bytes at once
|
17
|
+
sleep(0.01) # Be friendly to other processes
|
18
|
+
end
|
19
|
+
sf.close
|
20
|
+
}
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class RecordingVDR
|
2
|
+
def initialize(recording)
|
3
|
+
@parent = recording
|
4
|
+
end
|
5
|
+
def process!()
|
6
|
+
return false
|
7
|
+
target_file = @parent.target_dir + "/#{@parent.friendly_name}.ts"
|
8
|
+
FileDir.mkdirtree(@parent.target_dir)
|
9
|
+
tf = File.new(target_file, 'wb:ascii-8bit')
|
10
|
+
source_files = Dir.glob("#{@parent.directory}/*.ts")
|
11
|
+
source_files.sort!
|
12
|
+
source_files.each { | source_file |
|
13
|
+
sf = File.new(source_file, 'rb:ascii-8bit')
|
14
|
+
while not sf.eof?
|
15
|
+
tf.write(sf.read(1*(2**20))) # Only read some bytes at once
|
16
|
+
sleep(0.01) # Be friendly to other processes
|
17
|
+
end
|
18
|
+
sf.close
|
19
|
+
}
|
20
|
+
end
|
21
|
+
end
|
data/lib/recordings.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rchardet'
|
3
|
+
require 'find'
|
4
|
+
|
5
|
+
require 'recording'
|
6
|
+
|
7
|
+
class Recordings
|
8
|
+
def initialize()
|
9
|
+
@recordings_db = Hash.new
|
10
|
+
end
|
11
|
+
def scan()
|
12
|
+
basedir = '/var/vdr/video'
|
13
|
+
found_directories = Array.new
|
14
|
+
Find.find(basedir) { | entry |
|
15
|
+
entry.force_encoding('BINARY')
|
16
|
+
# Guess encoding of filename
|
17
|
+
cd = CharDet.detect(entry)
|
18
|
+
encoding = cd['encoding']
|
19
|
+
#p encoding
|
20
|
+
entry.force_encoding(encoding)
|
21
|
+
# Look for the index file created by VDR
|
22
|
+
if File.basename(entry) == "index" then
|
23
|
+
directory = File.dirname(entry)
|
24
|
+
found_directories << directory
|
25
|
+
if @recordings_db[directory] == nil then
|
26
|
+
# Found a new entry
|
27
|
+
p directory
|
28
|
+
add(directory)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
}
|
32
|
+
@recordings_db.each { | recording |
|
33
|
+
recording.delete! unless found_directories.include?(recording.directory)
|
34
|
+
}
|
35
|
+
end
|
36
|
+
def dump()
|
37
|
+
File.new('/var/vdr/video/rubyVDRconvert.recordings.marshal', 'wb:ascii-8bit') { | f |
|
38
|
+
f.write(Marshal.dump(@recordings_db))
|
39
|
+
}
|
40
|
+
end
|
41
|
+
def load()
|
42
|
+
begin
|
43
|
+
@recordings_db = Marshal.load(File.read('/var/vdr/video/rubyVDRconvert.recordings.marshal'))
|
44
|
+
rescue
|
45
|
+
@recordings_db = Hash.new
|
46
|
+
end
|
47
|
+
end
|
48
|
+
def add(directory)
|
49
|
+
# TODO: Add a new recording that was found in the specified directory
|
50
|
+
# Ensure that VDR has finished writing the recording by checking the mtime of the index file
|
51
|
+
# Wait at least 30 seconds after VDR has finished
|
52
|
+
return false if (Time.now - File.mtime(directory + '/index')) > 30
|
53
|
+
@recordings_db[directory] = Recording.new(directory)
|
54
|
+
@recordings_db[directory].process!
|
55
|
+
end
|
56
|
+
def delete(recording)
|
57
|
+
# TODO: Delete the recording
|
58
|
+
end
|
59
|
+
end
|
metadata
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rubyVDRconvert
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Daniel Frank
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-11-07 00:00:00 +01:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: rchardet
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 1
|
29
|
+
- 3
|
30
|
+
- 0
|
31
|
+
version: 1.3.0
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
description:
|
35
|
+
email: scripts@danielfrank.net
|
36
|
+
executables:
|
37
|
+
- rubyVDRconvert
|
38
|
+
extensions: []
|
39
|
+
|
40
|
+
extra_rdoc_files: []
|
41
|
+
|
42
|
+
files:
|
43
|
+
- lib/file_dir.rb
|
44
|
+
- lib/processing_thread.rb
|
45
|
+
- lib/recording.rb
|
46
|
+
- lib/recording_ts.rb
|
47
|
+
- lib/recording_vdr.rb
|
48
|
+
- lib/recordings.rb
|
49
|
+
has_rdoc: true
|
50
|
+
homepage:
|
51
|
+
licenses: []
|
52
|
+
|
53
|
+
post_install_message:
|
54
|
+
rdoc_options: []
|
55
|
+
|
56
|
+
require_paths:
|
57
|
+
- lib
|
58
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
segments:
|
63
|
+
- 1
|
64
|
+
- 9
|
65
|
+
- 2
|
66
|
+
version: 1.9.2
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
segments:
|
72
|
+
- 0
|
73
|
+
version: "0"
|
74
|
+
requirements: []
|
75
|
+
|
76
|
+
rubyforge_project:
|
77
|
+
rubygems_version: 1.3.6
|
78
|
+
signing_key:
|
79
|
+
specification_version: 3
|
80
|
+
summary: background maintenance script for VDR
|
81
|
+
test_files: []
|
82
|
+
|