mockturtl / cinnamon-weather

DEPRECATED. Use linuxmint/cinnamon-spices-applets instead.
https://cinnamon-spices.linuxmint.com/applets/view/17
28 stars 35 forks source link

Stop Work in Cinnamon 2.8.8 #147

Closed iksws closed 8 years ago

iksws commented 8 years ago

Your applet stop working in cinnamon 2.8.8 well I need this weather infos hehe I look your code and I think yahoo weather change API I make some changes in your code and working now :D but I change WOEID and now i not get more XML get pure JSON

not more 4 leters and 4 numbers, now is only number of the city in geodata! After my WOEID is BRXX0043 now my WOEID in applet conf is 27455819 I use this link to get my id http://woeid.rosselliot.co.nz/lookup/brasilia well is it!

FULL CODE CHANGED

//"use strict"

//----------------------------------
// imports
//----------------------------------

/**
 * /usr/share/gjs-1.0/
 * /usr/share/gnome-js/
 */
const Cairo = imports.cairo
const Lang = imports.lang
// http://developer.gnome.org/glib/unstable/glib-The-Main-Event-Loop.html
const Mainloop = imports.mainloop

/**
 * /usr/share/gjs-1.0/overrides/
 * /usr/share/gir-1.0/
 * /usr/lib/cinnamon/
 */
const Gio = imports.gi.Gio
const Gtk = imports.gi.Gtk
const Json = imports.gi.Json
// http://developer.gnome.org/libsoup/stable/libsoup-client-howto.html
const Soup = imports.gi.Soup
// http://developer.gnome.org/st/stable/
const St = imports.gi.St

/**
 * /usr/share/cinnamon/js/
 */
const Applet = imports.ui.applet
const Config = imports.misc.config
const PopupMenu = imports.ui.popupMenu
const Settings = imports.ui.settings
const Util = imports.misc.util

//----------------------------------------------------------------------
//
// Constants
//
//----------------------------------------------------------------------

const UUID = "weather@mockturtl"
const APPLET_ICON = "view-refresh-symbolic"
const CMD_SETTINGS = "cinnamon-settings applets " + UUID
const WOEID_URL = "http://edg3.co.uk/snippets/weather-location-codes/"
const CMD_WOEID_LOOKUP = "xdg-open " + WOEID_URL

// Conversion Factors
const WEATHER_CONV_MPH_IN_MPS = 2.23693629
const WEATHER_CONV_KPH_IN_MPS = 3.6
const WEATHER_CONV_KNOTS_IN_MPS = 1.94384449

// Magic strings
const BLANK = '   '
const ELLIPSIS = '...'
const EN_DASH = '\u2013'

// Query
//const QUERY_PARAMS = '?format=json&q=select '
//const QUERY_TABLE = 'feednormalizer where url="http://xml.weather.yahoo.com/forecastrss/'
//const QUERY_VIEW = '*'
//const QUERY_URL = 'http://query.yahooapis.com/v1/public/yql' + QUERY_PARAMS + QUERY_VIEW + ' from ' + QUERY_TABLE
//const QUERY_URL = 'https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20=%20%27455819%27&format=json'

// Schema keys
const WEATHER_CITY_KEY = 'locationLabelOverride'
const WEATHER_REFRESH_INTERVAL = 'refreshInterval'
const WEATHER_SHOW_COMMENT_IN_PANEL_KEY = 'showCommentInPanel'
const WEATHER_SHOW_SUNRISE_KEY = 'showSunrise'
const WEATHER_SHOW_24HOURS_KEY = 'show24Hours'
const WEATHER_SHOW_FIVEDAY_FORECAST_KEY = 'showFivedayForecast'
const WEATHER_SHOW_TEXT_IN_PANEL_KEY = 'showTextInPanel'
const WEATHER_TRANSLATE_CONDITION_KEY = 'translateCondition'
const WEATHER_TEMPERATURE_UNIT_KEY = 'temperatureUnit'
const WEATHER_PRESSURE_UNIT_KEY = 'pressureUnit'
const WEATHER_USE_SYMBOLIC_ICONS_KEY = 'useSymbolicIcons'
const WEATHER_WIND_SPEED_UNIT_KEY = 'windSpeedUnit'
const WEATHER_WOEID_KEY = 'woeid'

const KEYS = [
  WEATHER_TEMPERATURE_UNIT_KEY,
  WEATHER_WIND_SPEED_UNIT_KEY,
  WEATHER_CITY_KEY,
  WEATHER_WOEID_KEY,
  WEATHER_TRANSLATE_CONDITION_KEY,
  WEATHER_SHOW_TEXT_IN_PANEL_KEY,
  WEATHER_SHOW_COMMENT_IN_PANEL_KEY,
  WEATHER_SHOW_SUNRISE_KEY,
  WEATHER_SHOW_24HOURS_KEY,
  WEATHER_SHOW_FIVEDAY_FORECAST_KEY,
  WEATHER_REFRESH_INTERVAL,
  WEATHER_PRESSURE_UNIT_KEY
]

// Signals
const SIGNAL_CHANGED = 'changed::'
const SIGNAL_CLICKED = 'clicked'
const SIGNAL_REPAINT = 'repaint'

// stylesheet.css
const STYLE_LOCATION_LINK = 'weather-current-location-link'
const STYLE_SUMMARYBOX = 'weather-current-summarybox'
const STYLE_SUMMARY = 'weather-current-summary'
const STYLE_DATABOX = 'weather-current-databox'
const STYLE_ICON = 'weather-current-icon'
const STYLE_ICONBOX = 'weather-current-iconbox'
const STYLE_DATABOX_CAPTIONS = 'weather-current-databox-captions'
const STYLE_ASTRONOMY = 'weather-current-astronomy'
const STYLE_FORECAST_ICON = 'weather-forecast-icon'
const STYLE_FORECAST_DATABOX = 'weather-forecast-databox'
const STYLE_FORECAST_DAY = 'weather-forecast-day'
const STYLE_CONFIG = 'weather-config'
const STYLE_DATABOX_VALUES = 'weather-current-databox-values'
const STYLE_FORECAST_SUMMARY = 'weather-forecast-summary'
const STYLE_FORECAST_TEMPERATURE = 'weather-forecast-temperature'
const STYLE_FORECAST_BOX = 'weather-forecast-box'
const STYLE_PANEL_BUTTON = 'panel-button'
const STYLE_POPUP_SEPARATOR_MENU_ITEM = 'popup-separator-menu-item'
const STYLE_CURRENT = 'current'
const STYLE_FORECAST = 'forecast'
const STYLE_WEATHER_MENU = 'weather-menu'

const WeatherUnits = {
  CELSIUS: 'celsius',
  FAHRENHEIT: 'fahrenheit'
}

const WeatherWindSpeedUnits = {
  KPH: 'kph',
  MPH: 'mph',
  MPS: 'm/s',
  KNOTS: 'knots'
}

const WeatherPressureResponseUnits = {
  MBAR: 'mb',
  PSI: 'in'
}

const WeatherPressureUnits = {
  MBAR: 'mbar',
  MMHG: 'mm Hg',
  INHG: 'in Hg',
  PA: 'Pa',
  KPA: 'kPa',
  PSI: 'psi',
  ATM: 'atm',
  AT: 'at'
}

// Pressure conversion factors
const WEATHER_CONV_KPA_IN_MBAR = 0.1
const WEATHER_CONV_PA_IN_MBAR = 100
const WEATHER_CONV_MMHG_IN_MBAR = 750.0615613e-3
const WEATHER_CONV_INHG_IN_MBAR = 2.952998307e-2
const WEATHER_CONV_AT_IN_MBAR = 1.019716213e-3
const WEATHER_CONV_ATM_IN_MBAR = 0.986923169e-3
const WEATHER_CONV_PSI_IN_MBAR = 14.5037738e-3

const WEATHER_CONV_MBAR_IN_INHG = 3.3863886667e+1
const WEATHER_CONV_KPA_IN_INHG = 3.386389
const WEATHER_CONV_PA_IN_INHG = 3.386389e+3
const WEATHER_CONV_MMHG_IN_INHG = 25.4
const WEATHER_CONV_PSI_IN_INHG = 491.154152e-3
const WEATHER_CONV_AT_IN_INHG = 34.531554e-3
const WEATHER_CONV_ATM_IN_INHG = 33.421054e-3

//----------------------------------------------------------------------
//
// Soup
//
//----------------------------------------------------------------------

// Soup session (see https://bugzilla.gnome.org/show_bug.cgi?id=661323#c64)
const _httpSession = new Soup.SessionAsync()
Soup.Session.prototype.add_feature.call(_httpSession, new Soup.ProxyResolverDefault())

//----------------------------------------------------------------------
//
// Logging
//
//----------------------------------------------------------------------

function log(message) {
  global.log(UUID + "#" + log.caller.name + ": " + message)
}

function logError(error) {
  global.logError(UUID + "#" + logError.caller.name + ": " + error)
}

//----------------------------------------------------------------
//
// l10n
//
//----------------------------------------------------------------------

const GLib = imports.gi.GLib
const Gettext = imports.gettext
Gettext.bindtextdomain(UUID, GLib.get_home_dir() + "/.local/share/locale")

function _(str) {
  return Gettext.dgettext(UUID, str)
}

//----------------------------------------------------------------------
//
// MyApplet
//
//----------------------------------------------------------------------

function MyApplet(metadata, orientation, panelHeight, instanceId) {
  this.settings = new Settings.AppletSettings(this, UUID, instanceId)
  this._init(orientation, panelHeight, instanceId)
}

MyApplet.prototype = {
  __proto__: Applet.TextIconApplet.prototype

, refreshAndRebuild: function refreshAndRebuild() {
    this.refreshWeather(false)
    this.rebuild()
  }

, dumpKeys: function dumpKeys() {
    for (let k in KEYS) {
      let key = KEYS[k]
      let keyProp = "_" + key
      log(keyProp + "=" + this[keyProp])
    }
  }

, woeidLookup: function() {
    Util.spawnCommandLine(CMD_WOEID_LOOKUP)
  }

    // Override Methods: TextIconApplet
, _init: function _init(orientation, panelHeight, instanceId) {
    Applet.TextIconApplet.prototype._init.call(this, orientation, panelHeight, instanceId)

      // Interface: TextIconApplet
      this.set_applet_icon_name(APPLET_ICON)
      this.set_applet_label(_("..."))
      this.set_applet_tooltip(_("Click to open"))

      // PopupMenu
      this.menuManager = new PopupMenu.PopupMenuManager(this)
      this.menu = new Applet.AppletPopupMenu(this, orientation)
      this.menu.actor.add_style_class_name(STYLE_WEATHER_MENU)
      this.menuManager.addMenu(this.menu)

      //----------------------------------
      // bind settings
      //----------------------------------

      for (let k in KEYS) {
        let key = KEYS[k]
        let keyProp = "_" + key
        this.settings.bindProperty(Settings.BindingDirection.IN, key, keyProp,
                                   this.refreshAndRebuild, null)
      }
      //log("bound settings")

      this.updateIconType()

      this.settings.connect(SIGNAL_CHANGED + WEATHER_USE_SYMBOLIC_ICONS_KEY, Lang.bind(this, function() {
        this.updateIconType()
        this._applet_icon.icon_type = this._icon_type
        this._currentWeatherIcon.icon_type = this._icon_type
        let daysToShow = this._showFivedayForecast ? 5 : 2
        for (let i = 0; i < daysToShow; i++) {
          this._forecast[i].Icon.icon_type = this._icon_type
        }
        this.refreshWeather(false)
      }))

      // configuration via context menu is automatically provided in Cinnamon 2.0+
      let cinnamonVersion = Config.PACKAGE_VERSION.split('.')
      let majorVersion = parseInt(cinnamonVersion[0])
      //log("cinnamonVersion=" + cinnamonVersion +  "; majorVersion=" + majorVersion)

      // for Cinnamon 1.x, build a menu item
      if (majorVersion < 2) {
        let itemLabel = _("Settings")
        let settingsMenuItem = new Applet.MenuItem(itemLabel, Gtk.STOCK_EDIT, Lang.bind(this, function() {
            Util.spawnCommandLine(CMD_SETTINGS)
        }))
        this._applet_context_menu.addMenuItem(settingsMenuItem)
      }

      //------------------------------
      // render graphics container
      //------------------------------

      // build menu
      let mainBox = new St.BoxLayout({ vertical: true })
      this.menu.addActor(mainBox)

      //  today's forecast
      this._currentWeather = new St.Bin({ style_class: STYLE_CURRENT })
      mainBox.add_actor(this._currentWeather)

      //  horizontal rule
      this._separatorArea = new St.DrawingArea({ style_class: STYLE_POPUP_SEPARATOR_MENU_ITEM })
      this._separatorArea.width = 200
      this._separatorArea.connect(SIGNAL_REPAINT, Lang.bind(this, this._onSeparatorAreaRepaint))
      mainBox.add_actor(this._separatorArea)

      //  tomorrow's forecast
      this._futureWeather = new St.Bin({ style_class: STYLE_FORECAST })
      mainBox.add_actor(this._futureWeather)

      this.rebuild()

      //------------------------------
      // run
      //------------------------------
      Mainloop.timeout_add_seconds(3, Lang.bind(this, function mainloopTimeout() {
        this.refreshWeather(true)
      }))
   }

  // Override Methods: Applet
, on_applet_clicked: function on_applet_clicked(event) {
    this.menu.toggle()
  }

, _onSeparatorAreaRepaint: function onSeparatorAreaRepaint(area) {
    let cr = area.get_context()
    let themeNode = area.get_theme_node()
    let [width, height] = area.get_surface_size()
    let margin = themeNode.get_length('-margin-horizontal')
    let gradientHeight = themeNode.get_length('-gradient-height')
    let startColor = themeNode.get_color('-gradient-start')
    let endColor = themeNode.get_color('-gradient-end')
    let gradientWidth = (width - margin * 2)
    let gradientOffset = (height - gradientHeight) / 2
    let pattern = new Cairo.LinearGradient(margin, gradientOffset, width - margin, gradientOffset + gradientHeight)

    pattern.addColorStopRGBA(0, startColor.red / 255, startColor.green / 255, startColor.blue / 255, startColor.alpha / 255)
    pattern.addColorStopRGBA(0.5, endColor.red / 255, endColor.green / 255, endColor.blue / 255, endColor.alpha / 255)
    pattern.addColorStopRGBA(1, startColor.red / 255, startColor.green / 255, startColor.blue / 255, startColor.alpha / 255)
    cr.setSource(pattern)
    cr.rectangle(margin, gradientOffset, gradientWidth, gradientHeight)
    cr.fill()
  }

  //----------------------------------------------------------------------
  //
  // Methods
  //
  //----------------------------------------------------------------------

, updateIconType: function updateIconType() {
    this._icon_type = this.settings.getValue(WEATHER_USE_SYMBOLIC_ICONS_KEY) ?
                        St.IconType.SYMBOLIC :
                        St.IconType.FULLCOLOR
  }

, loadJsonAsync: function loadJsonAsync(url, callback) {
    let context = this
    let message = Soup.Message.new('GET', url)
    _httpSession.queue_message(message, function soupQueue(session, message) {
    //session.send_message (message);
    let jp = new Json.Parser()
    try{
      jp.load_from_data(message.response_body.data, -1)
    } catch(error) {
        logError(error)
    }

     callback.call(context, jp.get_root().get_object())
    })
  }

, parseDay: function(abr) {
    let yahoo_days = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']
    for (let i = 0; i < yahoo_days.length; i++) {
      if (yahoo_days[i].substr(0, abr.length) == abr.toLowerCase()) {
        return i
      }
    }
    return 0
  }

, refreshWeather: function refreshWeather(recurse) {
    //log("recurse=" + recurse)
    //this.dumpKeys()
   this.loadJsonAsync(this.weatherUrl(), function(json) {
      try {
       let weather = json.get_object_member('query').get_object_member('results').get_object_member('channel')
        let weather_c = weather.get_object_member('item').get_object_member('condition')
        let forecast = weather.get_object_member('item').get_array_member('forecast').get_elements()

        let location = weather.get_object_member('location').get_string_member('city')
        if (this.nonempty(this._locationLabelOverride))
          location = this._locationLabelOverride

        // Refresh current weather
        let comment = weather_c.get_string_member('text')
        if (this._translateCondition)
          comment = this.weatherCondition(weather_c.get_string_member('code'))

        let humidity = weather.get_object_member('atmosphere').get_string_member('humidity') + ' %'

        let pressure = weather.get_object_member('atmosphere').get_string_member('pressure')
        //let pressure_unit = weather.get_object_member('units').get_string_member('pressure')
        //log('pressure: ' + pressure + ' ' + pressure_unit)

        let sunrise = weather.get_object_member('astronomy').get_string_member('sunrise')
        let sunset = weather.get_object_member('astronomy').get_string_member('sunset')

        let temperature = weather_c.get_string_member('temp')

        let wind = weather.get_object_member('wind').get_string_member('speed')
        let wind_chill = weather.get_object_member('wind').get_string_member('chill')
        let wind_direction = this.compassDirection(weather.get_object_member('wind').get_string_member('direction'))
        //let wind_unit = weather.get_object_member('units').get_string_member('speed')

        let iconname = this.weatherIconSafely(weather_c.get_string_member('code'))
        this._currentWeatherIcon.icon_name = iconname
        this._icon_type == St.IconType.SYMBOLIC ?
          this.set_applet_icon_symbolic_name(iconname) :
          this.set_applet_icon_name(iconname)

        if (this._showTextInPanel) {
          if (this._showCommentInPanel) {
            this.set_applet_label(comment + ' ' + temperature + ' ' + this.unitToUnicode())
          } else {
            this.set_applet_label(temperature + ' ' + this.unitToUnicode())
          }
        } else {
          this.set_applet_label('')
        }

        this._currentWeatherSummary.text = comment
        this._currentWeatherTemperature.text = temperature + ' ' + this.unitToUnicode()
        this._currentWeatherHumidity.text = humidity

        // Override wind units with our preference
        // Need to consider what units the Yahoo API has returned it in
        switch (this._windSpeedUnit) {
          case WeatherWindSpeedUnits.KPH:
            // Round to whole units
            if (this._temperatureUnit == WeatherUnits.FAHRENHEIT) {
              wind = Math.round (wind / WEATHER_CONV_MPH_IN_MPS * WEATHER_CONV_KPH_IN_MPS)
            }
            // Otherwise no conversion needed - already in correct units
            break
          case WeatherWindSpeedUnits.MPH:
            // Round to whole units
            if (this._temperatureUnit == WeatherUnits.CELSIUS) {
              wind = Math.round (wind / WEATHER_CONV_KPH_IN_MPS * WEATHER_CONV_MPH_IN_MPS)
            }
            // Otherwise no conversion needed - already in correct units
            break
          case WeatherWindSpeedUnits.MPS:
            // Precision to one decimal place as 1 m/s is quite a large unit
            if (this._temperatureUnit == WeatherUnits.CELSIUS) {
              wind = Math.round ((wind / WEATHER_CONV_KPH_IN_MPS) * 10)/ 10
            } else {
              wind = Math.round ((wind / WEATHER_CONV_MPH_IN_MPS) * 10)/ 10
            }
            break
          case WeatherWindSpeedUnits.KNOTS:
            // Round to whole units
            if (this._temperatureUnit == WeatherUnits.CELSIUS) {
              wind = Math.round (wind / WEATHER_CONV_KPH_IN_MPS * WEATHER_CONV_KNOTS_IN_MPS)
            } else {
              wind = Math.round (wind / WEATHER_CONV_MPH_IN_MPS * WEATHER_CONV_KNOTS_IN_MPS)
            }
            break
        }
        this._currentWeatherWind.text = (wind_direction ? wind_direction + ' ' : '') + wind + ' ' + _(this._windSpeedUnit)
        this._currentWeatherWindChill.text = wind_chill + ' ' + this.unitToUnicode()

        // Override pressure units with our preference
        // Need to consider what units the Yahoo API has returned it in
        switch (this._pressureUnit) {
          case WeatherPressureUnits.MBAR:
            if (this._temperatureUnit == WeatherUnits.FAHRENHEIT) {
              pressure = pressure * WEATHER_CONV_MBAR_IN_INHG
            }
            // Otherwise no conversion needed - already in correct units
            pressure = parseFloat(pressure).toFixed(2)
            break
          case WeatherPressureUnits.INHG:
            if (this._temperatureUnit == WeatherUnits.CELSIUS) {
              pressure = pressure * WEATHER_CONV_INHG_IN_MBAR
            }
            // Otherwise no conversion needed - already in correct units
            pressure = parseFloat(pressure).toFixed(2)
            break
          case WeatherPressureUnits.PSI:
            if (this._temperatureUnit == WeatherUnits.CELSIUS) {
              pressure = pressure * WEATHER_CONV_PSI_IN_MBAR
            } else {
              pressure = pressure * WEATHER_CONV_PSI_IN_INHG
            }
            pressure = parseFloat(pressure).toFixed(3)
            break
          case WeatherPressureUnits.MMHG:
            if (this._temperatureUnit == WeatherUnits.CELSIUS) {
              pressure = pressure * WEATHER_CONV_MMHG_IN_MBAR
            } else {
              pressure = pressure * WEATHER_CONV_MMHG_IN_INHG
            }
            pressure = Math.round(pressure)
            break
          case WeatherPressureUnits.AT:
            if (this._temperatureUnit == WeatherUnits.CELSIUS) {
              pressure = pressure * WEATHER_CONV_AT_IN_MBAR
            } else {
              pressure = pressure * WEATHER_CONV_AT_IN_INHG
            }
            pressure = pressure.toFixed(4)
            break
          case WeatherPressureUnits.ATM:
            if (this._temperatureUnit == WeatherUnits.CELSIUS) {
              pressure = pressure * WEATHER_CONV_ATM_IN_MBAR
            } else {
              pressure = pressure * WEATHER_CONV_ATM_IN_INHG
            }
            pressure = pressure.toFixed(4)
            break
          case WeatherPressureUnits.PA:
            if (this._temperatureUnit == WeatherUnits.CELSIUS) {
              pressure = pressure * WEATHER_CONV_PA_IN_MBAR
            } else {
              pressure = pressure * WEATHER_CONV_PA_IN_INHG
            }
            pressure = Math.round(pressure)
            break
          case WeatherPressureUnits.KPA:
            if (this._temperatureUnit == WeatherUnits.CELSIUS) {
              pressure = pressure * WEATHER_CONV_KPA_IN_MBAR
            } else {
              pressure = pressure * WEATHER_CONV_KPA_IN_INHG
            }
            pressure = parseFloat(pressure).toFixed(2)
            break
        }
        this._currentWeatherPressure.text = pressure + ' ' + _(this._pressureUnit)

        // location is a button
        this._currentWeatherLocation.url = weather.get_string_member('link')
        this._currentWeatherLocation.label = _(location)

        // gettext can't see these inline
        let sunriseText = _('Sunrise')
        let sunsetText = _('Sunset')

        let sunriseTime = this._show24Hours ? (this.convertTo24(sunrise)) : sunrise
        let sunsetTime = this._show24Hours ? (this.convertTo24(sunset)) : sunset

        this._currentWeatherSunrise.text = this._showSunrise ? (sunriseText + ': ' + sunriseTime ) : ''
        this._currentWeatherSunset.text = this._showSunrise ? (sunsetText + ': ' + sunsetTime) : ''

        // Refresh forecast
        let daysToShow = this._showFivedayForecast ? 5 : 2
        for (let i = 0; i < daysToShow; i++) {
          let forecastUi = this._forecast[i]
          let forecastData = forecast[i].get_object()

          let code = forecastData.get_string_member('code')
          let t_low = forecastData.get_string_member('low')
          let t_high = forecastData.get_string_member('high')

          let comment = forecastData.get_string_member('text')
          if (this._translateCondition)
            comment = this.weatherCondition(code)

          forecastUi.Day.text = this.localeDay(forecastData.get_string_member('day'))
          forecastUi.Temperature.text = t_low + ' ' + '\u002F' + ' ' + t_high + ' ' + this.unitToUnicode()
          forecastUi.Summary.text = comment
          forecastUi.Icon.icon_name = this.weatherIconSafely(code)          
        }        
      } catch(error) {
        logError(error)
      }
    })

    if (recurse) {
      Mainloop.timeout_add_seconds(this._refreshInterval * 60, Lang.bind(this, function() {
        this.refreshWeather(true)
      }))
    }
  }

, convertTo24: function convertTo24(timeStr) {
    let s = timeStr.indexOf(':')
    let t = timeStr.indexOf(' ')
    let n = timeStr.length
    let hh = timeStr.substr(0, s)
    let mm = timeStr.substring(s + 1, t)

    if (parseInt(hh) < 10) // pad
      hh = '0' + hh

    let beforeNoon = timeStr.substr(n - 2).toLowerCase() == 'am'
    if (beforeNoon) {
      if (hh == '12') // 12 AM -> 00
        hh = '00'

      return hh + ':' + mm
    }

    if (hh == '12') // 12 PM -> ok
      return hh + ':' + mm

    return (parseInt(hh) + 12).toString() + ':' + mm
  }

, destroyCurrentWeather: function destroyCurrentWeather() {
    if (this._currentWeather.get_child() != null)
      this._currentWeather.get_child().destroy()
  }

, destroyFutureWeather: function destroyFutureWeather() {
    if (this._futureWeather.get_child() != null)
      this._futureWeather.get_child().destroy()
  }

, showLoadingUi: function showLoadingUi() {
    this.destroyCurrentWeather()
    this.destroyFutureWeather()
    this._currentWeather.set_child(new St.Label({ text: _('Loading current weather ...') }))
    this._futureWeather.set_child(new St.Label({ text: _('Loading future weather ...') }))
  }

, rebuild: function rebuild() {
    this.showLoadingUi()
    this.rebuildCurrentWeatherUi()
    this.rebuildFutureWeatherUi()
  }

, rebuildCurrentWeatherUi: function rebuildCurrentWeatherUi() {
    this.destroyCurrentWeather()

    // This will hold the icon for the current weather
    this._currentWeatherIcon = new St.Icon({
      icon_type: this._icon_type,
      icon_size: 64,
      icon_name: APPLET_ICON,
      style_class: STYLE_ICON
    })

    // The summary of the current weather
    this._currentWeatherSummary = new St.Label({
      text: _('Loading ...'),
      style_class: STYLE_SUMMARY
    })

    this._currentWeatherLocation = new St.Button({
      reactive: true,
      label: _('Refresh')
    })

    this._currentWeatherLocation.style_class = STYLE_LOCATION_LINK

    // link to the details page
    this._currentWeatherLocation.connect(SIGNAL_CLICKED, Lang.bind(this, function() {
      if (this._currentWeatherLocation.url == null) {
        this.refreshWeather(false)
      } else {
        Gio.app_info_launch_default_for_uri(
          this._currentWeatherLocation.url,
          global.create_app_launch_context()
        )
      }
    }))

    let bb = new St.BoxLayout({
      vertical: true,
      style_class: STYLE_SUMMARYBOX
    })
    bb.add_actor(this._currentWeatherLocation)
    bb.add_actor(this._currentWeatherSummary)

    let textOb = { text: ELLIPSIS }
    this._currentWeatherSunrise = new St.Label(textOb)
    this._currentWeatherSunset = new St.Label(textOb)

    let ab = new St.BoxLayout({
      style_class: STYLE_ASTRONOMY
    })

    ab.add_actor(this._currentWeatherSunrise)
    let ab_spacerlabel = new St.Label({ text: BLANK })
    ab.add_actor(ab_spacerlabel)
    ab.add_actor(this._currentWeatherSunset)

    let bb_spacerlabel = new St.Label({ text: BLANK })
    bb.add_actor(bb_spacerlabel)
    bb.add_actor(ab)

    // Other labels
    this._currentWeatherTemperature = new St.Label(textOb)
    this._currentWeatherHumidity = new St.Label(textOb)
    this._currentWeatherPressure = new St.Label(textOb)
    this._currentWeatherWind = new St.Label(textOb)
    this._currentWeatherWindChill = new St.Label(textOb)

    let rb = new St.BoxLayout({
      style_class: STYLE_DATABOX
    })
    let rb_captions = new St.BoxLayout({
      vertical: true,
      style_class: STYLE_DATABOX_CAPTIONS
    })
    let rb_values = new St.BoxLayout({
      vertical: true,
      style_class: STYLE_DATABOX_VALUES
    })
    rb.add_actor(rb_captions)
    rb.add_actor(rb_values)

    rb_captions.add_actor(new St.Label({text: _('Temperature:')}))
    rb_values.add_actor(this._currentWeatherTemperature)
    rb_captions.add_actor(new St.Label({text: _('Humidity:')}))
    rb_values.add_actor(this._currentWeatherHumidity)
    rb_captions.add_actor(new St.Label({text: _('Pressure:')}))
    rb_values.add_actor(this._currentWeatherPressure)
    rb_captions.add_actor(new St.Label({text: _('Wind:')}))
    rb_values.add_actor(this._currentWeatherWind)
    rb_captions.add_actor(new St.Label({text: _('Wind Chill:')}))
    rb_values.add_actor(this._currentWeatherWindChill)

    let xb = new St.BoxLayout()
    xb.add_actor(bb)
    xb.add_actor(rb)

    let box = new St.BoxLayout({
      style_class: STYLE_ICONBOX
    })
    box.add_actor(this._currentWeatherIcon)
    box.add_actor(xb)
    this._currentWeather.set_child(box)
  }

, rebuildFutureWeatherUi: function rebuildFutureWeatherUi() {
    this.destroyFutureWeather()

    this._forecast = []
    this._forecastBox = new St.BoxLayout()
    this._futureWeather.set_child(this._forecastBox)

    let daysToShow = this._showFivedayForecast ? 5 : 2
    for (let i = 0; i < daysToShow; i++) {
      let forecastWeather = {}

      forecastWeather.Icon = new St.Icon({
        icon_type: this._icon_type,
        icon_size: 48,
        icon_name: APPLET_ICON,
        style_class: STYLE_FORECAST_ICON
      })
      forecastWeather.Day = new St.Label({
        style_class: STYLE_FORECAST_DAY
      })
      forecastWeather.Summary = new St.Label({
        style_class: STYLE_FORECAST_SUMMARY
      })
      forecastWeather.Temperature = new St.Label({
        style_class: STYLE_FORECAST_TEMPERATURE
      })

      let by = new St.BoxLayout({
        vertical: true,
        style_class: STYLE_FORECAST_DATABOX
      })
      by.add_actor(forecastWeather.Day)
      by.add_actor(forecastWeather.Summary)
      by.add_actor(forecastWeather.Temperature)

      let bb = new St.BoxLayout({
        style_class: STYLE_FORECAST_BOX
      })
      bb.add_actor(forecastWeather.Icon)
      bb.add_actor(by)

      this._forecast[i] = forecastWeather
      this._forecastBox.add_actor(bb)
    }
  }

  //----------------------------------------------------------------------
  //
  // Properties
  //
  //----------------------------------------------------------------------

, unitToUrl: function() {
    return this._temperatureUnit == WeatherUnits.FAHRENHEIT ? 'f' : 'c'
  }

, unitToUnicode: function() {
    return this._temperatureUnit == WeatherUnits.FAHRENHEIT ? '\u2109' : '\u2103'
  }

, weatherUrl: function weatherUrl() {
    //let output = QUERY_URL + ' where location="' + this._woeid + '" and u="' + this.unitToUrl() + '"'
    let output = 'https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20=%20%' +  this._woeid + '%27&format=json'
    return output
  }

, weatherIcon: function(code) {
    /* see http://developer.yahoo.com/weather/#codetable */
    /* fallback icons are: weather-clear-night weather-clear weather-few-clouds-night weather-few-clouds weather-fog weather-overcast weather-severe-alert weather-showers weather-showers-scattered weather-snow weather-storm */
    switch (parseInt(code, 10)) {
      case 0:/* tornado */
        return ['weather-severe-alert']
      case 1:/* tropical storm */
        return ['weather-severe-alert']
      case 2:/* hurricane */
        return ['weather-severe-alert']
      case 3:/* severe thunderstorms */
        return ['weather-severe-alert']
      case 4:/* thunderstorms */
        return ['weather-storm']
      case 5:/* mixed rain and snow */
        return ['weather-snow-rain', 'weather-snow']
      case 6:/* mixed rain and sleet */
        return ['weather-snow-rain', 'weather-snow']
      case 7:/* mixed snow and sleet */
        return ['weather-snow']
      case 8:/* freezing drizzle */
        return ['weather-freezing-rain', 'weather-showers']
      case 9:/* drizzle */
        return ['weather-fog']
      case 10:/* freezing rain */
        return ['weather-freezing-rain', 'weather-showers']
      case 11:/* showers */
        return ['weather-showers']
      case 12:/* showers */
        return ['weather-showers']
      case 13:/* snow flurries */
        return ['weather-snow']
      case 14:/* light snow showers */
        return ['weather-snow']
      case 15:/* blowing snow */
        return ['weather-snow']
      case 16:/* snow */
        return ['weather-snow']
      case 17:/* hail */
        return ['weather-snow']
      case 18:/* sleet */
        return ['weather-snow']
      case 19:/* dust */
        return ['weather-fog']
      case 20:/* foggy */
        return ['weather-fog']
      case 21:/* haze */
        return ['weather-fog']
      case 22:/* smoky */
        return ['weather-fog']
      case 23:/* blustery */
        return ['weather-few-clouds']
      case 24:/* windy */
        return ['weather-few-clouds']
      case 25:/* cold */
        return ['weather-few-clouds']
      case 26:/* cloudy */
        return ['weather-overcast']
      case 27:/* mostly cloudy (night) */
        return ['weather-clouds-night', 'weather-few-clouds-night']
      case 28:/* mostly cloudy (day) */
        return ['weather-clouds', 'weather-overcast']
      case 29:/* partly cloudy (night) */
        return ['weather-few-clouds-night']
      case 30:/* partly cloudy (day) */
        return ['weather-few-clouds']
      case 31:/* clear (night) */
        return ['weather-clear-night']
      case 32:/* sunny */
        return ['weather-clear']
      case 33:/* fair (night) */
        return ['weather-clear-night']
      case 34:/* fair (day) */
        return ['weather-clear']
      case 35:/* mixed rain and hail */
        return ['weather-snow-rain', 'weather-showers']
      case 36:/* hot */
        return ['weather-clear']
      case 37:/* isolated thunderstorms */
        return ['weather-storm']
      case 38:/* scattered thunderstorms */
        return ['weather-storm']
      case 39:/* http://developer.yahoo.com/forum/YDN-Documentation/Yahoo-Weather-API-Wrong-Condition-Code/1290534174000-1122fc3d-da6d-34a2-9fb9-d0863e6c5bc6 */
      case 40:/* scattered showers */
        return ['weather-showers-scattered', 'weather-showers']
      case 41:/* heavy snow */
        return ['weather-snow']
      case 42:/* scattered snow showers */
        return ['weather-snow']
      case 43:/* heavy snow */
        return ['weather-snow']
      case 44:/* partly cloudy */
        return ['weather-few-clouds']
      case 45:/* thundershowers */
        return ['weather-storm']
      case 46:/* snow showers */
        return ['weather-snow']
      case 47:/* isolated thundershowers */
        return ['weather-storm']
      case 3200:/* not available */
      default:
        return ['weather-severe-alert']
    }
  }

, weatherIconSafely: function(code) {
    let iconname = this.weatherIcon(code)
    for (let i = 0; i < iconname.length; i++) {
      if (this.hasIcon(iconname[i]))
        return iconname[i]
    }
    return 'weather-severe-alert'
  }

, hasIcon: function(icon) {
    return Gtk.IconTheme.get_default().has_icon(icon + (this._icon_type == St.IconType.SYMBOLIC ? '-symbolic' : ''))
  }

, nonempty: function(str) {
    return (str != null && str.length > 0)
  }

, weatherCondition: function(code) {
    switch (parseInt(code, 10)){
      case 0:/* tornado */
        return _('Tornado')
      case 1:/* tropical storm */
        return _('Tropical storm')
      case 2:/* hurricane */
        return _('Hurricane')
      case 3:/* severe thunderstorms */
        return _('Severe thunderstorms')
      case 4:/* thunderstorms */
        return _('Thunderstorms')
      case 5:/* mixed rain and snow */
        return _('Mixed rain and snow')
      case 6:/* mixed rain and sleet */
        return _('Mixed rain and sleet')
      case 7:/* mixed snow and sleet */
        return _('Mixed snow and sleet')
      case 8:/* freezing drizzle */
        return _('Freezing drizzle')
      case 9:/* drizzle */
        return _('Drizzle')
      case 10:/* freezing rain */
        return _('Freezing rain')
      case 11:/* showers */
        return _('Showers')
      case 12:/* showers */
        return _('Showers')
      case 13:/* snow flurries */
        return _('Snow flurries')
      case 14:/* light snow showers */
        return _('Light snow showers')
      case 15:/* blowing snow */
        return _('Blowing snow')
      case 16:/* snow */
        return _('Snow')
      case 17:/* hail */
        return _('Hail')
      case 18:/* sleet */
        return _('Sleet')
      case 19:/* dust */
        return _('Dust')
      case 20:/* foggy */
        return _('Foggy')
      case 21:/* haze */
        return _('Haze')
      case 22:/* smoky */
        return _('Smoky')
      case 23:/* blustery */
        return _('Blustery')
      case 24:/* windy */
        return _('Windy')
      case 25:/* cold */
        return _('Cold')
      case 26:/* cloudy */
        return _('Cloudy')
      case 27:/* mostly cloudy (night) */
      case 28:/* mostly cloudy (day) */
        return _('Mostly cloudy')
      case 29:/* partly cloudy (night) */
      case 30:/* partly cloudy (day) */
        return _('Partly cloudy')
      case 31:/* clear (night) */
        return _('Clear')
      case 32:/* sunny */
        return _('Sunny')
      case 33:/* fair (night) */
      case 34:/* fair (day) */
        return _('Fair')
      case 35:/* mixed rain and hail */
        return _('Mixed rain and hail')
      case 36:/* hot */
        return _('Hot')
      case 37:/* isolated thunderstorms */
        return _('Isolated thunderstorms')
      case 38:/* scattered thunderstorms */
      case 39:/* scattered thunderstorms */
        return _('Scattered thunderstorms')
      case 40:/* scattered showers */
        return _('Scattered showers')
      case 41:/* heavy snow */
        return _('Heavy snow')
      case 42:/* scattered snow showers */
        return _('Scattered snow showers')
      case 43:/* heavy snow */
        return _('Heavy snow')
      case 44:/* partly cloudy */
        return _('Partly cloudy')
      case 45:/* thundershowers */
        return _('Thundershowers')
      case 46:/* snow showers */
        return _('Snow showers')
      case 47:/* isolated thundershowers */
        return _('Isolated thundershowers')
      case 3200:/* not available */
      default:
        return _('Not available')
    }
  }

, localeDay: function(abr) {
    let days = [_('Monday'), _('Tuesday'), _('Wednesday'), _('Thursday'), _('Friday'), _('Saturday'), _('Sunday')]
    return days[this.parseDay(abr)]
  }

, compassDirection: function(deg) {
    let directions = [_('N'), _('NE'), _('E'), _('SE'), _('S'), _('SW'), _('W'), _('NW')]
    return directions[Math.round(deg / 45) % directions.length]
  }
}

//----------------------------------------------------------------------
//
// Entry point
//
//----------------------------------------------------------------------

function main(metadata, orientation, panelHeight, instanceId) {
  //log("v" + metadata.version + ", cinnamon " + Config.PACKAGE_VERSION)
  return new MyApplet(metadata, orientation, panelHeight, instanceId)
}
LinuxEngineer commented 8 years ago

I fixed it like this Just need to change the query block:

// Query
const QUERY_PARAMS = '?q=select'
const QUERY_TABLE = 'weather.forcast'
const QUERY_VIEW = '*'
const QUERY_CMD = this.woeid
const QUERY_URL = 'http://query.yahooapis.com/v1/public/yql' + QUERY_PARAMS + QUERY_VIEW + ' from ' + QUERY_TABLE + 'where ' +QUERY_CMD

Also need to change the WOEID_URL:

const UUID = "weather@mockturtl"
const APPLET_ICON = "view-refresh-symbolic"
const CMD_SETTINGS = "cinnamon-settings applets " + UUID
const WOEID_URL = "http://woeid.rosselliot.co.nz"
const CMD_WOEID_LOOKUP = "xdg-open " + WOEID_URL

Lastly have to change weatherURL:

, weatherUrl: function weatherUrl() {

    let output = QUERY_URL + "format=json&callback="
    //let output = QUERY_URL + this._woeid + '_' + this.unitToUrl() + '.xml"'
    return output
  }
MavropaliasG commented 8 years ago

It has stopped working for me too. However I'm total noob I don't know how to fix it like the guys above.

brub2 commented 8 years ago

Same trouble here. I tried to replace the applet.js file by the file proposed by iksws without success. I also try to directly edit like LinuxEngineer. As I understand, we must also change the WOIED to complete the fix and I now have a 4 digits code (before, it was a longer mix of letters and numbers).

marceloavan commented 8 years ago

The PR #143 contains a solution already applied in the source code. And if you have some doubt to install the applet, the issue #146 have the step's to do it.

RileyStarlight commented 8 years ago

+1 here! Fixed using code in #143

mockturtl commented 8 years ago

duplicates #127