tlapse 0.7.0 → 0.8.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b430e71598aedbebbca7591db61fafc406df196a4f6e052156f45acd570a9775
4
- data.tar.gz: 57d8a73fc5d746bed749f51107d7880ea1bdafd67e2175285fa4ad61abc20404
3
+ metadata.gz: 2f9ba7284d147763881cdb94e11e8bb77369be4eb1c43ec1b290382700f0a004
4
+ data.tar.gz: 3ba78dd8eec0d82fbae34003c6dd525ca3e6df4ebbc0ea1e70dc2eaea97da50e
5
5
  SHA512:
6
- metadata.gz: cbe3f73147112a94f2384826d463f0f0b169a6517251919fffc544a0e8b479fe892a154e59e68cdffbf733464c65318a6473bec3f869aad29f8c4918b3b580df
7
- data.tar.gz: 241a51427ccd092e73cadbe84b5e6416118a80f3baf2e0cba02213d79a42d59e926c09f2744d020ef5ffb2853ba993c2f001938db3a0647afa1f4039f8eaee4d
6
+ metadata.gz: bb467169d60beaa2e9f5b3a8bfa88cb0264873ead65fe3254ea19e1780ebd75b48cb095270338e72142c4b0934ecb60b7fcc2b73ec6a38fe72ab471a809f17ea
7
+ data.tar.gz: edea957cce99cbc196fef32eb3766be708bc8b58d37b4f1269daa4f3104deed929eb56f33be2b98b9a961d12ec8a9c2a03a54a8239ce3e207a795b62bfcc7f76
data/.gitignore CHANGED
@@ -9,3 +9,4 @@
9
9
  /tmp/
10
10
  *.gem
11
11
  .byebug_history
12
+ coverage
data/README.md CHANGED
@@ -4,19 +4,27 @@ 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 sunset, capture one image every 10 minutes
16
+ * From 9 AM to 1 PM, capture one image every 10 minutes
17
17
 
18
18
  ```
19
- 0 9 * * * cd $HOME && eval "$(tlapse until_sunset --interval 10)" >> capture.log
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
@@ -25,6 +33,14 @@ Find better documentation by running `tlapse help` or `tlapse help SUBCOMMAND`
25
33
 
26
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).
@@ -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
@@ -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,4 @@
1
+ module Tlapse
2
+ class NoSuchConfigOption < StandardError; end
3
+ class ConfigOptionInvalid < StandardError; end
4
+ end
@@ -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
- s = solar_event.compute_official_sunrise(TZ)
11
- n = Time.new
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
- s = solar_event.compute_official_sunset(TZ)
17
- n = Time.new
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
- SolarEventCalculator.new date, LAT, LON
22
+ lat, lon = Tlapse::Config.get "lat", "lon"
23
+ SolarEventCalculator.new date, lat, lon
24
24
  end
25
25
  end
26
26
  end
@@ -1,3 +1,3 @@
1
1
  module Tlapse
2
- VERSION = "0.7.0"
2
+ VERSION = "0.8.0"
3
3
  end
data/tlapse.gemspec CHANGED
@@ -23,6 +23,7 @@ Gem::Specification.new do |spec|
23
23
  spec.add_development_dependency "rspec", "~> 3.0"
24
24
  spec.add_development_dependency "byebug", "~> 8.2"
25
25
  spec.add_development_dependency "timecop", "~> 0.8"
26
+ spec.add_development_dependency "simplecov", "~> 0.15"
26
27
 
27
28
  spec.add_dependency "activesupport", "~> 5"
28
29
  spec.add_dependency "RubySunrise", "~> 0.3"
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.7.0
4
+ version: 0.8.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: 2017-12-23 00:00:00.000000000 Z
11
+ date: 2018-01-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0.8'
83
+ - !ruby/object:Gem::Dependency
84
+ name: simplecov
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
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
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.15'
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: activesupport
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -149,7 +163,6 @@ files:
149
163
  - ".rspec"
150
164
  - ".ruby-version"
151
165
  - ".travis.yml"
152
- - ":w"
153
166
  - Gemfile
154
167
  - LICENSE.txt
155
168
  - README.md
@@ -161,7 +174,10 @@ files:
161
174
  - lib/tlapse/capture.rb
162
175
  - lib/tlapse/cli/alpha.rb
163
176
  - lib/tlapse/cli/cli.rb
177
+ - lib/tlapse/cli/config.rb
178
+ - lib/tlapse/config.rb
164
179
  - lib/tlapse/doctor.rb
180
+ - lib/tlapse/errors.rb
165
181
  - lib/tlapse/logger.rb
166
182
  - lib/tlapse/server.rb
167
183
  - lib/tlapse/solar_event.rb
@@ -189,7 +205,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
189
205
  version: '0'
190
206
  requirements: []
191
207
  rubyforge_project:
192
- rubygems_version: 2.7.3
208
+ rubygems_version: 2.7.4
193
209
  signing_key:
194
210
  specification_version: 4
195
211
  summary: Automated time lapse photography via gphoto2
data/:w DELETED
@@ -1,3 +0,0 @@
1
- module Tlapse
2
- VERSION = "0.6.0"
3
- end