trecs 0.0.1.alpha
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.bundle/config +1 -0
- data/.gitignore +4 -0
- data/.rspec +2 -0
- data/.spec +0 -0
- data/.travis.yml +4 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +38 -0
- data/LICENCE.txt +22 -0
- data/README.org +44 -0
- data/Rakefile +7 -0
- data/bin/trecs +33 -0
- data/bin/trecs_message +20 -0
- data/bin/trecs_terminal +25 -0
- data/doc/steps.org +18 -0
- data/lib/player.rb +75 -0
- data/lib/players/zip_file_player.rb +56 -0
- data/lib/recorder.rb +68 -0
- data/lib/recorders/message_recorder.rb +18 -0
- data/lib/recorders/ttyrec_recorder.rb +13 -0
- data/lib/recorders/zip_file_recorder.rb +41 -0
- data/lib/recording_strategies/incremental_recording_strategy.rb +25 -0
- data/lib/recording_strategies/ttyrec_recording_strategy.rb +30 -0
- data/lib/recording_strategy.rb +10 -0
- data/lib/screens/terminal_screen.rb +22 -0
- data/lib/timestamps.rb +22 -0
- data/lib/trecs/version.rb +3 -0
- data/sandbox/create_recording.rb +28 -0
- data/sandbox/lipsum_end +1 -0
- data/sandbox/lipsum_start +1 -0
- data/sandbox/record +50 -0
- data/sandbox/record_diff +26 -0
- data/sandbox/record_script_file +45 -0
- data/spec/player_spec.rb +196 -0
- data/spec/recorder_spec.rb +248 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/timestamps_spec.rb +44 -0
- data/spec/trecs_message_spec.rb +125 -0
- data/spec/trecs_spec.rb +110 -0
- data/spec/zip_file_recorder_spec.rb +58 -0
- data/trecs.gemspec +31 -0
- metadata +179 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f6e8706df641c011fc594a3589b732af9903e583
|
4
|
+
data.tar.gz: 55584a0ad79f7860e323e92717158cecd52b495d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 87c2377954222bf2af45037321ff28fe74a9ab8a302d0b78e8f3391f08fc2d6a3d07b1e31e38e32c68d64869f73558ee58131470cce8142d704148221623b622
|
7
|
+
data.tar.gz: c4118a76ee41f5c279d0b911a19772fdb8953319c7f7d4b310fbd51e15855f793daab5486c44610b85d1bbd14d439a1b4287d4a08e66598488e1696aa544ccf7
|
data/.bundle/config
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--- {}
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.spec
ADDED
File without changes
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
trecs (0.0.1.alpha)
|
5
|
+
rubyzip (~> 1.0.0)
|
6
|
+
trollop (~> 2.0)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
diff-lcs (1.2.4)
|
12
|
+
given_core (3.5.4)
|
13
|
+
sorcerer (>= 0.3.7)
|
14
|
+
rake (10.3.2)
|
15
|
+
rspec (2.13.0)
|
16
|
+
rspec-core (~> 2.13.0)
|
17
|
+
rspec-expectations (~> 2.13.0)
|
18
|
+
rspec-mocks (~> 2.13.0)
|
19
|
+
rspec-core (2.13.1)
|
20
|
+
rspec-expectations (2.13.0)
|
21
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
22
|
+
rspec-given (3.5.4)
|
23
|
+
given_core (= 3.5.4)
|
24
|
+
rspec (>= 2.12)
|
25
|
+
rspec-mocks (2.13.1)
|
26
|
+
rubyzip (1.0.0)
|
27
|
+
sorcerer (1.0.2)
|
28
|
+
trollop (2.0)
|
29
|
+
|
30
|
+
PLATFORMS
|
31
|
+
ruby
|
32
|
+
|
33
|
+
DEPENDENCIES
|
34
|
+
bundler (~> 1.6)
|
35
|
+
rake
|
36
|
+
rspec (~> 2.12)
|
37
|
+
rspec-given (~> 3.5.4)
|
38
|
+
trecs!
|
data/LICENCE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Federico Iachetti
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.org
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
#+TITLE: README.org
|
2
|
+
#+AUTHOR: Federico Martín Iachetti
|
3
|
+
#+EMAIL: iachetti.federico@gmail.com
|
4
|
+
#+LANGUAGE: en
|
5
|
+
#+OPTIONS: H:3 num:t toc:t \n:nil @:t ::t |:t ^:nil -:t f:t *:t <:t
|
6
|
+
#+OPTIONS: TeX:t LaTeX:t skip:nil d:nil todo:t pri:nil tags:not-in-toc
|
7
|
+
#+INFOJS_OPT: view:nil toc:nil ltoc:t mouse:underline buttons:0 path:http://orgmode.org/org-info.js
|
8
|
+
#+EXPORT_SELECT_TAGS: export
|
9
|
+
#+EXPORT_EXCLUDE_TAGS: noexport
|
10
|
+
|
11
|
+
#+BEGIN_EXAMPLE
|
12
|
+
__________
|
13
|
+
/ o \
|
14
|
+
| ____|
|
15
|
+
| |___
|
16
|
+
| ____/
|
17
|
+
_| |
|
18
|
+
_| |===E
|
19
|
+
/\ _| ===E
|
20
|
+
\ \___| |
|
21
|
+
\___ /
|
22
|
+
_____ ____ _/
|
23
|
+
|_ _| _ \ ___ ___ ___
|
24
|
+
| | | |_) / _ \/ __/ __|
|
25
|
+
| | | _ < __/ (__\__ \
|
26
|
+
|_| |_| \_\___|\___|___/
|
27
|
+
|
28
|
+
#+END_EXAMPLE
|
29
|
+
* T-Recs
|
30
|
+
Text Recordings.
|
31
|
+
|
32
|
+
Record screencasts in plain text.
|
33
|
+
|
34
|
+
** Just an Idea
|
35
|
+
The idea is to create a tool that allows to record text somehow and then reproduce it just as you would reproduce a video.
|
36
|
+
|
37
|
+
** Some specifications
|
38
|
+
|
39
|
+
- It should have controls (play, pause, ffw, rew, stop, rec)
|
40
|
+
- It should have some kind of timestamp, so it can be synchronized with other resources
|
41
|
+
- The other resources:
|
42
|
+
+ Audio track
|
43
|
+
+ Video track
|
44
|
+
+ Browser extension (so, if you are recording the development of a web page, you could see in a browser the current snapshot of the page)
|
data/Rakefile
ADDED
data/bin/trecs
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift(File.expand_path("../../lib", __FILE__))
|
4
|
+
|
5
|
+
require "trollop"
|
6
|
+
|
7
|
+
require "timestamps"
|
8
|
+
require "players/zip_file_player"
|
9
|
+
|
10
|
+
options = Trollop::options do
|
11
|
+
opt :file_name, "File to process", short: 'f', type: String
|
12
|
+
opt :time, "Frame at time", short: 't', type: String
|
13
|
+
opt :current_time, "Returns the current playback time", short: 'c'
|
14
|
+
opt :step, "Time im ms between frames", short: 's', default: 100
|
15
|
+
|
16
|
+
opt :timestamps, "Returns the list of existing frame timestamps"
|
17
|
+
|
18
|
+
opt :testing, "Ticks without waiting. Use this option only for testing purpuses"
|
19
|
+
end
|
20
|
+
|
21
|
+
file_name = options[:file_name]
|
22
|
+
if file_name
|
23
|
+
if File.exist?(file_name)
|
24
|
+
player = TRecs::ZipFilePlayer.new(options)
|
25
|
+
if options[:timestamps]
|
26
|
+
p player.timestamps
|
27
|
+
else
|
28
|
+
player.play
|
29
|
+
end
|
30
|
+
else
|
31
|
+
puts "File #{file_name} does not exist."
|
32
|
+
end
|
33
|
+
end
|
data/bin/trecs_message
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift(File.expand_path("../../lib", __FILE__))
|
4
|
+
|
5
|
+
require "trollop"
|
6
|
+
|
7
|
+
require "recorders/message_recorder"
|
8
|
+
|
9
|
+
options = Trollop::options do
|
10
|
+
opt :file_name, "File to process", short: 'f', type: String
|
11
|
+
opt :message, "Message to record", short: 'm', type: String
|
12
|
+
opt :step, "Time between frames in milliseconds", short: 's', default: 100
|
13
|
+
end
|
14
|
+
|
15
|
+
if options[:file_name]
|
16
|
+
recorder = TRecs::MessageRecorder.new(options)
|
17
|
+
recorder.record
|
18
|
+
else
|
19
|
+
puts "Please give a file name"
|
20
|
+
end
|
data/bin/trecs_terminal
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift(File.expand_path("../../lib", __FILE__))
|
4
|
+
|
5
|
+
require "trollop"
|
6
|
+
|
7
|
+
require "recorders/ttyrec_recorder"
|
8
|
+
|
9
|
+
options = Trollop::options do
|
10
|
+
# opt :input_file, "File to process", short: 'i', type: String
|
11
|
+
opt :output_file, "Output file", short: 'o', type: String
|
12
|
+
end
|
13
|
+
|
14
|
+
options[:input_file] ||= "/tmp/ttyrecord"
|
15
|
+
|
16
|
+
if options[:output_file] # && options[:input_file]
|
17
|
+
puts "Recording ..."
|
18
|
+
options[:height], options[:width] = `stty size`.split(" ").map(&:to_i)
|
19
|
+
system "ttyrec #{options[:input_file]}"
|
20
|
+
recorder = TRecs::TtyrecRecorder.new(options)
|
21
|
+
recorder.record
|
22
|
+
puts "Finish Recording ..."
|
23
|
+
else
|
24
|
+
puts "Please give an input and an output file file name"
|
25
|
+
end
|
data/doc/steps.org
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#+OPTIONS: H:3 num:t toc:t \n:nil @:t ::t |:t ^:nil -:t f:t *:t <:t
|
2
|
+
#+OPTIONS: TeX:t LaTeX:t skip:nil d:nil todo:t pri:nil tags:not-in-toc
|
3
|
+
#+INFOJS_OPT: view:nil toc:nil ltoc:t mouse:underline buttons:0 path:http://orgmode.org/org-info.js
|
4
|
+
|
5
|
+
* Crear el binario trecs
|
6
|
+
Ésto es para poder comenzar a testear con código que funcione de una
|
7
|
+
trecs reproduce un archivo *.trecs conformado por un zip y una serie de archivos que representan los frames
|
8
|
+
|
9
|
+
* Extraer Player en su propia clase
|
10
|
+
Hacer que el binario llame directamente a la clase
|
11
|
+
|
12
|
+
* Extraer todo lo relacionado con el formato en particular a una nueva clase
|
13
|
+
Extraer todo lo relacionado con el formato en particular a una nueva clase, dejando sólo lo relacionado con reproducir frames, timestamps en Player
|
14
|
+
|
15
|
+
* Crear clase Screen
|
16
|
+
Screen sería el lugar sonde va a ir a parar el frame para ser visualizado.
|
17
|
+
* Extraer todo lo posible del binario hacia player
|
18
|
+
Hacer que el binario sea una cáscara y que el player sea el verdadero "main"
|
data/lib/player.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
require "timestamps"
|
2
|
+
require "screens/terminal_screen"
|
3
|
+
|
4
|
+
module TRecs
|
5
|
+
class Player
|
6
|
+
attr_reader :output
|
7
|
+
|
8
|
+
def initialize(time: nil, step: 100, output: TerminalScreen.new, testing: false, **options)
|
9
|
+
@current_time = time
|
10
|
+
@step = step
|
11
|
+
@ticks = time ? Array(time.to_i) : ticks
|
12
|
+
@output = output
|
13
|
+
@testing = testing
|
14
|
+
end
|
15
|
+
|
16
|
+
def play
|
17
|
+
ticks.each do |time|
|
18
|
+
play_frame(time)
|
19
|
+
sleep(sleep_time) unless testing
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def tick(time=current_time)
|
24
|
+
self.current_time = time
|
25
|
+
get_frame(time)
|
26
|
+
end
|
27
|
+
|
28
|
+
def timestamps
|
29
|
+
@timestamps ||= get_timestamps.sort
|
30
|
+
end
|
31
|
+
|
32
|
+
def generate_ticks
|
33
|
+
ticks = [0]
|
34
|
+
curr = 0
|
35
|
+
while(curr < timestamps.last.to_i)
|
36
|
+
curr += step
|
37
|
+
ticks << curr
|
38
|
+
end
|
39
|
+
ticks
|
40
|
+
end
|
41
|
+
|
42
|
+
def ticks
|
43
|
+
@ticks ||= generate_ticks
|
44
|
+
end
|
45
|
+
|
46
|
+
def play_frame(time)
|
47
|
+
output.clear
|
48
|
+
output.puts tick(time_at(time))
|
49
|
+
end
|
50
|
+
|
51
|
+
def time_at(time)
|
52
|
+
Timestamps.new(timestamps).time_at(time)
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
attr_accessor :current_time
|
57
|
+
attr_reader :step
|
58
|
+
attr_reader :testing
|
59
|
+
|
60
|
+
|
61
|
+
|
62
|
+
def get_timestamps
|
63
|
+
[]
|
64
|
+
end
|
65
|
+
|
66
|
+
def get_frame(time)
|
67
|
+
""
|
68
|
+
end
|
69
|
+
|
70
|
+
def sleep_time
|
71
|
+
# TODO: Fix this to use the current time
|
72
|
+
@sleep_time ||= (step/1000.0)*0.8
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require "zip"
|
2
|
+
require "player"
|
3
|
+
|
4
|
+
module TRecs
|
5
|
+
class ZipFilePlayer < Player
|
6
|
+
include FileUtils
|
7
|
+
|
8
|
+
def initialize(file_name: "", **options)
|
9
|
+
@file_name = file_name
|
10
|
+
|
11
|
+
create_directory
|
12
|
+
extract_file
|
13
|
+
|
14
|
+
super(**options)
|
15
|
+
end
|
16
|
+
|
17
|
+
# this
|
18
|
+
def get_frame(time)
|
19
|
+
File.read(file_to_read(time))
|
20
|
+
end
|
21
|
+
|
22
|
+
# this
|
23
|
+
def get_timestamps
|
24
|
+
return [] unless file_name
|
25
|
+
Dir.glob("#{dir}/*").each.map do |line|
|
26
|
+
line[/\/(\d++)\Z/, 1].to_i
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
attr_reader :file_name
|
32
|
+
attr_reader :dir
|
33
|
+
|
34
|
+
def file_to_read(time)
|
35
|
+
file_array = []
|
36
|
+
file_array << @dir
|
37
|
+
file_array << "/"
|
38
|
+
file_array << time
|
39
|
+
file_to_read = file_array.join
|
40
|
+
end
|
41
|
+
|
42
|
+
def create_directory
|
43
|
+
@dir = Dir.mktmpdir
|
44
|
+
end
|
45
|
+
|
46
|
+
def extract_file
|
47
|
+
Zip::File.open(file_name) do |file|
|
48
|
+
file.each do |f|
|
49
|
+
f.extract "#{dir}/#{f.name}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
data/lib/recorder.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
module TRecs
|
2
|
+
class Recorder
|
3
|
+
attr_writer :current_time
|
4
|
+
attr_reader :step
|
5
|
+
|
6
|
+
def initialize(step: 100, **options)
|
7
|
+
@step = step
|
8
|
+
end
|
9
|
+
|
10
|
+
def next_timestamp
|
11
|
+
@current_time = -step unless @current_time
|
12
|
+
@current_time += step
|
13
|
+
end
|
14
|
+
|
15
|
+
def current_time(time=nil)
|
16
|
+
if time
|
17
|
+
@current_time = time
|
18
|
+
end
|
19
|
+
@current_time
|
20
|
+
end
|
21
|
+
|
22
|
+
def current_content(content=nil)
|
23
|
+
if content
|
24
|
+
@current_content = content
|
25
|
+
end
|
26
|
+
@current_content
|
27
|
+
end
|
28
|
+
|
29
|
+
def current_frame(time: next_timestamp, content:)
|
30
|
+
current_time(time)
|
31
|
+
current_content(content)
|
32
|
+
|
33
|
+
if previous_content != content
|
34
|
+
create_frame
|
35
|
+
self.previous_content = content
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def record
|
40
|
+
start
|
41
|
+
perform_recording
|
42
|
+
finish
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
attr_accessor :recording
|
47
|
+
attr_accessor :previous_content
|
48
|
+
attr_reader :recording_strategy
|
49
|
+
|
50
|
+
def start
|
51
|
+
self.current_time = nil
|
52
|
+
self.recording = true
|
53
|
+
setup
|
54
|
+
end
|
55
|
+
|
56
|
+
def finish
|
57
|
+
render
|
58
|
+
self.recording = false
|
59
|
+
end
|
60
|
+
|
61
|
+
def create_frame
|
62
|
+
end
|
63
|
+
|
64
|
+
def perform_recording
|
65
|
+
recording_strategy.perform
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require "timestamps"
|
2
|
+
|
3
|
+
require "recorders/zip_file_recorder"
|
4
|
+
require "recording_strategies/incremental_recording_strategy"
|
5
|
+
|
6
|
+
|
7
|
+
module TRecs
|
8
|
+
class MessageRecorder < ZipFileRecorder
|
9
|
+
attr_reader :message
|
10
|
+
|
11
|
+
def initialize(message:, **options)
|
12
|
+
@message = message
|
13
|
+
@recording_strategy = IncrementalRecordingStrategy.new(recorder: self, message: message)
|
14
|
+
super(**options)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "timestamps"
|
2
|
+
|
3
|
+
require "recorders/zip_file_recorder"
|
4
|
+
require "recording_strategies/ttyrec_recording_strategy"
|
5
|
+
|
6
|
+
module TRecs
|
7
|
+
class TtyrecRecorder < ZipFileRecorder
|
8
|
+
def initialize(input_file:, output_file:, **options)
|
9
|
+
@recording_strategy = TtyrecRecordingStrategy.new(recorder: self, file: input_file, **options)
|
10
|
+
super(file_name: output_file, **options)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require "zip"
|
2
|
+
require "recorder"
|
3
|
+
|
4
|
+
module TRecs
|
5
|
+
class ZipFileRecorder < Recorder
|
6
|
+
include FileUtils
|
7
|
+
def initialize(file_name:, **options)
|
8
|
+
super(**options)
|
9
|
+
@file_name = file_name
|
10
|
+
delete_file
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
attr_reader :file_name
|
15
|
+
attr_reader :frames
|
16
|
+
|
17
|
+
# this
|
18
|
+
def setup
|
19
|
+
@frames = {}
|
20
|
+
end
|
21
|
+
|
22
|
+
def render
|
23
|
+
Zip::File.open(file_name, Zip::File::CREATE) do |trecs_file|
|
24
|
+
frames.each do |timestamp, content|
|
25
|
+
Tempfile.open(timestamp.to_s) do |temp_file|
|
26
|
+
temp_file.write(content)
|
27
|
+
trecs_file.add(timestamp.to_s, temp_file)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def create_frame
|
34
|
+
frames[current_time] = current_content
|
35
|
+
end
|
36
|
+
|
37
|
+
def delete_file
|
38
|
+
rm file_name if File.exists? file_name
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "recording_strategy"
|
2
|
+
module TRecs
|
3
|
+
class IncrementalRecordingStrategy < RecordingStrategy
|
4
|
+
def initialize(message:, **options)
|
5
|
+
@message = message
|
6
|
+
super(**options)
|
7
|
+
end
|
8
|
+
|
9
|
+
def perform
|
10
|
+
message.each_char.each_with_object("") do |current_char, current_msg|
|
11
|
+
current_msg << current_char
|
12
|
+
|
13
|
+
time = timestamp_for(current_msg)
|
14
|
+
content = current_msg.dup
|
15
|
+
recorder.current_frame(time: time, content: content)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
private
|
19
|
+
attr_reader :message
|
20
|
+
|
21
|
+
def timestamp_for(message)
|
22
|
+
(message.size - 1) * recorder.step
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "recording_strategy"
|
2
|
+
module TRecs
|
3
|
+
class TtyrecRecordingStrategy < RecordingStrategy
|
4
|
+
def initialize(file:, height: 24, width: 80, **options)
|
5
|
+
@file = File.new(file)
|
6
|
+
@frames = []
|
7
|
+
@full_output = ""
|
8
|
+
@height = height
|
9
|
+
@width = width
|
10
|
+
super
|
11
|
+
end
|
12
|
+
|
13
|
+
def perform
|
14
|
+
while !@file.eof?
|
15
|
+
sec, usec, len = @file.read(12).unpack('VVV')
|
16
|
+
@full_output << @file.read(len)
|
17
|
+
|
18
|
+
data_array = @full_output.each_line.to_a
|
19
|
+
height = data_array.size > @height ? @height : 0
|
20
|
+
frame = data_array[-height..-1].join
|
21
|
+
|
22
|
+
prev_timestamp ||= [ sec, usec ].join('.').to_f
|
23
|
+
curr_timestamp = [ sec, usec ].join('.').to_f
|
24
|
+
offset = ((curr_timestamp - prev_timestamp)*1000).to_i
|
25
|
+
|
26
|
+
recorder.current_frame(time: offset, content: frame)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "delegate"
|
2
|
+
|
3
|
+
module TRecs
|
4
|
+
class TerminalScreen < SimpleDelegator
|
5
|
+
def clear
|
6
|
+
puts "\e[H\e[2J"
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@obj = $stdout
|
11
|
+
super(@obj)
|
12
|
+
end
|
13
|
+
|
14
|
+
def __getobj__
|
15
|
+
@obj
|
16
|
+
end
|
17
|
+
|
18
|
+
def __setobj__(obj)
|
19
|
+
@obj = obj
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/timestamps.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
class Timestamps
|
2
|
+
attr_reader :collection
|
3
|
+
|
4
|
+
def initialize(collection)
|
5
|
+
@collection = collection
|
6
|
+
end
|
7
|
+
|
8
|
+
def time_at(time=0)
|
9
|
+
time = time.to_s.to_i
|
10
|
+
return 0 if collection.empty?
|
11
|
+
return collection.first if time <= collection.first
|
12
|
+
return collection.last if time >= collection.last
|
13
|
+
collection.each_cons(2) do |a, b|
|
14
|
+
if b == time
|
15
|
+
return b
|
16
|
+
end
|
17
|
+
if b > time
|
18
|
+
return a
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
require 'zip'
|
3
|
+
|
4
|
+
include FileUtils
|
5
|
+
def create_recording(file_name: "")
|
6
|
+
rm file_name if File.exists? file_name
|
7
|
+
recording_dir = "./frames"
|
8
|
+
rm_rf recording_dir
|
9
|
+
mkdir_p recording_dir
|
10
|
+
|
11
|
+
yield recording_dir
|
12
|
+
|
13
|
+
files_to_record = Dir.glob("#{recording_dir}/*")
|
14
|
+
|
15
|
+
Zip::File.open(file_name, Zip::File::CREATE) do |trecs_file|
|
16
|
+
files_to_record.each do |file_to_rec|
|
17
|
+
dest_file_name = File.basename(file_to_rec)
|
18
|
+
trecs_file.add(dest_file_name, file_to_rec)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
rm_rf Dir.glob("#{recording_dir}")
|
22
|
+
end
|
23
|
+
|
24
|
+
def create_frame(content: "", time: 0)
|
25
|
+
File.open("./frames/#{time.to_i}", File::WRONLY|File::CREAT) do |f|
|
26
|
+
f << content
|
27
|
+
end
|
28
|
+
end
|
data/sandbox/lipsum_end
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
@@ -0,0 +1 @@
|
|
1
|
+
Lorem ipsum dolor sit amet.
|