You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
141 lines
3.7 KiB
141 lines
3.7 KiB
require 'delegate'
|
|
require 'erb'
|
|
require 'yaml'
|
|
|
|
require_relative 'alfred'
|
|
require_relative 'forecaster'
|
|
require_relative 'location'
|
|
require_relative 'spark'
|
|
|
|
ICONS = {
|
|
'clear-day' => 'Sun',
|
|
'clear-night' => 'Moon',
|
|
'rain' => 'Cloud-Rain',
|
|
'snow' => 'Cloud-Snow',
|
|
'sleet' => 'Cloud-Snow-Alt',
|
|
'wind' => 'Wind',
|
|
'fog' => 'Cloud-Fog',
|
|
'cloudy' => 'Cloud',
|
|
'partly-cloudy-day' => 'Cloud-Sun',
|
|
'partly-cloudy-night' => 'Cloud-Moon',
|
|
}
|
|
|
|
Precipitation = Struct.new(:intensity, :probability) do
|
|
def self.from_forecast(forecast)
|
|
self.new(*forecast.values_at('precipIntensity', 'precipProbability'))
|
|
end
|
|
|
|
def human_intensity
|
|
case intensity
|
|
when 0...0.002
|
|
'no'
|
|
when 0.002...0.017
|
|
'very light'
|
|
when 0.017...0.1
|
|
'light'
|
|
when 0.1...0.4
|
|
'moderate'
|
|
else
|
|
'heavy'
|
|
end
|
|
end
|
|
|
|
def to_s
|
|
"#{(probability*100).to_i}% chance of #{human_intensity} rain."
|
|
end
|
|
end
|
|
|
|
query = ARGV.shift || ''
|
|
location = if query.empty?
|
|
lat, long = Alfred::Config['DEFAULT_LAT_LONG'].split(?,).map(&:to_f)
|
|
Location.new(Alfred::Config['DEFAULT_LOCATION'], lat, long)
|
|
else
|
|
Location.new(query)
|
|
end
|
|
forecast = Forecaster.forecast(location)
|
|
|
|
items = Items.new
|
|
|
|
items << Item.new(
|
|
uid: :location,
|
|
arg: "#{location.lat.round(4)},#{location.long.round(4)}",
|
|
valid: true,
|
|
title: location.name,
|
|
icon: 'icons/forecast.ico',
|
|
)
|
|
|
|
currently = forecast['currently']
|
|
precip = Precipitation.from_forecast(currently)
|
|
subtitle = [ "#{currently['temperature'].round}°" ]
|
|
subtitle << "Feels like #{currently['apparentTemperature'].round}°"
|
|
subtitle << precip.to_s if precip.probability > 0
|
|
items << Item.new(
|
|
uid: :currently,
|
|
title: currently['summary'],
|
|
subtitle: subtitle.join(' · '),
|
|
icon: "icons/#{ICONS[currently['icon']]}.png",
|
|
)
|
|
|
|
minutely = forecast['minutely']
|
|
if minutely
|
|
intensity = minutely['data'].map {|m| m['precipIntensity'] }
|
|
intensity = intensity.select.with_index {|_,i| i % 4 == 0 }
|
|
min, max = intensity.minmax
|
|
intensity = intensity.map {|i| 1000 * i }
|
|
|
|
subtitle = ["#{min.round(3)}\" #{Spark.new(intensity)} #{max.round(3)}\""]
|
|
|
|
probability = minutely['data'].map {|m| (100 * m['precipProbability']).round }
|
|
probability = probability.select.with_index {|_,i| i % 5 == 0 }
|
|
min, max = probability.minmax
|
|
|
|
subtitle << "#{min}% #{Spark.new(probability, max: 100)} #{max}%"
|
|
|
|
items << Item.new(
|
|
uid: :minutely,
|
|
title: minutely['summary'],
|
|
subtitle: subtitle.join(' · '),
|
|
icon: "icons/#{ICONS[minutely['icon']]}.png",
|
|
)
|
|
end
|
|
|
|
hourly = forecast['hourly']
|
|
|
|
intensity = hourly['data'].map {|m| m['precipIntensity'] }
|
|
intensity = intensity.select.with_index {|_,i| i % 4 == 0 }
|
|
min, max = intensity.minmax
|
|
intensity = intensity.map {|i| 1000 * i }
|
|
|
|
subtitle = ["#{min.round(3)}\" #{Spark.new(intensity)} #{max.round(3)}\""]
|
|
|
|
probability = hourly['data'].map {|m| (100 * m['precipProbability']).round }
|
|
probability = probability.select.with_index {|_,i| i % 4 == 0 }
|
|
min, max = probability.minmax
|
|
|
|
subtitle << "#{min}% #{Spark.new(probability, max: 100)} #{max}%"
|
|
|
|
items << Item.new(
|
|
uid: :hourly,
|
|
title: hourly['summary'],
|
|
subtitle: subtitle.join(' · '),
|
|
icon: "icons/#{ICONS[hourly['icon']]}.png",
|
|
)
|
|
|
|
forecast['daily']['data'][1..6].each do |data|
|
|
wday = Time.at(data['time']).strftime('%A')
|
|
precip = Precipitation.from_forecast(data)
|
|
|
|
subtitle = [ "Low: #{data['apparentTemperatureMin'].round}°",
|
|
"High: #{data['apparentTemperatureMax'].round}°" ]
|
|
subtitle << precip.to_s if precip.probability > 0
|
|
|
|
items << Item.new(
|
|
uid: wday,
|
|
title: "#{wday} - #{data['summary']}",
|
|
subtitle: subtitle.join(' · '),
|
|
icon: "icons/#{ICONS[data['icon']]}.png",
|
|
)
|
|
end
|
|
|
|
puts items.to_s
|