himawari 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/.rubocop.yml +52 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +36 -0
- data/LICENSE +21 -0
- data/README.md +73 -0
- data/Rakefile +13 -0
- data/bin/setup +5 -0
- data/doc/img/h_2020-06-01T0100.png +0 -0
- data/doc/img/h_2020-11-29T0110.png +0 -0
- data/doc/img/t_2020-12-01T0410-1_0.png +0 -0
- data/exe/himawari +6 -0
- data/himawari.gemspec +35 -0
- data/lib/himawari.rb +33 -0
- data/lib/himawari/base.rb +135 -0
- data/lib/himawari/download.rb +143 -0
- data/lib/himawari/net_utils.rb +31 -0
- data/lib/himawari/no_image.png +0 -0
- data/lib/himawari/os_utils.rb +128 -0
- data/lib/himawari/process.rb +81 -0
- data/spec/test_base.rb +54 -0
- data/spec/test_helper.rb +42 -0
- data/spec/test_net.rb +28 -0
- metadata +149 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 62481fb8ecb232de59856604c05dea5b09f65ecc5b799892861548ff02d973dc
|
4
|
+
data.tar.gz: 1572d43032c289465c7af40f119a94fd6e2837394daeff5bdd26d2b5b362401e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4a8b27e15225991ee80a77117abc18b04939ee4870cf90b70b11a7160631097e00bfdf4dc4b61d6cc480e5743970f0e70c5d0634a5cce0d6c1cfd1a1ceb027af
|
7
|
+
data.tar.gz: 9b52bad56dfc83a3edb2a5e255d9bd6d009072c607435e21239c53de5c61ae77dfb3568294d553a357b2e3e2e47946d10e4a1549c9c217b607cd1378cd315779
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
AllCops:
|
2
|
+
DisplayCopNames: true
|
3
|
+
StyleGuideCopsOnly: false
|
4
|
+
TargetRubyVersion: 2.5
|
5
|
+
Exclude:
|
6
|
+
- data/**/*
|
7
|
+
|
8
|
+
Layout/LineLength:
|
9
|
+
Enabled: true
|
10
|
+
Max: 130
|
11
|
+
|
12
|
+
Metrics/AbcSize:
|
13
|
+
Enabled: false
|
14
|
+
|
15
|
+
Metrics/MethodLength:
|
16
|
+
Enabled: true
|
17
|
+
Max: 25
|
18
|
+
Exclude:
|
19
|
+
- spec/**/*
|
20
|
+
|
21
|
+
Metrics/BlockLength:
|
22
|
+
Exclude:
|
23
|
+
- spec/**/*
|
24
|
+
- ./*.gemspec
|
25
|
+
|
26
|
+
Metrics/CyclomaticComplexity:
|
27
|
+
Max: 9
|
28
|
+
# Exclude:
|
29
|
+
|
30
|
+
Metrics/PerceivedComplexity:
|
31
|
+
Max: 11
|
32
|
+
# Exclude:
|
33
|
+
|
34
|
+
Lint/RaiseException:
|
35
|
+
Enabled: true
|
36
|
+
|
37
|
+
Lint/StructNewOverride:
|
38
|
+
Enabled: true
|
39
|
+
|
40
|
+
Style/FrozenStringLiteralComment:
|
41
|
+
Enabled: true
|
42
|
+
Exclude:
|
43
|
+
- exe/**/*
|
44
|
+
|
45
|
+
Style/HashEachMethods:
|
46
|
+
Enabled: true
|
47
|
+
|
48
|
+
Style/HashTransformKeys:
|
49
|
+
Enabled: true
|
50
|
+
|
51
|
+
Style/HashTransformValues:
|
52
|
+
Enabled: true
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
himawari (0.1.0)
|
5
|
+
httparty (~> 0.17.3)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
coderay (1.1.2)
|
11
|
+
httparty (0.17.3)
|
12
|
+
mime-types (~> 3.0)
|
13
|
+
multi_xml (>= 0.5.2)
|
14
|
+
method_source (1.0.0)
|
15
|
+
mime-types (3.3.1)
|
16
|
+
mime-types-data (~> 3.2015)
|
17
|
+
mime-types-data (3.2019.1009)
|
18
|
+
minitest (5.14.0)
|
19
|
+
multi_xml (0.6.0)
|
20
|
+
pry (0.13.1)
|
21
|
+
coderay (~> 1.1)
|
22
|
+
method_source (~> 1.0)
|
23
|
+
rake (13.0.1)
|
24
|
+
|
25
|
+
PLATFORMS
|
26
|
+
ruby
|
27
|
+
|
28
|
+
DEPENDENCIES
|
29
|
+
bundler (~> 2.1.4)
|
30
|
+
himawari!
|
31
|
+
minitest (~> 5.14.0)
|
32
|
+
pry (~> 0.13.1)
|
33
|
+
rake (~> 13.0.1)
|
34
|
+
|
35
|
+
BUNDLED WITH
|
36
|
+
2.1.4
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2020 engura
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
# himawari
|
2
|
+
Access images from the [himawari8 weather satellite](https://himawari8.nict.go.jp)] (courtesy of NICT) and compose near real-time desktop backgrounds of Earth or use the high-res images for other personal uses. For example....
|
3
|
+
![full globe](doc/img/h_2020-06-01T0100.png)
|
4
|
+
![high res section](doc/img/h_2020-11-29T0110.png)
|
5
|
+
|
6
|
+
# Installation
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
```
|
9
|
+
gem 'himawari'
|
10
|
+
```
|
11
|
+
And then execute:
|
12
|
+
```
|
13
|
+
bundle
|
14
|
+
```
|
15
|
+
Or install it yourself as:
|
16
|
+
```
|
17
|
+
gem install himawari
|
18
|
+
```
|
19
|
+
## Install CLI Dependencies
|
20
|
+
Mac:
|
21
|
+
```
|
22
|
+
brew install imagemagick # https://github.com/minimagick/minimagick
|
23
|
+
brew install parallel # https://linux.die.net/man/1/parallel
|
24
|
+
```
|
25
|
+
or Linux: run `bin/setup`
|
26
|
+
|
27
|
+
# Usage
|
28
|
+
|
29
|
+
You can use it as a CLI executable, or as a library.
|
30
|
+
|
31
|
+
*RUN EXAMPLE*: `himawari -w /home/User/himawari -d /home/User/Pictures/live -r 4 -f top -m day -v`
|
32
|
+
|
33
|
+
To set cron (with all the supplied arguments):
|
34
|
+
`himawari -w /home/User/himawari -d /home/User/Pictures/live -r 4 -f top -m day -v -c set`
|
35
|
+
and then to remove it from cron:
|
36
|
+
`himawari -w /home/User/himawari -d /home/User/Pictures/live -r 4 -f top -m day -v -c clear`
|
37
|
+
|
38
|
+
### Details
|
39
|
+
- Grabs a tiled image from Himawari, (each photo of Earth is split into square tiles of 550x550px) reassembles it into one image, and optionally copies one of the downloaded images into a `destination` folder to use as a desktop background.
|
40
|
+
![a tile](doc/img/t_2020-12-01T0410-1_0.png)
|
41
|
+
- Can change the resolution. Default is "2", smallest. Maximum is "20". It will produce an jpg of ~200MB in size for the full planet. The allowed steps are [2, 4, 8, 16, 20]. Resolution of 2 means that the image is composed of *2* tiles across, so the full image becomes 1100px wide/high. An image of resolution *factor 4* is then 550 * 4 = 2200px across. And the maximum one is 20 * 550 = 11000px X 11000px!!!!!
|
42
|
+
- Since the images can be kinda big, we can customize which part of the planet we want to see: `top`, `full` planet, or bottom (`low`).
|
43
|
+
- When using the `autorun` option (it's the method that command line utility uses), we save the last 48hrs in a folder (`working_dir`). We can then have 2 options: either show what is `now` outside, or! cycle the last complete 24 hours with a new background photo every 2 minutes? Because the images are all downloaded at once, and then an incremental download of one photo as needed, the internet traffic is relatively reasonable. Cycling the background photos doesn't need to access internet or download anything.
|
44
|
+
|
45
|
+
- 1. do NOT attempt to fetch data from black listed WiFis
|
46
|
+
- 2. if no internet, just show last available data
|
47
|
+
- 3. keep only 1 day's worth of images (~144 photos)
|
48
|
+
- 4. check for `No Image` images and skip those (until? if?) they become available
|
49
|
+
|
50
|
+
# Development
|
51
|
+
After checking out the repo, doing the steps in `installation` above and messing around with the code, run `rake test` and `rubocop` to use the tests and make sure everything is ok. To run a specific test, use `rake test TEST=spec/test_base.rb TESTOPTS="--name=test_bad_params --seed=1234"` and as for rubocop: `rubocop lib/himawari/base.rb`
|
52
|
+
|
53
|
+
## Building the gem on local machine/from source
|
54
|
+
navigate to the gem's directory and...
|
55
|
+
Manually:
|
56
|
+
```
|
57
|
+
gem build himawari.gemspec
|
58
|
+
gem install himawari-#.#.#.gem # replace the # with the most recent version
|
59
|
+
```
|
60
|
+
Semi-manually (the end result is same as above):
|
61
|
+
```
|
62
|
+
bundle exec rake install
|
63
|
+
```
|
64
|
+
|
65
|
+
## Releasing a new version of the Gem
|
66
|
+
- Update the version number in `himawari.gemspec`
|
67
|
+
- run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the .gem file to [rubygems.org](https://rubygems.org).
|
68
|
+
|
69
|
+
# Contributing
|
70
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/engura/himawari.
|
71
|
+
|
72
|
+
# License
|
73
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rake/testtask'
|
5
|
+
|
6
|
+
Rake::TestTask.new(:test) do |t|
|
7
|
+
t.libs << 'spec'
|
8
|
+
t.libs << 'lib'
|
9
|
+
t.test_files = FileList['spec/**/test_*.rb']
|
10
|
+
end
|
11
|
+
|
12
|
+
desc 'Run tests'
|
13
|
+
task default: :test
|
data/bin/setup
ADDED
Binary file
|
Binary file
|
Binary file
|
data/exe/himawari
ADDED
data/himawari.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = 'himawari'
|
5
|
+
s.version = '0.1.0'
|
6
|
+
s.date = '2020-12-15'
|
7
|
+
s.summary = 'Grabs latest images from the himawari8 weather satellite'
|
8
|
+
s.description = 'Makes pretty, high-res backgrounds from the real-time photos of Earth by Himawari8,' \
|
9
|
+
'or is intended for similar personal usage. Please see the readme for more!'
|
10
|
+
s.authors = ['engura']
|
11
|
+
s.email = ['engura@gmail.com']
|
12
|
+
s.homepage = 'https://github.com/engura/himawari'
|
13
|
+
s.license = 'MIT'
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split
|
16
|
+
s.bindir = 'exe'
|
17
|
+
s.executables = s.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
18
|
+
s.test_files = s.files.grep(%r{^(tests|spec|features)/})
|
19
|
+
s.require_paths = ['lib']
|
20
|
+
|
21
|
+
s.add_runtime_dependency 'httparty', '~> 0.17.3'
|
22
|
+
|
23
|
+
s.add_development_dependency 'bundler', '~> 2.1.4'
|
24
|
+
s.add_development_dependency 'minitest', '~> 5.14.0'
|
25
|
+
s.add_development_dependency 'pry', '~> 0.13.1'
|
26
|
+
s.add_development_dependency 'rake', '~> 13.0.1'
|
27
|
+
|
28
|
+
s.requirements << 'Mac OSX or Linux... Windows `not supported yet` due to the lack of the following:'
|
29
|
+
s.requirements << 'parallel, ~>20161222 (Let\'s download in parallel)'
|
30
|
+
s.requirements << 'ImageMagick, ~>6.9.10-23 (Specifically, the `montage` utility)'
|
31
|
+
s.requirements << 'common utilities: find, touch, crontab, curl, iwgetid, rm, bash'
|
32
|
+
|
33
|
+
s.post_install_message = "Thanks for installing! Have fun with the amazing pics of our Home made\n" \
|
34
|
+
'accessible to us for FREE by NICT. And please, don\'t break their website!!'
|
35
|
+
end
|
data/lib/himawari.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
require_relative './himawari/base.rb'
|
4
|
+
require_relative './himawari/os_utils.rb'
|
5
|
+
require_relative './himawari/net_utils.rb'
|
6
|
+
require_relative './himawari/process.rb'
|
7
|
+
require_relative './himawari/download.rb'
|
8
|
+
|
9
|
+
# encapsulates all the functions pertaining to acquiring images from the himawari8 satellite in near real-time
|
10
|
+
# from HIMAWARI_URL (defined in the Base Class)
|
11
|
+
module Himawari
|
12
|
+
def self.autorun(params = {})
|
13
|
+
h = Download.new(params)
|
14
|
+
h.cron_action ? h.crontab : h.update_backgrnd ^ h.start
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.get_pic(params = {})
|
18
|
+
t = validate(params[:datetime])
|
19
|
+
Download.new(params).pic(t, OsUtils.tenmin(t.min, t.min))
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.get_pics(params = {})
|
23
|
+
Download.new(params).pics(validate(params[:from]), validate(params[:to]))
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.validate(stamp)
|
27
|
+
return stamp if stamp.is_a? Time
|
28
|
+
return Time.parse("#{stamp}+00:00") if stamp.is_a? String
|
29
|
+
|
30
|
+
t = Time.now.utc - 600 # 600secs == 10.minutes ago
|
31
|
+
Time.new(t.year, t.month, t.day, t.hour, t.min / 10 * 10, 0, '+00:00')
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
require 'httparty'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'pathname'
|
6
|
+
require 'optparse'
|
7
|
+
# require 'pry'
|
8
|
+
|
9
|
+
module Himawari
|
10
|
+
MONITOR_ASPECT = 16.0 / 9
|
11
|
+
UPDATE_RATE = 2 # int; update the pic once every `UPDATE_RATE` minutes
|
12
|
+
HIMAWARI_URL = 'https://himawari8-dl.nict.go.jp/himawari8/img/D531106'
|
13
|
+
|
14
|
+
# Local (JST) midnight happens @14:10 UTC, so we have to use pics in interval of [2.days.ago@14:40 .. 1.day.ago@14:40]
|
15
|
+
LOCAL_MIDNIGHT = '1410'
|
16
|
+
|
17
|
+
# sets up the methods for Himawari that do not have to do with accessing the internet. ie:
|
18
|
+
# - it sets up all the default and customized params, builds awareness of the locally stored pics
|
19
|
+
# - implements "setting" the background (copies a downloaded image into a different folder)
|
20
|
+
class Base
|
21
|
+
attr_reader :now, :app_root, :work_path, :data_path, :destination_path, :focus, :mode, :resolution,
|
22
|
+
:latest_local, :latest_remote, :verbose, :by_schedule, :blacklist_wifi, :cron_action
|
23
|
+
|
24
|
+
# relative to the location of the script: Pathname.new(File.expand_path('../', __FILE__))
|
25
|
+
# relative to the current working dir: Dir.pwd
|
26
|
+
def initialize(params = {})
|
27
|
+
init_paths(params[:workdir])
|
28
|
+
@destination_path = params[:destination]
|
29
|
+
|
30
|
+
@now = Time.now.utc
|
31
|
+
@focus = params[:focus] || :top
|
32
|
+
@mode = params[:mode] || :day
|
33
|
+
@resolution = params[:resolution] || 2
|
34
|
+
@latest_local = find_latest_local
|
35
|
+
@latest_remote = nil
|
36
|
+
@verbose = params[:verbose]
|
37
|
+
@by_schedule = params[:by_schedule]
|
38
|
+
@blacklist_wifi = params[:blacklist] || []
|
39
|
+
@cron_action = params[:cron]
|
40
|
+
end
|
41
|
+
|
42
|
+
def up_to_date?
|
43
|
+
puts "Latest local: #{latest_local[:timestamp]}" if verbose
|
44
|
+
if now - latest_local[:timestamp] < 10 * 60
|
45
|
+
puts 'Local pic is up to date; no need to go online.' if verbose
|
46
|
+
return true
|
47
|
+
end
|
48
|
+
false
|
49
|
+
end
|
50
|
+
|
51
|
+
def background(img)
|
52
|
+
return false unless img && params_valid?
|
53
|
+
|
54
|
+
cmd = "sleep 5 ; rm -f #{destination_path}/*.png ; cp #{img} #{destination_path}"
|
55
|
+
# "osascript -e 'tell application \"System Events\" to tell DESKTOP to set picture to \"#{img}\"'"
|
56
|
+
puts cmd if verbose
|
57
|
+
system(cmd)
|
58
|
+
end
|
59
|
+
|
60
|
+
def update_backgrnd
|
61
|
+
return false unless mode == :day && params_valid?
|
62
|
+
|
63
|
+
# only rotate the background if we have one complete rotation of the globe saved
|
64
|
+
sexy_pics = full_24hrs_available
|
65
|
+
# puts sexy_pics
|
66
|
+
return false unless sexy_pics
|
67
|
+
|
68
|
+
i = (now.hour * 60 + now.min) / UPDATE_RATE % sexy_pics.count
|
69
|
+
puts "#{i} :: #{(now.hour * 60 + now.min)} % #{sexy_pics.count} switching to #{sexy_pics[i]}" if verbose
|
70
|
+
background(sexy_pics[i])
|
71
|
+
end
|
72
|
+
|
73
|
+
def crontab(action = nil)
|
74
|
+
@cron_action = action if action
|
75
|
+
return false unless cron_action && params_valid?
|
76
|
+
|
77
|
+
cmd = '* * * * * PATH=/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin himawari ' \
|
78
|
+
"-s -m #{mode} -f #{focus} -r #{resolution} -d '#{destination_path}' -w '#{work_path}' -b #{blacklist_wifi.join(',')}"
|
79
|
+
OsUtils.crontab(cmd, cron_action)
|
80
|
+
cmd
|
81
|
+
end
|
82
|
+
|
83
|
+
def params_valid?
|
84
|
+
unless %i[full top mid low].include?(focus) && %i[live day].include?(mode) &&
|
85
|
+
[2, 4, 8, 16, 20].include?(resolution) && blacklist_wifi.is_a?(Array) &&
|
86
|
+
(!destination_path || (destination_path && File.directory?(destination_path) && destination_path != '/'))
|
87
|
+
puts 'Invalid params. Please double check them.'
|
88
|
+
return false
|
89
|
+
end
|
90
|
+
true
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
# returns array of pic_names to choose a background from, or false if we do not have enough pictures for a full 24hr rotation
|
96
|
+
def full_24hrs_available
|
97
|
+
prev_pic = ''
|
98
|
+
sexy_pics = []
|
99
|
+
|
100
|
+
Dir["#{data_path}/h_*.png"].sort { |x, y| y <=> x }.each do |pic|
|
101
|
+
pic_time = pic[-8, 4]
|
102
|
+
return sexy_pics if sexy_pics.count.positive? && pic_time < LOCAL_MIDNIGHT && LOCAL_MIDNIGHT <= prev_pic
|
103
|
+
|
104
|
+
sexy_pics.unshift(pic) if sexy_pics.count.positive? || pic_time < LOCAL_MIDNIGHT && LOCAL_MIDNIGHT <= prev_pic
|
105
|
+
prev_pic = pic_time
|
106
|
+
end
|
107
|
+
false
|
108
|
+
end
|
109
|
+
|
110
|
+
def init_paths(workdir)
|
111
|
+
@app_root = workdir && File.directory?(workdir) ? workdir : Dir.pwd
|
112
|
+
@work_path = @app_root
|
113
|
+
@data_path = "#{@app_root}/data"
|
114
|
+
|
115
|
+
@app_root = Pathname.new(File.expand_path(__dir__))
|
116
|
+
Dir.mkdir(@data_path) unless File.exist?(@data_path)
|
117
|
+
end
|
118
|
+
|
119
|
+
def find_latest_local
|
120
|
+
# we can't select by timestamp, because those could be messed up. Instead, just search for "latest" by filename
|
121
|
+
# latest_pic = `ls -t #{data_path}/h_* | head -1`
|
122
|
+
twodays_ago = now - 86_400 * 2
|
123
|
+
latest = { timestamp: nil }
|
124
|
+
failsafe = { filename: nil, timestamp: Time.new(twodays_ago.year, twodays_ago.month, twodays_ago.day, 0, 0, 0, '+00:00') }
|
125
|
+
|
126
|
+
Dir["#{data_path}/h_*.png"].each do |pic|
|
127
|
+
stamp = Time.parse(pic[0..-5].insert(-3, ':') + ':00+00:00')
|
128
|
+
`touch -t #{stamp.strftime('%Y%m%d%H%M.%S')} #{pic}`
|
129
|
+
latest = { filename: pic, timestamp: stamp } if !latest[:timestamp] || latest[:timestamp] < stamp
|
130
|
+
end
|
131
|
+
|
132
|
+
latest[:timestamp] && latest[:timestamp] > twodays_ago ? latest : failsafe
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
module Himawari
|
4
|
+
# Let's expand our basic Himawari class with the ability to actually download stuff
|
5
|
+
# in addition to the downloading, we will also need to:
|
6
|
+
# - parse CLI arguments / set crontab (OsUtils)
|
7
|
+
# - check network status (NetUtils)
|
8
|
+
# - check and try to fix downloaded picture Tiles (Process)
|
9
|
+
class Download < Base
|
10
|
+
extend OsUtils
|
11
|
+
include NetUtils
|
12
|
+
include Process
|
13
|
+
|
14
|
+
def start
|
15
|
+
return false unless everything_ok && pics_updated?
|
16
|
+
|
17
|
+
set_background(latest_local[:filename], destination_path) if mode == :live
|
18
|
+
# clean up: remove any files that are more than 2 days old
|
19
|
+
`find #{data_path} -name \"*.png\" -type f -mtime +2 -exec rm -f {} \\;`
|
20
|
+
end
|
21
|
+
|
22
|
+
def pics(from_datetime, to_datetime)
|
23
|
+
# returns true if any new pictures were downloaded from the web, false otherwise
|
24
|
+
pic_dwnlded = false
|
25
|
+
from_datetime += 10 * 60 # +10.minutes from our latest pic on local drive
|
26
|
+
|
27
|
+
while from_datetime <= to_datetime
|
28
|
+
tenmin = if last_iter?(from_datetime, to_datetime)
|
29
|
+
OsUtils.tenmin(from_datetime.min, to_datetime.min)
|
30
|
+
elsif !pic_dwnlded # i.e. it's while's first iteration. don't update the whole hour, only the remaining minutes
|
31
|
+
OsUtils.tenmin(from_datetime.min)
|
32
|
+
else
|
33
|
+
OsUtils.tenmin
|
34
|
+
end
|
35
|
+
|
36
|
+
pic_dwnlded = pic(from_datetime, tenmin)
|
37
|
+
|
38
|
+
break if last_iter?(from_datetime, to_datetime) || !pic_dwnlded
|
39
|
+
|
40
|
+
from_datetime = if to_datetime - from_datetime > 3600
|
41
|
+
from_datetime + 3600
|
42
|
+
else
|
43
|
+
Time.new(to_datetime.year, to_datetime.month, to_datetime.day, to_datetime.hour, 0, 0, '+00:00')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
if verbose
|
48
|
+
puts pic_dwnlded ? "Latest Fetched: #{find_latest_local[:timestamp]}" : 'Nothing downloaded.'
|
49
|
+
end
|
50
|
+
pic_dwnlded
|
51
|
+
end
|
52
|
+
|
53
|
+
# `parallel --header : 'montage -mode concatenate -tile 2x {00,10,01,11}/{year}-{mo}-{dy}T{hr}{tenmin}000-*.png
|
54
|
+
# full/{year}-{mo}-{dy}T{hr}{tenmin}000.png' ::: year 2015 ::: mo 11 ::: dy {27..28} ::: hr {00..23} ::: tenmin {0..5}`
|
55
|
+
def pic(timestamp, tenmin = '{0..5}')
|
56
|
+
return false unless everything_ok
|
57
|
+
|
58
|
+
if timestamp > latest_remote
|
59
|
+
puts "Can't download #{timestamp} because it is newer than the most recent available (#{latest_remote})"
|
60
|
+
return false
|
61
|
+
end
|
62
|
+
|
63
|
+
yr = timestamp.year.to_s.rjust(2, '0')
|
64
|
+
mo = timestamp.month.to_s.rjust(2, '0')
|
65
|
+
dy = timestamp.day.to_s.rjust(2, '0')
|
66
|
+
hr = timestamp.hour.to_s.rjust(2, '0')
|
67
|
+
x, y = download_region
|
68
|
+
|
69
|
+
command1 = 'parallel -j5 --delay 0.1 --header : '\
|
70
|
+
"'curl -sC - \"#{HIMAWARI_URL}/"\
|
71
|
+
"#{resolution}d/550/{year}/{mo}/{dy}/{hr}{tenmin}000_{x}_{y}.png\" > "\
|
72
|
+
"#{data_path}/t_{year}-{mo}-{dy}T{hr}{tenmin}0-{y}_{x}.png'"\
|
73
|
+
" ::: year #{yr} ::: mo #{mo} ::: dy #{dy} ::: hr #{hr} ::: tenmin #{tenmin} ::: x #{x} ::: y #{y}"
|
74
|
+
command2 = 'parallel --header : '\
|
75
|
+
"'montage -mode concatenate -tile #{resolution}x #{data_path}/t_{year}-{mo}-{dy}T{hr}{tenmin}0-*.png "\
|
76
|
+
"#{data_path}/h_{year}-{mo}-{dy}T{hr}{tenmin}0.png'"\
|
77
|
+
" ::: year #{yr} ::: mo #{mo} ::: dy #{dy} ::: hr #{hr} ::: tenmin #{tenmin}"
|
78
|
+
# command3 = 'parallel convert -channel R -gamma 1.2 -channel G -gamma 1.1 +channel -sigmoidal-contrast 3,50% {} '\
|
79
|
+
# "pretty/{/} ::: #{data_path}/*.png"
|
80
|
+
|
81
|
+
# system(command1) # works totally fine on mac...
|
82
|
+
# OOOK>> I have NO idea why linux is not parsing {..} from parallel above and instead sticks it as a literal,
|
83
|
+
# but we need to make it work >> hack it this way for the time being...
|
84
|
+
script = "#{data_path}/script_#{yr}_#{yr}_#{mo}_#{dy}_#{hr}.sh"
|
85
|
+
OsUtils.scriptify_sys(script, command1)
|
86
|
+
|
87
|
+
check_tiles
|
88
|
+
|
89
|
+
# system(command2) # works totally fine on mac...
|
90
|
+
OsUtils.scriptify_sys(script, command2)
|
91
|
+
`rm #{data_path}/t_*`
|
92
|
+
true
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def everything_ok
|
98
|
+
@everything_ok ||= params_valid? && checks_passed?
|
99
|
+
end
|
100
|
+
|
101
|
+
def checks_passed?
|
102
|
+
if blacklisted_wifi?
|
103
|
+
puts "Blacklisted Network; Won't go online"
|
104
|
+
return false
|
105
|
+
end
|
106
|
+
|
107
|
+
# we don't want to spam himawari's site more than once every 10 minutes while running on a schedule
|
108
|
+
return false if by_schedule && now.min % 10 != 1
|
109
|
+
|
110
|
+
if `find #{data_path} -name \"t_*.png\"`.length.positive?
|
111
|
+
puts 'Another himawari process is still downloading/processing files.\n' \
|
112
|
+
'(There are tiles (t_*.png) in the `data` folder.) Quitting w/o overlapping.'
|
113
|
+
return false
|
114
|
+
end
|
115
|
+
|
116
|
+
unless internet_connection?
|
117
|
+
puts "Not online? Can't reach #{HIMAWARI_URL}"
|
118
|
+
return false
|
119
|
+
end
|
120
|
+
true
|
121
|
+
end
|
122
|
+
|
123
|
+
def last_iter?(from, to)
|
124
|
+
from.day == to.day && from.hour == to.hour
|
125
|
+
end
|
126
|
+
|
127
|
+
def pics_updated?
|
128
|
+
pics(latest_local[:timestamp], latest_remote) unless up_to_date?
|
129
|
+
end
|
130
|
+
|
131
|
+
def download_region
|
132
|
+
x = "{0..#{resolution - 1}}"
|
133
|
+
y = if focus == :top # :full :mid :low
|
134
|
+
"{0..#{(resolution / MONITOR_ASPECT).ceil - 1}}"
|
135
|
+
elsif focus == :low
|
136
|
+
"{#{resolution - (resolution / MONITOR_ASPECT).ceil}..#{resolution - 1}}"
|
137
|
+
else # full / mid
|
138
|
+
"{0..#{resolution - 1}}"
|
139
|
+
end
|
140
|
+
[x, y]
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
module Himawari
|
4
|
+
# Network-related methods to help establish whether there is network access and
|
5
|
+
# figure out if we are on a possibly "metered" connection (via a hard-coded SSID blacklist)
|
6
|
+
module NetUtils
|
7
|
+
def internet_connection?
|
8
|
+
uid = now.to_i * 1_000
|
9
|
+
r = HTTParty.get("#{HIMAWARI_URL}/latest.json?uid=#{uid}", { timeout: 10 })
|
10
|
+
# puts "#{HIMAWARI_URL}/latest.json?uid=#{uid}" if verbose
|
11
|
+
if r.code == 200
|
12
|
+
puts "Latest Himawari: #{r['date']}" if verbose
|
13
|
+
@latest_remote = Time.parse(r['date'] + '+00:00')
|
14
|
+
return true
|
15
|
+
end
|
16
|
+
false
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def blacklisted_wifi?
|
22
|
+
current_wifi = if OsUtils.os == :mac
|
23
|
+
`networksetup -getairportnetwork en0`
|
24
|
+
elsif OsUtils.os == :linux
|
25
|
+
`iwgetid -r`
|
26
|
+
end
|
27
|
+
puts current_wifi if verbose
|
28
|
+
current_wifi && blacklist_wifi.any? { |wifi| current_wifi.include?(wifi) }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
Binary file
|
@@ -0,0 +1,128 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
module Himawari
|
4
|
+
# all the misc. functions for dealing with CLI and/or OS...
|
5
|
+
module OsUtils
|
6
|
+
def self.os
|
7
|
+
if RUBY_PLATFORM =~ /win32/
|
8
|
+
:win
|
9
|
+
elsif RUBY_PLATFORM =~ /linux/
|
10
|
+
:linux
|
11
|
+
elsif RUBY_PLATFORM =~ /darwin/
|
12
|
+
:mac
|
13
|
+
elsif RUBY_PLATFORM =~ /freebsd/
|
14
|
+
:freebsd
|
15
|
+
else
|
16
|
+
:unknown
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# rubocop:disable Metrics/MethodLength, Metrics/BlockLength
|
21
|
+
def self.parse_cli_args
|
22
|
+
params = {}
|
23
|
+
|
24
|
+
OptionParser.new do |opts|
|
25
|
+
opts.banner = 'Usage: himawari [params]'
|
26
|
+
|
27
|
+
opts.on('-f', '--focus STRING', String, 'Which section of the planet to focus on? ' \
|
28
|
+
'Valid values are `full`, `top`, `mid`, `low`. Default is `top`.') do |o|
|
29
|
+
params[:focus] = o.to_sym if %w[full top mid low].include? o
|
30
|
+
end
|
31
|
+
|
32
|
+
opts.on('-m', '--mode STRING', String, 'Valid values are `day` (cycles pics in the `destination` folder from the' \
|
33
|
+
'most recent day) or `live` (copies the latest photo downloaded ' \
|
34
|
+
'to `destination`) Default is `day`.') do |o|
|
35
|
+
params[:mode] = :live if o == 'live'
|
36
|
+
end
|
37
|
+
|
38
|
+
opts.on('-r', '--resolution INT', Integer, 'Adjust the resolution of the downloaded image. Valid numbers are ' \
|
39
|
+
'2, 4, 8, 16, 20. 20 is the highest resolution and 2 is the default. ' \
|
40
|
+
'For a 4k-monitor a setting of 4 seems sufficient.') do |o|
|
41
|
+
params[:resolution] = o if o <= 20 && o.positive? && o.even?
|
42
|
+
end
|
43
|
+
|
44
|
+
opts.on('-d', '--destination PATH', String, 'The folder where to copy a background image. If left blank, images will ' \
|
45
|
+
'just be downloaded, but won\'t be copied anywhere afterward.') do |o|
|
46
|
+
params[:destination] = o if File.directory?(o)
|
47
|
+
end
|
48
|
+
|
49
|
+
opts.on('-w', '--workdir PATH', String, 'The folder where to save all the downloaded pics. If left blank, ' \
|
50
|
+
'images will be saved to the `./data` directory relative to your ' \
|
51
|
+
'current path of working dir.') do |o|
|
52
|
+
params[:workdir] = o if File.directory?(o)
|
53
|
+
end
|
54
|
+
|
55
|
+
opts.on('-b', '--blacklist STRING,STRING...', Array, 'Blacklist SSIDs of networks from which we do not want to go ' \
|
56
|
+
'online to download new images.') do |o|
|
57
|
+
params[:blacklist] = o
|
58
|
+
end
|
59
|
+
|
60
|
+
opts.on('-c', '--cron STRING', String, 'Can `set`/`clear` cron with the specified params, so we can update the images ' \
|
61
|
+
'automatically') do |o|
|
62
|
+
params[:cron] = o.to_sym if %w[set clear].include? o
|
63
|
+
end
|
64
|
+
|
65
|
+
opts.on('-v', '--verbose', 'Increase verbosity: mostly for debugging') do |o|
|
66
|
+
params[:verbose] = o
|
67
|
+
end
|
68
|
+
|
69
|
+
opts.on('-s', '--schedule', 'Flag for determining when the script is run by schedule/automatically.') do |o|
|
70
|
+
params[:by_schedule] = o
|
71
|
+
end
|
72
|
+
|
73
|
+
opts.on('-h', '--help', 'Prints this help & exits') do
|
74
|
+
puts opts
|
75
|
+
exit
|
76
|
+
end
|
77
|
+
end.parse! # (into: params)
|
78
|
+
|
79
|
+
params
|
80
|
+
end
|
81
|
+
# rubocop:enable Metrics/MethodLength, Metrics/BlockLength
|
82
|
+
|
83
|
+
def self.scriptify_sys(script, command)
|
84
|
+
`echo "#!/bin/bash\n#{command}" > #{script}`
|
85
|
+
`chmod +x #{script} && #{script}`
|
86
|
+
`rm #{script}`
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.tenmin(from = 0, to = 59)
|
90
|
+
"{#{from / 10}..#{to / 10}}"
|
91
|
+
end
|
92
|
+
|
93
|
+
# to force crossfade:
|
94
|
+
# https://apple.stackexchange.com/questions/141834/applescript-to-change-desktop-image-on-all-monitors
|
95
|
+
|
96
|
+
# set picture rotation to 1 -- turn on wallpaper cycling
|
97
|
+
# set change interval to -1 -- force a change to happen right now
|
98
|
+
# delay 1.5 -- wait a bit to allow for the fade transition - you may want to play w/ this #
|
99
|
+
# set picture of item N of theDesktops to POSIX file ("/Users/vladimir/chie/lib/space/data/h_2019-11-06T0220.png")
|
100
|
+
# -- set wallpaper to wallpaper you want
|
101
|
+
# set picture rotation to 0 -- turn off wallpaper cycling
|
102
|
+
|
103
|
+
# tell application "System Events"
|
104
|
+
# tell every desktop
|
105
|
+
# tell desktop 1
|
106
|
+
# set pictures folder to "/Library/Desktop Pictures"
|
107
|
+
# set picture rotation to 2 -- using interval
|
108
|
+
# set change interval to 1800
|
109
|
+
# set random order to true
|
110
|
+
# end tell
|
111
|
+
# tell desktop 2
|
112
|
+
# set pictures folder to "/Library/Desktop Pictures/Mine"
|
113
|
+
# set picture rotation to 2 -- using interval
|
114
|
+
# set change interval to 1800
|
115
|
+
# set random order to true
|
116
|
+
# end tell
|
117
|
+
# end tell
|
118
|
+
|
119
|
+
# to silence the status mails, add MAILTO='' at the top of the crontab manually
|
120
|
+
def self.crontab(cmd, action)
|
121
|
+
if action == :set
|
122
|
+
`(crontab -l ; echo \"#{cmd}\") 2>&1 | grep -v \"no crontab\" | sort | uniq | crontab -`
|
123
|
+
else
|
124
|
+
`(crontab -l ; echo \"#{cmd}\") 2>&1 | grep -v \"no crontab\" | grep -v himawari | sort | uniq | crontab -`
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
module Himawari
|
4
|
+
# these methods provide checking and (trying to) fix the Tiles that we downloaded from the web.
|
5
|
+
# sometimes, the connection might be bad, and instead of an actual PNG for a Tile, we get a blank empty file.
|
6
|
+
# in other times, we get a special "no_image" png. This one is annoying. It IS a real picture,
|
7
|
+
# but it most CERTAINLY is NOT a picture of the Earth. (These normally come back during 0240 and 1440 timestamps)
|
8
|
+
# -- Himawari does not take photos when the Sun is in the view of the Satellite. Well, we wouldn't be able to see
|
9
|
+
# the Earth at those times anyway due to the Sun's brightness.
|
10
|
+
module Process
|
11
|
+
private
|
12
|
+
|
13
|
+
def check_tiles
|
14
|
+
@control_size ||= File.size("#{app_root}/no_image.png")
|
15
|
+
bad_tiles = {}
|
16
|
+
Dir["#{data_path}/t_*.png"].each do |tile|
|
17
|
+
bad_tiles = process_bad_tiles(bad_tiles, tile) if bad_tile?(tile)
|
18
|
+
end
|
19
|
+
recover_bad_sectors(bad_tiles)
|
20
|
+
end
|
21
|
+
|
22
|
+
def process_bad_tiles(bad_tiles, tile)
|
23
|
+
i = File.basename(tile[0..-9])
|
24
|
+
ending = tile[-7, 3]
|
25
|
+
stamp = Time.parse(i.dup.insert(-3, ':') + ':00+00:00')
|
26
|
+
bad_tiles[i] = [] unless bad_tiles.dig(i)
|
27
|
+
bad_tiles[i] << [
|
28
|
+
himawari_format(stamp, ending),
|
29
|
+
himawari_format(stamp - 600, ending),
|
30
|
+
himawari_format(stamp - 1_200, ending)
|
31
|
+
]
|
32
|
+
# `cp #{tile} #{tile.gsub('/t_', '/x_')}`
|
33
|
+
# no need to delete individual "bad tiles" because we will try to recover them.
|
34
|
+
# But upon failure, will delete the whole himawari image
|
35
|
+
# File.delete(tile)
|
36
|
+
bad_tiles
|
37
|
+
end
|
38
|
+
|
39
|
+
def himawari_format(stamp, tile_end)
|
40
|
+
"#{stamp.year}/#{stamp.month}/#{stamp.day}/#{stamp.hour}#{stamp.min}00_#{tile_end}"
|
41
|
+
end
|
42
|
+
|
43
|
+
def png?(file)
|
44
|
+
File.size(file).positive? && IO.read(file, 4).force_encoding('utf-8') == "\x89PNG"
|
45
|
+
end
|
46
|
+
|
47
|
+
def bad_tile?(tile)
|
48
|
+
!png?(tile) || File.size(tile) == @control_size && system("cmp #{tile} #{app_root}/no_image.png")
|
49
|
+
end
|
50
|
+
|
51
|
+
# bad_tiles structure:
|
52
|
+
# { "t_2019-11-11T0240": [ [ [tile_url_1, tile_url_2, tile_url_3] ], [array_of_tiles], [array_of_tiles] ] }
|
53
|
+
def recover_bad_sectors(bad_tiles)
|
54
|
+
bad_tiles.each do |bad_pic_name, sectors|
|
55
|
+
pic_not_good = true
|
56
|
+
|
57
|
+
if sectors.count >= resolution # don't try to fix/recover pics that have too many pieces missing
|
58
|
+
puts "#{bad_pic_name} has #{sectors.count} pieces missing. Too many. Can't recover & will delete the whole thing!"
|
59
|
+
else
|
60
|
+
puts "#{bad_pic_name} has #{sectors.count} pieces missing. Will try to recover/fill in with older data."
|
61
|
+
p sectors
|
62
|
+
tile = "#{data_path}/#{bad_pic_name}-#{sectors[0][-3, 3]}.png"
|
63
|
+
sectors.each do |bad_tile|
|
64
|
+
`curl -sC - "#{HIMAWARI_URL}/#{resolution}d/550/#{bad_tile}.png" > #{tile}`
|
65
|
+
if bad_tile?(tile) # yep, it's bad...
|
66
|
+
# File.delete(tile)
|
67
|
+
pic_not_good = true
|
68
|
+
else
|
69
|
+
puts "#{tile} was recovered using #{bad_tile}!"
|
70
|
+
pic_not_good = false
|
71
|
+
break
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
# either too many pieces missing, or couldn't recover the wholes. It will look UGLY after reassembly,
|
76
|
+
# so just bite the bullet and get rid of the whole thing
|
77
|
+
`rm #{data_path}/#{bad_pic_name}*` if pic_not_good
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/spec/test_base.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
class TestBase < HimawariTest
|
6
|
+
# Firstly, let's check our params sanity...
|
7
|
+
def test_bad_params
|
8
|
+
bad_params = [
|
9
|
+
{ resolution: 5 },
|
10
|
+
{ focus: :bad },
|
11
|
+
{ mode: 'live' },
|
12
|
+
{ blacklist: 'live' },
|
13
|
+
{ destination: '/definitely/a/bad_path' }
|
14
|
+
]
|
15
|
+
bad_combos = (1..bad_params.count).flat_map { |length| bad_params.combination(length).to_a }
|
16
|
+
|
17
|
+
bad_combos.each do |params|
|
18
|
+
params = (params + [{ workdir: @@workdir }]).reduce({}, :merge)
|
19
|
+
|
20
|
+
# out = \
|
21
|
+
capture_stdout do
|
22
|
+
puts params
|
23
|
+
assert_equal false, @himawari.new(params).params_valid?
|
24
|
+
end
|
25
|
+
# puts out
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_up_to_date
|
30
|
+
h = @himawari.new({ workdir: @@workdir })
|
31
|
+
assert_equal false, h.up_to_date?
|
32
|
+
|
33
|
+
h.latest_local[:timestamp] = Time.now - 300 # 300 == 5.minutes
|
34
|
+
assert_equal true, h.up_to_date?
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_set_background
|
38
|
+
destination = "#{@@workdir}/data/selected_background"
|
39
|
+
Dir.mkdir(destination) unless File.exist?(destination)
|
40
|
+
|
41
|
+
h = @himawari.new({ workdir: @@workdir, destination: destination })
|
42
|
+
sample = Dir["#{h.data_path}/h_*.png"].sample
|
43
|
+
|
44
|
+
assert_equal !sample.nil?, h.background(sample)
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_cron
|
48
|
+
cmd = @himawari.new({ workdir: @@workdir }).crontab(:set)
|
49
|
+
assert_equal true, `crontab -l | grep \"#{cmd}\"`.size.positive?
|
50
|
+
|
51
|
+
@himawari.new({ workdir: @@workdir }).crontab(:clear)
|
52
|
+
assert_equal true, `crontab -l | grep \"#{cmd}\"`.empty?
|
53
|
+
end
|
54
|
+
end
|
data/spec/test_helper.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require_relative '../lib/himawari.rb'
|
5
|
+
|
6
|
+
class HimawariTest < Minitest::Test
|
7
|
+
# rubocop:disable Style/ClassVars
|
8
|
+
@@workdir = Pathname.new(File.expand_path(__dir__))
|
9
|
+
# rubocop:enable Style/ClassVars
|
10
|
+
|
11
|
+
def setup
|
12
|
+
@himawari = Himawari::Download
|
13
|
+
date1 = Time.parse('2019-01-01 00:00:00 +00:00')
|
14
|
+
date2 = Time.parse('2020-06-01 00:00:00 +00:00')
|
15
|
+
@timestamp = Time.at((date2.to_f - date1.to_f) * rand + date1.to_f)
|
16
|
+
|
17
|
+
# 1200secs == 20.minutes 02:40 and 14:40 are "bad" timestamps because
|
18
|
+
# we know 100% that himawari does not take photos at those times
|
19
|
+
@timestamp -= 1200 if @timestamp.min == 40 && [2, 14].include?(@timestamp.hour)
|
20
|
+
end
|
21
|
+
|
22
|
+
# def teardown
|
23
|
+
# puts 'run after each test'
|
24
|
+
# end
|
25
|
+
|
26
|
+
def capture_stdout
|
27
|
+
original_stdout = $stdout # capture previous value of $stdout
|
28
|
+
$stdout = StringIO.new # assign a string buffer to $stdout
|
29
|
+
yield # perform the body of the user code
|
30
|
+
$stdout.string # return the contents of the string buffer
|
31
|
+
ensure
|
32
|
+
$stdout = original_stdout # restore $stdout to its previous value
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.cleanup
|
36
|
+
puts "Cleanup: Removing #{@@workdir}/data"
|
37
|
+
`rm -r #{@@workdir}/data*` if File.directory?("#{@@workdir}/data")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
HimawariTest.cleanup
|
42
|
+
Minitest.after_run { HimawariTest.cleanup }
|
data/spec/test_net.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
class TestNet < HimawariTest
|
6
|
+
# Do the main methods function w/o crashing?
|
7
|
+
def test_get_pic
|
8
|
+
puts "Try to get a pic from #{@timestamp}"
|
9
|
+
assert_equal true, Himawari.get_pic(datetime: @timestamp, workdir: @@workdir)
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_get_pic_blacklisted_wifi
|
13
|
+
current_wifi = if Himawari::OsUtils.os == :mac
|
14
|
+
`networksetup -getairportnetwork en0`
|
15
|
+
elsif Himawari::OsUtils.os == :linux
|
16
|
+
`iwgetid -r`
|
17
|
+
end
|
18
|
+
|
19
|
+
capture_stdout do
|
20
|
+
assert_equal false, Himawari.get_pic(datetime: @timestamp, workdir: @@workdir, blacklist: [current_wifi])
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_get_pics
|
25
|
+
puts "Try to get pics in #{@timestamp} ~ #{@timestamp + 3600 * 2}"
|
26
|
+
assert_equal true, Himawari.get_pics(from: @timestamp, to: @timestamp + 3600 * 2, workdir: @@workdir)
|
27
|
+
end
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: himawari
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- engura
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-12-15 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: httparty
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.17.3
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.17.3
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 2.1.4
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 2.1.4
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 5.14.0
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 5.14.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.13.1
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.13.1
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 13.0.1
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 13.0.1
|
83
|
+
description: Makes pretty, high-res backgrounds from the real-time photos of Earth
|
84
|
+
by Himawari8,or is intended for similar personal usage. Please see the readme for
|
85
|
+
more!
|
86
|
+
email:
|
87
|
+
- engura@gmail.com
|
88
|
+
executables:
|
89
|
+
- himawari
|
90
|
+
extensions: []
|
91
|
+
extra_rdoc_files: []
|
92
|
+
files:
|
93
|
+
- ".gitignore"
|
94
|
+
- ".rubocop.yml"
|
95
|
+
- Gemfile
|
96
|
+
- Gemfile.lock
|
97
|
+
- LICENSE
|
98
|
+
- README.md
|
99
|
+
- Rakefile
|
100
|
+
- bin/setup
|
101
|
+
- doc/img/h_2020-06-01T0100.png
|
102
|
+
- doc/img/h_2020-11-29T0110.png
|
103
|
+
- doc/img/t_2020-12-01T0410-1_0.png
|
104
|
+
- exe/himawari
|
105
|
+
- himawari.gemspec
|
106
|
+
- lib/himawari.rb
|
107
|
+
- lib/himawari/base.rb
|
108
|
+
- lib/himawari/download.rb
|
109
|
+
- lib/himawari/net_utils.rb
|
110
|
+
- lib/himawari/no_image.png
|
111
|
+
- lib/himawari/os_utils.rb
|
112
|
+
- lib/himawari/process.rb
|
113
|
+
- spec/test_base.rb
|
114
|
+
- spec/test_helper.rb
|
115
|
+
- spec/test_net.rb
|
116
|
+
homepage: https://github.com/engura/himawari
|
117
|
+
licenses:
|
118
|
+
- MIT
|
119
|
+
metadata: {}
|
120
|
+
post_install_message: |-
|
121
|
+
Thanks for installing! Have fun with the amazing pics of our Home made
|
122
|
+
accessible to us for FREE by NICT. And please, don't break their website!!
|
123
|
+
rdoc_options: []
|
124
|
+
require_paths:
|
125
|
+
- lib
|
126
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - ">="
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
131
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
132
|
+
requirements:
|
133
|
+
- - ">="
|
134
|
+
- !ruby/object:Gem::Version
|
135
|
+
version: '0'
|
136
|
+
requirements:
|
137
|
+
- 'Mac OSX or Linux... Windows `not supported yet` due to the lack of the following:'
|
138
|
+
- parallel, ~>20161222 (Let's download in parallel)
|
139
|
+
- ImageMagick, ~>6.9.10-23 (Specifically, the `montage` utility)
|
140
|
+
- 'common utilities: find, touch, crontab, curl, iwgetid, rm, bash'
|
141
|
+
rubyforge_project:
|
142
|
+
rubygems_version: 2.7.6.2
|
143
|
+
signing_key:
|
144
|
+
specification_version: 4
|
145
|
+
summary: Grabs latest images from the himawari8 weather satellite
|
146
|
+
test_files:
|
147
|
+
- spec/test_base.rb
|
148
|
+
- spec/test_helper.rb
|
149
|
+
- spec/test_net.rb
|