OSDN Git Service

スカパー番組表への対応不足修正
[tainavi/TinyBannavi.git] / TinyBannavi / src / tainavi / PlugIn_CSPSkyperfectTV2012.java
1 package tainavi;\r
2 \r
3 import java.io.File;\r
4 import java.io.UnsupportedEncodingException;\r
5 import java.net.URLDecoder;\r
6 import java.util.ArrayList;\r
7 import java.util.Calendar;\r
8 import java.util.Date;\r
9 import java.util.GregorianCalendar;\r
10 import java.util.HashMap;\r
11 import java.util.regex.Matcher;\r
12 import java.util.regex.Pattern;\r
13 \r
14 \r
15 public class PlugIn_CSPSkyperfectTV2012 extends TVProgramUtils implements TVProgram,Cloneable {\r
16 \r
17         public PlugIn_CSPSkyperfectTV2012 clone() {\r
18                 return (PlugIn_CSPSkyperfectTV2012) super.clone();\r
19         }\r
20         \r
21         private static final String thisEncoding = "UTF-8";\r
22         \r
23         \r
24         /*******************************************************************************\r
25          * 種族の特性\r
26          ******************************************************************************/\r
27         \r
28         @Override\r
29         public String getTVProgramId() { return "スカパー!"; }\r
30         \r
31         @Override\r
32         public ProgType getType() { return ProgType.PROG; }\r
33         @Override\r
34         public ProgSubtype getSubtype() { return ProgSubtype.CS; }\r
35         \r
36         // エリア選択はない\r
37         @Override\r
38         public boolean isAreaSelectSupported() { return false; }\r
39 \r
40         /*******************************************************************************\r
41          * 個体の特性\r
42          ******************************************************************************/\r
43         \r
44         @Override\r
45         public int getTimeBarStart() {return 5;}\r
46         \r
47         private int getDogDays() { return ((getExpandTo8())?(8):(7)); }\r
48         \r
49         \r
50         /*******************************************************************************\r
51          * 定数\r
52          ******************************************************************************/\r
53         \r
54         private static final String XTYPE_BASIC = "e2";\r
55         private static final String XTYPE_PREMIUM = "HD";\r
56         \r
57         private static final String CHNM_PREFIX_BS = "BS";\r
58         private static final String CHNM_PREFIX_CS = "CS";\r
59         private static final String CHNM_PREFIX_PR = "Ch.";\r
60         \r
61         private static final String CHID_PREFIX_BS = "BS";\r
62         private static final String CHID_PREFIX_CS = "CS";\r
63         private static final String CHID_PREFIX_PR = "HD";\r
64         \r
65         private final String MSGID = "["+getTVProgramId()+"] ";\r
66         private final String ERRID = "[ERROR]"+MSGID;\r
67         private final String DBGID = "[DEBUG]"+MSGID;\r
68         \r
69         \r
70         /*******************************************************************************\r
71          * 部品\r
72          ******************************************************************************/\r
73         \r
74         protected ArrayList<ProgList> newplist;\r
75         \r
76         private HashMap<String,String> nf = null;\r
77         private HashMap<String,String> gf = null;\r
78         \r
79         \r
80         //\r
81         private static final HashMap<String,ProgGenre> genremap = new HashMap<String, TVProgram.ProgGenre>() {\r
82 \r
83                 private static final long serialVersionUID = 1L;\r
84 \r
85                 {\r
86                         put("アニメ/特撮",ProgGenre.ANIME);\r
87                         put("こども向け/教育",ProgGenre.ANIME);\r
88                         \r
89                         put("映画",ProgGenre.MOVIE);\r
90                         put("洋画",ProgGenre.MOVIE);\r
91                         put("邦画",ProgGenre.MOVIE);\r
92                         \r
93                         put("ドラマ/演劇",ProgGenre.DORAMA);\r
94                         put("ドラマ",ProgGenre.DORAMA);\r
95                         \r
96                         put("劇場/公演",ProgGenre.THEATER);\r
97                         \r
98                         put("ドキュメンタリー/教養",ProgGenre.DOCUMENTARY);\r
99 \r
100                         put("音楽",ProgGenre.MUSIC);\r
101                         \r
102                         put("バラエティー",ProgGenre.VARIETYSHOW);\r
103                         put("バラエティ",ProgGenre.VARIETYSHOW);\r
104                         \r
105                         put("スポーツ",ProgGenre.SPORTS);\r
106                         \r
107                         put("ニュース/報道",ProgGenre.NEWS);\r
108                         \r
109                         put("アダルト",ProgGenre.NOGENRE);\r
110                 }\r
111         };\r
112         \r
113         //\r
114         @Override\r
115         public void loadProgram(String areaCode, boolean force) {\r
116                 // 新しい入れ物(トップ)を用意する\r
117                 newplist = new ArrayList<ProgList>();\r
118                 \r
119                 nf = new HashMap<String, String>();\r
120                 gf = new HashMap<String, String>();\r
121                 \r
122                 // 最終日の24時以降の情報は、+1したとこから取得する\r
123                 int counterMax = getSortedCRlist().size() * (getDogDays()+1);\r
124                 int counter=1;\r
125                 for ( Center c : getSortedCRlist() ) {\r
126                         if (getDebug()) System.err.println(DBGID+"load program: "+c.getCenter());\r
127                         _loadProgram(c, force, counter, counterMax);\r
128                         counter += getDogDays()+1;\r
129                 }\r
130                 \r
131                 // 古いデータから補完できないかな?\r
132                 CompensatesPrograms(newplist);\r
133                 \r
134                 // 解析用\r
135                 {\r
136                         for ( String f : nf.keySet() ) {\r
137                                 System.err.println(String.format("【デバッグ情報】未定義のフラグです: [%s]",f));\r
138                         }\r
139                         for ( String g : gf.keySet() ) {\r
140                                 System.err.println(String.format("【デバッグ情報】未定義のジャンルです: [%s]",g));\r
141                         }\r
142                 }\r
143                 \r
144                 // 古い番組データを置き換える\r
145                 pcenter = newplist;\r
146         }\r
147         \r
148         /* ここまで */\r
149 \r
150         \r
151         \r
152         /*\r
153          * 非公開メソッド\r
154          */\r
155         protected void _loadProgram(Center cr, boolean force, int counter, int counterMax) {\r
156                 //\r
157                 try {\r
158                         // progfilesの読み出し\r
159                         \r
160                         // 局リストの追加\r
161                         ProgList pl = new ProgList();\r
162                         pl.Center = cr.getCenter();\r
163                         pl.CenterId = cr.getLink();\r
164                         pl.ChId = "";\r
165                         {\r
166                                 int onid = -1;\r
167                                 if ( cr.getCenterOrig().startsWith(CHNM_PREFIX_BS) ) {\r
168                                         onid = 4;\r
169                                 }\r
170                                 else if ( cr.getCenterOrig().startsWith(CHNM_PREFIX_CS) ) {\r
171                                         onid = 7;\r
172                                 }\r
173                                 if ( onid != -1 ) {\r
174                                         Matcher ma = Pattern.compile("(\\d+)").matcher(cr.getCenterOrig());\r
175                                         if ( ma.find() ) {\r
176                                                 ContentIdDIMORA.decodeChId(String.format("%04X%04X%04X", onid,0,Integer.valueOf(ma.group(1))));\r
177                                                 pl.ChId = ContentIdDIMORA.getContentId(0,"");\r
178                                         }\r
179                                 }\r
180                         }\r
181                         pl.Area = cr.getAreaCode();\r
182                         pl.BgColor = cr.getBgColor();\r
183                         pl.enabled = true;\r
184                         newplist.add(pl);\r
185                         \r
186                         // 日付リストの追加\r
187                         getDate(pl);\r
188 \r
189                         //\r
190                         for ( int dtidx=0; dtidx<pl.pdate.size(); dtidx++ ) {\r
191                                 //\r
192                                 GregorianCalendar cal = CommonUtils.getCalendar(pl.pdate.get(dtidx).Date);\r
193                                 \r
194                                 boolean isNextpageExist = true;\r
195                                 for ( int pgidx=1; isNextpageExist; pgidx++ ) {\r
196                                         \r
197                                         final String progCacheFile = \r
198                                                         pgidx == 1 ? String.format("%s%sSKP2012_%s_%d.txt", getProgDir(), File.separator, pl.CenterId, cal.get(Calendar.DAY_OF_MONTH)) :\r
199                                                                          String.format("%s%sSKP2012_%s_%d_%d.txt", getProgDir(), File.separator, pl.CenterId, cal.get(Calendar.DAY_OF_MONTH),pgidx);\r
200                                         //\r
201                                         File f = new File(progCacheFile);\r
202                                         if (force == true ||\r
203                                                         (f.exists() == true && isCacheOld(progCacheFile) == true) ||\r
204                                                         (f.exists() == false && isCacheOld(null) == true)) {\r
205                                                 //\r
206                                                 String xtype = (pl.CenterId.startsWith(CHID_PREFIX_BS) || pl.CenterId.startsWith(CHID_PREFIX_CS)) ? XTYPE_BASIC : XTYPE_PREMIUM;\r
207                                                 String chid = xtype != XTYPE_PREMIUM ? pl.CenterId : pl.CenterId.replaceFirst("^"+CHID_PREFIX_PR, "");\r
208                                                 String dt = CommonUtils.getDateYMD(cal);\r
209                                                 String url = "http://bangumi.skyperfectv.co.jp/"+xtype+"/channel:"+chid+"/date:"+dt.substring(2)+"/";\r
210                                                 if ( pgidx > 1 ) {\r
211                                                         url += "?p="+pgidx;\r
212                                                 }\r
213                                                 /*\r
214                                                 if ( pl.ChId.length() == 0 ) {\r
215                                                         url = "http://bangumi.skyperfectv.co.jp/api/version:3/search/date:"+dt.substring(2)+"/channel:"+pl.CenterId+"/?api_key=336eec3423";\r
216                                                 }\r
217                                                 else {\r
218                                                         url = "http://www.skyperfectv.co.jp/xml/"+dt+"_"+pl.ChId.substring(2)+".xml";\r
219                                                 }\r
220                                                 */\r
221                                                 webToFile(url, progCacheFile, thisEncoding);\r
222                                                 \r
223                                                 printProgress("(オンライン)を取得しました", counter+dtidx, pgidx, counterMax, pl.Center, cal.get(Calendar.DAY_OF_MONTH), url);\r
224                                         }\r
225                                         else if (CommonUtils.isFileAvailable(f,10)) {\r
226                                                 printProgress("(キャッシュ)を取得しました", counter+dtidx, pgidx, counterMax, pl.Center, cal.get(Calendar.DAY_OF_MONTH), progCacheFile);\r
227                                         }\r
228                                         else {\r
229                                                 printProgress("(キャッシュ)がみつかりません", counter+dtidx, pgidx, counterMax, pl.Center, cal.get(Calendar.DAY_OF_MONTH), progCacheFile);\r
230                                                 break;\r
231                                         }\r
232                 \r
233                                         String response = CommonUtils.read4file(progCacheFile, true);\r
234                                         if ( response == null || ! response.matches("^.*<a href=\"\\?p=\\d+[^>]+?>次.*$") ) {\r
235                                                 isNextpageExist = false;\r
236                                         }\r
237                                         \r
238                                         // 番組リストの追加\r
239                                         try {\r
240                                                 getPrograms(pl, dtidx, response);\r
241                                                 /*\r
242                                                 if ( pl.ChId.length() == 0 ) {\r
243                                                         getPrograms(pl, i, response);\r
244                                                 }\r
245                                                 else {\r
246                                                         getPrograms_basic(pl, i, response);\r
247                                                 }\r
248                                                 */\r
249                                         }\r
250                                         catch ( Exception e ) {\r
251                                                 e.printStackTrace();\r
252                                         }\r
253                                 }\r
254                         }\r
255                         \r
256                         // 日付の調整\r
257                         refreshList(pl.pdate);\r
258                 }\r
259                 catch (Exception e) {\r
260                         // 例外\r
261                         System.out.println("Exception: _loadProgram()");\r
262                 }\r
263         }\r
264         \r
265         private void printProgress(String msg, int count, int pgidx, int countMax, String center, int date, String uri) {\r
266                 reportProgress(String.format("%s %s: (%d/%d) page=%d %s[%d日]    %s", getTVProgramId(), msg, count, countMax, pgidx, center, date, uri));\r
267         }\r
268         //\r
269         private void getDate(ProgList pl) {\r
270                 // 日付の処理\r
271                 GregorianCalendar c = new GregorianCalendar();\r
272                 c.setTime(new Date());\r
273                 if ( CommonUtils.isLateNight(c) ) {\r
274                         // 4時までは当日扱いにする\r
275                         c.add(Calendar.DATE, -1);\r
276                 }\r
277                 // 最終日の24時以降の情報は、+1したとこから取得する\r
278                 for ( int i=0; i<getDogDays()+1; i++ ) {\r
279                         ProgDateList cl = new ProgDateList();\r
280                         cl.Date = CommonUtils.getDate(c);\r
281                         pl.pdate.add(cl);\r
282                         \r
283                         c.add(Calendar.DATE,1);\r
284                 }\r
285         }\r
286         \r
287         //\r
288         private void refreshList(ArrayList<ProgDateList> pcenter) {\r
289                 // 日付を直すよ\r
290                 for ( int i=0; i<pcenter.size(); i++ ) {\r
291                         ProgDateList pl = pcenter.get(i);\r
292                         GregorianCalendar ca = CommonUtils.getCalendar(pl.Date);\r
293                         for ( int j=pl.pdetail.size()-1,k=0; j>=0; j--,k++ ) {\r
294                                 ProgDetailList pdl = pl.pdetail.get(j);\r
295                                 GregorianCalendar cz = (GregorianCalendar) ca.clone();\r
296                                 if ( k == 0 ) {\r
297                                         if ( CommonUtils.isLateNight(pdl.start.substring(0,2)) ) {\r
298                                                 // 最後尾の開始日は翌日だった\r
299                                                 ca.add(Calendar.DATE, 1);\r
300                                                 cz = (GregorianCalendar) ca.clone();\r
301                                         }\r
302                                         else if ( pdl.start.compareTo(pdl.end) > 0 ) {\r
303                                                 // 翌日にまたがる\r
304                                                 cz.add(Calendar.DATE, 1);\r
305                                         }\r
306                                 }\r
307                                 else {\r
308                                         if ( pdl.start.compareTo(pdl.end) > 0 ) {\r
309                                                 // 前日からまたがる\r
310                                                 ca.add(Calendar.DATE, -1);\r
311                                         }\r
312                                 }\r
313                                 pdl.accurateDate = CommonUtils.getDate(ca);\r
314                                 pdl.startDateTime = CommonUtils.getDate(ca,false)+" "+pdl.start;\r
315                                 pdl.endDateTime = CommonUtils.getDate(cz,false)+" "+pdl.end;\r
316                         }\r
317                 }\r
318 \r
319                 // 隙間を埋めつつ一個にまとめる\r
320                 ProgDateList all = new ProgDateList();\r
321                 all.pdetail = new ArrayList<ProgDetailList>();\r
322                 for ( ProgDateList pcl : pcenter ) {\r
323                         for ( ProgDetailList pdl : pcl.pdetail ) {\r
324                                 if ( all.row == 0 ) {\r
325                                         String prevend = CommonUtils.getDateTime(CommonUtils.getCalendar(pcenter.get(0).Date+" 05:00"));\r
326                                         if ( prevend.compareTo(pdl.startDateTime) < 0 ) {\r
327                                                 // 最前列の情報がとれなかった\r
328                                                 addEnmptyInfo(all, prevend, pdl.startDateTime);\r
329                                         }\r
330                                 }\r
331                                 else {\r
332                                         ProgDetailList prevpdl = all.pdetail.get(all.pdetail.size()-1);\r
333                                         if ( prevpdl.startDateTime.equals(pdl.startDateTime) ) {\r
334                                                 // 重複は破棄\r
335                                                 continue;\r
336                                         }\r
337                                         else if ( prevpdl.endDateTime.compareTo(pdl.startDateTime) < 0 ) {\r
338                                                 // 隙間を埋める\r
339                                                 addEnmptyInfo(all, prevpdl.endDateTime, pdl.startDateTime);\r
340                                         }\r
341                                 }\r
342                                 all.pdetail.add(pdl);\r
343                                 all.row += pdl.length;\r
344                         }\r
345                         // 元のリストはリセット\r
346                         pcl.pdetail = new ArrayList<ProgDetailList>();\r
347                         pcl.row = 0;\r
348                 }\r
349                 \r
350                 // 各日に振り分ける\r
351                 for ( ProgDetailList pdl : all.pdetail ) {\r
352                         int cnt = 0;\r
353                         for ( ProgDateList pcl : pcenter ) {\r
354                                 GregorianCalendar cz = CommonUtils.getCalendar(pcl.Date+" 05:00");\r
355                                 String da = CommonUtils.getDateTime(cz);\r
356                                 cz.add(Calendar.DATE, 1);\r
357                                 String dz = CommonUtils.getDateTime(cz);\r
358                                 if ( CommonUtils.isOverlap(pdl.startDateTime, pdl.endDateTime, da, dz, true) ) {\r
359                                         if ( cnt++ == 0 ) {\r
360                                                 pcl.pdetail.add(pdl);\r
361                                         }\r
362                                         else {\r
363                                                 pcl.pdetail.add(pdl.clone());\r
364                                         }\r
365                                 }\r
366                         }\r
367                 }\r
368                 \r
369                 // 24時以降の情報は日付+1したとこから取得しているので、最終日の次のリストは削除\r
370                 pcenter.remove(pcenter.size()-1);\r
371                 \r
372                 // 総時間数等を整理する\r
373                 for ( ProgDateList pcl : pcenter ) {\r
374                         // 1日の合計分数を足し合わせる\r
375                         for ( ProgDetailList pdl : pcl.pdetail ) {\r
376                                 String da = (pcl.row == 0) ? pcl.Date+" 05:00" : pdl.startDateTime;\r
377                                 pdl.length = (int)(CommonUtils.getCompareDateTime(pdl.endDateTime, da)/60000L);\r
378                                 pcl.row += pdl.length;\r
379                         }\r
380                         // おしりがとどかない場合(デメリット:これをやると、サイト側のエラーで欠けてるのか、そもそも休止なのかの区別がつかなくなる)\r
381                         if ( pcl.row < 24*60 ) {\r
382                                 GregorianCalendar ca = CommonUtils.getCalendar(pcl.Date+" 05:00");\r
383                                 GregorianCalendar cz = (GregorianCalendar) ca.clone();\r
384                                 ca.add(Calendar.MINUTE, pcl.row);\r
385                                 cz.add(Calendar.MINUTE, 24*60);\r
386                                 addEnmptyInfo(pcl, CommonUtils.getDateTime(ca), CommonUtils.getDateTime(cz));\r
387                         }\r
388                 }\r
389         }\r
390         \r
391         //\r
392         private void getPrograms(ProgList pl, int dtidx, String response) {\r
393                 \r
394                 ProgDateList pcl = pl.pdate.get(dtidx);\r
395                 \r
396                 String[][] keys = {\r
397                                 { "class", "pg-title" },\r
398                                 { "class", "start-time" },\r
399                                 { "class", "end-time" },\r
400                                 { "class", "pg-genre" },\r
401                                 { "class", "pg-explanation" },\r
402                                 { "id", "actor-name" },\r
403                 };\r
404                 \r
405                 Matcher ma = Pattern.compile("<tbody\\s+id=\"event-\\d+\"[^>]*?>(.+?)</tbody>",Pattern.DOTALL).matcher(response);\r
406                 for ( int cnt = 0; ma.find(); cnt++ ) {\r
407                         ProgDetailList pdl = new ProgDetailList();\r
408                         String subtitle = "";\r
409                         String person = "";\r
410                                 \r
411                         for ( String[] k : keys ) {\r
412                                 Matcher mb = Pattern.compile("<span\\s+"+k[0]+"=\""+k[1]+"\"[^>]*?>\\s*(.+?)\\s*</span>",Pattern.DOTALL).matcher(ma.group(1));\r
413                                 while ( mb.find() ) {\r
414                                         if ( mb.group(1) == null ) {\r
415                                                 continue;\r
416                                         }\r
417                                         \r
418                                         if ( k[1].equals("pg-title") ) {\r
419                                                 pdl.title = CommonUtils.unEscape(mb.group(1)).trim();\r
420                                         }\r
421                                         else if ( k[1].equals("start-time") ) {\r
422                                                 pdl.start = mb.group(1);\r
423                                         }\r
424                                         else if ( k[1].equals("end-time") ) {\r
425                                                 pdl.end = mb.group(1);\r
426 /*                                              \r
427                                                 GregorianCalendar c = CommonUtils.getCalendar(pcl.Date);\r
428                                                 \r
429                                                 if ( cnt == 0 && pdl.start.compareTo(pdl.end) > 0 ) {\r
430                                                         c.add(Calendar.DATE, -1);\r
431                                                 }\r
432                                                 pdl.accurateDate = CommonUtils.getDate(c);\r
433                                                 pdl.startDateTime = CommonUtils.getDate(c,false)+" "+pdl.start;\r
434                                                 \r
435                                                 if ( pdl.start.compareTo(pdl.end) > 0 ) {\r
436                                                         c.add(Calendar.DATE, 1);\r
437                                                 }\r
438                                                 pdl.endDateTime = CommonUtils.getDate(c,false)+" "+pdl.end;\r
439 */\r
440                                                 pdl.length = CommonUtils.getRecMinVal(pdl.start, pdl.end);\r
441                                         }\r
442                                         else if ( k[1].equals("pg-genre") ) {\r
443                                                 Matcher mc = Pattern.compile("/large_genre:(.+?)/medium_genre:(.+?)/",Pattern.DOTALL).matcher(mb.group(1));\r
444                                                 if ( mc.find() ) {\r
445                                                         try {\r
446                                                                 String grstr = URLDecoder.decode(mc.group(1),"utf8").replaceAll("/", "/");\r
447                                                                 ProgGenre gr = ProgGenre.get(grstr);\r
448                                                                 if ( gr == null ) {\r
449                                                                         gr = genremap.get(grstr);\r
450                                                                         if (gr == null) {\r
451                                                                                 // 未定義のジャンルです!\r
452                                                                                 gr = ProgGenre.NOGENRE;\r
453                                                                                 gf.put(grstr,null);\r
454                                                                         }\r
455                                                                 }\r
456                                                                 if ( pdl.genre == null || (pdl.genre == ProgGenre.NOGENRE && gr != ProgGenre.NOGENRE) ) {\r
457                                                                         pdl.genre = gr;\r
458                                                                 }\r
459                                                                 \r
460                                                                 String sgstr = URLDecoder.decode(mc.group(2),"utf8").replaceAll("ィー", "ィ");\r
461                                                                 ProgSubgenre sg = ProgSubgenre.get(gr, sgstr);\r
462                                                                 if ( sg == null ) {\r
463                                                                         // 未定義のサブジャンルです!\r
464                                                                         ArrayList<ProgSubgenre> vals = ProgSubgenre.values(gr);\r
465                                                                         sg = vals.get(vals.size()-1);\r
466                                                                 }\r
467                                                                 pdl.subgenre = sg;\r
468                                                         } catch (UnsupportedEncodingException e) {\r
469                                                                 e.printStackTrace();\r
470                                                                 pdl.genre = ProgGenre.NOGENRE;\r
471                                                                 pdl.subgenre = ProgSubgenre.NOGENRE_ETC;\r
472                                                         }\r
473                                                 }\r
474                                                 else {\r
475                                                         pdl.genre = ProgGenre.NOGENRE;\r
476                                                         pdl.subgenre = ProgSubgenre.NOGENRE_ETC;\r
477                                                 }\r
478                                         }\r
479                                         else if ( k[1].equals("pg-explanation") ) {\r
480                                                 pdl.detail += CommonUtils.decBr(CommonUtils.unEscape(mb.group(1))).trim()+"\n";\r
481                                         }\r
482                                         else if ( k[1].equals("actor-name") ) {\r
483                                                 person += "、"+CommonUtils.unEscape(mb.group(1)).trim();\r
484                                         }\r
485                                 }\r
486                         }\r
487                         \r
488                         // 出演者\r
489                         if ( person.length() > 0 ) {\r
490                                 person = person.substring(1);\r
491                         }\r
492                         \r
493                         // くっつけてみる\r
494                         pdl.detail =\r
495                                         ((subtitle.length()>0)?(subtitle+DETAIL_SEP):(""))\r
496                                         +pdl.detail\r
497                                         +((person.length()>0)?(DETAIL_SEP+person):(""));\r
498                         pdl.detail = pdl.detail.replaceFirst("[\r\n]+$", "");\r
499 \r
500                         Matcher mb = Pattern.compile("<img\\s+src=\"/i/icon_(.+?)\\.gif",Pattern.DOTALL).matcher(ma.group(1));\r
501                         while ( mb.find() ) {\r
502                                 if ( mb.group(1).equals("5.1") ) {\r
503                                         pdl.addOption(ProgOption.SURROUND);\r
504                                 }\r
505                                 else if ( mb.group(1).equals("jimaku") ) {\r
506                                         pdl.addOption(ProgOption.SUBTITLE);\r
507                                 }\r
508                                 else if ( mb.group(1).equals("2kakoku") ) {\r
509                                         pdl.addOption(ProgOption.BILINGUAL);\r
510                                 }\r
511                                 else if ( mb.group(1).equals("fukikae") ) {\r
512                                         pdl.addOption(ProgOption.STANDIN);\r
513                                 }\r
514                                 else if ( mb.group(1).equals("tajuu") ) {\r
515                                         pdl.addOption(ProgOption.MULTIVOICE);\r
516                                 }\r
517                                 else if ( mb.group(1).equals("r15") || mb.group(1).equals("r18") || mb.group(1).equals("adult") ) {\r
518                                         pdl.addOption(ProgOption.RATING);\r
519                                 }\r
520                                 else if ( mb.group(1).equals("ppv") ) {\r
521                                         pdl.addOption(ProgOption.PV);\r
522                                 }\r
523                                 else if ( mb.group(1).equals("nama") ) {\r
524                                         pdl.addOption(ProgOption.LIVE);\r
525                                 }\r
526                                 else {\r
527                                         nf.put(mb.group(1), null);\r
528                                 }\r
529                         }\r
530                         \r
531                         // タイトルから各種フラグを分離する\r
532                         doSplitFlags(pdl, nf);\r
533                         \r
534                         // サブタイトル分離(ポインタを活用してメモリを節約する)\r
535                         doSplitSubtitle(pdl);\r
536                         \r
537                         // 番組ID\r
538                         if ( ContentIdDIMORA.isValid(pl.ChId) ) {\r
539                                 pdl.progid = pl.ChId;\r
540                         }\r
541                         \r
542                         // その他フラグ\r
543                         pdl.extension = false;\r
544                         pdl.nosyobo = false;\r
545                         \r
546                         pcl.pdetail.add(pdl);\r
547                         \r
548                         if (getDebug()) System.err.println(DBGID+"program: "+pdl.startDateTime+" - "+pdl.endDateTime+" "+pdl.length+"m "+pdl.noscrumble+" "+pdl.title);\r
549                 }\r
550         }\r
551 \r
552         \r
553         /**\r
554          * こちらは番組IDがとれる代わりに出演者情報がとれなくなるので保留とする\r
555          */\r
556         private void getPrograms_basic(ProgList pl, int dtidx, String response) {\r
557                 \r
558                 Matcher ma = Pattern.compile("<SIInformation(.+?)</SIInformation>",Pattern.DOTALL).matcher(response);\r
559                 while ( ma.find() ) {\r
560                         Matcher mb = Pattern.compile("eventId=\"(.+?)\".+?broadCastStartDate=\"(\\d{8})(\\d{4})",Pattern.DOTALL).matcher(ma.group(1));\r
561                         if ( mb.find() ) {\r
562                                 \r
563                         }\r
564                         /*\r
565                         mb = Pattern.compile("<(.+?)>(.+?)</\\1>",Pattern.DOTALL).matcher(ma.group(1));\r
566                         while ( mb.find() ) {\r
567                                 if ( mb.group(1).equals("ChannelName") ) {\r
568                                         \r
569                                 }\r
570                                 else if ( mb.group(1).equals("Title") ) {\r
571                                         \r
572                                 }\r
573                                 else if ( mb.group(1).equals("Synopsis") ) {\r
574                                         \r
575                                 }\r
576                                 else if ( mb.group(1).equals("Genres") ) {\r
577                                         Matcher mc = Pattern.compile("<Genre majorGenreId=\".+?\" minorGenreId=\".+?\"",Pattern.DOTALL).matcher(mb.group(2));\r
578                                         while ( mc.find() ) {\r
579                                                 \r
580                                         }\r
581                                 }\r
582                         }\r
583                         */\r
584                 }\r
585         }\r
586 \r
587         \r
588         /*\r
589          * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
590          * ★★★★★ 放送地域を取得する(TVAreaから降格)-ここから ★★★★★\r
591          * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
592          */\r
593         \r
594         /*\r
595          * 公開メソッド\r
596          */\r
597         \r
598         @Override\r
599         public String getDefaultArea() {return "全国";}\r
600         private String getDefaultCode() {return "SKP2012";}\r
601         \r
602         @Override\r
603         public void loadAreaCode() {\r
604                 aclist = new ArrayList<AreaCode>();\r
605                 AreaCode ac = new AreaCode();\r
606                 ac.setArea(getDefaultArea());\r
607                 ac.setCode(getDefaultCode());\r
608                 ac.setSelected(true);\r
609                 aclist.add(ac);\r
610         }\r
611         @Override\r
612         public void saveAreaCode() {}\r
613         \r
614         @Override\r
615         public String getArea(String code) { return(getDefaultArea()); }\r
616         @Override\r
617         public String getCode(String area) { return(getDefaultCode()); }\r
618         @Override\r
619         public String setSelectedAreaByName(String area) { return(getDefaultCode()); }\r
620         @Override\r
621         public String getSelectedArea() { return(getDefaultArea()); }\r
622         @Override\r
623         public String getSelectedCode() { return(getDefaultCode()); }\r
624         \r
625         /*\r
626          * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
627          * ★★★★★ 放送地域を取得する(TVAreaから降格)-ここまで ★★★★★\r
628          * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
629          */\r
630         \r
631         \r
632         \r
633         /*\r
634          * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
635          * ★★★★★ 放送局を選択する(TVCenterから降格)-ここから ★★★★★\r
636          * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
637          */\r
638         \r
639         /*\r
640          * 公開メソッド\r
641          */\r
642 \r
643         // 設定ファイルがなければWebから取得\r
644         @Override\r
645         public void loadCenter(String code, boolean force) {\r
646                 \r
647                 if ( code == null ) {\r
648                         System.out.println(ERRID+"地域コードがnullです.");\r
649                         return;\r
650                 }\r
651                 \r
652                 String centerListFile = getCenterListFile(getTVProgramId(), code);\r
653                 \r
654                 if (force) {\r
655                         File f = new File(centerListFile);\r
656                         f.delete();\r
657                 }\r
658                 \r
659                 File f = new File(centerListFile);\r
660                 if (f.exists() == true) {\r
661                         @SuppressWarnings("unchecked")\r
662                         ArrayList<Center> tmp = (ArrayList<Center>)CommonUtils.readXML(centerListFile);\r
663                         if ( tmp != null ) {\r
664                                 crlist = tmp;\r
665 \r
666                                 // 放送局名変換\r
667                                 attachChFilters();\r
668                                 \r
669                                 String[][] prs = {\r
670                                                 {CHNM_PREFIX_BS, CHID_PREFIX_BS},\r
671                                                 {CHNM_PREFIX_CS, CHID_PREFIX_CS},\r
672                                                 {CHNM_PREFIX_PR, CHID_PREFIX_PR},\r
673                                 };\r
674                                 \r
675                                 // 2013.11 新旧変換\r
676                                 for ( Center cr : crlist ) {\r
677                                         for ( String[] a : prs ) {\r
678                                                 if ( cr.getCenterOrig().startsWith(a[0]) ) {\r
679                                                         if ( ! cr.getLink().startsWith(a[1]) ) {\r
680                                                                 Matcher ma = Pattern.compile("^.*?(\\d+)",Pattern.DOTALL).matcher(cr.getCenterOrig());\r
681                                                                 if ( ma.find() ) {\r
682                                                                         String chid = a[1]+ma.group(1);\r
683                                                                         System.err.println(DBGID+"converted: "+cr.getCenterOrig()+", "+cr.getLink()+" -> "+chid);\r
684                                                                         cr.setLink(chid);\r
685                                                                 }\r
686                                                         }\r
687                                                         \r
688                                                         break;\r
689                                                 }\r
690                                         }\r
691                                 }\r
692                                 \r
693                                 System.out.println("放送局リストを読み込みました: "+centerListFile);\r
694                                 return;\r
695                         }\r
696                         else {\r
697                                 System.out.println("放送局リストの読み込みに失敗しました: "+centerListFile);\r
698                         }\r
699                 }\r
700 \r
701                 // 放送局をつくるよ\r
702                 ArrayList<Center> newcrlist = new ArrayList<Center>();\r
703                 \r
704                 for ( String xtype : new String[] { XTYPE_BASIC,XTYPE_PREMIUM } ) {\r
705                         ArrayList<Center> crl = getCenters(xtype,code);\r
706                         if ( crl != null ) {\r
707                                 reportProgress("放送局情報を取得しました: ("+xtype+") "+crl.size()+"ch");\r
708                         }\r
709                         \r
710                         for ( Center cr : crl ) {\r
711                                 newcrlist.add(cr);\r
712                         }\r
713                 }\r
714                 \r
715                 if ( newcrlist.size() == 0 ) {\r
716                         System.err.println(ERRID+"放送局情報の取得結果が0件だったため情報を更新しません");\r
717                         return;\r
718                 }\r
719                 \r
720                 crlist = newcrlist;\r
721                 attachChFilters();      // 放送局名にフィルタをかける\r
722                 saveCenter();\r
723         }\r
724         \r
725         private ArrayList<Center> getCenters(String xtype, String areacode) {\r
726                 \r
727                 ArrayList<Center> crl = new ArrayList<Center>();\r
728                 \r
729                 String url = String.format("http://bangumi.skyperfectv.co.jp/index/channel/%s/",xtype);\r
730                 if (getDebug()) System.err.println(DBGID+"get page: "+url);\r
731                 String response = webToBuffer(url,thisEncoding,true);\r
732                 if ( response == null ) {\r
733                         reportProgress("放送局情報の取得に失敗しました: "+xtype);\r
734                         return null;\r
735                 }\r
736                 \r
737                 Matcher ma = Pattern.compile("<td class=\"channel-icon\">\\s*<a href=\".*?/channel:(.+?)/\".*?>\\s*<img src=\".*?\" alt=\"(.+?)\"",Pattern.DOTALL).matcher(response);\r
738                 while ( ma.find() ) {\r
739                         String chid = (xtype.equals(XTYPE_PREMIUM) ? CHID_PREFIX_PR : "") + ma.group(1);\r
740                         String chnm = CommonUtils.toHANALNUM(CommonUtils.unEscape(ma.group(2))).replaceFirst("[  \\t]+▲$", "");\r
741                         \r
742                         // 統一性がない\r
743                         if ( xtype.equals(XTYPE_PREMIUM) && ! chnm.startsWith(CHNM_PREFIX_PR) ) {\r
744                                 chnm = CHNM_PREFIX_PR+chnm;\r
745                         }\r
746                         \r
747                         Center cr = new Center();\r
748                         cr.setAreaCode(areacode);\r
749                         cr.setType("");\r
750                         cr.setEnabled(true);\r
751                         cr.setCenterOrig(chnm);\r
752                         cr.setLink(chid);\r
753                         \r
754                         int idx = 0;\r
755                         for ( Center ct : crl ) {\r
756                                 if ( ct.getCenterOrig().compareTo(cr.getCenterOrig()) > 0 ) {\r
757                                         break;\r
758                                 }\r
759                                 idx++;\r
760                         }\r
761                         crl.add(idx, cr);\r
762                         \r
763                         if (getDebug()) System.err.println(DBGID+"center: "+cr.getCenterOrig()+", "+cr.getLink());\r
764                 }\r
765                 \r
766                 return crl;\r
767         }\r
768         \r
769         /*\r
770          * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
771          * ★★★★★ 放送局を選択する(TVCenterから降格)-ここまで ★★★★★\r
772          * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
773          */\r
774 }\r