astropanel 2.3 → 2.6

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.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/bin/astropanel +103 -68
  3. metadata +4 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: de884bc4fb426c44911a873006857920bd52313fcd5ac719578a4bc3357877a6
4
- data.tar.gz: b367c2e2ba020f6bf3cd982da21d9cec58bce2d9e3598afca28d19ab0108e53d
3
+ metadata.gz: 939fa439565527c2c8b9f0ce4e1e13ab008bd3c23f153efd9e2e01d65a50fe45
4
+ data.tar.gz: 368bbb21a445bfff885cbf6a9b1f526fe11531cdb9be1ad0ad02760ca5818416
5
5
  SHA512:
6
- metadata.gz: fd9cc4447bf4900d393986a317daf171cc460dbbed69fc3debcb8d90115e1dcc6d37fc3f3bb7bc8d66c13770adbcc7daee90372e74b56d515e3f3c19082c03b5
7
- data.tar.gz: 57eadc094de148690f8a3a2b60c52c3933730a8a127f6b7a9d8ed7da70009833bbbdce88ee73caf0f72ca8db9ef69adf298fcd421d3e3c274785d96d1e55f3dc
6
+ metadata.gz: f393f7af8500905358502ef1a78b1e9c3808e883f8febc21bec01f84221b101fd00a305a5e7c6d522baf1fcf1343e9f9c42765fc542e2b673d925739880fa272
7
+ data.tar.gz: dd1447a1e2c3cc56f4e4d30e5284d0ceef71bc45e2dae203017b054789e4c3bbcb6ef826a682751bb39198a543c26203b03088571765ede52211e1fc1b5c5148
data/bin/astropanel CHANGED
@@ -14,7 +14,7 @@
14
14
  # for any damages resulting from its use. Further, I am under no
15
15
  # obligation to maintain or extend this software. It is provided
16
16
  # on an 'as is' basis without any expressed or implied warranty.
17
- # Version: 2.3: Greaceful exit when networks is down
17
+ # Version: 2.6: Bug fix
18
18
 
19
19
  # LOAD MODULES {{{1
20
20
  require 'io/console'
@@ -31,9 +31,6 @@ include Rcurses::Input
31
31
  include Rcurses::Cursor
32
32
 
33
33
  # BASIC SETUP {{{1
34
- $stdin.raw!
35
- $stdin.echo = false
36
-
37
34
  CONFIG_FILE = File.join(Dir.home, '.ap.conf')
38
35
 
39
36
  # CLASS EXTENSIONS {{{1
@@ -56,13 +53,6 @@ class String # {{{2
56
53
  end
57
54
  end
58
55
 
59
- # AT_EXIT {{{1
60
- at_exit do
61
- $stdin.cooked!
62
- $stdin.echo = true
63
- Rcurses.clear_screen
64
- Cursor.show
65
- end
66
56
 
67
57
  # EPHEMERIS CORE {{{1
68
58
  class Ephemeris
@@ -728,27 +718,40 @@ class AstroPanelApp
728
718
  @header.say(txt.ljust(cols))
729
719
  end
730
720
 
731
- def update_titles # {{{2
721
+ # Update the top‐bar title line, safely handling missing planet data
722
+ def update_titles
732
723
  _, cols = IO.console.winsize
733
724
 
734
- title = " …#{@cloudlimit}% …#{@humiditylimit}% "\
735
- "#{@templimit}°C… …#{@windlimit}m/s".fg(244)
725
+ # Base limits display
726
+ title = " …#{@cloudlimit}% …#{@humiditylimit}% " \
727
+ "#{@templimit}°C… …#{@windlimit}m/s".fg(244)
736
728
 
737
- date = @weather[@index][:date]
738
- hr = @weather[@index][:hour]
739
- col = cond_color(@index)
740
-
741
- # fetch this day's moon info (illumination % and phase name)
742
- mp, mp_name = @planets[date].values_at(:mphase, :mph_s)
729
+ # Current date/hour
730
+ if @weather[@index]
731
+ date = @weather[@index][:date]
732
+ hr = @weather[@index][:hour]
733
+ col = cond_color(@index)
734
+ else
735
+ date = nil
736
+ hr = nil
737
+ col = 244
738
+ end
743
739
 
744
740
  title << ' ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ '.fg(244)
745
- title << "#{date} (#{Date.parse(date).strftime("%A")}) #{hr}:00".b.fg(col)
746
- title << " Moon: #{mp_name} (#{mp}%)".fg(244)
741
+ title << "#{date}#{ date ? " (#{Date.parse(date).strftime("%A")}) #{hr}:00" : ""}".b.fg(col)
742
+
743
+ # Safely fetch moon‐phase info (mphase/mph_s) if it exists
744
+ if date && (pd = @planets[date])
745
+ mp, mp_name = pd.values_at(:mphase, :mph_s)
746
+ title << " Moon: #{mp_name} (#{mp}%)".fg(244)
747
+ else
748
+ title << " Moon: unavailable".fg(244)
749
+ end
747
750
 
751
+ @titles.clear
748
752
  @titles.say(title.ljust(cols))
749
753
  end
750
754
 
751
-
752
755
  def update_footer # {{{2
753
756
  _, cols = IO.console.winsize
754
757
  cmds = "?=Help l=Loc a=Lat o=Lon c=Cloud h=Hum t=Temp w=Wind b=Bortle " \
@@ -758,70 +761,81 @@ class AstroPanelApp
758
761
  end
759
762
 
760
763
  def update_left # {{{2
761
- # build an array of all lines
762
- date_n = date_n = ''
763
- all_lines = @weather.each_with_index.map do |w,i|
764
- col = cond_color(i) # choose row‐color
765
- mp = @planets[w[:date]][:mphase]
766
-
767
- # fixed‐width values tinted
768
- date_o = date_n
769
- date_n = w[:date]
770
- date_s = (date_n == date_o ? " ".ljust(10) : date_n)
771
- hour_s = w[:hour]
764
+ date_o = ''
765
+ date_n = ''
766
+
767
+ all_lines = @weather.each_with_index.map do |w, i|
768
+ col = cond_color(i)
769
+
770
+ # Safely fetch planet data for this date (may be nil)
771
+ pd = @planets[w[:date]] || {}
772
+ mp = pd[:mphase]
773
+
774
+ # Prepare date display, only show the date when it changes
775
+ date_o = date_n
776
+ date_n = w[:date]
777
+ date_s = (date_n == date_o ? ' '.ljust(10) : date_n)
778
+
779
+ # Fixed‐width weather columns
780
+ hour_s = w[:hour]
772
781
  cloud_s = "#{w[:cloud]}%".rjust(4)
773
782
  hum_s = "#{w[:humidity]}%".rjust(5)
774
783
  tmp_s = "#{w[:temp]}°C".rjust(6)
775
784
  wnd_s = "#{w[:wind]}(#{w[:wdir]})".rjust(8)
776
785
 
777
- # start composing this row
786
+ # Build the left‐pane row
778
787
  row = "#{date_s} ".fg(col)
779
788
  ul = "#{hour_s} #{cloud_s} #{hum_s} #{tmp_s} #{wnd_s}".fg(col)
780
789
  ul = ul.u if i == @index
781
790
  row += ul
782
791
 
783
- # event marker
792
+ # Event marker
784
793
  if ev = @events[w[:date]] and ev[:time][0..1] == w[:hour]
785
794
  row += " !".fg(col)
786
795
  else
787
796
  row += " "
788
797
  end
789
798
 
790
- # one‐space‐prefixed visibility blocks
791
- BODIES.each_with_index do |b,i|
792
- rise = @planets[w[:date]][:"#{b}_rise"][0..1].to_i rescue nil
793
- set = @planets[w[:date]][:"#{b}_set"][0..1].to_i rescue nil
794
- hr = w[:hour].to_i
795
-
796
- above = if rise.nil? || set.nil?
797
- false
798
- elsif rise > set
799
- hr >= rise || hr <= set
799
+ # Visibility blocks for Sun, Moon & planets
800
+ BODIES.each_with_index do |b, j|
801
+ # Extract just the hour component from rise/set, convert to Integer
802
+ rise_h = pd[:"#{b}_rise"] ? pd[:"#{b}_rise"][0..1].to_i : nil
803
+ set_h = pd[:"#{b}_set"] ? pd[:"#{b}_set"][0..1].to_i : nil
804
+ hr = w[:hour].to_i
805
+
806
+ above = if rise_h.nil? || set_h.nil?
807
+ false
808
+ elsif rise_h > set_h
809
+ (hr >= rise_h) || (hr <= set_h)
810
+ else
811
+ (hr >= rise_h) && (hr <= set_h)
812
+ end
813
+
814
+ # Choose block character and color
815
+ block_char = (0..1) === j ? '█' : '┃'
816
+ if above
817
+ color = (b == 'moon' ? moon_phase_color(mp) : BODY_COLORS[b])
818
+ block = block_char.fg(color)
800
819
  else
801
- hr >= rise && hr <= set
820
+ block = ' '
802
821
  end
803
- block = above ? ((0..1) === i ? '█' : '┃').fg(b == 'moon' ? moon_phase_color(mp) : BODY_COLORS[b]) : ' '
822
+
804
823
  row << " #{block}"
805
824
  end
806
825
 
807
826
  row
808
827
  end
809
828
 
810
- # stash into the left pane’s buffer
829
+ # Write into the pane buffer and center the selection
811
830
  @left.text = all_lines.join("\n")
831
+ height = @left.h
812
832
 
813
- # figure out how many rows we can show
814
- height = @left.h
815
-
816
- # center the selection (3-row “scroll‐off”)…
817
833
  top = @index - (height / 2)
818
834
  top = 0 if top < 0
819
835
  max_top = all_lines.size - height
820
836
  top = max_top if top > max_top
821
837
 
822
838
  @left.ix = top
823
-
824
- # redraw just the left pane
825
839
  @left.refresh
826
840
  end
827
841
 
@@ -914,11 +928,23 @@ class AstroPanelApp
914
928
  end
915
929
 
916
930
  def get_weather # {{{2
931
+ # Fetch weather from met.no, but never let network errors crash the app
917
932
  uri = URI("https://api.met.no/weatherapi/locationforecast/2.0/complete?lat=#{@lat}&lon=#{@lon}")
918
933
  req = Net::HTTP::Get.new(uri)
919
934
  req['User-Agent'] = 'astropanel/1.0 g@isene.com'
920
- res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
921
-
935
+
936
+ begin
937
+ res = Net::HTTP.start(uri.hostname, uri.port,
938
+ use_ssl: true,
939
+ read_timeout: 10) do |http|
940
+ http.request(req)
941
+ end
942
+ rescue SocketError, Socket::ResolutionError, Timeout::Error, Net::OpenTimeout => e
943
+ @footer.say("⚠️ Weather fetch failed: #{e.class}: #{e.message}")
944
+ @weather = []
945
+ return
946
+ end
947
+
922
948
  if res.is_a?(Net::HTTPSuccess)
923
949
  series = JSON.parse(res.body)
924
950
  .dig('properties','timeseries') || []
@@ -939,7 +965,7 @@ class AstroPanelApp
939
965
  }
940
966
  end
941
967
  else
942
- @footer.say("Weather API error: #{res.code} #{res.message}")
968
+ @footer.say("⚠️ Weather API error: #{res.code} #{res.message}")
943
969
  @weather = []
944
970
  end
945
971
  end
@@ -985,25 +1011,34 @@ class AstroPanelApp
985
1011
  end
986
1012
 
987
1013
  def get_planets # {{{2
1014
+ # Build @planets entries for each unique date in @weather
988
1015
  @planets.clear
989
- 12.times do |i|
990
- date = (Date.today + i).strftime('%F')
991
- ep = Ephemeris.new(date,@lat,@lon,@tz.to_i)
1016
+
1017
+ # Collect exactly the dates we need (in first-seen order)
1018
+ dates = @weather.map { |w| w[:date] }.uniq
1019
+
1020
+ dates.each do |date|
1021
+ # Compute a fresh Ephemeris for that date
1022
+ ep = Ephemeris.new(date, @lat, @lon, @tz.to_i)
1023
+
1024
+ # Start with the printed table + moon phase info
992
1025
  entry = {
993
1026
  table: ep.print,
994
- mphase: ep.mphase, # e.g. 67.4
995
- mph_s: ep.mph_s # e.g. "Waxing gibbous"
1027
+ mphase: ep.mphase,
1028
+ mph_s: ep.mph_s
996
1029
  }
997
- Ephemeris::BODY_ORDER.each do |b|
998
- arr = ep.send(b)
999
- entry[:"#{b}_rise"] = arr[5]
1000
- entry[:"#{b}_set"] = arr[7]
1030
+
1031
+ # Add rise/set times for each body
1032
+ Ephemeris::BODY_ORDER.each do |body|
1033
+ arr = ep.send(body)
1034
+ entry[:"#{body}_rise"] = arr[5]
1035
+ entry[:"#{body}_set"] = arr[7]
1001
1036
  end
1037
+
1002
1038
  @planets[date] = entry
1003
1039
  end
1004
1040
  end
1005
1041
 
1006
-
1007
1042
  def get_events # {{{2
1008
1043
  @events.clear
1009
1044
  uri = URI(
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: astropanel
3
3
  version: !ruby/object:Gem::Version
4
- version: '2.3'
4
+ version: '2.6'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Geir Isene
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-05-11 00:00:00.000000000 Z
11
+ date: 2025-05-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rcurses
@@ -28,8 +28,8 @@ description: 'This program shows essential data in order to plan your observatio
28
28
  9 days weather forecast, full ephemeris for the Sun, the Moon and all major planets,
29
29
  complete with graphic representation of rise/set times, detailed info for each day
30
30
  with important astronomical events, star chart displayed in the terminal and more.
31
- New in 2.0: Full rewrite using rcurses (https://github.com/isene/rcurses). 2.3:
32
- Greaceful exit when networks is down.'
31
+ New in 2.0: Full rewrite using rcurses (https://github.com/isene/rcurses). 2.6:
32
+ Bug fix.'
33
33
  email: g@isene.com
34
34
  executables:
35
35
  - astropanel