tlapse 0.6.2 → 0.9.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 +4 -4
- data/.github/workflows/publish.yml +27 -0
- data/.github/workflows/ruby.yml +25 -0
- data/.gitignore +1 -0
- data/.ruby-version +1 -1
- data/README.md +38 -6
- data/lib/tlapse.rb +1 -0
- data/lib/tlapse/capture.rb +5 -0
- data/lib/tlapse/cli/alpha.rb +61 -4
- data/lib/tlapse/cli/cli.rb +6 -2
- data/lib/tlapse/cli/config.rb +67 -0
- data/lib/tlapse/config.rb +136 -0
- data/lib/tlapse/errors.rb +4 -0
- data/lib/tlapse/logger.rb +18 -0
- data/lib/tlapse/solar_event.rb +9 -9
- data/lib/tlapse/util.rb +19 -8
- data/lib/tlapse/version.rb +1 -1
- data/lib/tlapse/video.rb +10 -8
- data/tlapse.gemspec +9 -5
- metadata +45 -20
- data/.travis.yml +0 -13
- data/:w +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 106f754399b01a1832979389bc94fb9d7e0cd0425ff2783839f78529f55d7666
|
4
|
+
data.tar.gz: 65b360c321a2d8baef64e1673d4468037628116736b3d9b7295535ea70d18d9d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d96e6168415a2f4d8909251cf8df8b2922174ef5ea474c856cb58bb6fb8b166884fabee9e3097b0fea968f2e13c12133265d14747951ee0c9439217f4720fc4d
|
7
|
+
data.tar.gz: 783e162a545afc25cb52d13b82749fa786f719fc72006619fab1a1b53d5d0eb3e2b07cfba8f36f92a27f90bfe420440cf43c22b99d9c4affbf7b7b97896f18ad
|
@@ -0,0 +1,27 @@
|
|
1
|
+
name: Publish to Rubygems
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
tags:
|
6
|
+
- '*'
|
7
|
+
|
8
|
+
jobs:
|
9
|
+
publish:
|
10
|
+
runs-on: ubuntu-latest
|
11
|
+
steps:
|
12
|
+
- uses: actions/checkout@v2
|
13
|
+
- name: Set up Ruby
|
14
|
+
uses: ruby/setup-ruby@v1
|
15
|
+
with:
|
16
|
+
ruby-version: ${{ matrix.ruby-version }}
|
17
|
+
- name: Install dependencies
|
18
|
+
run: bundle install
|
19
|
+
- name: gem build
|
20
|
+
run: gem build tlapse.gemspec
|
21
|
+
- name: gem push
|
22
|
+
env:
|
23
|
+
GEM_HOST_API_KEY: ${{ secrets.RUBYGEMS_API_KEY }}
|
24
|
+
run: |
|
25
|
+
tag=$(git describe --tags)
|
26
|
+
tag=${tag:1}
|
27
|
+
gem push "tlapse-$tag.gem"
|
@@ -0,0 +1,25 @@
|
|
1
|
+
name: Ruby
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [ master ]
|
6
|
+
pull_request:
|
7
|
+
branches: [ master ]
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
test:
|
11
|
+
runs-on: ubuntu-latest
|
12
|
+
strategy:
|
13
|
+
matrix:
|
14
|
+
ruby-version: [2.5, 2.6, 2.7, '3.0']
|
15
|
+
steps:
|
16
|
+
- uses: actions/checkout@v2
|
17
|
+
- name: Set up Ruby
|
18
|
+
uses: ruby/setup-ruby@v1
|
19
|
+
with:
|
20
|
+
ruby-version: ${{ matrix.ruby-version }}
|
21
|
+
- name: Install dependencies
|
22
|
+
run: bundle install
|
23
|
+
- name: Run tests
|
24
|
+
run: bundle exec rspec
|
25
|
+
|
data/.gitignore
CHANGED
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.7.2
|
data/README.md
CHANGED
@@ -4,27 +4,43 @@ Automated time lapse photography using gphoto2.
|
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
7
|
-
1. Install gphoto2
|
7
|
+
1. Install gphoto2 and ffmpeg
|
8
8
|
|
9
|
-
* macOS: `brew install gphoto2`
|
10
|
-
* Debian/Ubuntu: `sudo apt install gphoto2`
|
9
|
+
* macOS: `brew install gphoto2 ffmpeg`
|
10
|
+
* Debian/Ubuntu: `sudo apt install gphoto2 ffmpeg`
|
11
11
|
|
12
12
|
2. `gem install tlapse`
|
13
13
|
|
14
14
|
## Example: Integrate with cron
|
15
15
|
|
16
|
-
* From 9 AM to
|
16
|
+
* From 9 AM to 1 PM, capture one image every 10 minutes
|
17
17
|
|
18
18
|
```
|
19
|
-
0 9 * * * cd $HOME &&
|
19
|
+
0 9 * * * cd $HOME && tlapse alpha capture --until 1pm --interval 10
|
20
|
+
```
|
21
|
+
|
22
|
+
* From 3 PM to sunset, capture an image every minute. Compile the result into a video.
|
23
|
+
* You should [configure](#configuration) your coordinates to accurately
|
24
|
+
determine sunset in your location
|
25
|
+
|
26
|
+
```
|
27
|
+
0 15 * * * cd $HOME && tlapse alpha capture --until sunset --interval 10 --compile
|
20
28
|
```
|
21
29
|
|
22
30
|
## CLI
|
23
31
|
|
24
32
|
Find better documentation by running `tlapse help` or `tlapse help SUBCOMMAND`
|
25
33
|
|
26
|
-
* `tlapse
|
34
|
+
* `tlapse capture_single` - Capture an image using the tethered camera
|
27
35
|
* `tlapse until_sunset` - Generate a gphoto2 command which captures images until sunset
|
36
|
+
* You should [configure](#configuration) your coordinates to accurately
|
37
|
+
determine sunset in your location
|
38
|
+
|
39
|
+
#### Alpha CLI
|
40
|
+
|
41
|
+
These are early-stage features which are likely to change quite a bit before they're ready for prime time.
|
42
|
+
|
43
|
+
* `tlapse alpha capture` - Capture a series of timelapse images (see `tlapse alpha capture --help` for options)
|
28
44
|
|
29
45
|
## API
|
30
46
|
|
@@ -45,6 +61,22 @@ Mostly useful for cronjobs and the like.
|
|
45
61
|
# => "gphoto2 --capture-image-and-download -I 1800 -F 11 --filename '%Y-%m-%d_%H-%M-%S.jpg'"
|
46
62
|
```
|
47
63
|
|
64
|
+
## Configuration <a name="configuration"/>
|
65
|
+
|
66
|
+
So sunrise and sunset calculations are correct for your location, it is
|
67
|
+
advisable to configure your (approximate) coordintes using the CLI. Defaults are
|
68
|
+
for Raleigh, NC, which is probably not where you live.
|
69
|
+
|
70
|
+
You can get rough coordinates from https://www.iplocation.net/
|
71
|
+
|
72
|
+
```
|
73
|
+
tlapse config set lat YOUR_LATITUDE
|
74
|
+
tlapse config set lon YOUR_LONGITUDE
|
75
|
+
|
76
|
+
# Optionally also configure your timezone to make date formatting nicer
|
77
|
+
tlapze config set tz YOUR_TIMEZONE (e.g. America/New_York)
|
78
|
+
```
|
79
|
+
|
48
80
|
## License
|
49
81
|
|
50
82
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/lib/tlapse.rb
CHANGED
data/lib/tlapse/capture.rb
CHANGED
@@ -4,11 +4,16 @@ module Tlapse
|
|
4
4
|
module Capture
|
5
5
|
|
6
6
|
CAPTURE_FILENAME = "%Y-%m-%d_%H-%M-%S.jpg"
|
7
|
+
CAPTURE_DIRNAME = "%Y-%m-%d"
|
7
8
|
|
8
9
|
def self.capture_filename
|
9
10
|
CAPTURE_FILENAME
|
10
11
|
end
|
11
12
|
|
13
|
+
def self.capture_dirname
|
14
|
+
CAPTURE_DIRNAME
|
15
|
+
end
|
16
|
+
|
12
17
|
def self.capture_single
|
13
18
|
`gphoto2 --capture-image-and-download --filename '#{capture_filename}'`
|
14
19
|
end
|
data/lib/tlapse/cli/alpha.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
require "thor"
|
2
|
+
require "rainbow"
|
3
|
+
require "fileutils"
|
2
4
|
|
3
5
|
module Tlapse::CLI
|
4
6
|
class Alpha < Thor
|
@@ -41,7 +43,7 @@ module Tlapse::CLI
|
|
41
43
|
FileUtils.rm video.outfile
|
42
44
|
puts "Removed file #{video.outfile}"
|
43
45
|
else
|
44
|
-
|
46
|
+
Tlapse::Logger.error! "#{video.outfile} exists. Use -f to overwrite or " \
|
45
47
|
"-o to specify a different output file."
|
46
48
|
end
|
47
49
|
end
|
@@ -49,13 +51,68 @@ module Tlapse::CLI
|
|
49
51
|
video.create!
|
50
52
|
end
|
51
53
|
|
52
|
-
desc "
|
54
|
+
desc "organize", "Cannonically organize pictures in the current directory"
|
53
55
|
option :dry_run,
|
54
56
|
desc: "Print out what would change without actually changing anything",
|
55
57
|
type: :boolean,
|
56
58
|
default: false
|
57
|
-
def
|
58
|
-
Tlapse::Util.
|
59
|
+
def organize
|
60
|
+
Tlapse::Util.organize! dry_run: options[:dry_run]
|
61
|
+
end
|
62
|
+
|
63
|
+
desc "capture", "Capture a series of timelapse photos"
|
64
|
+
option :interval,
|
65
|
+
desc: "The interval (in minutes) at which pictures will be taken",
|
66
|
+
type: :numeric,
|
67
|
+
default: 5,
|
68
|
+
aliases: %i(i)
|
69
|
+
option :until,
|
70
|
+
desc: %(Time to stop capturing. Can use special "sunset" or "sunrise"),
|
71
|
+
type: :string,
|
72
|
+
default: "sunset"
|
73
|
+
option :compile,
|
74
|
+
desc: "When done capturing, compile photos into a video",
|
75
|
+
type: :boolean,
|
76
|
+
default: false
|
77
|
+
option :compile_out,
|
78
|
+
desc: "Specify the name for the generated video file",
|
79
|
+
type: :string,
|
80
|
+
default: "out.mkv"
|
81
|
+
def capture
|
82
|
+
dirname = Time.now.strftime(Tlapse::Capture.capture_dirname)
|
83
|
+
FileUtils.mkdir_p dirname
|
84
|
+
Dir.chdir dirname
|
85
|
+
|
86
|
+
cmd = Tlapse::Capture.timelapse_command(
|
87
|
+
to: parse_time(options[:until]),
|
88
|
+
interval: options[:interval].minutes
|
89
|
+
)
|
90
|
+
|
91
|
+
if options[:compile]
|
92
|
+
video = Tlapse::Video.new(
|
93
|
+
outfile: options[:compile_out]
|
94
|
+
)
|
95
|
+
|
96
|
+
if video.outfile_exists?
|
97
|
+
Tlapse::Logger.error! "The file #{video.outfile} already exists in" \
|
98
|
+
" the directory #{dirname}. Please delete it or use the" \
|
99
|
+
" --compile-out option to specify a different filename."
|
100
|
+
end
|
101
|
+
|
102
|
+
cmd += " && #{video.create_command}"
|
103
|
+
end
|
104
|
+
|
105
|
+
exec cmd
|
106
|
+
end
|
107
|
+
|
108
|
+
no_commands do
|
109
|
+
def parse_time(time)
|
110
|
+
case time
|
111
|
+
when "sunset" then Tlapse::SolarEvent.sunset
|
112
|
+
when "sunrise" then Tlapse::SolarEvent.sunrise
|
113
|
+
else Time.parse(time)
|
114
|
+
end
|
115
|
+
end
|
59
116
|
end
|
60
117
|
end
|
61
118
|
end
|
data/lib/tlapse/cli/cli.rb
CHANGED
@@ -2,6 +2,7 @@ require "thor"
|
|
2
2
|
require "active_support/core_ext/numeric/time.rb"
|
3
3
|
require "tlapse"
|
4
4
|
require "tlapse/cli/alpha"
|
5
|
+
require "tlapse/cli/config"
|
5
6
|
|
6
7
|
module Tlapse::CLI
|
7
8
|
class CLI < Thor
|
@@ -15,8 +16,8 @@ module Tlapse::CLI
|
|
15
16
|
puts Tlapse::VERSION
|
16
17
|
end
|
17
18
|
|
18
|
-
desc "
|
19
|
-
def
|
19
|
+
desc "capture_single", "Capture a single photo, saving it to the current directory"
|
20
|
+
def capture_single
|
20
21
|
Tlapse::Capture.capture_single
|
21
22
|
end
|
22
23
|
|
@@ -31,6 +32,9 @@ module Tlapse::CLI
|
|
31
32
|
puts Tlapse::Capture.timelapse_command_while_sun_is_up(interval: interval)
|
32
33
|
end
|
33
34
|
|
35
|
+
desc "config", "Read and write config options"
|
36
|
+
subcommand "config", Tlapse::CLI::Config
|
37
|
+
|
34
38
|
desc "alpha", "Get early access to in-development (and likely unstable) commands"
|
35
39
|
subcommand "alpha", Tlapse::CLI::Alpha
|
36
40
|
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require "thor"
|
2
|
+
require "tlapse/config"
|
3
|
+
|
4
|
+
module Tlapse::CLI
|
5
|
+
class Config < Thor
|
6
|
+
desc "list", "List available configuration options"
|
7
|
+
def list
|
8
|
+
config = Tlapse::Config.list.dup
|
9
|
+
opts = config.keys
|
10
|
+
|
11
|
+
values = Tlapse::Config.get *opts
|
12
|
+
|
13
|
+
config = config.transform_values.with_index do |original, index|
|
14
|
+
default = original[:default]
|
15
|
+
default = default.call if default.respond_to? :call
|
16
|
+
original[:default] = default
|
17
|
+
|
18
|
+
original[:value] = values[index].to_s
|
19
|
+
|
20
|
+
original
|
21
|
+
end
|
22
|
+
|
23
|
+
# Make a simple table.
|
24
|
+
max_name = opts.max_by(&:length).length
|
25
|
+
max_desc = opts.max_by { |opt| config[opt][:desc].length }
|
26
|
+
max_desc = config[max_desc][:desc].length
|
27
|
+
max_value = opts.max_by { |opt| config[opt][:value].length }
|
28
|
+
max_value = config[max_value][:value].length
|
29
|
+
|
30
|
+
config.each_pair do |option, meta|
|
31
|
+
desc, default = meta.values_at :desc, :default
|
32
|
+
name_padded = option.ljust(max_name, " ")
|
33
|
+
desc_padded = meta[:desc].ljust(max_desc, " ")
|
34
|
+
#value_padded = meta[:value].ljust(max_value, " ")
|
35
|
+
value_padded = meta[:value]
|
36
|
+
|
37
|
+
puts "#{name_padded} -> #{desc_padded} -> #{value_padded} (default: #{default})"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
desc "get OPTION", "Get the value for the given config option"
|
42
|
+
def get(*options)
|
43
|
+
puts Tlapse::Config.get *options
|
44
|
+
rescue Tlapse::NoSuchConfigOption
|
45
|
+
Tlapse::Logger.error! "The config option \"#{option}\" does not exist. " \
|
46
|
+
"Run tlapse config list for a full list of available options"
|
47
|
+
end
|
48
|
+
|
49
|
+
desc "set OPTION VALUE", "Set the given config option to the given value"
|
50
|
+
def set(option, value)
|
51
|
+
Tlapse::Config.set option, value
|
52
|
+
rescue Tlapse::NoSuchConfigOption
|
53
|
+
Tlapse::Logger.error! "The config option \"#{option}\" does not exist. " \
|
54
|
+
"Run tlapse config list for a full list of available options"
|
55
|
+
rescue Tlapse::ConfigOptionInvalid => invalid
|
56
|
+
Tlapse::Logger.error! invalid.message
|
57
|
+
end
|
58
|
+
|
59
|
+
desc "unset OPTION", "Restore the given option to its default state"
|
60
|
+
def unset(option)
|
61
|
+
Tlapse::Config.unset option
|
62
|
+
rescue Tlapse::NoSuchConfigOption
|
63
|
+
Tlapse::Logger.error! "The config option \"#{option}\" does not exist. " \
|
64
|
+
"Run tlapse config list for a full list of available options"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require "yaml"
|
2
|
+
require "fileutils"
|
3
|
+
require "tlapse/errors"
|
4
|
+
require "active_support/time_with_zone"
|
5
|
+
|
6
|
+
module Tlapse
|
7
|
+
class Config
|
8
|
+
Validation = Struct.new :method, :error
|
9
|
+
|
10
|
+
CONFIG_OPTIONS = {
|
11
|
+
"lat" => {
|
12
|
+
default: 35.779590,
|
13
|
+
desc: "Your current latitude",
|
14
|
+
type: :float
|
15
|
+
},
|
16
|
+
"lon" => {
|
17
|
+
default: -78.638179,
|
18
|
+
desc: "Your current longitude",
|
19
|
+
type: :float
|
20
|
+
},
|
21
|
+
"tz" => {
|
22
|
+
default: -> { Tlapse::Config.current_tz },
|
23
|
+
desc: "Your current timezone",
|
24
|
+
type: :string,
|
25
|
+
validations: [
|
26
|
+
Validation.new(
|
27
|
+
->(tz) { TZInfo::Timezone.get(tz) },
|
28
|
+
->(tz) do
|
29
|
+
zones = ActiveSupport::TimeZone.all.map do |tz|
|
30
|
+
tz.tzinfo.name
|
31
|
+
end.uniq.sort.join("\n")
|
32
|
+
|
33
|
+
"#{tz} is not a valid timezone. Valid zones are:\n\n#{zones}"
|
34
|
+
end
|
35
|
+
)
|
36
|
+
]
|
37
|
+
}
|
38
|
+
}.freeze
|
39
|
+
|
40
|
+
CONFIG_KEYS = CONFIG_OPTIONS.keys.freeze
|
41
|
+
|
42
|
+
CONFIG_PATH = File.expand_path ".config/tlapse/tlapse.yaml", Dir.home
|
43
|
+
|
44
|
+
CONFIG_UNDEFINED = :undefined
|
45
|
+
|
46
|
+
def self.list
|
47
|
+
CONFIG_OPTIONS
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.get(*options)
|
51
|
+
values = Array(options).map do |option|
|
52
|
+
verify_option_exists! option
|
53
|
+
|
54
|
+
value = value_for option
|
55
|
+
value == CONFIG_UNDEFINED ? default_for(option) : value
|
56
|
+
end
|
57
|
+
|
58
|
+
values.length == 1 ? values.first : values
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.set(option, value)
|
62
|
+
verify_option_exists! option
|
63
|
+
validate! option, value
|
64
|
+
|
65
|
+
values = user_values
|
66
|
+
|
67
|
+
if value == default_for(option)
|
68
|
+
values.delete option
|
69
|
+
else
|
70
|
+
values[option] = value
|
71
|
+
end
|
72
|
+
|
73
|
+
save values
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.unset(option)
|
77
|
+
set option, default_for(option)
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def self.current_tz
|
83
|
+
utc_offset = Time.now.utc_offset
|
84
|
+
tz = ActiveSupport::TimeZone.all.find { |tz| tz.utc_offset == utc_offset }
|
85
|
+
tz&.tzinfo&.name || "America/New_York"
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.cast(option, value)
|
89
|
+
case type_for(option)
|
90
|
+
when :integer then value.to_i
|
91
|
+
when :float then value.to_f
|
92
|
+
when :string then value.to_s
|
93
|
+
else value
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.verify_option_exists!(option)
|
98
|
+
raise Tlapse::NoSuchConfigOption unless CONFIG_KEYS.include? option
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.value_for(option)
|
102
|
+
value = user_values[option]
|
103
|
+
value ? cast(option, value) : CONFIG_UNDEFINED
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.default_for(option)
|
107
|
+
default = CONFIG_OPTIONS.dig option, :default
|
108
|
+
default = default.call if default.respond_to? :call
|
109
|
+
cast option, default
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.type_for(option)
|
113
|
+
CONFIG_OPTIONS.dig option, :type
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.user_values
|
117
|
+
File.exists?(CONFIG_PATH) ? YAML.load_file(CONFIG_PATH) : {}
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.save(user_values)
|
121
|
+
FileUtils.mkdir_p File.dirname CONFIG_PATH
|
122
|
+
File.write CONFIG_PATH, user_values.to_yaml
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.validate!(option, value)
|
126
|
+
Array(CONFIG_OPTIONS.dig(option, :validations)).each do |validation|
|
127
|
+
begin
|
128
|
+
validation.method.call value
|
129
|
+
rescue
|
130
|
+
message = validation.error.call value
|
131
|
+
raise ConfigOptionInvalid, message
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require "rainbow"
|
2
|
+
|
3
|
+
module Tlapse
|
4
|
+
class Logger
|
5
|
+
ERROR_COLOR = :red
|
6
|
+
|
7
|
+
def self.error(message)
|
8
|
+
puts Rainbow(message).fg ERROR_COLOR
|
9
|
+
end
|
10
|
+
|
11
|
+
##
|
12
|
+
# Print the error message and then exit
|
13
|
+
def self.error!(message, exit_code: 1)
|
14
|
+
error message
|
15
|
+
exit exit_code
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/tlapse/solar_event.rb
CHANGED
@@ -1,26 +1,26 @@
|
|
1
1
|
require "solareventcalculator"
|
2
|
+
require "tlapse/config"
|
2
3
|
|
3
4
|
module Tlapse
|
4
5
|
module SolarEvent
|
5
|
-
LAT = 35.779590
|
6
|
-
LON = -78.638179
|
7
|
-
TZ = "America/New_York"
|
8
|
-
|
9
6
|
def self.sunrise
|
10
|
-
|
11
|
-
|
7
|
+
tz = Tlapse::Config.get "tz"
|
8
|
+
s = solar_event.compute_official_sunrise(tz)
|
9
|
+
n = Time.new
|
12
10
|
Time.new(n.year, n.month, n.day, s.hour, s.minute)
|
13
11
|
end
|
14
12
|
|
15
13
|
def self.sunset
|
16
|
-
|
17
|
-
|
14
|
+
tz = Tlapse::Config.get "tz"
|
15
|
+
s = solar_event.compute_official_sunset(tz)
|
16
|
+
n = Time.new
|
18
17
|
Time.new(n.year, n.month, n.day, s.hour, s.minute)
|
19
18
|
end
|
20
19
|
|
21
20
|
def self.solar_event
|
22
21
|
date = Date.new
|
23
|
-
|
22
|
+
lat, lon = Tlapse::Config.get "lat", "lon"
|
23
|
+
SolarEventCalculator.new date, lat, lon
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
data/lib/tlapse/util.rb
CHANGED
@@ -2,18 +2,29 @@ require "fileutils"
|
|
2
2
|
|
3
3
|
module Tlapse
|
4
4
|
class Util
|
5
|
-
def self.
|
5
|
+
def self.organize!(dry_run: false)
|
6
6
|
Dir["*.jpg"].each do |filename|
|
7
|
-
|
8
|
-
if filename != normalized
|
9
|
-
puts "Rename #{filename} to #{normalized}"
|
10
|
-
FileUtils.mv(filename, normalized) unless dry_run
|
11
|
-
end
|
7
|
+
normalize_path! filename, dry_run: dry_run
|
12
8
|
end
|
13
9
|
end
|
14
10
|
|
15
|
-
def self.
|
16
|
-
|
11
|
+
def self.normalize_path!(file, dry_run: false)
|
12
|
+
dirname = normalized_dirname(file)
|
13
|
+
FileUtils.mkdir dirname unless File.exist? dirname || dry_run
|
14
|
+
|
15
|
+
filename = normalized_filename(file)
|
16
|
+
path = File.join dirname, filename
|
17
|
+
|
18
|
+
puts "Rename #{file} to #{path}"
|
19
|
+
FileUtils.mv file, path unless dry_run
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.normalized_dirname(file)
|
23
|
+
File.mtime(file).strftime(Tlapse::Capture.capture_dirname)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.normalized_filename(file)
|
27
|
+
File.mtime(file).strftime(Tlapse::Capture.capture_filename)
|
17
28
|
end
|
18
29
|
end
|
19
30
|
end
|
data/lib/tlapse/version.rb
CHANGED
data/lib/tlapse/video.rb
CHANGED
@@ -9,7 +9,7 @@ module Tlapse
|
|
9
9
|
@outfile = opts.fetch :out, "out.mkv"
|
10
10
|
end
|
11
11
|
|
12
|
-
def
|
12
|
+
def create_command
|
13
13
|
command = "ffmpeg"
|
14
14
|
command += " -pattern_type glob"
|
15
15
|
command += " -i '*.jpg'"
|
@@ -17,15 +17,17 @@ module Tlapse
|
|
17
17
|
command += " -r #{@framerate}"
|
18
18
|
command += " -vcodec #{@codec}"
|
19
19
|
command += " #{@outfile}"
|
20
|
-
|
21
|
-
|
20
|
+
command
|
21
|
+
end
|
22
|
+
|
23
|
+
def create!
|
24
|
+
cmd = create_command
|
25
|
+
puts cmd
|
26
|
+
exec cmd
|
22
27
|
end
|
23
28
|
|
24
|
-
##
|
25
|
-
# @return whether the output file already exists
|
26
29
|
def outfile_exists?
|
27
30
|
File.exist? @outfile
|
28
31
|
end
|
29
|
-
|
30
|
-
|
31
|
-
end # Tlapse
|
32
|
+
end
|
33
|
+
end
|
data/tlapse.gemspec
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
lib = File.expand_path(
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require
|
4
|
+
require "tlapse/version"
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "tlapse"
|
8
8
|
spec.version = Tlapse::VERSION
|
9
9
|
spec.authors = ["Justin Toniazzo"]
|
10
|
-
spec.email = ["
|
10
|
+
spec.email = ["jutonz@hey.com"]
|
11
11
|
|
12
12
|
spec.summary = "Automated time lapse photography via gphoto2"
|
13
13
|
spec.homepage = "https://github.com/jutonz/tlapse"
|
@@ -18,13 +18,17 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.executables = %w(tlapse)
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.
|
21
|
+
spec.required_ruby_version = ">= 2.5"
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 2.1"
|
22
24
|
spec.add_development_dependency "rake", "~> 10.0"
|
23
25
|
spec.add_development_dependency "rspec", "~> 3.0"
|
24
26
|
spec.add_development_dependency "byebug", "~> 8.2"
|
25
27
|
spec.add_development_dependency "timecop", "~> 0.8"
|
28
|
+
spec.add_development_dependency "simplecov", "~> 0.15"
|
26
29
|
|
27
|
-
spec.add_dependency "activesupport", "
|
30
|
+
spec.add_dependency "activesupport", "~> 5"
|
28
31
|
spec.add_dependency "RubySunrise", "~> 0.3"
|
29
32
|
spec.add_dependency "thor", "~> 0.20"
|
33
|
+
spec.add_dependency "rainbow", "~> 3"
|
30
34
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tlapse
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Toniazzo
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-05-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '1
|
19
|
+
version: '2.1'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '1
|
26
|
+
version: '2.1'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -81,25 +81,33 @@ dependencies:
|
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0.8'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
84
|
+
name: simplecov
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- - "
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.15'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
88
95
|
- !ruby/object:Gem::Version
|
89
|
-
version:
|
90
|
-
|
96
|
+
version: '0.15'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: activesupport
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
91
102
|
- !ruby/object:Gem::Version
|
92
|
-
version: '5
|
103
|
+
version: '5'
|
93
104
|
type: :runtime
|
94
105
|
prerelease: false
|
95
106
|
version_requirements: !ruby/object:Gem::Requirement
|
96
107
|
requirements:
|
97
|
-
- - "
|
98
|
-
- !ruby/object:Gem::Version
|
99
|
-
version: 5.0.0.beta3
|
100
|
-
- - "<"
|
108
|
+
- - "~>"
|
101
109
|
- !ruby/object:Gem::Version
|
102
|
-
version: '5
|
110
|
+
version: '5'
|
103
111
|
- !ruby/object:Gem::Dependency
|
104
112
|
name: RubySunrise
|
105
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -128,20 +136,34 @@ dependencies:
|
|
128
136
|
- - "~>"
|
129
137
|
- !ruby/object:Gem::Version
|
130
138
|
version: '0.20'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: rainbow
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '3'
|
146
|
+
type: :runtime
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '3'
|
131
153
|
description:
|
132
154
|
email:
|
133
|
-
-
|
155
|
+
- jutonz@hey.com
|
134
156
|
executables:
|
135
157
|
- tlapse
|
136
158
|
extensions: []
|
137
159
|
extra_rdoc_files: []
|
138
160
|
files:
|
139
161
|
- ".editorconfig"
|
162
|
+
- ".github/workflows/publish.yml"
|
163
|
+
- ".github/workflows/ruby.yml"
|
140
164
|
- ".gitignore"
|
141
165
|
- ".rspec"
|
142
166
|
- ".ruby-version"
|
143
|
-
- ".travis.yml"
|
144
|
-
- ":w"
|
145
167
|
- Gemfile
|
146
168
|
- LICENSE.txt
|
147
169
|
- README.md
|
@@ -153,7 +175,11 @@ files:
|
|
153
175
|
- lib/tlapse/capture.rb
|
154
176
|
- lib/tlapse/cli/alpha.rb
|
155
177
|
- lib/tlapse/cli/cli.rb
|
178
|
+
- lib/tlapse/cli/config.rb
|
179
|
+
- lib/tlapse/config.rb
|
156
180
|
- lib/tlapse/doctor.rb
|
181
|
+
- lib/tlapse/errors.rb
|
182
|
+
- lib/tlapse/logger.rb
|
157
183
|
- lib/tlapse/server.rb
|
158
184
|
- lib/tlapse/solar_event.rb
|
159
185
|
- lib/tlapse/util.rb
|
@@ -172,15 +198,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
172
198
|
requirements:
|
173
199
|
- - ">="
|
174
200
|
- !ruby/object:Gem::Version
|
175
|
-
version: '
|
201
|
+
version: '2.5'
|
176
202
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
177
203
|
requirements:
|
178
204
|
- - ">="
|
179
205
|
- !ruby/object:Gem::Version
|
180
206
|
version: '0'
|
181
207
|
requirements: []
|
182
|
-
|
183
|
-
rubygems_version: 2.7.3
|
208
|
+
rubygems_version: 3.1.4
|
184
209
|
signing_key:
|
185
210
|
specification_version: 4
|
186
211
|
summary: Automated time lapse photography via gphoto2
|
data/.travis.yml
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
language: ruby
|
2
|
-
rvm:
|
3
|
-
- 2.4.2
|
4
|
-
before_install:
|
5
|
-
- gem install bundler -v 1.16.0
|
6
|
-
deploy:
|
7
|
-
provider: rubygems
|
8
|
-
api_key:
|
9
|
-
secure: ADSomrV73iRb/Xp7cV5nFd4z1uj976o7RlOzHAD93GL5vc6SrF6XXo19llAvU2mUm/VnAMzddv5dGsMegCIuZy83dA0mrdVws0EDeG1UKvPxPR5PVBm+IqYNQzAAQvgoEMiZnAZwBCwFTo8IUAj6camleklOQZzaRwfn/SGXt8wQNrUCVQrR/6+eRo86Thj1DTkJ1NTVOtZ15Z6u2Pvd3zFo4LohAcGVxYAW4hnRcw/czPyXnzYJu7XPT72MLA3FCaV4SBuhd7NlsOVdRThOZ+vbfCr/JgkqUcaBglWX2SqzNOQTC7tWFOO5dAQ9ekAmjEe45/ALFq9I6YFrdvbHhoJltls32k40F2TwL9Oqu+Or6n410elTC3/ltf2Ir4W31/RDq+6kWd8RBQ052fYicQwTxuO0N3rsOqdxZwmWJc/DPg+0Fau5KLjc0nD/Q2Kr1grcJ+48bRZxrMHUAeTzVsTCSPR+nY1ZrtWmJmVhdyyKT/xApW5OyQDB8EO3+5GtBb9ab8oTkMd2guDn9rydZv7OGlBMbItEme1cqhsLSsUX+YZrWsoRFnywL3ntSSCq7s9ergCrcIayp/loV6fWM4YLjRdWoB6K6fbYGgMW00HKEOr0lus+5pP+gUMxjoLLa/pBnv6kDq4VlpkPp3raUyXAuH/RxSHZsKAQ1CZWfSo=
|
10
|
-
gem: tlapse
|
11
|
-
on:
|
12
|
-
tags: true
|
13
|
-
repo: jutonz/tlapse
|