[Xfce4-commits] <xfce4-weather-plugin:master> Fetch and cache astronomical data for multiple days.

Harald Judt noreply at xfce.org
Sun Jan 12 01:08:02 CET 2014


Updating branch refs/heads/master
         to 2e9ef8c8b50f2505b5f21bf2280a3588f6647af0 (commit)
       from fe6baf20e0d6e873efc013b9da13a0abb817abc5 (commit)

commit 2e9ef8c8b50f2505b5f21bf2280a3588f6647af0
Author: Harald Judt <h.judt at gmx.at>
Date:   Sat Apr 6 18:10:24 2013 +0200

    Fetch and cache astronomical data for multiple days.
    
    met.no sunrise API provides astronomical data for up to 30 days in the
    future (requesting more than that will result in an error page).
    We can make use of that and cache it, similar as we do for the forecast
    data. current_astro will point to the astronomical data for the current
    day.
    
    Download will now happen in intervals of 24 hours, not at a fixed time
    at midnight as previously. The current conditions updates will take
    care that astronomical data gets updated for the present day, because
    they happen exactly at midnight and thus save us from adding additional
    logic having to deal with that.

 panel-plugin/weather-data.c    |  130 ++++++++++++++++--
 panel-plugin/weather-data.h    |   14 +-
 panel-plugin/weather-debug.c   |    7 +-
 panel-plugin/weather-parsers.c |  126 +++++++++++++++---
 panel-plugin/weather-parsers.h |   10 ++
 panel-plugin/weather-summary.c |   22 ++--
 panel-plugin/weather.c         |  284 +++++++++++++++++++++++-----------------
 panel-plugin/weather.h         |    3 +-
 8 files changed, 438 insertions(+), 158 deletions(-)

diff --git a/panel-plugin/weather-data.c b/panel-plugin/weather-data.c
index 2c21399..5f626e1 100644
--- a/panel-plugin/weather-data.c
+++ b/panel-plugin/weather-data.c
@@ -760,6 +760,33 @@ make_combined_timeslice(xml_weather *wd,
 
 
 void
+merge_astro(GArray *astrodata,
+            const xml_astro *astro)
+{
+    xml_astro *old_astro, *new_astro;
+    guint index;
+
+    g_assert(astrodata != NULL);
+    if (G_UNLIKELY(astrodata == NULL))
+        return;
+
+    /* copy astro, as it may be deleted by the calling function */
+    new_astro = xml_astro_copy(astro);
+
+    /* check for and replace existing astrodata of the same date */
+    if ((old_astro = get_astro(astrodata, astro->day, &index))) {
+        xml_astro_free(old_astro);
+        g_array_remove_index(astrodata, index);
+        g_array_insert_val(astrodata, index, new_astro);
+        weather_debug("Replaced existing astrodata at %d.", index);
+    } else {
+        g_array_append_val(astrodata, new_astro);
+        weather_debug("Appended new astrodata to the existing data.");
+    }
+}
+
+
+void
 merge_timeslice(xml_weather *wd,
                 const xml_time *timeslice)
 {
@@ -851,6 +878,52 @@ time_calc_day(const struct tm time_tm,
 
 
 /*
+ * Compare two xml_astro structs using their date (days) field.
+ */
+gint
+xml_astro_compare(gconstpointer a,
+                  gconstpointer b)
+{
+    xml_astro *a1 = *(xml_astro **) a;
+    xml_astro *a2 = *(xml_astro **) b;
+
+    if (G_UNLIKELY(a1 == NULL && a2 == NULL))
+        return 0;
+    if (G_UNLIKELY(a1 == NULL))
+        return 1;
+    if (G_UNLIKELY(a2 == NULL))
+        return -1;
+
+    return (gint) difftime(a2->day, a1->day) * -1;
+}
+
+
+void
+astrodata_clean(GArray *astrodata)
+{
+    xml_astro *astro;
+    time_t now_t = time(NULL);
+    gint i;
+
+    if (G_UNLIKELY(astrodata == NULL))
+        return;
+
+    for (i = 0; i < astrodata->len; i++) {
+        astro = g_array_index(astrodata, xml_astro *, i);
+        if (G_UNLIKELY(astro == NULL))
+            continue;
+        if (difftime(now_t, astro->day) >= 24 * 3600) {
+            weather_debug("Removing expired astrodata:");
+            weather_dump(weather_dump_astrodata, astro);
+            xml_astro_free(astro);
+            g_array_remove_index(astrodata, i--);
+            weather_debug("Remaining astrodata entries: %d", astrodata->len);
+        }
+    }
+}
+
+
+/*
  * Compare two xml_time structs using their start and end times,
  * returning the result as a qsort()-style comparison function (less
  * than zero for first arg is less than second arg, zero for equal,
@@ -1072,25 +1145,62 @@ make_current_conditions(xml_weather *wd,
 
 
 /*
+ * Add days to time_t and set the calculated day to midnight.
+ */
+time_t
+day_at_midnight(time_t day_t,
+                const gint add_days)
+{
+    struct tm day_tm;
+
+    day_tm = *localtime(&day_t);
+    day_tm.tm_mday += add_days;
+    day_tm.tm_hour = day_tm.tm_min = day_tm.tm_sec = 0;
+    day_tm.tm_isdst = -1;
+    day_t = mktime(&day_tm);
+    return day_t;
+}
+
+
+/*
+ * Returns astro data for a given day.
+ */
+xml_astro *
+get_astro_data_for_day(const GArray *astrodata,
+                       const gint day)
+{
+    xml_astro *astro;
+    time_t day_t = time(NULL);
+    gint i;
+
+    if (G_UNLIKELY(astrodata == NULL))
+        return NULL;
+
+    day_t = day_at_midnight(day_t, day);
+
+    for (i = 0; i < astrodata->len; i++) {
+        astro = g_array_index(astrodata, xml_astro *, i);
+        if (astro && (difftime(astro->day, day_t) == 0))
+            return astro;
+    }
+
+    return NULL;
+}
+
+
+/*
  * Get all point data relevant for a given day.
  */
 GArray *
 get_point_data_for_day(xml_weather *wd,
-                       int day)
+                       gint day)
 {
     GArray *found;
     xml_time *timeslice;
-    struct tm day_tm;
-    time_t day_t;
+    time_t day_t = time(NULL);
     gint i;
 
-    /* calculate 00:00 for the requested day */
-    time(&day_t);
-    day_tm = *localtime(&day_t);
-    day_tm.tm_mday += day;
-    day_tm.tm_hour = day_tm.tm_min = day_tm.tm_sec = 0;
-    day_tm.tm_isdst = -1;
-    day_t = mktime(&day_tm);
+    day_t = day_at_midnight(day_t, day);
 
     /* loop over weather data and pick relevant point data */
     found = g_array_new(FALSE, TRUE, sizeof(xml_time *));
diff --git a/panel-plugin/weather-data.h b/panel-plugin/weather-data.h
index 9cade29..2641a3a 100644
--- a/panel-plugin/weather-data.h
+++ b/panel-plugin/weather-data.h
@@ -134,9 +134,15 @@ time_t time_calc_hour(struct tm time_tm,
 time_t time_calc_day(struct tm time_tm,
                      gint days);
 
+gint xml_astro_compare(gconstpointer a,
+                       gconstpointer b);
+
 gint xml_time_compare(gconstpointer a,
                       gconstpointer b);
 
+void merge_astro(GArray *astrodata,
+                 const xml_astro *astro);
+
 void merge_timeslice(xml_weather *wd,
                      const xml_time *timeslice);
 
@@ -145,8 +151,14 @@ xml_time *get_current_conditions(const xml_weather *wd);
 xml_time *make_current_conditions(xml_weather *wd,
                                   time_t now_t);
 
+time_t day_at_midnight(time_t day_t,
+                       const gint add_days);
+
+xml_astro *get_astro_data_for_day(const GArray *astrodata,
+                                  const gint day_t);
+
 GArray *get_point_data_for_day(xml_weather *wd,
-                               int day);
+                               const gint day);
 
 xml_time *make_forecast_data(xml_weather *wd,
                              GArray *daydata,
diff --git a/panel-plugin/weather-debug.c b/panel-plugin/weather-debug.c
index 4a4acf9..2d30e0c 100644
--- a/panel-plugin/weather-debug.c
+++ b/panel-plugin/weather-debug.c
@@ -204,11 +204,12 @@ weather_dump_icon_theme(const icon_theme *theme)
 gchar *
 weather_dump_astrodata(const xml_astro *astro)
 {
-    gchar *out, *sunrise, *sunset, *moonrise, *moonset;
+    gchar *out, *day, *sunrise, *sunset, *moonrise, *moonset;
 
     if (!astro)
         return g_strdup("No astronomical data.");
 
+    day = format_date(astro->day, "%Y-%m-%d", TRUE);
     sunrise = format_date(astro->sunrise, "%c", TRUE);
     sunset = format_date(astro->sunset, "%c", TRUE);
     moonrise = format_date(astro->moonrise, "%c", TRUE);
@@ -216,6 +217,8 @@ weather_dump_astrodata(const xml_astro *astro)
 
     out = g_strdup_printf("Astronomical data:\n"
                           "  --------------------------------------------\n"
+                          "  day: %s\n"
+                          "  --------------------------------------------\n"
                           "  sunrise: %s\n"
                           "  sunset: %s\n"
                           "  sun never rises: %s\n"
@@ -227,6 +230,7 @@ weather_dump_astrodata(const xml_astro *astro)
                           "  moon never sets: %s\n"
                           "  moon phase: %s\n"
                           "  --------------------------------------------",
+                          day,
                           sunrise,
                           sunset,
                           YESNO(astro->sun_never_rises),
@@ -236,6 +240,7 @@ weather_dump_astrodata(const xml_astro *astro)
                           YESNO(astro->moon_never_rises),
                           YESNO(astro->moon_never_sets),
                           astro->moon_phase);
+    g_free(day);
     g_free(sunrise);
     g_free(sunset);
     g_free(moonrise);
diff --git a/panel-plugin/weather-parsers.c b/panel-plugin/weather-parsers.c
index 369adf8..0f321ba 100644
--- a/panel-plugin/weather-parsers.c
+++ b/panel-plugin/weather-parsers.c
@@ -94,6 +94,30 @@ get_timeslice(xml_weather *wd,
 }
 
 
+xml_astro *
+get_astro(const GArray *astrodata,
+          const time_t day_t,
+          guint *index)
+{
+    xml_astro *astro;
+    gint i;
+
+    g_assert(astrodata != NULL);
+    if (G_UNLIKELY(astrodata == NULL))
+        return NULL;
+
+    for (i = 0; i < astrodata->len; i++) {
+        astro = g_array_index(astrodata, xml_astro *, i);
+        if (astro && astro->day == day_t) {
+            if (index != NULL)
+                *index = i;
+            return astro;
+        }
+    }
+    return NULL;
+}
+
+
 time_t
 parse_timestring(const gchar *ts,
                  gchar *format) {
@@ -404,37 +428,58 @@ parse_astro_location(xmlNode *cur_node,
 }
 
 
+static xml_astro *
+parse_astro_time(xmlNode *cur_node)
+{
+    xmlNode *child_node;
+    xml_astro *astro;
+    gchar *date;
+
+    astro = g_slice_new0(xml_astro);
+    if (G_UNLIKELY(astro == NULL))
+        return NULL;
+
+    date = PROP(cur_node, "date");
+    astro->day = parse_timestring(date, "%Y-%m-%d");
+    astro->day = day_at_midnight(astro->day, 0);
+    xmlFree(date);
+
+    for (child_node = cur_node->children; child_node;
+         child_node = child_node->next)
+        if (NODE_IS_TYPE(child_node, "location"))
+            parse_astro_location(child_node, astro);
+    return astro;
+}
+
+
 /*
  * Look at http://api.yr.no/weatherapi/sunrise/1.0/schema for information
  * of elements and attributes to expect.
  */
-xml_astro *
-parse_astro(xmlNode *cur_node)
+gboolean
+parse_astrodata(xmlNode *cur_node,
+                GArray *astrodata)
 {
-    xmlNode *child_node, *time_node = NULL;
+    xmlNode *child_node;
     xml_astro *astro;
 
+    g_assert(astrodata != NULL);
+    if (G_UNLIKELY(astrodata == NULL))
+        return FALSE;
+
     g_assert(cur_node != NULL);
     if (G_UNLIKELY(cur_node == NULL || !NODE_IS_TYPE(cur_node, "astrodata")))
-        return NULL;
-
-    astro = g_slice_new0(xml_astro);
-    if (G_UNLIKELY(astro == NULL))
-        return NULL;
+        return FALSE;
 
     for (child_node = cur_node->children; child_node;
          child_node = child_node->next)
         if (NODE_IS_TYPE(child_node, "time")) {
-            time_node = child_node;
-            break;
+            if ((astro = parse_astro_time(child_node))) {
+                merge_astro(astrodata, astro);
+                xml_astro_free(astro);
+            }
         }
-
-    if (G_LIKELY(time_node))
-        for (child_node = time_node->children; child_node;
-             child_node = child_node->next)
-            if (NODE_IS_TYPE(child_node, "location"))
-                parse_astro_location(child_node, astro);
-    return astro;
+    return TRUE;
 }
 
 
@@ -614,6 +659,36 @@ xml_location_free(xml_location *loc)
 
 
 /*
+ * Deep copy xml_astro struct.
+ */
+xml_astro *
+xml_astro_copy(const xml_astro *src)
+{
+    xml_astro *dst;
+
+    if (G_UNLIKELY(src == NULL))
+        return NULL;
+
+    dst = g_slice_new0(xml_astro);
+    g_assert(dst != NULL);
+    if (G_UNLIKELY(dst == NULL))
+        return NULL;
+
+    dst->day = src->day;
+    dst->sunrise = src->sunrise;
+    dst->sunset = src->sunset;
+    dst->sun_never_rises = src->sun_never_rises;
+    dst->sun_never_sets = src->sun_never_sets;
+    dst->moonrise = src->moonrise;
+    dst->moonset = src->moonset;
+    dst->moon_never_rises = src->moon_never_rises;
+    dst->moon_never_sets = src->moon_never_sets;
+    dst->moon_phase = g_strdup(src->moon_phase);
+    return dst;
+}
+
+
+/*
  * Deep copy xml_time struct.
  */
 xml_time *
@@ -749,6 +824,23 @@ xml_astro_free(xml_astro *astro)
 
 
 void
+astrodata_free(GArray *astrodata)
+{
+    xml_astro *astro;
+    gint i;
+
+    if (G_UNLIKELY(astrodata == NULL))
+        return;
+    for (i = 0; i < astrodata->len; i++) {
+        astro = g_array_index(astrodata, xml_astro *, i);
+        if (astro)
+            xml_astro_free(astro);
+    }
+    g_array_free(astrodata, FALSE);
+}
+
+
+void
 xml_geolocation_free(xml_geolocation *geo)
 {
     g_assert(geo != NULL);
diff --git a/panel-plugin/weather-parsers.h b/panel-plugin/weather-parsers.h
index 4e00665..954d16b 100644
--- a/panel-plugin/weather-parsers.h
+++ b/panel-plugin/weather-parsers.h
@@ -80,6 +80,8 @@ typedef struct {
 } xml_weather;
 
 typedef struct {
+    time_t day;
+
     time_t sunrise;
     time_t sunset;
     gboolean sun_never_rises;
@@ -143,11 +145,17 @@ xml_time *get_timeslice(xml_weather *wd,
                         const time_t end_t,
                         guint *index);
 
+xml_astro *get_astro(const GArray *astrodata,
+                     const time_t day_t,
+                     guint *index);
+
 xmlDoc *get_xml_document(SoupMessage *msg);
 
 gpointer parse_xml_document(SoupMessage *msg,
                             XmlParseFunc parse_func);
 
+xml_astro *xml_astro_copy(const xml_astro *src);
+
 xml_time *xml_time_copy(const xml_time *src);
 
 void xml_time_free(xml_time *timeslice);
@@ -158,6 +166,8 @@ void xml_weather_clean(xml_weather *wd);
 
 void xml_astro_free(xml_astro *astro);
 
+void astrodata_free(GArray *astrodata);
+
 void xml_geolocation_free(xml_geolocation *geo);
 
 void xml_place_free(xml_place *place);
diff --git a/panel-plugin/weather-summary.c b/panel-plugin/weather-summary.c
index bd80c74..33e52fb 100644
--- a/panel-plugin/weather-summary.c
+++ b/panel-plugin/weather-summary.c
@@ -416,48 +416,48 @@ create_summary_tab(plugin_data *data)
 
     /* sun and moon */
     APPEND_BTEXT(_("\nAstronomical Data\n"));
-    if (data->astrodata) {
-        if (data->astrodata->sun_never_rises) {
+    if (data->current_astro) {
+        if (data->current_astro->sun_never_rises) {
             value = g_strdup(_("\tSunrise:\t\tThe sun never rises today.\n"));
             APPEND_TEXT_ITEM_REAL(value);
-        } else if (data->astrodata->sun_never_sets) {
+        } else if (data->current_astro->sun_never_sets) {
             value = g_strdup(_("\tSunset:\t\tThe sun never sets today.\n"));
             APPEND_TEXT_ITEM_REAL(value);
         } else {
-            sunrise = format_date(data->astrodata->sunrise, NULL, TRUE);
+            sunrise = format_date(data->current_astro->sunrise, NULL, TRUE);
             value = g_strdup_printf(_("\tSunrise:\t\t%s\n"), sunrise);
             g_free(sunrise);
             APPEND_TEXT_ITEM_REAL(value);
 
-            sunset = format_date(data->astrodata->sunset, NULL, TRUE);
+            sunset = format_date(data->current_astro->sunset, NULL, TRUE);
             value = g_strdup_printf(_("\tSunset:\t\t%s\n\n"), sunset);
             g_free(sunset);
             APPEND_TEXT_ITEM_REAL(value);
         }
 
-        if (data->astrodata->moon_phase)
+        if (data->current_astro->moon_phase)
             value = g_strdup_printf(_("\tMoon phase:\t%s\n"),
                                     translate_moon_phase
-                                    (data->astrodata->moon_phase));
+                                    (data->current_astro->moon_phase));
         else
             value = g_strdup(_("\tMoon phase:\tUnknown\n"));
         APPEND_TEXT_ITEM_REAL(value);
 
-        if (data->astrodata->moon_never_rises) {
+        if (data->current_astro->moon_never_rises) {
             value =
                 g_strdup(_("\tMoonrise:\tThe moon never rises today.\n"));
             APPEND_TEXT_ITEM_REAL(value);
-        } else if (data->astrodata->moon_never_sets) {
+        } else if (data->current_astro->moon_never_sets) {
             value =
                 g_strdup(_("\tMoonset:\tThe moon never sets today.\n"));
             APPEND_TEXT_ITEM_REAL(value);
         } else {
-            moonrise = format_date(data->astrodata->moonrise, NULL, TRUE);
+            moonrise = format_date(data->current_astro->moonrise, NULL, TRUE);
             value = g_strdup_printf(_("\tMoonrise:\t%s\n"), moonrise);
             g_free(moonrise);
             APPEND_TEXT_ITEM_REAL(value);
 
-            moonset = format_date(data->astrodata->moonset, NULL, TRUE);
+            moonset = format_date(data->current_astro->moonset, NULL, TRUE);
             value = g_strdup_printf(_("\tMoonset:\t%s\n"), moonset);
             g_free(moonset);
             APPEND_TEXT_ITEM_REAL(value);
diff --git a/panel-plugin/weather.c b/panel-plugin/weather.c
index ce772c2..9ca51af 100644
--- a/panel-plugin/weather.c
+++ b/panel-plugin/weather.c
@@ -45,6 +45,12 @@
 #define CONN_RETRY_INTERVAL_SMALL (10)
 #define CONN_RETRY_INTERVAL_LARGE (10 * 60)
 
+/* met.no sunrise API returns data for up to 30 days in the future and
+   will return an error page if too many days are requested. Let's
+   play it safe and request fewer than that, since we can only get a
+   10 days forecast too. */
+#define ASTRODATA_MAX_DAYS 25
+
 /* power saving update interval in seconds used as a precaution to
    deal with suspend/resume events etc., when nothing needs to be
    updated earlier: */
@@ -370,6 +376,22 @@ update_scrollbox(plugin_data *data,
 }
 
 
+/* get the present day's astrodata */
+static void
+update_current_astrodata(plugin_data *data)
+{
+    time_t now_t = time(NULL);
+
+    if ((data->current_astro == NULL && data->astrodata) ||
+        (data->current_astro &&
+         difftime(data->current_astro->day, now_t) >= 24 * 3600)) {
+        data->current_astro = get_astro_data_for_day(data->astrodata, 0);
+        weather_debug("Updated astrodata for the present day.");
+        weather_dump(weather_dump_astrodata, data->current_astro);
+    }
+}
+
+
 static void
 update_current_conditions(plugin_data *data,
                           gboolean immediately)
@@ -400,10 +422,13 @@ update_current_conditions(plugin_data *data,
         make_current_conditions(data->weatherdata,
                                 data->conditions_update->last);
 
+    /* update astrodata for the present day */
+    update_current_astrodata(data);
+
     /* schedule next update */
     now_tm.tm_min += 5;
     data->conditions_update->next = mktime(&now_tm);
-    data->night_time = is_night_time(data->astrodata);
+    data->night_time = is_night_time(data->current_astro);
     schedule_next_wakeup(data);
 
     /* update widgets */
@@ -452,12 +477,13 @@ cb_astro_update(SoupSession *session,
                 gpointer user_data)
 {
     plugin_data *data = user_data;
-    xml_astro *astro = NULL;
+    xmlDoc *doc;
+    xmlNode *root_node;
     time_t now_t;
-    struct tm now_tm;
+    gboolean parsing_error = TRUE;
 
     time(&now_t);
-    now_tm = *localtime(&now_t);
+    data->astro_update->attempt++;
     if ((msg->status_code == 200 || msg->status_code == 203)) {
         if (msg->status_code == 203)
             g_warning
@@ -467,47 +493,38 @@ cb_astro_update(SoupSession *session,
                    "within a few month. Please file a bug on "
                    "https://bugzilla.xfce.org if no one else has done so "
                    "yet."));
-        if ((astro = (xml_astro *)
-             parse_xml_document(msg, (XmlParseFunc) parse_astro))) {
-            if (data->astrodata)
-                xml_astro_free(data->astrodata);
-            data->astrodata = astro;
-
-            /* schedule next update at 00:00 of the next day */
-            data->astro_update->last = now_t;
-            data->astro_update->next =
-                time_calc(now_tm, 0, 0, 1, 0 - now_tm.tm_hour,
-                          0 - now_tm.tm_min, 0 - now_tm.tm_sec);
-            data->astro_update->attempt = 0;
-        } else
+
+        doc = get_xml_document(msg);
+        if (G_LIKELY(doc)) {
+            root_node = xmlDocGetRootElement(doc);
+            if (G_LIKELY(root_node))
+                if (parse_astrodata(root_node, data->astrodata)) {
+                    /* schedule next update */
+                    data->astro_update->attempt = 0;
+                    data->astro_update->last = now_t;
+                    parsing_error = FALSE;
+                }
+            xmlFreeDoc(doc);
+        }
+        if (parsing_error)
             g_warning(_("Error parsing astronomical data!"));
     } else
         g_warning(_("Download of astronomical data failed with "
                     "HTTP Status Code %d, Reason phrase: %s"),
                   msg->status_code, msg->reason_phrase);
+    data->astro_update->next = calc_next_download_time(data->astro_update,
+                                                       now_t);
 
-    if (G_UNLIKELY(astro == NULL)) {
-        /* download or parsing failed, schedule retry */
-        data->astro_update->attempt++;
-        data->astro_update->next = calc_next_download_time(data->astro_update,
-                                                           now_t);
-
-        /* invalidate obsolete sunrise/sunset data */
-        if (data->astrodata != NULL &&
-            difftime(data->astrodata->sunset, now_t) < 0 &&
-            difftime(data->astrodata->sunrise, now_t) < 0) {
-            xml_astro_free(data->astrodata);
-            data->astrodata = NULL;
-            weather_debug("Obsolete astronomical data has been invalidated.");
-        }
-    }
+    astrodata_clean(data->astrodata);
+    g_array_sort(data->astrodata, (GCompareFunc) xml_astro_compare);
+    update_current_astrodata(data);
 
     /* update icon */
-    data->night_time = is_night_time(data->astrodata);
+    data->night_time = is_night_time(data->current_astro);
     update_icon(data);
 
     schedule_next_wakeup(data);
-    weather_dump(weather_dump_astrodata, data->astrodata);
+    weather_dump(weather_dump_astrodata, data->current_astro);
 }
 
 
@@ -573,8 +590,8 @@ update_handler(plugin_data *data)
 {
     gchar *url;
     gboolean night_time;
-    time_t now_t;
-    struct tm now_tm;
+    time_t now_t, end_t;
+    struct tm now_tm, end_tm;
 
     g_assert(data != NULL);
     if (G_UNLIKELY(data == NULL))
@@ -597,13 +614,22 @@ update_handler(plugin_data *data)
            this is to prevent spawning multiple updates in a row */
         data->astro_update->next = time_calc_hour(now_tm, 1);
 
+        /* calculate date range for request */
+        end_t = time_calc_day(now_tm, ASTRODATA_MAX_DAYS);
+        end_tm = *localtime(&end_t);
+
         /* build url */
         url = g_strdup_printf("http://api.yr.no/weatherapi/sunrise/1.0/?"
-                              "lat=%s;lon=%s;date=%04d-%02d-%02d",
+                              "lat=%s;lon=%s;"
+                              "from=%04d-%02d-%02d;"
+                              "to=%04d-%02d-%02d",
                               data->lat, data->lon,
                               now_tm.tm_year + 1900,
                               now_tm.tm_mon + 1,
-                              now_tm.tm_mday);
+                              now_tm.tm_mday,
+                              end_tm.tm_year + 1900,
+                              end_tm.tm_mon + 1,
+                              end_tm.tm_mday);
 
         /* start receive thread */
         g_message(_("getting %s"), url);
@@ -647,7 +673,8 @@ update_handler(plugin_data *data)
     }
 
     /* update night time status and icon */
-    night_time = is_night_time(data->astrodata);
+    update_current_astrodata(data);
+    night_time = is_night_time(data->current_astro);
     if (data->night_time != night_time) {
         weather_debug("Night time status changed, updating icon.");
         data->night_time = night_time;
@@ -684,14 +711,14 @@ schedule_next_wakeup(plugin_data *data)
 
     /* If astronomical data is unavailable, current conditions update
        will usually handle night/day. */
-    if (data->astrodata) {
+    if (data->current_astro) {
         if (data->night_time &&
-            difftime(data->astrodata->sunrise, now_t) >= 0)
-            SCHEDULE_WAKEUP_COMPARE(data->astrodata->sunrise,
+            difftime(data->current_astro->sunrise, now_t) >= 0)
+            SCHEDULE_WAKEUP_COMPARE(data->current_astro->sunrise,
                                     "sunrise icon change");
         if (!data->night_time &&
-            difftime(data->astrodata->sunset, now_t) >= 0)
-            SCHEDULE_WAKEUP_COMPARE(data->astrodata->sunset,
+            difftime(data->current_astro->sunset, now_t) >= 0)
+            SCHEDULE_WAKEUP_COMPARE(data->current_astro->sunset,
                                     "sunset icon change");
     }
 
@@ -1013,6 +1040,7 @@ write_cache_file(plugin_data *data)
     xml_weather *wd = data->weatherdata;
     xml_time *timeslice;
     xml_location *loc;
+    xml_astro *astro;
     gchar *file, *start, *end, *point, *now, *value;
     gchar *date_format = "%Y-%m-%dT%H:%M:%SZ";
     time_t now_t = time(NULL);
@@ -1034,38 +1062,49 @@ write_cache_file(plugin_data *data)
         CACHE_APPEND("last_weather_download=%s\n", value);
         g_free(value);
     }
+    if (G_LIKELY(data->astro_update)) {
+        value = format_date(data->astro_update->last, date_format, FALSE);
+        CACHE_APPEND("last_astro_download=%s\n", value);
+        g_free(value);
+    }
     now = format_date(now_t, date_format, FALSE);
     CACHE_APPEND("cache_date=%s\n\n", now);
     g_free(now);
 
     if (data->astrodata) {
-        start = format_date(data->astrodata->sunrise, date_format, FALSE);
-        end = format_date(data->astrodata->sunset, date_format, FALSE);
-        g_string_append_printf(out, "[astrodata]\n");
-        CACHE_APPEND("sunrise=%s\n", start);
-        CACHE_APPEND("sunset=%s\n", end);
-        CACHE_APPEND("sun_never_rises=%s\n",
-                     data->astrodata->sun_never_rises ? "true" : "false");
-        CACHE_APPEND("sun_never_sets=%s\n",
-                     data->astrodata->sun_never_sets ? "true" : "false");
-        g_free(start);
-        g_free(end);
-
-        start = format_date(data->astrodata->moonrise, date_format, FALSE);
-        end = format_date(data->astrodata->moonset, date_format, FALSE);
-        CACHE_APPEND("moonrise=%s\n", start);
-        CACHE_APPEND("moonset=%s\n", end);
-        CACHE_APPEND("moon_never_rises=%s\n",
-                     data->astrodata->moon_never_rises ? "true" : "false");
-        CACHE_APPEND("moon_never_sets=%s\n",
-                     data->astrodata->moon_never_sets ? "true" : "false");
-        CACHE_APPEND("moon_phase=%s\n", data->astrodata->moon_phase);
-        g_free(start);
-        g_free(end);
-
-        now = format_date(now_t, date_format, FALSE);
-        CACHE_APPEND("last_astro_download=%s\n\n", now);
-        g_free(now);
+        for (i = 0; i < data->astrodata->len; i++) {
+            astro = g_array_index(data->astrodata, xml_astro *, i);
+            if (G_UNLIKELY(astro == NULL))
+                continue;
+            value = format_date(astro->day, date_format, TRUE);
+            start = format_date(astro->sunrise, date_format, FALSE);
+            end = format_date(astro->sunset, date_format, FALSE);
+            g_string_append_printf(out, "[astrodata%d]\n", i);
+            CACHE_APPEND("day=%s\n", value);
+            CACHE_APPEND("sunrise=%s\n", start);
+            CACHE_APPEND("sunset=%s\n", end);
+            CACHE_APPEND("sun_never_rises=%s\n",
+                         astro->sun_never_rises ? "true" : "false");
+            CACHE_APPEND("sun_never_sets=%s\n",
+                         astro->sun_never_sets ? "true" : "false");
+            g_free(value);
+            g_free(start);
+            g_free(end);
+
+            start = format_date(astro->moonrise, date_format, FALSE);
+            end = format_date(astro->moonset, date_format, FALSE);
+            CACHE_APPEND("moonrise=%s\n", start);
+            CACHE_APPEND("moonset=%s\n", end);
+            CACHE_APPEND("moon_never_rises=%s\n",
+                         astro->moon_never_rises ? "true" : "false");
+            CACHE_APPEND("moon_never_sets=%s\n",
+                         astro->moon_never_sets ? "true" : "false");
+            CACHE_APPEND("moon_phase=%s\n", astro->moon_phase);
+            g_free(start);
+            g_free(end);
+
+            g_string_append(out, "\n");
+        }
     } else
         g_string_append(out, "\n");
 
@@ -1128,11 +1167,10 @@ read_cache_file(plugin_data *data)
     xml_weather *wd;
     xml_time *timeslice = NULL;
     xml_location *loc = NULL;
-    time_t now_t = time(NULL), cache_date_t, astro_data_t;
-    struct tm cache_date_tm;
+    xml_astro *astro = NULL;
+    time_t now_t = time(NULL), cache_date_t;
     gchar *file, *locname = NULL, *lat = NULL, *lon = NULL, *group = NULL;
     gchar *timestring;
-    gdouble diff;
     gint msl, num_timeslices = 0, i, j;
 
     g_assert(data != NULL);
@@ -1201,55 +1239,60 @@ read_cache_file(plugin_data *data)
                                     data->weather_update->last);
         g_free(timestring);
     }
+    if (G_LIKELY(data->astro_update)) {
+        CACHE_READ_STRING(timestring, "last_astro_download");
+        data->astro_update->last = parse_timestring(timestring, NULL);
+        data->astro_update->next =
+            calc_next_download_time(data->astro_update,
+                                    data->astro_update->last);
+        g_free(timestring);
+    }
 
     /* read cached astrodata if available and up-to-date */
-    group = "astrodata";
-    cache_date_tm = *localtime(&cache_date_t);
-    astro_data_t =
-        time_calc(cache_date_tm, 0, 0, 0, 0 - cache_date_tm.tm_hour,
-                  0 - cache_date_tm.tm_min, 0 - cache_date_tm.tm_sec);
-    diff = difftime(now_t, astro_data_t);
-    if (g_key_file_has_group(keyfile, group)
-        && diff > 0 && diff < 24 * 3600) {
-        weather_debug("Reusing cached astrodata instead of downloading it.");
-
-        /* clear current astro data if present */
-        if (data->astrodata)
-            xml_astro_free(data->astrodata);
-        data->astrodata = g_slice_new0(xml_astro);
-
+    i = 0;
+    group = g_strdup_printf("astrodata%d", i);
+    while (g_key_file_has_group(keyfile, group)) {
+        if (i == 0)
+            weather_debug("Reusing cached astrodata instead of downloading it.");
+
+        astro = g_slice_new0(xml_astro);
+        if (G_UNLIKELY(astro == NULL))
+            break;
+
+        CACHE_READ_STRING(timestring, "day");
+        astro->day = parse_timestring(timestring, NULL);
+        astro->day = day_at_midnight(astro->day, 0);
+        g_free(timestring);
         CACHE_READ_STRING(timestring, "sunrise");
-        data->astrodata->sunrise = parse_timestring(timestring, NULL);
+        astro->sunrise = parse_timestring(timestring, NULL);
         g_free(timestring);
         CACHE_READ_STRING(timestring, "sunset");
-        data->astrodata->sunset = parse_timestring(timestring, NULL);
+        astro->sunset = parse_timestring(timestring, NULL);
         g_free(timestring);
-        data->astrodata->sun_never_rises =
+        astro->sun_never_rises =
             g_key_file_get_boolean(keyfile, group, "sun_never_rises", NULL);
-        data->astrodata->sun_never_sets =
+        astro->sun_never_sets =
             g_key_file_get_boolean(keyfile, group, "sun_never_sets", NULL);
 
         CACHE_READ_STRING(timestring, "moonrise");
-        data->astrodata->moonrise = parse_timestring(timestring, NULL);
+        astro->moonrise = parse_timestring(timestring, NULL);
         g_free(timestring);
         CACHE_READ_STRING(timestring, "moonset");
-        data->astrodata->moonset = parse_timestring(timestring, NULL);
+        astro->moonset = parse_timestring(timestring, NULL);
         g_free(timestring);
-        CACHE_READ_STRING(data->astrodata->moon_phase, "moon_phase");
-        data->astrodata->moon_never_rises =
+        CACHE_READ_STRING(astro->moon_phase, "moon_phase");
+        astro->moon_never_rises =
             g_key_file_get_boolean(keyfile, group, "moon_never_rises", NULL);
-        data->astrodata->moon_never_sets =
+        astro->moon_never_sets =
             g_key_file_get_boolean(keyfile, group, "moon_never_sets", NULL);
 
-        if (G_LIKELY(data->astro_update)) {
-            CACHE_READ_STRING(timestring, "last_astro_download");
-            data->astro_update->last = parse_timestring(timestring, NULL);
-            g_free(timestring);
-            data->astro_update->next =
-                time_calc(cache_date_tm, 0, 0, 1, 0 - cache_date_tm.tm_hour,
-                          0 - cache_date_tm.tm_min, 0 - cache_date_tm.tm_sec);
-        }
+        merge_astro(data->astrodata, astro);
+        xml_astro_free(astro);
+
+        g_free(group);
+        group = g_strdup_printf("astrodata%d", ++i);
     }
+    g_free(group);
     group = NULL;
 
     /* parse available timeslices */
@@ -1352,6 +1395,7 @@ update_weatherdata_with_reset(plugin_data *data)
 
     /* make use of previously saved data */
     read_cache_file(data);
+    update_current_astrodata(data);
 
     /* schedule downloads immediately */
     time(&now_t);
@@ -1595,16 +1639,19 @@ weather_get_tooltip_text(const plugin_data *data)
     interval_end = format_date(conditions->end, "%H:%M", TRUE);
 
     /* use sunrise and sunset times if available */
-    if (data->astrodata)
-        if (data->astrodata->sun_never_rises) {
+    if (data->current_astro)
+        if (data->current_astro->sun_never_rises) {
             sunval = g_strdup(_("The sun never rises today."));
-        } else if (data->astrodata->sun_never_sets) {
+        } else if (data->current_astro->sun_never_sets) {
             sunval = g_strdup(_("The sun never sets today."));
         } else {
-            sunrise = format_date(data->astrodata->sunrise, "%H:%M:%S", TRUE);
-            sunset = format_date(data->astrodata->sunset, "%H:%M:%S", TRUE);
-            sunval = g_strdup_printf(_("The sun rises at %s and sets at %s."),
-                                     sunrise, sunset);
+            sunrise = format_date(data->current_astro->sunrise,
+                                  "%H:%M:%S", TRUE);
+            sunset = format_date(data->current_astro->sunset,
+                                 "%H:%M:%S", TRUE);
+            sunval =
+                g_strdup_printf(_("The sun rises at %s and sets at %s."),
+                                sunrise, sunset);
             g_free(sunrise);
             g_free(sunset);
         }
@@ -1741,6 +1788,7 @@ xfceweather_create_control(XfcePanelPlugin *plugin)
 #endif
     data->units = g_slice_new0(units_config);
     data->weatherdata = make_weather_data();
+    data->astrodata = g_array_sized_new(FALSE, TRUE, sizeof(xml_astro *), 30);
     data->cache_file_max_age = CACHE_FILE_MAX_AGE;
     data->show_scrollbox = TRUE;
     data->scrollbox_lines = 1;
@@ -1864,9 +1912,6 @@ xfceweather_free(XfcePanelPlugin *plugin,
     if (data->weatherdata)
         xml_weather_free(data->weatherdata);
 
-    if (data->astrodata)
-        xml_astro_free(data->astrodata);
-
     if (data->units)
         g_slice_free(units_config, data->units);
 
@@ -1886,8 +1931,12 @@ xfceweather_free(XfcePanelPlugin *plugin,
     g_slice_free(update_info, data->astro_update);
     g_slice_free(update_info, data->conditions_update);
 
-    /* free label array */
+    /* free current data */
+    data->current_astro = NULL;
+
+    /* free arrays */
     g_array_free(data->labels, TRUE);
+    astrodata_free(data->astrodata);
 
     /* free icon theme */
     icon_theme_free(data->icon_theme);
@@ -2044,6 +2093,7 @@ weather_construct(XfcePanelPlugin *plugin)
     xfceweather_read_config(plugin, data);
     update_timezone(data);
     read_cache_file(data);
+    update_current_astrodata(data);
     scrollbox_set_visible(data);
     gtk_scrollbox_set_fontname(GTK_SCROLLBOX(data->scrollbox),
                                data->scrollbox_font);
diff --git a/panel-plugin/weather.h b/panel-plugin/weather.h
index 69c2e8f..575a77a 100644
--- a/panel-plugin/weather.h
+++ b/panel-plugin/weather.h
@@ -86,7 +86,8 @@ typedef struct {
     GtkOrientation panel_orientation;
     gboolean single_row;
     xml_weather *weatherdata;
-    xml_astro *astrodata;
+    GArray *astrodata;
+    xml_astro *current_astro;
 
     update_info *astro_update;
     update_info *weather_update;


More information about the Xfce4-commits mailing list