OSDN Git Service

時間切れコミット
[tainavi/TinyBannavi.git] / TinyBannavi / src / tainavi / PlugIn_TVPMSN.java
1 \r
2 package tainavi;\r
3 \r
4 import java.io.File;\r
5 import java.util.ArrayList;\r
6 import java.util.Calendar;\r
7 import java.util.Date;\r
8 import java.util.GregorianCalendar;\r
9 import java.util.HashMap;\r
10 import java.util.LinkedHashMap;\r
11 import java.util.regex.Matcher;\r
12 import java.util.regex.Pattern;\r
13 \r
14 \r
15 public class PlugIn_TVPMSN extends TVProgramUtils implements TVProgram,Cloneable {\r
16 \r
17         private static final String thisEncoding = "UTF-8"; \r
18         \r
19         /* 必須コード  - ここから */\r
20         \r
21         // 種族の特性\r
22         @Override\r
23         public String getTVProgramId() { return "MSNエンタメ"; }\r
24         \r
25         @Override\r
26         public ProgType getType() { return ProgType.PROG; }\r
27         @Override\r
28         public ProgSubtype getSubtype() { return ProgSubtype.TERRA; }\r
29 \r
30         //\r
31         @Override\r
32         public PlugIn_TVPMSN clone() {\r
33                 return (PlugIn_TVPMSN) super.clone();\r
34         }\r
35         \r
36         // 個体の特性\r
37 \r
38         @Override\r
39         public int getTimeBarStart() {return 5;}\r
40         \r
41         private int getDogDays() { return ((getExpandTo8())?(8):(7)); }\r
42 \r
43         private static final int bscntMax = 10;\r
44         private int bscnt = 4;\r
45         public void setBscnt(int n) { bscnt = n; }\r
46         \r
47         private String getBscntFile() { return String.format("env"+File.separator+"bscnt.%s",getTVProgramId()); }\r
48         \r
49         /*******************************************************************************\r
50          * 定数\r
51          ******************************************************************************/\r
52         \r
53         private final String MSGID = "["+getTVProgramId()+"] ";\r
54         private final String ERRID = "[ERROR]"+MSGID;\r
55         private final String DBGID = "[DEBUG]"+MSGID;\r
56         \r
57         // 新しい入れ物の臨時格納場所\r
58         private ArrayList<ProgList> newplist = null;\r
59         \r
60         private HashMap<String,String> nf = null;\r
61         \r
62         \r
63         @Override\r
64         public void loadProgram(String areaCode, boolean force) {\r
65                 \r
66                 // 新しい入れ物(トップ)を用意する\r
67                 newplist = new ArrayList<ProgList>();\r
68                 \r
69                 nf = new HashMap<String, String>();\r
70                 \r
71                 // 地域コードごとの参照ページ数の入れ物を用意する\r
72                 LinkedHashMap<String,Integer> pages = new LinkedHashMap<String, Integer>();\r
73                 \r
74                 // 参照する地域コードをまとめる\r
75                 if ( areaCode.equals(allCode) ) {\r
76                         // 「全国」\r
77                         for ( Center cr : crlist ) {\r
78                                 if ( cr.getOrder() > 0 ) {\r
79                                         // 有効局の地域コードのみ集める\r
80                                         pages.put(cr.getAreaCode(),0);\r
81                                 }\r
82                         }\r
83                 }\r
84                 else {\r
85                         // 地域個別\r
86                         pages.put(areaCode,0);\r
87                         pages.put(bsCode,0);\r
88                 }\r
89                 \r
90                 // トップの下に局ごとのリストを生やす\r
91                 for ( String ac : pages.keySet() ) {\r
92                         for ( Center cr : crlist ) {\r
93                                 if ( ac.equals(cr.getAreaCode()) ) {\r
94                                         ProgList pl = new ProgList();\r
95                                         pl.Area = cr.getAreaCode();\r
96                                         pl.SubArea = cr.getType();\r
97                                         pl.Center = cr.getCenter();\r
98                                         pl.BgColor = cr.getBgColor();\r
99                                         \r
100                                         // <TABLE>タグの列数を決め打ちで処理するので、設定上無効な局も内部的には列の1つとして必要\r
101                                         pl.enabled = (cr.getOrder()>0)?(true):(false);\r
102                                         \r
103                                         newplist.add(pl);\r
104                                         \r
105                                         int pg = Integer.valueOf(cr.getType());\r
106                                         if ( pl.enabled && pages.get(ac) < pg ) {\r
107                                                 // 地域コードごとの最大参照ページ数を格納する\r
108                                                 pages.put(ac,pg);\r
109                                         }\r
110                                 }\r
111                         }\r
112                 }\r
113 \r
114                 // 局の下に日付ごとのリストを生やす\r
115                 GregorianCalendar cal = new GregorianCalendar();\r
116                 cal.setTime(new Date());\r
117                 if ( CommonUtils.isLateNight(cal) ) {\r
118                         // 4時までは当日扱いにする\r
119                         cal.add(Calendar.DATE, -1);\r
120                 }\r
121                 GregorianCalendar cale = (GregorianCalendar) cal.clone();\r
122                 for (int i=0; i<getDogDays(); i++) {\r
123                         String date = CommonUtils.getDate(cale);\r
124                         for ( ProgList pl : newplist ) {\r
125                                 ProgDateList cl = new ProgDateList();\r
126                                 cl.Date = date;\r
127                                 pl.pdate.add(cl);\r
128                         }\r
129                         cale.add(Calendar.DATE, 1);\r
130                 }\r
131 \r
132                 // 参照する総ページ数を計算\r
133                 int counterMax = 0;\r
134                 for ( String ac : pages.keySet() ) {\r
135                         counterMax += pages.get(ac)*getDogDays();\r
136                 }\r
137                 \r
138                 // 日付の下に番組情報ごとのリストを生やす(MSNは1ページに複数局存在する)\r
139                 int counter = 1;\r
140                 for ( String ac : pages.keySet() ) {\r
141                         cale = (GregorianCalendar) cal.clone();\r
142                         for ( int i=0; i<getDogDays(); i++ ) {\r
143                                 String date = CommonUtils.getDateYMD(cale);\r
144                                 for ( int d=1; d<=pages.get(ac) && d<=REFPAGESMAX; d++ ) {      // 最大{REFPAGESMAX}ページまでしか参照しない\r
145                                         String url;\r
146                                         if ( ac.equals(bsCode) ) {\r
147                                                 url = "http://program.tv.jp.msn.com/tv.php?site=032&mode=06&category=d"+d+"&area="+ac+"&template=program&sdate="+date+"&shour=05&lhour=24";\r
148                                         }\r
149                                         else {\r
150                                                 if ( d == 1 ) {\r
151                                                         url = "http://program.tv.jp.msn.com/tv.php?site=032&mode=06&category=g&area="+ac+"&template=program&sdate="+date+"&shour=05&lhour=24";\r
152                                                 }\r
153                                                 else {\r
154                                                         url = "http://program.tv.jp.msn.com/tv.php?site=032&mode=06&category=s&area="+ac+"&template=program&sdate="+date+"&shour=05&lhour=24";\r
155                                                 }\r
156                                         }\r
157                                         _loadProgram(ac, String.valueOf(d), url, force, i, cale.get(Calendar.MONTH)+1, cale.get(Calendar.DATE), counter++, counterMax);\r
158                                 }\r
159                                 \r
160                                 cale.add(Calendar.DATE, 1);\r
161                         }\r
162                 }\r
163                 \r
164                 // 開始・終了日時を正しい値に計算しなおす\r
165                 for (ProgList pl : newplist) {\r
166                         setAccurateDate(pl.pdate);\r
167                 }\r
168                 \r
169                 // 解析用\r
170                 {\r
171                         for ( String f : nf.keySet() ) {\r
172                                 System.err.println(String.format("【デバッグ情報】未定義のフラグは[?]と表示されます。: [%s]",f));\r
173                         }\r
174                 }\r
175                 \r
176                 // 古い番組データを置き換える\r
177                 pcenter = newplist;\r
178         }\r
179         \r
180         /* ここまで */\r
181         \r
182         \r
183         \r
184         /*\r
185          * 非公開メソッド等\r
186          */\r
187         \r
188         private void _loadProgram(String areacode, String page, String url, boolean force, int wdaycol, int month, int day, int counter, int counterMax) {\r
189                 // progfilesの読み出し\r
190                 //\r
191                 final String progCacheFile = String.format(getProgDir()+File.separator+"TVMSN_%s_%s_%04d.html", areacode, page, day);\r
192                 try {\r
193                         File f = new File(progCacheFile);\r
194                         if (force == true ||\r
195                                         (f.exists() == true && isCacheOld(progCacheFile) == true) ||\r
196                                         (f.exists() == false && isCacheOld(null) == true)) {\r
197                                 webToFile(url, progCacheFile, thisEncoding);\r
198                                 reportProgress(String.format("%s(%s)を取得しました[%s-%02d日-%sページ]: (%d/%d) %s",getTVProgramId(),"オンライン",getArea(areacode),day,page,counter,counterMax,url));\r
199                         }\r
200                         else if (CommonUtils.isFileAvailable(f,10)) {\r
201                                 reportProgress(String.format("%s(%s)を取得しました[%s-%02d日-%sページ]: (%d/%d) %s",getTVProgramId(),"キャッシュ",getArea(areacode),day,page,counter,counterMax,url));\r
202                         }\r
203                         else {\r
204                                 reportProgress(String.format("%s(%s)がみつかりません[%s-%02d日-%sページ]: (%d/%d) %s",getTVProgramId(),"キャッシュ",getArea(areacode),day,page,counter,counterMax,url));\r
205                                 return;\r
206                         }\r
207 \r
208                         // キャッシュファイルの読み込み\r
209                         String response = CommonUtils.read4file(progCacheFile, false);\r
210                         \r
211                         // キャッシュが不整合を起こしていたら投げ捨てる\r
212                         Matcher ma = Pattern.compile(String.format("<h1 class=\"headtext\">%d月%d日",month,day)).matcher(response);\r
213                         if ( ! ma.find() ) {\r
214                                 reportProgress(getTVProgramId()+"(キャッシュ)が無効です: ("+counter+"/"+counterMax+") "+progCacheFile);\r
215                                 return;\r
216                         }\r
217                 \r
218                         // 番組リストの追加\r
219                         getPrograms(areacode, page, wdaycol, response);\r
220                 }\r
221                 catch (Exception e) {\r
222                         // 例外\r
223                 }\r
224         }\r
225         \r
226         //\r
227         \r
228         private void getPrograms(String areacode, String page, int wdaycol, String src) {\r
229                 Matcher ma = Pattern.compile("\n(<TD ROWSPAN =(\\d+) CLASS = \".*?\">&nbsp;</TD>|<td width=\".*?\" valign=\".*?\" id=\".*?\" ROWSPAN =.*?</A></DIV></TD>)").matcher(src);\r
230                 while (ma.find()) {\r
231                         \r
232                         \r
233                         //\r
234                         ProgDetailList pdl = new ProgDetailList();\r
235                         //\r
236                         if (ma.group(1).startsWith("<TD")) {\r
237                                 //System.err.println(ma.group(1));\r
238                                 pdl.title = "番組情報がありません";\r
239                                 pdl.length = Integer.valueOf(ma.group(2));\r
240                         }\r
241                         else {\r
242                                 // 1 : length\r
243                                 // 2 : genre\r
244                                 // 3 : link\r
245                                 // 4 : title\r
246                                 // 5,6 : start-hour,min\r
247                                 // 7,8 : end-hour,min\r
248                                 // 9,10 : detail1,detail2\r
249                                 Matcher mb = Pattern.compile("<td width=\".*?\" valign=\".*?\" id=\".*?\" ROWSPAN =(\\d+) CLASS = \"(.*?)\"><DIV [^>]*?><a href=.*?onClick=\"xClickACT\\(\'\\.(.+?)\'\\);.*?<h1>(.*?)</h1><h2>.*?(\\d\\d):(\\d\\d)~(\\d\\d):(\\d\\d).*?</h2><p>(.*?)</p><p>(.*?)</p>.*?</A></DIV></TD>").matcher(ma.group(1));\r
250                                 if ( ! mb.find() ) {\r
251                                         System.err.println("TVMSN: unexpected string= "+ma.group(1));\r
252                                         continue;\r
253                                 }\r
254                                 \r
255                                 // タイトル\r
256                                 {\r
257                                         pdl.title = replaceMarks(pdl, CommonUtils.unEscape(mb.group(4)));\r
258                                         pdl.splitted_title = pdl.title;\r
259                                 }\r
260                                         \r
261                                 \r
262                                 // 番組詳細\r
263                                 {\r
264                                         if (mb.group(9).length() > 0) {\r
265                                                 pdl.detail = CommonUtils.unEscape(String.format("%s\n%s", mb.group(9),mb.group(10)));\r
266                                         }\r
267                                         else {\r
268                                                 pdl.detail = CommonUtils.unEscape(mb.group(10));\r
269                                         }\r
270                                         \r
271                                         pdl.detail = replaceMarks(pdl, pdl.detail);\r
272                                         \r
273                                         //\r
274                                         pdl.detail = pdl.detail.replaceAll("<a[^>]*?>", "");\r
275                                         pdl.detail = pdl.detail.replaceAll("</a>", "");\r
276                                         \r
277                                         pdl.splitted_detail = pdl.detail;\r
278                                 }\r
279                                 \r
280                                 // 検索用インデックス\r
281                                 pdl.titlePop = TraceProgram.replacePop(pdl.title);\r
282                                 pdl.detailPop = TraceProgram.replacePop(pdl.detail);\r
283                                 pdl.SearchStrKeys = TraceProgram.splitKeys(pdl.titlePop);\r
284                                 \r
285                                 // 詳細へのリンク\r
286                                 pdl.link = "http://program.tv.jp.msn.com"+mb.group(3);\r
287                                 \r
288                                 // 番組長\r
289                                 pdl.length = Integer.valueOf(mb.group(1));\r
290                                 \r
291                                 \r
292                                 // ジャンル\r
293                                 if (mb.group(2).equals(allCode)) {\r
294                                         pdl.genre = ProgGenre.NOGENRE;\r
295                                 }\r
296                                 else if (mb.group(2).equals("anime")) {\r
297                                         pdl.genre = ProgGenre.ANIME;\r
298                                 }\r
299                                 else if (mb.group(2).equals("movie")) {\r
300                                         pdl.genre = ProgGenre.MOVIE;\r
301                                 }\r
302                                 else if (mb.group(2).equals("dorama")) {\r
303                                         pdl.genre = ProgGenre.DORAMA;\r
304                                 }\r
305                                 else if (mb.group(2).equals("sports")) {\r
306                                         pdl.genre = ProgGenre.SPORTS;\r
307                                 }\r
308                                 else {\r
309                                         pdl.genre = ProgGenre.NOGENRE;\r
310                                 }\r
311                                 \r
312                                 // 開始・終了時刻\r
313                                 GregorianCalendar c = new GregorianCalendar();\r
314                                 c.setTime(new Date());\r
315                                 c.set(Calendar.HOUR_OF_DAY, Integer.valueOf(mb.group(5)));\r
316                                 c.set(Calendar.MINUTE, Integer.valueOf(mb.group(6)));\r
317                                 pdl.start = String.format("%02d:%02d", c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE));\r
318                                 \r
319                                 c.set(Calendar.HOUR_OF_DAY, Integer.valueOf(mb.group(7)));\r
320                                 c.set(Calendar.MINUTE, Integer.valueOf(mb.group(8)));\r
321                                 pdl.end = String.format("%02d:%02d", c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE));\r
322                         }\r
323 \r
324                         //\r
325                         int col = -1;\r
326                         int rowMin = 9999;\r
327                         for ( int i=0; i<newplist.size(); i++ ) {\r
328                                 ProgList pl = newplist.get(i);\r
329                                 if ( ! (pl.Area.equals(areacode) && pl.SubArea.equals(page)) ) {\r
330                                         continue;\r
331                                 }\r
332                                 if (pl.pdate.get(wdaycol).row < rowMin) {\r
333                                         col = i;\r
334                                         rowMin = pl.pdate.get(wdaycol).row;\r
335                                 }\r
336                         }\r
337                         if (col < 0) {\r
338                                 continue;\r
339                         }\r
340                         ProgDateList pcl = newplist.get(col).pdate.get(wdaycol);\r
341                         pcl.pdetail.add(pdl);\r
342                         pcl.row += pdl.length;\r
343                 }\r
344         }\r
345         \r
346         private String replaceMarks(ProgDetailList pdl, String text) {\r
347                 \r
348                 HashMap<String, Integer> xf = new HashMap<String, Integer>();\r
349                 \r
350                 // フラグを拾う\r
351                 {\r
352                         String[] marks = new String[] {\r
353                                         "shin",         // 新番組\r
354                                         "saisyu",       // 最終回\r
355                                         "sai",          // 再放送\r
356                                         "hatsu",        // 初回放送\r
357                                         "ppv",          // [PV]ペイパービュー\r
358                                         "moji",         // [字]文字多重放送\r
359                                         "nikakoku",     // [二]二か国語放送\r
360                                         "taju",         // [多]音声多重放送\r
361                                         "dubbed",       // [吹]吹き替え\r
362                                         "data"          // [デ]データ放送\r
363                                                                 // [生]生放送(ないよ)\r
364                         };\r
365                         \r
366                         for (int i=0; i<marks.length; i++) {\r
367                                 String mark = marks[i];\r
368                                 String expr = String.format("/ico_%s\\.gif>", mark);\r
369                                 Matcher mx = Pattern.compile(expr, Pattern.DOTALL).matcher(text);\r
370                                 if ( mx.find() ) {\r
371                                         xf.put(mark, i);\r
372                                 }\r
373                         }\r
374                         \r
375                         for ( String mark : xf.keySet() ) {\r
376                                 String expr = String.format("<img src=http://img.tv.msn.co.jp/s/ico_%s\\.gif>", mark);\r
377                                 text = text.replaceAll(expr,"");\r
378                                 switch (xf.get(mark)) {\r
379                                 case 0:\r
380                                         pdl.flag = ProgFlags.NEW;\r
381                                         break;\r
382                                 case 1:\r
383                                         pdl.flag = ProgFlags.LAST;\r
384                                         break;\r
385                                 case 2:\r
386                                         pdl.addOption(ProgOption.REPEAT);\r
387                                         break;\r
388                                 case 3:\r
389                                         pdl.addOption(ProgOption.FIRST);\r
390                                         break;\r
391                                 case 4:\r
392                                         pdl.addOption(ProgOption.PV);\r
393                                         break;\r
394                                 case 5:\r
395                                         pdl.addOption(ProgOption.SUBTITLE);\r
396                                         break;\r
397                                 case 6:\r
398                                         pdl.addOption(ProgOption.BILINGUAL);\r
399                                         break;\r
400                                 case 7:\r
401                                         pdl.addOption(ProgOption.MULTIVOICE);\r
402                                         break;\r
403                                 case 8:\r
404                                         pdl.addOption(ProgOption.STANDIN);\r
405                                         break;\r
406                                 case 9:\r
407                                         pdl.addOption(ProgOption.DATA);\r
408                                         break;\r
409                                 }\r
410                         }\r
411                 }\r
412 \r
413                 // 置換する\r
414                 {\r
415                         HashMap<String,String> marks = new HashMap<String,String>();\r
416                         // 置換するコード\r
417                         marks.put("director", "[監]");\r
418                         marks.put("guest", "[ゲ]");\r
419                         marks.put("jikkyo", "[実]");\r
420                         marks.put("kaisetsusya", "[解]");\r
421                         marks.put("katari", "[語]");\r
422                         marks.put("koe", "[声]");\r
423                         marks.put("org", "[原]");\r
424                         marks.put("plot", "[脚]");\r
425                         marks.put("shikai", "[司]");\r
426                         marks.put("syutsuen", "[出]");\r
427                         marks.put("n", "[N]");\r
428                         marks.put("tenki", "[天]");\r
429                         marks.put("zen", "(前編)");\r
430                         marks.put("kou", "(後編)");\r
431                         // 無視するコード\r
432                         marks.put("s", "");\r
433                         marks.put("3d", "");\r
434                         marks.put("eiga", "");\r
435                         marks.put("hand", "");\r
436                         \r
437                         for ( String mark : marks.keySet() ) {\r
438                                 String expr = String.format("<img src=http://img.tv.msn.co.jp/s/ico_%s\\.gif>", mark);\r
439                                 text = text.replaceAll(expr,marks.get(mark));\r
440                         }\r
441                 }\r
442                 \r
443                 // 未解析のマーク\r
444                 Matcher mx = Pattern.compile("/ico_(.*?)\\.gif>", Pattern.DOTALL).matcher(text);\r
445                 while ( mx.find() ) {\r
446                         nf.put(mx.group(1), null);\r
447                 }\r
448                 for ( String mark : nf.keySet() ) {\r
449                         String expr = String.format("<img src=http://img.tv.msn.co.jp/s/ico_%s\\.gif>", mark);\r
450                         text = text.replaceAll(expr,"[?]");\r
451                 }\r
452 \r
453                 return text;\r
454         }\r
455         \r
456         /*\r
457          * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
458          * ★★★★★ 放送地域を取得する(TVAreaから降格)-ここから ★★★★★\r
459          * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
460          */\r
461 \r
462         /*\r
463          * 公開メソッド\r
464          */\r
465         \r
466         //\r
467         @Override\r
468         public String getDefaultArea() {return "東京";}\r
469         \r
470         //\r
471         @Override\r
472         public void loadAreaCode(){\r
473                 \r
474                 // 設定ファイルが存在していればファイルから\r
475                 File f = new File(getAreaSelectedFile());\r
476                 if ( f.exists() ) {\r
477                         @SuppressWarnings("unchecked")\r
478                         ArrayList<AreaCode> tmp = (ArrayList<AreaCode>) CommonUtils.readXML(getAreaSelectedFile());\r
479                         if ( tmp != null ) {\r
480                                 System.out.println("地域リストを読み込みました: "+getAreaSelectedFile());\r
481                                 aclist = tmp;\r
482                     return;\r
483                         }\r
484 \r
485                         System.out.println("地域リストの読み込みに失敗しました: "+getAreaSelectedFile());\r
486                 }\r
487                 \r
488                 // 地域一覧の作成\r
489                 ArrayList<AreaCode> newaclist = new ArrayList<AreaCode>();\r
490 \r
491                 // 存在していなければWeb上から\r
492                 String response = "";\r
493                 {\r
494                         String uri = "http://program.tv.jp.msn.com/tv.php?site=032&mode=06&template=program&category=g&shour=05&lhour=24";\r
495                         response = webToBuffer(uri, thisEncoding, true);\r
496                         if ( response == null ) {\r
497                                 System.out.println("地域情報の取得に失敗しました: "+uri);\r
498                                 return;\r
499                         }\r
500                 }\r
501                 \r
502                 Matcher ma = Pattern.compile("<select name=\"area\" size=\"1\">(.+?)</select>").matcher(response);\r
503                 if (ma.find()) {\r
504                         Matcher mb = Pattern.compile("<option value=\"([^\"]+?)\" ?(selected=\"selected\")?>(.+?)</option>").matcher(ma.group(1));\r
505                         while (mb.find()) {\r
506                                 AreaCode ac = new AreaCode();\r
507                                 ac.setArea(mb.group(3));\r
508                                 ac.setCode(mb.group(1));\r
509                                 newaclist.add(ac);\r
510                         }\r
511                 }\r
512                 \r
513                 if ( newaclist.size() == 0 ) {\r
514                         System.err.println(ERRID+"地域一覧の取得結果が0件だったため情報を更新しません");\r
515                         return;\r
516                 }\r
517                 \r
518                 {\r
519                         {\r
520                                 AreaCode ac = new AreaCode();\r
521                                 ac.setArea("全国");\r
522                                 ac.setCode(allCode);\r
523                                 newaclist.add(0,ac);\r
524                         }\r
525                         {\r
526                                 AreaCode ac = new AreaCode();\r
527                                 ac.setArea("BS");\r
528                                 ac.setCode(bsCode);\r
529                                 newaclist.add(ac);\r
530                         }\r
531                 }\r
532                 \r
533                 aclist = newaclist;\r
534                 saveAreaCode();\r
535         }\r
536 \r
537         /*\r
538          * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
539          * ★★★★★ 放送地域を取得する(TVAreaから降格)-ここまで ★★★★★\r
540          * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
541          */\r
542         \r
543         \r
544         \r
545         /*\r
546          * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
547          * ★★★★★ 放送局を選択する(TVCenterから降格)-ここから ★★★★★\r
548          * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
549          */\r
550         \r
551         /*\r
552          * 公開メソッド\r
553          */\r
554 \r
555         // 設定ファイルがなければWebから取得\r
556         @Override\r
557         public void loadCenter(String code, boolean force) {\r
558                 \r
559                 if ( code == null ) {\r
560                         System.out.println(ERRID+"地域コードがnullです.");\r
561                         return;\r
562                 }\r
563                 \r
564                 // BSのページ数の初期化(事前に判明していない場合は2)\r
565                 int bscntTmp = CommonUtils.loadCnt(getBscntFile());\r
566                 bscntTmp = bscnt = (bscntTmp > 0)?(bscntTmp):(3);\r
567                 \r
568                 //\r
569                 String centerListFile = getCenterListFile(getTVProgramId(), code);\r
570                 \r
571                 if (force) {\r
572                         File f = new File(centerListFile);\r
573                         f.delete();\r
574                 }\r
575                 \r
576                 File f = new File(centerListFile);\r
577                 if (f.exists() == true) {\r
578                         @SuppressWarnings("unchecked")\r
579                         ArrayList<Center> tmp = (ArrayList<Center>) CommonUtils.readXML(centerListFile);\r
580                         if ( tmp != null ) {\r
581                     \r
582                                 crlist = tmp;\r
583                                 \r
584                         // 放送局名変換\r
585                         attachChFilters();\r
586                         \r
587                                 System.out.println("放送局リストを読み込みました: "+centerListFile);\r
588                     return;\r
589                 }\r
590 \r
591                         System.out.println("放送局リストの読み込みに失敗しました: "+centerListFile);\r
592                 }\r
593                 \r
594                 // 放送局をつくるよ\r
595                 ArrayList<Center> newcrlist = new ArrayList<Center>();\r
596                 \r
597                 // 地上派・UHFは地域別に扱う\r
598 \r
599                 int cntMax = ((allCode.equals(code))?(aclist.size()-2):(1))*2 + bscnt;\r
600                 int cnt = 1;\r
601                 for (AreaCode ac : aclist) {\r
602                         if (ac.getCode().equals(bsCode)) {\r
603                                 continue;\r
604                         }\r
605                         else if (code.equals(allCode) && ac.getCode().equals(allCode)) {\r
606                                 continue;\r
607                         }\r
608                         else if ( ! code.equals(allCode) && ! ac.getCode().equals(code)) {\r
609                                 continue;\r
610                         }\r
611                                 \r
612                         String url;\r
613                         \r
614                         // 地上波\r
615                         url = "http://program.tv.jp.msn.com/tv.php?site=032&mode=06&template=program&category=g&area="+ac.getCode()+"&shour=05&lhour=24";\r
616                         if ( _loadCenter(newcrlist, ac.getCode(), "1", url) ) {\r
617                                 reportProgress(String.format("放送局情報を取得しました[%s%d]: (%d/%d) %s","地上波",cnt,cnt,cntMax,url));\r
618                         }\r
619                         cnt++;\r
620                         \r
621                         // UHF・BSアナログ\r
622                         url = "http://program.tv.jp.msn.com/tv.php?site=032&mode=06&template=program&category=s&area="+ac.getCode()+"&shour=05&lhour=24";\r
623                         if ( _loadCenter(newcrlist, ac.getCode(), "2", url) ) {\r
624                                 reportProgress(String.format("放送局情報を取得しました[%s%d]: (%d/%d) %s","地上波",cnt,cnt,cntMax,url));\r
625                         }\r
626                         cnt++;\r
627                 }\r
628                 \r
629                 // BS1・BS2は共通にする(bscntは_loadCenter()中で増加する可能性あり)\r
630                 \r
631                 for ( int d=1; d<=bscnt; d++ )\r
632                 {\r
633                         String url = "http://program.tv.jp.msn.com/tv.php?site=032&mode=06&template=program&category=d"+d+"&shour=05&lhour=24";\r
634                         if ( _loadCenter(newcrlist, bsCode, String.valueOf(d), url) ) {\r
635                                 reportProgress(String.format("放送局情報を取得しました[%s%d]: (%d/%d) %s","BS",d,cnt,cntMax,url));\r
636                         }\r
637                         cnt++;\r
638                 }\r
639                 \r
640                 // BSのページ数を記録する\r
641                 \r
642                 if ( bscntTmp < bscnt ) {\r
643                         reportProgress(String.format("BSのページ数が変更されました: %d→%d (最大%dまで)",bscntTmp,bscnt,bscntMax));\r
644                         CommonUtils.saveCnt(bscnt,getBscntFile());\r
645                 }\r
646                 \r
647                 if ( newcrlist.size() == 0 ) {\r
648                         System.err.println(ERRID+"放送局情報の取得結果が0件だったため情報を更新しません");\r
649                         return;\r
650                 }\r
651                 \r
652                 crlist = newcrlist;\r
653                 attachChFilters();      // 放送局名変換\r
654                 saveCenter();\r
655         }\r
656                 \r
657         private boolean _loadCenter(ArrayList<Center> newcrlist, String code, String page, String uri) {\r
658                 String response = null;\r
659                 {\r
660                         response = webToBuffer(uri, thisEncoding, true);\r
661                         if ( response == null ) {\r
662                                 System.out.println("放送局情報の取得に失敗しました: "+uri);\r
663                                 return false;\r
664                         }\r
665                 }\r
666                 \r
667                 // BSのページ数を計算する\r
668                 \r
669                 for ( int i=bscnt+1; i<=bscntMax; i++ ) {\r
670                         if ( ! response.matches(".*&category=d"+i+"\".*") ) {\r
671                                 if ( bscnt < i-1 ) {\r
672                                         bscnt = i-1;\r
673                                 }\r
674                                 break;\r
675                         }\r
676                 }\r
677                 \r
678                 // 局名リストに追加する\r
679                 \r
680                 Matcher ma = Pattern.compile("<!-- ↓ Station -->([\\s\\S]+?)<!-- ↑ Station -->").matcher(response);\r
681                 if (ma.find()) {\r
682                         Matcher mb = Pattern.compile("<TH width=\".*?\">\\s*(.+?)\\s*</th>").matcher(ma.group(1));\r
683                         while (mb.find()) {\r
684                                 String centerName;\r
685                                 String link;\r
686                                 Matcher mc = Pattern.compile("<a href =\"(.*?)\" id=\'ch01_h\' class=\"th_a\" target=\"_blank\"\\s*>\\s*(.+?)(<BR>|</a>)").matcher(mb.group(1));\r
687                                 if (mc.find()) {\r
688                                         centerName = CommonUtils.unEscape(mc.group(2));\r
689                                         link = mb.group(1);\r
690                                 }\r
691                                 else {\r
692                                         centerName = CommonUtils.unEscape(mb.group(1).replaceAll("<BR>", ""));\r
693                                         link = "";\r
694                                 }\r
695                                 \r
696                                 // NHK総合・NHK教育\r
697                                 centerName = centerName.replaceFirst("^NHK$", "NHK総合");\r
698                                 centerName = centerName.replaceFirst("^NHK Eテレ", "NHK Eテレ");\r
699                                 if ( ! code.startsWith(bsCode) && page.equals("1")) {\r
700                                         if (centerName.startsWith("NHK")) {\r
701                                                 centerName = centerName+"・"+getArea(code);\r
702                                         }\r
703                                 }\r
704                                 \r
705                                 Center cr = new Center();\r
706                                 cr.setAreaCode(code);\r
707                                 cr.setCenterOrig(centerName);\r
708                                 cr.setLink(link);\r
709                                 cr.setType(page);\r
710                                 cr.setEnabled(true);\r
711                                 newcrlist.add(cr);\r
712                         }\r
713                 }\r
714                 return true;\r
715         }\r
716         \r
717         /*\r
718          * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
719          * ★★★★★ 放送局を選択する(TVCenterから降格)-ここまで ★★★★★\r
720          * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
721          */\r
722 }\r