デスクトップマスコット「Apricot」に天気予報を追加するスクリプト

livedoor 天気情報
http://weather.livedoor.com/


livedoorのお天気Webサービスで公開されているAPIを使ってApricotに天気予報を追加するスクリプトを書いてみました。スクリプトを追加すると今日から明後日までの天気予報をキャラクターが喋るようになります。

このWebサービスは、イメージのURIも取得できるので上のスクリーンショットのようにイメージ付で表示出来るのが特にいいです。


下記のコードを拡張子をpy(例:Weather.py)にしてScriptsフォルダに保存すると、Apricotに天気予報を追加できます。
デフォルトは東京なので東京以外の方は、liveoorの公開している1次細分区定義表からcityのIDを変更する必要があります。

1次細分区定義表
http://weather.livedoor.com/forecast/rss/forecastmap.xml

# -*- encoding: utf-8 -*-

import clr
clr.AddReferenceByPartialName("System.Xml")
clr.AddReferenceByPartialName("Apricot")

from System import String, Uri, DateTime, TimeSpan, TimeZone, Convert
from System.IO import Stream, StreamReader
from System.Collections.Generic import List
from System.Globalization import CultureInfo, DateTimeStyles
from System.Text.RegularExpressions import Regex, RegexOptions, Match
from System.Timers import Timer
from System.Net import WebRequest, WebResponse
from System.Net.NetworkInformation import NetworkInterface
from System.Xml import XmlDocument, XmlNode, XmlAttribute
from Apricot import Entry

# livedoor Weather
# http://weather.livedoor.com/weather_hacks/webservice.html
# http://weather.livedoor.com/forecast/rss/forecastmap.xml
uriList = List[Uri]()
uriList.Add(Uri("http://weather.livedoor.com/forecast/webservice/rest/v1?city=63&day=today"))
uriList.Add(Uri("http://weather.livedoor.com/forecast/webservice/rest/v1?city=63&day=tomorrow"))
uriList.Add(Uri("http://weather.livedoor.com/forecast/webservice/rest/v1?city=63&day=dayaftertomorrow"))

format = "M月d日"

def parse(s):
	dt = DateTime()
	invalidTimeZone = False
	index = s.Length;
	match = Regex.Match(s, "\\s[\\+\\-0-9A-Z]+$", RegexOptions.CultureInvariant)

	if match.Success:
		index = match.Index
	else:
		invalidTimeZone = true

	dt = Convert.ToDateTime(s.Substring(0, index))

	if s.Length - index > 0:
		if s[index + 1] == '+':
			if s.Length - (index + 1) == 5:
				h = Convert.ToInt32(s.Substring(index + 2, 2))
				dt = dt.AddHours(-h)
				m = Convert.ToInt32(s.Substring(index + 4, 2))
				dt = dt.AddMinutes(-m)
			else:
				invalidTimeZone = true;
		elif s[index + 1] == '-':
			if s.Length - (index + 1) == 5:
				h = Convert.ToInt32(s.Substring(index + 2, 2))
				dt = dt.AddHours(h)
				m = Convert.ToInt32(s.Substring(index + 4, 2))
				dt = dt.AddMinutes(m)
			else:
				invalidTimeZone = true

	if invalidTimeZone == False:
		dt = dt.Add(TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now))

	return dt

def update():
	global dateTime, uriList, format

	try:
		if not NetworkInterface.GetIsNetworkAvailable() and uriList == None:
			return
		
		dt = DateTime()
		entryList = List[Entry]()
		
		for uri in uriList:
			request = WebRequest.Create(uri)
			response = request.GetResponse()
			stream = response.GetResponseStream()
			doc = XmlDocument()
			doc.Load(stream)

			for lwwsXmlNode in doc.SelectNodes("/lwws"):
				newEntry = Entry()
				telop = String.Empty
				title = String.Empty
				city = String.Empty
				forecastDate = String.Empty

				for xmlNode in lwwsXmlNode.ChildNodes:
					if xmlNode.Name.Equals("title"):
						title = xmlNode.InnerText
					if xmlNode.Name.Equals("telop"):
						telop = xmlNode.InnerText
					elif xmlNode.Name.Equals("link"):
						newEntry.Resource = Uri(xmlNode.InnerText)
					elif xmlNode.Name.Equals("author"):
						newEntry.Author = xmlNode.InnerText
					elif xmlNode.Name.Equals("forecastdate"):
						forecastDate = parse(xmlNode.InnerText).ToString(format)
					elif xmlNode.Name.Equals("publictime"):
						newEntry.Created = newEntry.Modified = parse(xmlNode.InnerText)
					elif xmlNode.Name.Equals("location"):
						for attr in xmlNode.Attributes:
							if attr.Name.Equals("city"):
								city = attr.Value
					elif xmlNode.Name.Equals("image"):
						for childXmlNode in xmlNode.ChildNodes:
							if childXmlNode.Name.Equals("url"):
								newEntry.ImageUri = Uri(childXmlNode.InnerText)
				
				newEntry.Title = city + " - " + telop + " - " + forecastDate

				if newEntry.Modified > dt:
					dt = newEntry.Modified

				if newEntry.Modified > dateTime:
					entryList.Add(newEntry)
			
			if stream != None:
				stream.Close()
			
			if response != None:
				response.Close()

		if entryList.Count > 0:
			Script.Alert(entryList)

			if dt > dateTime:
				dateTime = dt
			else:
				dateTime = DateTime.Now
		
	except:
		return

def onTimedEvent(timer, e):
	update()

	timer.Interval = 1000 * 60 * 5
	timer.AutoReset = True
	timer.Start()

def onStart(s, e):
	global timer
	timer.Interval = 1000 * 60
	timer.AutoReset = False
	timer.Start()

def onStop(s, e):
	global timer
	timer.Stop()

dateTime = DateTime()
timer = Timer()
timer.Elapsed += onTimedEvent
timer.Enabled = False
Script.Start += onStart
Script.Stop += onStop