OSDN Git Service

287721fb79745357f257b719111d8eccd905817d
[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 i=0; i<pl.pdate.size(); i++ ) {\r
191                                 //\r
192                                 GregorianCalendar cal = CommonUtils.getCalendar(pl.pdate.get(i).Date);\r
193                                 final String progCacheFile = String.format("%s%sSKP2012_%s_%d.txt", getProgDir(), File.separator, pl.CenterId, cal.get(Calendar.DAY_OF_MONTH));\r
194                                 //\r
195                                 File f = new File(progCacheFile);\r
196                                 if (force == true ||\r
197                                                 (f.exists() == true && isCacheOld(progCacheFile) == true) ||\r
198                                                 (f.exists() == false && isCacheOld(null) == true)) {\r
199                                         //\r
200                                         String xtype = (pl.CenterId.startsWith(CHID_PREFIX_BS) || pl.CenterId.startsWith(CHID_PREFIX_CS)) ? XTYPE_BASIC : XTYPE_PREMIUM;\r
201                                         String chid = xtype != XTYPE_PREMIUM ? pl.CenterId : pl.CenterId.replaceFirst("^"+CHID_PREFIX_PR, "");\r
202                                         String dt = CommonUtils.getDateYMD(cal);\r
203                                         String url = "http://bangumi.skyperfectv.co.jp/"+xtype+"/channel:"+chid+"/date:"+dt.substring(2)+"/";\r
204                                         /*\r
205                                         if ( pl.ChId.length() == 0 ) {\r
206                                                 url = "http://bangumi.skyperfectv.co.jp/api/version:3/search/date:"+dt.substring(2)+"/channel:"+pl.CenterId+"/?api_key=336eec3423";\r
207                                         }\r
208                                         else {\r
209                                                 url = "http://www.skyperfectv.co.jp/xml/"+dt+"_"+pl.ChId.substring(2)+".xml";\r
210                                         }\r
211                                         */\r
212                                         webToFile(url, progCacheFile, thisEncoding);\r
213                                         \r
214                                         reportProgress(getTVProgramId()+"(オンライン)を取得しました: ("+(counter+i)+"/"+counterMax+") "+pl.Center+"["+cal.get(Calendar.DAY_OF_MONTH)+"日]    "+url);\r
215                                 }\r
216                                 else if (CommonUtils.isFileAvailable(f,10)) {\r
217                                         reportProgress(getTVProgramId()+"(キャッシュ)を取得しました: ("+(counter+i)+"/"+counterMax+") "+pl.Center+"["+cal.get(Calendar.DAY_OF_MONTH)+"日]    "+progCacheFile);\r
218                                 }\r
219                                 else {\r
220                                         reportProgress(getTVProgramId()+"(キャッシュ)がみつかりません: ("+(counter+i)+"/"+counterMax+") "+pl.Center+"["+cal.get(Calendar.DAY_OF_MONTH)+"日]    "+progCacheFile);\r
221                                         continue;\r
222                                 }\r
223         \r
224                                 String response = CommonUtils.read4file(progCacheFile, true);\r
225                                 \r
226                                 // 番組リストの追加\r
227                                 try {\r
228                                         getPrograms(pl, i, response);\r
229                                         /*\r
230                                         if ( pl.ChId.length() == 0 ) {\r
231                                                 getPrograms(pl, i, response);\r
232                                         }\r
233                                         else {\r
234                                                 getPrograms_basic(pl, i, response);\r
235                                         }\r
236                                         */\r
237                                 }\r
238                                 catch ( Exception e ) {\r
239                                         e.printStackTrace();\r
240                                 }\r
241                         }\r
242                         \r
243                         // 日付の調整\r
244                         refreshList(pl.pdate);\r
245                 }\r
246                 catch (Exception e) {\r
247                         // 例外\r
248                         System.out.println("Exception: _loadProgram()");\r
249                 }\r
250         }\r
251         \r
252         //\r
253         private void getDate(ProgList pl) {\r
254                 // 日付の処理\r
255                 GregorianCalendar c = new GregorianCalendar();\r
256                 c.setTime(new Date());\r
257                 if ( CommonUtils.isLateNight(c) ) {\r
258                         // 4時までは当日扱いにする\r
259                         c.add(Calendar.DATE, -1);\r
260                 }\r
261                 // 最終日の24時以降の情報は、+1したとこから取得する\r
262                 for ( int i=0; i<getDogDays()+1; i++ ) {\r
263                         ProgDateList cl = new ProgDateList();\r
264                         cl.Date = CommonUtils.getDate(c);\r
265                         pl.pdate.add(cl);\r
266                         \r
267                         c.add(Calendar.DATE,1);\r
268                 }\r
269         }\r
270         \r
271         //\r
272         private void refreshList(ArrayList<ProgDateList> pcenter) {\r
273                 // 日付を直すよ\r
274                 for ( int i=0; i<pcenter.size(); i++ ) {\r
275                         ProgDateList pl = pcenter.get(i);\r
276                         GregorianCalendar ca = CommonUtils.getCalendar(pl.Date);\r
277                         for ( int j=pl.pdetail.size()-1,k=0; j>=0; j--,k++ ) {\r
278                                 ProgDetailList pdl = pl.pdetail.get(j);\r
279                                 GregorianCalendar cz = (GregorianCalendar) ca.clone();\r
280                                 if ( k == 0 ) {\r
281                                         if ( CommonUtils.isLateNight(pdl.start.substring(0,2)) ) {\r
282                                                 // 最後尾の開始日は翌日だった\r
283                                                 ca.add(Calendar.DATE, 1);\r
284                                                 cz = (GregorianCalendar) ca.clone();\r
285                                         }\r
286                                         else if ( pdl.start.compareTo(pdl.end) > 0 ) {\r
287                                                 // 翌日にまたがる\r
288                                                 cz.add(Calendar.DATE, 1);\r
289                                         }\r
290                                 }\r
291                                 else {\r
292                                         if ( pdl.start.compareTo(pdl.end) > 0 ) {\r
293                                                 // 前日からまたがる\r
294                                                 ca.add(Calendar.DATE, -1);\r
295                                         }\r
296                                 }\r
297                                 pdl.accurateDate = CommonUtils.getDate(ca);\r
298                                 pdl.startDateTime = CommonUtils.getDate(ca,false)+" "+pdl.start;\r
299                                 pdl.endDateTime = CommonUtils.getDate(cz,false)+" "+pdl.end;\r
300                         }\r
301                 }\r
302 \r
303                 // 隙間を埋めつつ一個にまとめる\r
304                 ProgDateList all = new ProgDateList();\r
305                 all.pdetail = new ArrayList<ProgDetailList>();\r
306                 for ( ProgDateList pcl : pcenter ) {\r
307                         for ( ProgDetailList pdl : pcl.pdetail ) {\r
308                                 if ( all.row == 0 ) {\r
309                                         String prevend = CommonUtils.getDateTime(CommonUtils.getCalendar(pcenter.get(0).Date+" 05:00"));\r
310                                         if ( prevend.compareTo(pdl.startDateTime) < 0 ) {\r
311                                                 // 最前列の情報がとれなかった\r
312                                                 addEnmptyInfo(all, prevend, pdl.startDateTime);\r
313                                         }\r
314                                 }\r
315                                 else {\r
316                                         ProgDetailList prevpdl = all.pdetail.get(all.pdetail.size()-1);\r
317                                         if ( prevpdl.startDateTime.equals(pdl.startDateTime) ) {\r
318                                                 // 重複は破棄\r
319                                                 continue;\r
320                                         }\r
321                                         else if ( prevpdl.endDateTime.compareTo(pdl.startDateTime) < 0 ) {\r
322                                                 // 隙間を埋める\r
323                                                 addEnmptyInfo(all, prevpdl.endDateTime, pdl.startDateTime);\r
324                                         }\r
325                                 }\r
326                                 all.pdetail.add(pdl);\r
327                                 all.row += pdl.length;\r
328                         }\r
329                         // 元のリストはリセット\r
330                         pcl.pdetail = new ArrayList<ProgDetailList>();\r
331                         pcl.row = 0;\r
332                 }\r
333                 \r
334                 // 各日に振り分ける\r
335                 for ( ProgDetailList pdl : all.pdetail ) {\r
336                         int cnt = 0;\r
337                         for ( ProgDateList pcl : pcenter ) {\r
338                                 GregorianCalendar cz = CommonUtils.getCalendar(pcl.Date+" 05:00");\r
339                                 String da = CommonUtils.getDateTime(cz);\r
340                                 cz.add(Calendar.DATE, 1);\r
341                                 String dz = CommonUtils.getDateTime(cz);\r
342                                 if ( CommonUtils.isOverlap(pdl.startDateTime, pdl.endDateTime, da, dz, true) ) {\r
343                                         if ( cnt++ == 0 ) {\r
344                                                 pcl.pdetail.add(pdl);\r
345                                         }\r
346                                         else {\r
347                                                 pcl.pdetail.add(pdl.clone());\r
348                                         }\r
349                                 }\r
350                         }\r
351                 }\r
352                 \r
353                 // 24時以降の情報は日付+1したとこから取得しているので、最終日の次のリストは削除\r
354                 pcenter.remove(pcenter.size()-1);\r
355                 \r
356                 // 総時間数等を整理する\r
357                 for ( ProgDateList pcl : pcenter ) {\r
358                         // 1日の合計分数を足し合わせる\r
359                         for ( ProgDetailList pdl : pcl.pdetail ) {\r
360                                 String da = (pcl.row == 0) ? pcl.Date+" 05:00" : pdl.startDateTime;\r
361                                 pdl.length = (int)(CommonUtils.getCompareDateTime(pdl.endDateTime, da)/60000L);\r
362                                 pcl.row += pdl.length;\r
363                         }\r
364                         // おしりがとどかない場合(デメリット:これをやると、サイト側のエラーで欠けてるのか、そもそも休止なのかの区別がつかなくなる)\r
365                         if ( pcl.row < 24*60 ) {\r
366                                 GregorianCalendar ca = CommonUtils.getCalendar(pcl.Date+" 05:00");\r
367                                 GregorianCalendar cz = (GregorianCalendar) ca.clone();\r
368                                 ca.add(Calendar.MINUTE, pcl.row);\r
369                                 cz.add(Calendar.MINUTE, 24*60);\r
370                                 addEnmptyInfo(pcl, CommonUtils.getDateTime(ca), CommonUtils.getDateTime(cz));\r
371                         }\r
372                 }\r
373         }\r
374         \r
375         //\r
376         private void getPrograms(ProgList pl, int dtidx, String response) {\r
377                 \r
378                 ProgDateList pcl = pl.pdate.get(dtidx);\r
379                 \r
380                 String[][] keys = {\r
381                                 { "class", "pg-title" },\r
382                                 { "class", "start-time" },\r
383                                 { "class", "end-time" },\r
384                                 { "class", "pg-genre" },\r
385                                 { "class", "pg-explanation" },\r
386                                 { "id", "actor-name" },\r
387                 };\r
388                 \r
389                 Matcher ma = Pattern.compile("<tbody\\s+id=\"event-\\d+\"[^>]*?>(.+?)</tbody>",Pattern.DOTALL).matcher(response);\r
390                 for ( int cnt = 0; ma.find(); cnt++ ) {\r
391                         ProgDetailList pdl = new ProgDetailList();\r
392                         String subtitle = "";\r
393                         String person = "";\r
394                                 \r
395                         for ( String[] k : keys ) {\r
396                                 Matcher mb = Pattern.compile("<span\\s+"+k[0]+"=\""+k[1]+"\"[^>]*?>\\s*(.+?)\\s*</span>",Pattern.DOTALL).matcher(ma.group(1));\r
397                                 while ( mb.find() ) {\r
398                                         if ( mb.group(1) == null ) {\r
399                                                 continue;\r
400                                         }\r
401                                         \r
402                                         if ( k[1].equals("pg-title") ) {\r
403                                                 pdl.title = CommonUtils.unEscape(mb.group(1)).trim();\r
404                                         }\r
405                                         else if ( k[1].equals("start-time") ) {\r
406                                                 pdl.start = mb.group(1);\r
407                                         }\r
408                                         else if ( k[1].equals("end-time") ) {\r
409                                                 pdl.end = mb.group(1);\r
410 /*                                              \r
411                                                 GregorianCalendar c = CommonUtils.getCalendar(pcl.Date);\r
412                                                 \r
413                                                 if ( cnt == 0 && pdl.start.compareTo(pdl.end) > 0 ) {\r
414                                                         c.add(Calendar.DATE, -1);\r
415                                                 }\r
416                                                 pdl.accurateDate = CommonUtils.getDate(c);\r
417                                                 pdl.startDateTime = CommonUtils.getDate(c,false)+" "+pdl.start;\r
418                                                 \r
419                                                 if ( pdl.start.compareTo(pdl.end) > 0 ) {\r
420                                                         c.add(Calendar.DATE, 1);\r
421                                                 }\r
422                                                 pdl.endDateTime = CommonUtils.getDate(c,false)+" "+pdl.end;\r
423 */\r
424                                                 pdl.length = CommonUtils.getRecMinVal(pdl.start, pdl.end);\r
425                                         }\r
426                                         else if ( k[1].equals("pg-genre") ) {\r
427                                                 Matcher mc = Pattern.compile("/large_genre:(.+?)/medium_genre:(.+?)/",Pattern.DOTALL).matcher(mb.group(1));\r
428                                                 if ( mc.find() ) {\r
429                                                         try {\r
430                                                                 String grstr = URLDecoder.decode(mc.group(1),"utf8").replaceAll("/", "/");\r
431                                                                 ProgGenre gr = ProgGenre.get(grstr);\r
432                                                                 if ( gr == null ) {\r
433                                                                         gr = genremap.get(grstr);\r
434                                                                         if (gr == null) {\r
435                                                                                 // 未定義のジャンルです!\r
436                                                                                 gr = ProgGenre.NOGENRE;\r
437                                                                                 gf.put(grstr,null);\r
438                                                                         }\r
439                                                                 }\r
440                                                                 if ( pdl.genre == null || (pdl.genre == ProgGenre.NOGENRE && gr != ProgGenre.NOGENRE) ) {\r
441                                                                         pdl.genre = gr;\r
442                                                                 }\r
443                                                                 \r
444                                                                 String sgstr = URLDecoder.decode(mc.group(2),"utf8").replaceAll("ィー", "ィ");\r
445                                                                 ProgSubgenre sg = ProgSubgenre.get(gr, sgstr);\r
446                                                                 if ( sg == null ) {\r
447                                                                         // 未定義のサブジャンルです!\r
448                                                                         ArrayList<ProgSubgenre> vals = ProgSubgenre.values(gr);\r
449                                                                         sg = vals.get(vals.size()-1);\r
450                                                                 }\r
451                                                                 pdl.subgenre = sg;\r
452                                                         } catch (UnsupportedEncodingException e) {\r
453                                                                 e.printStackTrace();\r
454                                                                 pdl.genre = ProgGenre.NOGENRE;\r
455                                                                 pdl.subgenre = ProgSubgenre.NOGENRE_ETC;\r
456                                                         }\r
457                                                 }\r
458                                                 else {\r
459                                                         pdl.genre = ProgGenre.NOGENRE;\r
460                                                         pdl.subgenre = ProgSubgenre.NOGENRE_ETC;\r
461                                                 }\r
462                                         }\r
463                                         else if ( k[1].equals("pg-explanation") ) {\r
464                                                 pdl.detail += CommonUtils.decBr(CommonUtils.unEscape(mb.group(1))).trim()+"\n";\r
465                                         }\r
466                                         else if ( k[1].equals("actor-name") ) {\r
467                                                 person += "、"+CommonUtils.unEscape(mb.group(1)).trim();\r
468                                         }\r
469                                 }\r
470                         }\r
471                         \r
472                         // 出演者\r
473                         if ( person.length() > 0 ) {\r
474                                 person = person.substring(1);\r
475                         }\r
476                         \r
477                         // くっつけてみる\r
478                         pdl.detail =\r
479                                         ((subtitle.length()>0)?(subtitle+DETAIL_SEP):(""))\r
480                                         +pdl.detail\r
481                                         +((person.length()>0)?(DETAIL_SEP+person):(""));\r
482                         pdl.detail = pdl.detail.replaceFirst("[\r\n]+$", "");\r
483 \r
484                         Matcher mb = Pattern.compile("<img\\s+src=\"/i/icon_(.+?)\\.gif",Pattern.DOTALL).matcher(ma.group(1));\r
485                         while ( mb.find() ) {\r
486                                 if ( mb.group(1).equals("5.1") ) {\r
487                                         pdl.addOption(ProgOption.SURROUND);\r
488                                 }\r
489                                 else if ( mb.group(1).equals("jimaku") ) {\r
490                                         pdl.addOption(ProgOption.SUBTITLE);\r
491                                 }\r
492                                 else if ( mb.group(1).equals("2kakoku") ) {\r
493                                         pdl.addOption(ProgOption.BILINGUAL);\r
494                                 }\r
495                                 else if ( mb.group(1).equals("fukikae") ) {\r
496                                         pdl.addOption(ProgOption.STANDIN);\r
497                                 }\r
498                                 else if ( mb.group(1).equals("tajuu") ) {\r
499                                         pdl.addOption(ProgOption.MULTIVOICE);\r
500                                 }\r
501                                 else if ( mb.group(1).equals("r15") || mb.group(1).equals("r18") || mb.group(1).equals("adult") ) {\r
502                                         pdl.addOption(ProgOption.RATING);\r
503                                 }\r
504                                 else if ( mb.group(1).equals("ppv") ) {\r
505                                         pdl.addOption(ProgOption.PV);\r
506                                 }\r
507                                 else if ( mb.group(1).equals("nama") ) {\r
508                                         pdl.addOption(ProgOption.LIVE);\r
509                                 }\r
510                                 else {\r
511                                         nf.put(mb.group(1), null);\r
512                                 }\r
513                         }\r
514                         \r
515                         // タイトルから各種フラグを分離する\r
516                         doSplitFlags(pdl, nf);\r
517                         \r
518                         // サブタイトル分離(ポインタを活用してメモリを節約する)\r
519                         doSplitSubtitle(pdl);\r
520                         \r
521                         // 番組ID\r
522                         if ( ContentIdDIMORA.isValid(pl.ChId) ) {\r
523                                 pdl.progid = pl.ChId;\r
524                         }\r
525                         \r
526                         // その他フラグ\r
527                         pdl.extension = false;\r
528                         pdl.nosyobo = false;\r
529                         \r
530                         pcl.pdetail.add(pdl);\r
531                         \r
532                         if (getDebug()) System.err.println(DBGID+"program: "+pdl.startDateTime+" - "+pdl.endDateTime+" "+pdl.length+"m "+pdl.noscrumble+" "+pdl.title);\r
533                 }\r
534         }\r
535 \r
536         \r
537         /**\r
538          * こちらは番組IDがとれる代わりに出演者情報がとれなくなるので保留とする\r
539          */\r
540         private void getPrograms_basic(ProgList pl, int dtidx, String response) {\r
541                 \r
542                 Matcher ma = Pattern.compile("<SIInformation(.+?)</SIInformation>",Pattern.DOTALL).matcher(response);\r
543                 while ( ma.find() ) {\r
544                         Matcher mb = Pattern.compile("eventId=\"(.+?)\".+?broadCastStartDate=\"(\\d{8})(\\d{4})",Pattern.DOTALL).matcher(ma.group(1));\r
545                         if ( mb.find() ) {\r
546                                 \r
547                         }\r
548                         /*\r
549                         mb = Pattern.compile("<(.+?)>(.+?)</\\1>",Pattern.DOTALL).matcher(ma.group(1));\r
550                         while ( mb.find() ) {\r
551                                 if ( mb.group(1).equals("ChannelName") ) {\r
552                                         \r
553                                 }\r
554                                 else if ( mb.group(1).equals("Title") ) {\r
555                                         \r
556                                 }\r
557                                 else if ( mb.group(1).equals("Synopsis") ) {\r
558                                         \r
559                                 }\r
560                                 else if ( mb.group(1).equals("Genres") ) {\r
561                                         Matcher mc = Pattern.compile("<Genre majorGenreId=\".+?\" minorGenreId=\".+?\"",Pattern.DOTALL).matcher(mb.group(2));\r
562                                         while ( mc.find() ) {\r
563                                                 \r
564                                         }\r
565                                 }\r
566                         }\r
567                         */\r
568                 }\r
569         }\r
570 \r
571         \r
572         /*\r
573          * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
574          * ★★★★★ 放送地域を取得する(TVAreaから降格)-ここから ★★★★★\r
575          * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
576          */\r
577         \r
578         /*\r
579          * 公開メソッド\r
580          */\r
581         \r
582         @Override\r
583         public String getDefaultArea() {return "全国";}\r
584         private String getDefaultCode() {return "SKP2012";}\r
585         \r
586         @Override\r
587         public void loadAreaCode() {\r
588                 aclist = new ArrayList<AreaCode>();\r
589                 AreaCode ac = new AreaCode();\r
590                 ac.setArea(getDefaultArea());\r
591                 ac.setCode(getDefaultCode());\r
592                 ac.setSelected(true);\r
593                 aclist.add(ac);\r
594         }\r
595         @Override\r
596         public void saveAreaCode() {}\r
597         \r
598         @Override\r
599         public String getArea(String code) { return(getDefaultArea()); }\r
600         @Override\r
601         public String getCode(String area) { return(getDefaultCode()); }\r
602         @Override\r
603         public String setSelectedAreaByName(String area) { return(getDefaultCode()); }\r
604         @Override\r
605         public String getSelectedArea() { return(getDefaultArea()); }\r
606         @Override\r
607         public String getSelectedCode() { return(getDefaultCode()); }\r
608         \r
609         /*\r
610          * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
611          * ★★★★★ 放送地域を取得する(TVAreaから降格)-ここまで ★★★★★\r
612          * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
613          */\r
614         \r
615         \r
616         \r
617         /*\r
618          * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
619          * ★★★★★ 放送局を選択する(TVCenterから降格)-ここから ★★★★★\r
620          * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
621          */\r
622         \r
623         /*\r
624          * 公開メソッド\r
625          */\r
626 \r
627         // 設定ファイルがなければWebから取得\r
628         @Override\r
629         public void loadCenter(String code, boolean force) {\r
630                 \r
631                 if ( code == null ) {\r
632                         System.out.println(ERRID+"地域コードがnullです.");\r
633                         return;\r
634                 }\r
635                 \r
636                 String centerListFile = getCenterListFile(getTVProgramId(), code);\r
637                 \r
638                 if (force) {\r
639                         File f = new File(centerListFile);\r
640                         f.delete();\r
641                 }\r
642                 \r
643                 File f = new File(centerListFile);\r
644                 if (f.exists() == true) {\r
645                         @SuppressWarnings("unchecked")\r
646                         ArrayList<Center> tmp = (ArrayList<Center>)CommonUtils.readXML(centerListFile);\r
647                         if ( tmp != null ) {\r
648                                 crlist = tmp;\r
649 \r
650                                 // 放送局名変換\r
651                                 attachChFilters();\r
652                                 \r
653                                 String[][] prs = {\r
654                                                 {CHNM_PREFIX_BS, CHID_PREFIX_BS},\r
655                                                 {CHNM_PREFIX_CS, CHID_PREFIX_CS},\r
656                                                 {CHNM_PREFIX_PR, CHID_PREFIX_PR},\r
657                                 };\r
658                                 \r
659                                 // 2013.11 新旧変換\r
660                                 for ( Center cr : crlist ) {\r
661                                         for ( String[] a : prs ) {\r
662                                                 if ( cr.getCenterOrig().startsWith(a[0]) ) {\r
663                                                         if ( ! cr.getLink().startsWith(a[1]) ) {\r
664                                                                 Matcher ma = Pattern.compile("^.*?(\\d+)",Pattern.DOTALL).matcher(cr.getCenterOrig());\r
665                                                                 if ( ma.find() ) {\r
666                                                                         String chid = a[1]+ma.group(1);\r
667                                                                         System.err.println(DBGID+"converted: "+cr.getCenterOrig()+", "+cr.getLink()+" -> "+chid);\r
668                                                                         cr.setLink(chid);\r
669                                                                 }\r
670                                                         }\r
671                                                         \r
672                                                         break;\r
673                                                 }\r
674                                         }\r
675                                 }\r
676                                 \r
677                                 System.out.println("放送局リストを読み込みました: "+centerListFile);\r
678                                 return;\r
679                         }\r
680                         else {\r
681                                 System.out.println("放送局リストの読み込みに失敗しました: "+centerListFile);\r
682                         }\r
683                 }\r
684 \r
685                 // 放送局をつくるよ\r
686                 ArrayList<Center> newcrlist = new ArrayList<Center>();\r
687                 \r
688                 for ( String xtype : new String[] { XTYPE_BASIC,XTYPE_PREMIUM } ) {\r
689                         ArrayList<Center> crl = getCenters(xtype,code);\r
690                         if ( crl != null ) {\r
691                                 reportProgress("放送局情報を取得しました: ("+xtype+") "+crl.size()+"ch");\r
692                         }\r
693                         \r
694                         for ( Center cr : crl ) {\r
695                                 newcrlist.add(cr);\r
696                         }\r
697                 }\r
698                 \r
699                 if ( newcrlist.size() == 0 ) {\r
700                         System.err.println(ERRID+"放送局情報の取得結果が0件だったため情報を更新しません");\r
701                         return;\r
702                 }\r
703                 \r
704                 crlist = newcrlist;\r
705                 attachChFilters();      // 放送局名にフィルタをかける\r
706                 saveCenter();\r
707         }\r
708         \r
709         private ArrayList<Center> getCenters(String xtype, String areacode) {\r
710                 \r
711                 ArrayList<Center> crl = new ArrayList<Center>();\r
712                 \r
713                 String url = String.format("http://bangumi.skyperfectv.co.jp/index/channel/%s/",xtype);\r
714                 if (getDebug()) System.err.println(DBGID+"get page: "+url);\r
715                 String response = webToBuffer(url,thisEncoding,true);\r
716                 if ( response == null ) {\r
717                         reportProgress("放送局情報の取得に失敗しました: "+xtype);\r
718                         return null;\r
719                 }\r
720                 \r
721                 Matcher ma = Pattern.compile("<td class=\"channel-icon\">\\s*<a href=\".*?/channel:(.+?)/\".*?>\\s*<img src=\".*?\" alt=\"(.+?)\"",Pattern.DOTALL).matcher(response);\r
722                 while ( ma.find() ) {\r
723                         String chid = (xtype.equals(XTYPE_PREMIUM) ? CHID_PREFIX_PR : "") + ma.group(1);\r
724                         String chnm = CommonUtils.toHANALNUM(CommonUtils.unEscape(ma.group(2))).replaceFirst("[  \\t]+▲$", "");\r
725                         \r
726                         // 統一性がない\r
727                         if ( xtype.equals(XTYPE_PREMIUM) && ! chnm.startsWith(CHNM_PREFIX_PR) ) {\r
728                                 chnm = CHNM_PREFIX_PR+chnm;\r
729                         }\r
730                         \r
731                         Center cr = new Center();\r
732                         cr.setAreaCode(areacode);\r
733                         cr.setType("");\r
734                         cr.setEnabled(true);\r
735                         cr.setCenterOrig(chnm);\r
736                         cr.setLink(chid);\r
737                         \r
738                         int idx = 0;\r
739                         for ( Center ct : crl ) {\r
740                                 if ( ct.getCenterOrig().compareTo(cr.getCenterOrig()) > 0 ) {\r
741                                         break;\r
742                                 }\r
743                                 idx++;\r
744                         }\r
745                         crl.add(idx, cr);\r
746                         \r
747                         if (getDebug()) System.err.println(DBGID+"center: "+cr.getCenterOrig()+", "+cr.getLink());\r
748                 }\r
749                 \r
750                 return crl;\r
751         }\r
752         \r
753         /*\r
754          * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
755          * ★★★★★ 放送局を選択する(TVCenterから降格)-ここまで ★★★★★\r
756          * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★\r
757          */\r
758 }\r