| 001 | #!/usr/bin/env osascript |
| 002 | #coding: utf-8 |
| 003 | ----+----1----+----2----+-----3----+----4----+----5----+----6----+----7 |
| 004 | (* |
| 005 | 気象庁のJSON取得 |
| 006 | Jsonの取得と解析は難しくないが |
| 007 | 『海がない気象台』『観測所にはURLがない』とかがあることをお忘れなく |
| 008 | V1初回作成 |
| 009 | V2 色々直した |
| 010 | v2.1 海なし県対応で修正した |
| 011 |
|
| 012 | com.cocolog-nifty.quicktimer.icefloe*) |
| 013 | ----+----1----+----2----+-----3----+----4----+----5----+----6----+----7 |
| 014 | use AppleScript version "2.8" |
| 015 | use framework "Foundation" |
| 016 | use framework "AppKit" |
| 017 | use framework "UniformTypeIdentifiers" |
| 018 | use scripting additions |
| 019 | property refMe : a reference to current application |
| 020 | #################### |
| 021 | #設定項目 |
| 022 | set strAreaUrl to "https://www.jma.go.jp/bosai/common/const/area.json" |
| 023 |
|
| 024 | #################### |
| 025 | #出力用テキスト |
| 026 | set ocidOutPutArray to refMe's NSMutableArray's alloc()'s init() |
| 027 | #################### |
| 028 | #URL |
| 029 | set ocidAreaUrlStr to refMe's NSString's stringWithString:(strAreaUrl) |
| 030 | set ocidAreaURL to refMe's NSURL's alloc()'s initWithString:(ocidAreaUrlStr) |
| 031 | #################### |
| 032 | #メタ |
| 033 |
|
| 034 | set strLF to ("" & linefeed & "") as text |
| 035 | set strCR to ("" & return & "") as text |
| 036 | set strCRLF to ("" & return & linefeed & "") as text |
| 037 | set strSpace to ("" & space & "") as text |
| 038 | set strTab to ("" & tab & "") as text |
| 039 | #################### |
| 040 | #NSDATA |
| 041 | set ocidOption to (refMe's NSDataReadingMappedIfSafe) |
| 042 | set listResponse to refMe's NSData's alloc()'s initWithContentsOfURL:(ocidAreaURL) options:(ocidOption) |error|:(reference) |
| 043 | if (item 2 of listResponse) = (missing value) then |
| 044 | log "initWithContentsOfURL 正常処理" |
| 045 | set ocidReadJsonData to (item 1 of listResponse) |
| 046 | else if (item 2 of listResponse) ≠ (missing value) then |
| 047 | set strErrorNO to (item 2 of listResponse)'s code() as text |
| 048 | set strErrorMes to (item 2 of listResponse)'s localizedDescription() as text |
| 049 | refMe's NSLog("■:" & strErrorNO & strErrorMes) |
| 050 | return "initWithContentsOfURL エラーしました" & strErrorNO & strErrorMes |
| 051 | end if |
| 052 | #################### |
| 053 | #JSON ルートがDICT |
| 054 | set ocidOption to (refMe's NSJSONReadingJSON5Allowed) |
| 055 | set listResponse to (refMe's NSJSONSerialization's JSONObjectWithData:(ocidReadJsonData) options:(ocidOption) |error|:(reference)) |
| 056 | if (item 2 of listResponse) = (missing value) then |
| 057 | log "JSONObjectWithData 正常処理" |
| 058 | set ocidJsonDict to (item 1 of listResponse) |
| 059 | else if (item 2 of listResponse) ≠ (missing value) then |
| 060 | set strErrorNO to (item 2 of listResponse)'s code() as text |
| 061 | set strErrorMes to (item 2 of listResponse)'s localizedDescription() as text |
| 062 | refMe's NSLog("■:" & strErrorNO & strErrorMes) |
| 063 | return "JSONObjectWithData エラーしました" & strErrorNO & strErrorMes |
| 064 | end if |
| 065 | #################### |
| 066 | #centers |
| 067 | set ocidCentersDict to ocidJsonDict's objectForKey:("centers") |
| 068 | set ocidCentersArray to ocidCentersDict's allKeys() |
| 069 | #ソート |
| 070 | set ocidCentersArray to ocidCentersArray's sortedArrayUsingSelector:("compare:") |
| 071 | #ダイアログ用の地方気象台名リスト |
| 072 | set listCenterName to {} as list |
| 073 | #逆引きDICT |
| 074 | set ocidReverseCenterDict to refMe's NSMutableDictionary's alloc()'s init() |
| 075 | repeat with itemKey in ocidCentersArray |
| 076 | set ocidCenter to (ocidCentersDict's valueForKey:(itemKey)) |
| 077 | set strCenterName to (ocidCenter's valueForKey:("officeName")) as text |
| 078 | copy strCenterName to end of listCenterName |
| 079 | (ocidReverseCenterDict's setValue:(itemKey) forKey:(strCenterName)) |
| 080 | end repeat |
| 081 | log ocidReverseCenterDict as record |
| 082 | #################### |
| 083 | #ダイアログ |
| 084 | set strName to (name of current application) as text |
| 085 | if strName is "osascript" then |
| 086 | tell application "SystemUIServer" to activate |
| 087 | else |
| 088 | tell current application to activate |
| 089 | end if |
| 090 | try |
| 091 | tell application "SystemUIServer" |
| 092 | activate |
| 093 | set valueResponse to (choose from list listCenterName with title "選んでください" with prompt "地方気象台を選んでください" default items (item 3 of listCenterName) OK button name "OK" cancel button name "キャンセル" with multiple selections allowed without empty selection allowed) |
| 094 | end tell |
| 095 | on error |
| 096 | tell application "SystemUIServer" to quit |
| 097 | log "Error choose from list" |
| 098 | return false |
| 099 | end try |
| 100 | tell application "SystemUIServer" to quit |
| 101 | if (class of valueResponse) is boolean then |
| 102 | log "Error キャンセルしました" |
| 103 | error "ユーザによってキャンセルされました。" number -128 |
| 104 | else if (class of valueResponse) is list then |
| 105 | if valueResponse is {} then |
| 106 | log "Error 何も選んでいません" |
| 107 | return false |
| 108 | else |
| 109 | set strResponse to (item 1 of valueResponse) as text |
| 110 | end if |
| 111 | end if |
| 112 | set ocidOutPutStrint to refMe's NSString's stringWithString:("天気予報: Center: " & strResponse & strLF) |
| 113 | (ocidOutPutArray's addObject:(ocidOutPutStrint)) |
| 114 | #################### |
| 115 | #逆引き辞書からセンター番号を取得 |
| 116 | set ocidCenterNo to ocidReverseCenterDict's valueForKey:(strResponse) |
| 117 | #センター番号からOffice情報を取得 |
| 118 | set ocidOfficeDict to (ocidCentersDict's objectForKey:(ocidCenterNo)) |
| 119 | #Office情報 DICTから気象台番号を取得 |
| 120 | set ocidOfficeNoArray to (ocidOfficeDict's objectForKey:("children")) |
| 121 | set ocidOfficeNoArray to ocidOfficeNoArray's sortedArrayUsingSelector:("compare:") |
| 122 | #################### |
| 123 | #offices |
| 124 | set ocidOfficesDict to ocidJsonDict's objectForKey:("offices") |
| 125 | set ocidOfficesArray to ocidOfficesDict's allKeys() |
| 126 | #測候所はURLがないので除外 |
| 127 | set appPredicate to refMe's NSPredicate's predicateWithFormat_("SELF CONTAINS %@", "測候所") |
| 128 | set ocidOfficesArrayRev to ocidOfficesArray's filteredArrayUsingPredicate:(appPredicate) |
| 129 | set ocidOfficesArray to ocidOfficesArrayRev's sortedArrayUsingSelector:("compare:") |
| 130 | #ダイアログ用の気象台名リスト |
| 131 | set listOfficesName to {} as list |
| 132 | #逆引きDICT |
| 133 | set ocidReverseOfficesDict to refMe's NSMutableDictionary's alloc()'s init() |
| 134 | repeat with itemKey in ocidOfficeNoArray |
| 135 | set ocidOffice to (ocidOfficesDict's valueForKey:(itemKey)) |
| 136 | set strOfficeName to (ocidOffice's valueForKey:("officeName")) as text |
| 137 | if strOfficeName does not contain "測候所" then |
| 138 | copy strOfficeName to end of listOfficesName |
| 139 | (ocidReverseOfficesDict's setValue:(itemKey) forKey:(strOfficeName)) |
| 140 | end if |
| 141 | end repeat |
| 142 | log ocidReverseOfficesDict as record |
| 143 | #################### |
| 144 | #ダイアログ |
| 145 | set strName to (name of current application) as text |
| 146 | if strName is "osascript" then |
| 147 | tell application "SystemUIServer" to activate |
| 148 | else |
| 149 | tell current application to activate |
| 150 | end if |
| 151 | try |
| 152 | tell application "SystemUIServer" |
| 153 | activate |
| 154 | set valueResponse to (choose from list listOfficesName with title "選んでください" with prompt "気象台を選んでください" default items (last item of listOfficesName) OK button name "OK" cancel button name "キャンセル" with multiple selections allowed without empty selection allowed) |
| 155 | end tell |
| 156 | on error |
| 157 | tell application "SystemUIServer" to quit |
| 158 | log "Error choose from list" |
| 159 | return false |
| 160 | end try |
| 161 | tell application "SystemUIServer" to quit |
| 162 | if (class of valueResponse) is boolean then |
| 163 | log "Error キャンセルしました" |
| 164 | error "ユーザによってキャンセルされました。" number -128 |
| 165 | else if (class of valueResponse) is list then |
| 166 | if valueResponse is {} then |
| 167 | log "Error 何も選んでいません" |
| 168 | return false |
| 169 | else |
| 170 | set strResponse to (item 1 of valueResponse) as text |
| 171 | end if |
| 172 | end if |
| 173 | set ocidOutPutStrint to refMe's NSString's stringWithString:("Office: " & strResponse & " 発表" & strLF) |
| 174 | (ocidOutPutArray's addObject:(ocidOutPutStrint)) |
| 175 | ####################### |
| 176 | #本処理 天気予報jSON取得 |
| 177 | set ocidOfficeNo to ocidReverseOfficesDict's valueForKey:(strResponse) |
| 178 | set strOfficeNo to ocidOfficeNo as text |
| 179 | #日付 |
| 180 | set strDate to doGetDateNo("yyyyMMddhhmmss") as text |
| 181 | ###URL整形 |
| 182 | set strURL to ("https://www.jma.go.jp/bosai/forecast/data/forecast/" & strOfficeNo & ".json?__time__=" & strDate & "") as text |
| 183 | log strCR & strURL & strCR |
| 184 | #################### |
| 185 | #URL |
| 186 | set ocidUrlStr to refMe's NSString's stringWithString:(strURL) |
| 187 | set ocidURL to refMe's NSURL's alloc()'s initWithString:(ocidUrlStr) |
| 188 | #################### |
| 189 | #NSDATA |
| 190 | set ocidOption to (refMe's NSDataReadingMappedIfSafe) |
| 191 | set listResponse to refMe's NSData's alloc()'s initWithContentsOfURL:(ocidURL) options:(ocidOption) |error|:(reference) |
| 192 | if (item 2 of listResponse) = (missing value) then |
| 193 | log "initWithContentsOfURL 正常処理" |
| 194 | set ocidReadJsonData to (item 1 of listResponse) |
| 195 | else if (item 2 of listResponse) ≠ (missing value) then |
| 196 | set strErrorNO to (item 2 of listResponse)'s code() as text |
| 197 | set strErrorMes to (item 2 of listResponse)'s localizedDescription() as text |
| 198 | refMe's NSLog("■:" & strErrorNO & strErrorMes) |
| 199 | return "initWithContentsOfURL エラーしました" & strErrorNO & strErrorMes |
| 200 | end if |
| 201 | #################### |
| 202 | #JSON ルートがArray |
| 203 | set ocidOption to (refMe's NSJSONReadingJSON5Allowed) |
| 204 | set listResponse to (refMe's NSJSONSerialization's JSONObjectWithData:(ocidReadJsonData) options:(ocidOption) |error|:(reference)) |
| 205 | if (item 2 of listResponse) = (missing value) then |
| 206 | log "JSONObjectWithData 正常処理" |
| 207 | set ocidJsonArray to (item 1 of listResponse) |
| 208 | else if (item 2 of listResponse) ≠ (missing value) then |
| 209 | set strErrorNO to (item 2 of listResponse)'s code() as text |
| 210 | set strErrorMes to (item 2 of listResponse)'s localizedDescription() as text |
| 211 | refMe's NSLog("■:" & strErrorNO & strErrorMes) |
| 212 | return "JSONObjectWithData エラーしました" & strErrorNO & strErrorMes |
| 213 | end if |
| 214 | #################### |
| 215 | #天気予報辞書 天気予報 と 習慣天気予報 |
| 216 | set ocidDailyDict to ocidJsonArray's firstObject() |
| 217 | set ocidWeeklyDict to ocidJsonArray's firstObject() |
| 218 | #################### |
| 219 | #各項目取得 |
| 220 | set ocidTimeSeriesArray to ocidDailyDict's objectForKey:("timeSeries") |
| 221 | set ocidWeathers to ocidTimeSeriesArray's firstObject() |
| 222 | set ocidRainPops to ocidTimeSeriesArray's objectAtIndex:(1) |
| 223 | set ocidTemps to ocidTimeSeriesArray's lastObject() |
| 224 | #################### |
| 225 | #天気予報 |
| 226 | set strOutPutStrint to ("") as text |
| 227 | set ocidAreaArray to ocidWeathers's objectForKey:("areas") |
| 228 | repeat with itemArea in ocidAreaArray |
| 229 | set strAreaName to ((itemArea's objectForKey:("area"))'s valueForKey:("name")) as text |
| 230 | set ocidWeathersArray to (itemArea's objectForKey:("weathers")) |
| 231 | set ocidWindsArray to (itemArea's objectForKey:("winds")) |
| 232 | set ocidWavesArray to (itemArea's objectForKey:("waves")) |
| 233 | set numCntWavesArray to ocidWeathersArray's |count|() |
| 234 | repeat with itemNo from 0 to (numCntWavesArray - 1) by 1 |
| 235 | set strOutPutStrint to ("" & strOutPutStrint & strAreaName & "地方" & strLF) as text |
| 236 | if itemNo = 0 then |
| 237 | set strOutPutStrint to ("" & strOutPutStrint & "今日の天気: ") as text |
| 238 | else if itemNo = 1 then |
| 239 | set strOutPutStrint to ("" & strOutPutStrint & "明日の天気: ") as text |
| 240 | else if itemNo = 2 then |
| 241 | set strOutPutStrint to ("" & strOutPutStrint & "明後日の天気: ") as text |
| 242 | end if |
| 243 | set strSetString to (ocidWeathersArray's objectAtIndex:(itemNo)) |
| 244 | set strOutPutStrint to ("" & strOutPutStrint & strSetString & strLF & strTab & "風: ") as text |
| 245 | set strSetString to (ocidWindsArray's objectAtIndex:(itemNo)) |
| 246 | set strOutPutStrint to ("" & strOutPutStrint & strSetString & strLF) as text |
| 247 | if ocidWavesArray ≠ (missing value) then |
| 248 | set strSetString to (ocidWavesArray's objectAtIndex:(itemNo)) |
| 249 | set strOutPutStrint to ("" & strOutPutStrint & strTab & "波: " & strSetString & strLF) as text |
| 250 | end if |
| 251 | end repeat |
| 252 | |
| 253 | set strOutPutStrint to ("" & strOutPutStrint & strLF) as text |
| 254 | end repeat |
| 255 | set ocidOutPutStrint to refMe's NSString's stringWithString:(strOutPutStrint) |
| 256 | ocidOutPutArray's addObject:(ocidOutPutStrint) |
| 257 | #################### |
| 258 | #降雨確率 |
| 259 | set strOutPutStrint to ("降水確率(6時間毎):" & strLF) as text |
| 260 | set ocidAreaArray to ocidRainPops's objectForKey:("areas") |
| 261 | repeat with itemArea in ocidAreaArray |
| 262 | set ocidAreaName to ((itemArea's objectForKey:("area"))'s valueForKey:("name")) |
| 263 | set strOutPutStrint to ("" & strOutPutStrint & ocidAreaName & "地域: ") as text |
| 264 | set ocidPopsString to ((itemArea's objectForKey:("pops"))'s componentsJoinedByString:("→")) |
| 265 | set strOutPutStrint to ("" & strOutPutStrint & ocidPopsString & strLF) as text |
| 266 | end repeat |
| 267 | set ocidOutPutStrint to refMe's NSString's stringWithString:(strOutPutStrint) |
| 268 | ocidOutPutArray's addObject:(ocidOutPutStrint) |
| 269 | #################### |
| 270 | #気温 |
| 271 | set strOutPutStrint to ("気温(12時間毎):" & strLF) as text |
| 272 | set ocidAreaArray to ocidTemps's objectForKey:("areas") |
| 273 | repeat with itemArea in ocidAreaArray |
| 274 | set ocidAreaName to ((itemArea's objectForKey:("area"))'s valueForKey:("name")) |
| 275 | set strOutPutStrint to ("" & strOutPutStrint & ocidAreaName & "地域: ") as text |
| 276 | set ocidTempString to ((itemArea's objectForKey:("temps"))'s componentsJoinedByString:("→")) |
| 277 | set strOutPutStrint to ("" & strOutPutStrint & ocidTempString & strLF) as text |
| 278 | end repeat |
| 279 | set ocidOutPutStrint to refMe's NSString's stringWithString:(strOutPutStrint) |
| 280 | (ocidOutPutArray's addObject:(ocidOutPutStrint)) |
| 281 | #################### |
| 282 | #出力用テキスト |
| 283 | set ocidJoinText to ocidOutPutArray's componentsJoinedByString:(strLF) |
| 284 | #保存先 |
| 285 | set appFileManager to refMe's NSFileManager's defaultManager() |
| 286 | set ocidTempDirURL to appFileManager's temporaryDirectory() |
| 287 | set ocidUUID to refMe's NSUUID's alloc()'s init() |
| 288 | set ocidUUIDString to ocidUUID's UUIDString |
| 289 | set ocidSaveDirPathURL to ocidTempDirURL's URLByAppendingPathComponent:(ocidUUIDString) isDirectory:(true) |
| 290 | # |
| 291 | set ocidAttrDict to refMe's NSMutableDictionary's alloc()'s init() |
| 292 | ocidAttrDict's setValue:(511) forKey:(refMe's NSFilePosixPermissions) |
| 293 | set listDone to appFileManager's createDirectoryAtURL:(ocidSaveDirPathURL) withIntermediateDirectories:(true) attributes:(ocidAttrDict) |error|:(reference) |
| 294 | if (item 1 of listDone) is false then |
| 295 | set strErrorNO to (item 2 of listDone)'s code() as text |
| 296 | set strErrorMes to (item 2 of listDone)'s localizedDescription() as text |
| 297 | refMe's NSLog("■:" & strErrorNO & strErrorMes) |
| 298 | log "createDirectoryAtURL エラーしました" & strErrorNO & strErrorMes |
| 299 | return false |
| 300 | end if |
| 301 | ###パス |
| 302 | set strFileName to "jma.txt" as text |
| 303 | set ocidSaveFilePathURL to ocidSaveDirPathURL's URLByAppendingPathComponent:(strFileName) isDirectory:false |
| 304 | set listDone to ocidJoinText's writeToURL:(ocidSaveFilePathURL) atomically:(true) encoding:(refMe's NSUTF8StringEncoding) |error|:(reference) |
| 305 | if (item 1 of listDone) is true then |
| 306 | set appSharedWorkspace to refMe's NSWorkspace's sharedWorkspace() |
| 307 | set boolDone to appSharedWorkspace's openURL:(ocidSaveFilePathURL) |
| 308 | |
| 309 | else if (item 1 of listDone) is false then |
| 310 | log (item 2 of listDone)'s localizedDescription() as text |
| 311 | return "保存に失敗しました" |
| 312 | end if |
| 313 |
|
| 314 | return ocidJoinText as text |
| 315 |
|
| 316 |
|
| 317 | to doGetDateNo(strDateFormat) |
| 318 | ####日付情報の取得 |
| 319 | set ocidDate to current application's NSDate's |date|() |
| 320 | ###日付のフォーマットを定義 |
| 321 | set ocidNSDateFormatter to current application's NSDateFormatter's alloc()'s init() |
| 322 | ocidNSDateFormatter's setLocale:(current application's NSLocale's localeWithLocaleIdentifier:"ja_JP_POSIX") |
| 323 | ocidNSDateFormatter's setDateFormat:strDateFormat |
| 324 | set ocidDateAndTime to ocidNSDateFormatter's stringFromDate:ocidDate |
| 325 | set strDateAndTime to ocidDateAndTime as text |
| 326 | return strDateAndTime |
| 327 | end doGetDateNo |