• R/O
  • HTTP
  • SSH
  • HTTPS

TinyBannavi: Commit

タイニー番組ナビゲータ本体


Commit MetaInfo

Revisión5f75abc952789efb704a25c558124363155eb1b7 (tree)
Tiempo2014-09-18 17:44:33
Autorpeeweedee <peeweedee@user...>
Commiterpeeweedee

Log Message

・リスト形式:CSVでクリップボードにコピー

Cambiar Resumen

Diferencia incremental

--- a/TinyBannavi/05_history.txt
+++ b/TinyBannavi/05_history.txt
@@ -10,6 +10,15 @@
1010 2chの番ナビスレ:http://toro.2ch.net/test/read.cgi/av/1352223253/
1111 ★☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆★
1212
13+3.22.17β+1.5.12(2014-09-18)
14+■変更点
15+ ・(レコーダ対応[DBR-T450]) 追加 ※予約ダイアログ上に表示されるが、指定できない設定項目があります
16+ ・(リスト形式) ツリーのプルダウンメニューにキーボードショートカットをつけた
17+ ・(リスト形式) 表示中のリストをCSV形式でクリップボードにコピーできるようにした
18+ ・(自動予約一覧) 放送局が複数選択されている場合に、放送局欄に最大3局まで表示するようにした
19+■バグ修正
20+ ・(レコーダ対応[S304Kほか]) 「おまかせ自動予約」かつエンコーダが「RE」の場合に予約一覧でエンコーダが「--」と表示される問題を修正(>>756.)
21+
1322 3.22.16β+1.5.12(2014-04-08)
1423 ■変更点
1524  ・(その他) CTRL+Fで検索ボックスに移動などのキーボードショートカットの追加(>>735.)
--- a/TinyBannavi/src/tainavi/AbsListedView.java
+++ b/TinyBannavi/src/tainavi/AbsListedView.java
@@ -1467,7 +1467,101 @@ public abstract class AbsListedView extends JPanel implements TickTimerListener
14671467 public Component getTableBody() {
14681468 return jTable_listed;
14691469 }
1470-
1470+
1471+ /**
1472+ * テキスト化
1473+ */
1474+ public String getCSV(boolean onlySelected) {
1475+ synchronized ( rowData ) {
1476+
1477+ StringBuilder sbCsv = new StringBuilder();
1478+
1479+ // ヘッダ
1480+ {
1481+ StringBuilder sbRow = new StringBuilder();
1482+ for (Enum h : CSV_HEADER.values()) {
1483+ sbRow.append(CommonUtils.toQuoted(h.name()));
1484+ sbRow.append(",");
1485+ }
1486+ sbRow.deleteCharAt(sbRow.length()-1);
1487+ sbRow.append("\n");
1488+ sbCsv.append(sbRow.toString());
1489+ }
1490+
1491+ // データ
1492+ if ( onlySelected ) {
1493+ for (int prow : jTable_listed.getSelectedRows()) {
1494+ sbCsv.append(foo(jTable_listed.convertRowIndexToModel(prow)));
1495+ }
1496+ }
1497+ else {
1498+ for ( int row=0; row < rowData.size(); row++ ) {
1499+ sbCsv.append(foo(row));
1500+ }
1501+ }
1502+ return sbCsv.toString();
1503+ }
1504+ }
1505+
1506+ private String foo(int row) {
1507+ ListedItem c = rowData.get(row);
1508+ ProgDetailList tvd = c.tvd;
1509+ StringBuilder sbRow = new StringBuilder();
1510+ for (Enum h : CSV_HEADER.values()) {
1511+ String v = "";
1512+ if (h == CSV_HEADER.RSVMARK) {
1513+ v = getRsvMarkString(c);
1514+ Matcher ma = Pattern.compile("\0.*$",Pattern.DOTALL).matcher(v);
1515+ if (ma.find()) {
1516+ v = ma.replaceAll("") ;
1517+ }
1518+ } else if (h == CSV_HEADER.PICKMARK) {
1519+ v = getPickMarkString(c);
1520+ Matcher ma = Pattern.compile("\0.*$",Pattern.DOTALL).matcher(v);
1521+ if (ma.find()) {
1522+ v = ma.replaceAll("") ;
1523+ }
1524+ } else if (h == CSV_HEADER.DUPMARK) {
1525+ v = getDupMarkString(c);
1526+ Matcher ma = Pattern.compile("\0.*$",Pattern.DOTALL).matcher(v);
1527+ if (ma.find()) {
1528+ v = ma.replaceAll("") ;
1529+ }
1530+ } else if (h == CSV_HEADER.CENTER) {
1531+ v = tvd.center;
1532+ } else if (h == CSV_HEADER.OPTION) {
1533+ v = c.prefix.replaceAll("\0", "");
1534+ } else if (h == CSV_HEADER.TITLE) {
1535+ v = tvd.title;
1536+ } else if (h == CSV_HEADER.DETAIL) {
1537+ v = tvd.detail;
1538+ } else if (h == CSV_HEADER.STARTDATETIME) {
1539+ v = tvd.startDateTime;
1540+ } else if (h == CSV_HEADER.ENDDATETIME) {
1541+ v = tvd.endDateTime;
1542+ } else if (h == CSV_HEADER.LENGTH) {
1543+ v = String.valueOf(tvd.length);
1544+ } else if (h == CSV_HEADER.GENRE) {
1545+ v = getGenreString(tvd);
1546+ } else if (h == CSV_HEADER.SEARCHLABEL) {
1547+ v = c.searchlabel;
1548+ } else if (h == CSV_HEADER.OKINIIRI) {
1549+ v = c.okiniiri;
1550+ } else if (h == CSV_HEADER.SCORE) {
1551+ v = String.valueOf(c.score);
1552+ } else if (h == CSV_HEADER.THRESHOLD) {
1553+ v = String.valueOf(c.threshold);
1554+ }
1555+ sbRow.append(CommonUtils.toQuoted(v));
1556+ sbRow.append(",");
1557+ }
1558+ sbRow.deleteCharAt(sbRow.length()-1);
1559+ sbRow.append("\n");
1560+ return sbRow.toString();
1561+ }
1562+
1563+ static enum CSV_HEADER { RSVMARK, PICKMARK, DUPMARK, CENTER, OPTION, TITLE, DETAIL, STARTDATETIME, ENDDATETIME, LENGTH, GENRE, SEARCHLABEL, OKINIIRI, SCORE, THRESHOLD };
1564+
14711565 /*******************************************************************************
14721566 * リスナー
14731567 ******************************************************************************/
@@ -1603,7 +1697,7 @@ public abstract class AbsListedView extends JPanel implements TickTimerListener
16031697 if (e.getButton() == MouseEvent.BUTTON3) {
16041698 if (e.getClickCount() == 1) {
16051699 // 右シングルクリックでメニューの表示
1606- t.getSelectionModel().setSelectionInterval(vrow,vrow);
1700+ t.getSelectionModel().addSelectionInterval(vrow,vrow);
16071701
16081702 int threshold = getThrValByRow(row);
16091703 String keyword = (threshold > 0) ? (getKeyValByRow(row)) : (tvd.title);
@@ -4225,21 +4319,13 @@ public abstract class AbsListedView extends JPanel implements TickTimerListener
42254319 if ( c.size( ) > column ) {
42264320 // 特殊なカラム
42274321 if ( column == ListedColumn.RSVMARK.getColumn() ) {
4228- if ( c.marker != null && c.marker.rsvmark != null ) {
4229- if ( c.marker.rsvmark != RsvMark.URABAN ) {
4230- return c.marker.rsvmark.mark+"\0"+c.hide_rsvmarkcolor;
4231- }
4232- else {
4233- return c.marker.rsvmark.mark+"\0"+URABAN_COLOR;
4234- }
4235- }
4236- return "";
4322+ return getRsvMarkString(c);
42374323 }
42384324 else if ( column == ListedColumn.PICKMARK.getColumn() ) {
4239- return (env.getShowRsvPickup() && c.marker != null && c.marker.pickmark != null) ? c.marker.pickmark.mark : "" ;
4325+ return getPickMarkString(c);
42404326 }
42414327 else if ( column == ListedColumn.DUPMARK.getColumn() ) {
4242- return (env.getShowRsvDup() && c.dupmark != null) ? c.dupmark.mark+"\0"+DUPMARK_COLOR : "";
4328+ return getDupMarkString(c);
42434329 }
42444330 else if ( column == ListedColumn.START.getColumn() ) {
42454331 return c.tvd.accurateDate+" "+c.tvd.start;
@@ -4248,13 +4334,7 @@ public abstract class AbsListedView extends JPanel implements TickTimerListener
42484334 return c.tvd.recmin+"m";
42494335 }
42504336 else if ( column == ListedColumn.GENRE.getColumn() ) {
4251- if ( c.tvd.subgenre != null ) {
4252- return c.tvd.genre.toString()+" - "+c.tvd.subgenre.toString();
4253- }
4254- else {
4255- // サブジャンルに非対応な番組表の場合
4256- return c.tvd.genre.toString();
4257- }
4337+ return getGenreString(c.tvd);
42584338 }
42594339 else if ( column == ListedColumn.OPTIONS.getColumn() && ! env.getSplitMarkAndTitle() ) {
42604340 // オプション分離がOFFです
@@ -4280,4 +4360,33 @@ public abstract class AbsListedView extends JPanel implements TickTimerListener
42804360
42814361 }
42824362
4363+ private String getRsvMarkString(ListedItem c) {
4364+ if ( c.marker != null && c.marker.rsvmark != null ) {
4365+ if ( c.marker.rsvmark != RsvMark.URABAN ) {
4366+ return c.marker.rsvmark.mark+"\0"+c.hide_rsvmarkcolor;
4367+ }
4368+ else {
4369+ return c.marker.rsvmark.mark+"\0"+URABAN_COLOR;
4370+ }
4371+ }
4372+ return "";
4373+ }
4374+
4375+ private String getPickMarkString(ListedItem c) {
4376+ return (env.getShowRsvPickup() && c.marker != null && c.marker.pickmark != null) ? c.marker.pickmark.mark : "" ;
4377+ }
4378+
4379+ private String getDupMarkString(ListedItem c) {
4380+ return (env.getShowRsvDup() && c.dupmark != null) ? c.dupmark.mark+"\0"+DUPMARK_COLOR : "";
4381+ }
4382+
4383+ private String getGenreString(ProgDetailList tvd) {
4384+ if ( tvd.subgenre != null ) {
4385+ return tvd.genre.toString()+" - "+tvd.subgenre.toString();
4386+ }
4387+ else {
4388+ // サブジャンルに非対応な番組表の場合
4389+ return tvd.genre.toString();
4390+ }
4391+ }
42834392 }
--- a/TinyBannavi/src/tainavi/CommonUtils.java
+++ b/TinyBannavi/src/tainavi/CommonUtils.java
@@ -1025,7 +1025,10 @@ public class CommonUtils {
10251025
10261026 return sb.toString();
10271027 }
1028-
1028+
1029+ public static String toQuoted(String s) {
1030+ return "\"" + s.replaceAll("\"","\"\"") + "\"";
1031+ }
10291032
10301033 /*******************************************************************************
10311034 * オブジェクト操作関連
--- a/TinyBannavi/src/tainavi/TVProgram.java
+++ b/TinyBannavi/src/tainavi/TVProgram.java
@@ -300,7 +300,7 @@ public interface TVProgram {
300300 public static final String csCode = "cs";
301301
302302 // タイトルの頭の邪魔な文字
303- public static final String titlePrefixRemoveExpr = "^(\\[(新|無|字|終|HV|SS|二|映|無料)\\]|無料≫|【無料】)+\\s*";
303+ public static final String titlePrefixRemoveExpr = "^(\\[(新|無|字|終|HV|SS|二|映|無料)\\]|無料≫|【無料】|【アニメ】)+\\s*";
304304 public static final String epnoNormalizeExpr = "([第#(])(\\d\\D|\\d$)";
305305
306306 // 種族の特性
--- a/TinyBannavi/src/tainavi/VersionInfo.java
+++ b/TinyBannavi/src/tainavi/VersionInfo.java
@@ -5,7 +5,7 @@ import java.util.regex.Pattern;
55
66
77 public class VersionInfo {
8- private static final String Version = "タイニー番組ナビゲータ 3.22.16β";
8+ private static final String Version = "タイニー番組ナビゲータ 3.22.17β";
99
1010 private static final String OSname = System.getProperty("os.name");
1111 private static final String OSvers = System.getProperty("os.version");
--- a/TinyBannavi/src/tainavi/Viewer.java
+++ b/TinyBannavi/src/tainavi/Viewer.java
@@ -2078,7 +2078,36 @@ public class Viewer extends JFrame implements ChangeListener,TickTimerListener,H
20782078 }
20792079
20802080 pop.addSeparator();
2081-
2081+
2082+ if ( mainWindow.isTabSelected(MWinTab.LISTED) ) {
2083+ {
2084+ JMenuItem menuItem = new JMenuItem("番組情報をCSVでコピー");
2085+ menuItem.addActionListener(new ActionListener() {
2086+ public void actionPerformed(ActionEvent e) {
2087+ String msg = listed.getCSV(false);
2088+ Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
2089+ StringSelection s = new StringSelection(msg);
2090+ cb.setContents(s, s);
2091+ }
2092+ });
2093+ pop.add(menuItem);
2094+ }
2095+ {
2096+ JMenuItem menuItem = new JMenuItem("選択中の番組情報をCSVでコピー");
2097+ menuItem.addActionListener(new ActionListener() {
2098+ public void actionPerformed(ActionEvent e) {
2099+ String msg = listed.getCSV(true);
2100+ Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
2101+ StringSelection s = new StringSelection(msg);
2102+ cb.setContents(s, s);
2103+ }
2104+ });
2105+ pop.add(menuItem);
2106+ }
2107+ }
2108+
2109+ pop.addSeparator();
2110+
20822111 // 延長感染源へ追加する
20832112 if (
20842113 tvd.type == ProgType.SYOBO ||
--- a/TinyBannavi/src/tainavi/plugintv/PlugIn_TVPTVGuide.java
+++ /dev/null
@@ -1,687 +0,0 @@
1-package tainavi.plugintv;
2-
3-import java.io.File;
4-import java.util.ArrayList;
5-import java.util.Calendar;
6-import java.util.Date;
7-import java.util.GregorianCalendar;
8-import java.util.HashMap;
9-import java.util.LinkedHashMap;
10-import java.util.regex.Matcher;
11-import java.util.regex.Pattern;
12-
13-import tainavi.AreaCode;
14-import tainavi.Center;
15-import tainavi.CommonUtils;
16-import tainavi.ProgDateList;
17-import tainavi.ProgDetailList;
18-import tainavi.ProgList;
19-import tainavi.TVProgram;
20-import tainavi.TVProgramUtils;
21-import tainavi.TVProgram.ProgFlags;
22-import tainavi.TVProgram.ProgGenre;
23-import tainavi.TVProgram.ProgOption;
24-import tainavi.TVProgram.ProgScrumble;
25-import tainavi.TVProgram.ProgSubtype;
26-import tainavi.TVProgram.ProgType;
27-
28-
29-public class PlugIn_TVPTVGuide extends TVProgramUtils implements TVProgram,Cloneable {
30-
31- public PlugIn_TVPTVGuide clone() {
32- return (PlugIn_TVPTVGuide) super.clone();
33- }
34-
35- private static final String thisEncoding = "UTF-8";
36-
37-
38- /*******************************************************************************
39- * 種族の特性
40- ******************************************************************************/
41-
42- @Override
43- public String getTVProgramId() { return "インターネットTVガイド"; }
44-
45- @Override
46- public ProgType getType() { return ProgType.PROG; }
47- @Override
48- public ProgSubtype getSubtype() { return ProgSubtype.TERRA; }
49-
50-
51- /*******************************************************************************
52- * 個体の特性
53- ******************************************************************************/
54-
55- @Override
56- public int getTimeBarStart() {return 5;}
57-
58- private int getDogDays() { return ((getExpandTo8())?(8):(7)); }
59-
60-
61- /*******************************************************************************
62- * 定数
63- ******************************************************************************/
64-
65- private final String MSGID = "["+getTVProgramId()+"] ";
66- private final String ERRID = "[ERROR]"+MSGID;
67- private final String DBGID = "[DEBUG]"+MSGID;
68-
69- /*******************************************************************************
70- * 部品
71- ******************************************************************************/
72-
73- // 新しい入れ物の臨時格納場所
74- protected final ArrayList<ProgList> newplist = new ArrayList<ProgList>();
75-
76- // 未定義のフラグの回収場所
77- private final HashMap<String,String> nf = new HashMap<String, String>();
78-
79-
80- /*******************************************************************************
81- * コンストラクタ
82- ******************************************************************************/
83-
84-
85- /*******************************************************************************
86- * 番組情報を取得する
87- ******************************************************************************/
88- @Override
89- public void loadProgram(String areaCode, boolean force) {
90-
91- // 入れ物を空にする
92- newplist.clear();
93- nf.clear();
94-
95- // 地域コードごとの参照ページ数の入れ物を用意する
96- LinkedHashMap<String,Integer> pages = new LinkedHashMap<String, Integer>();
97-
98- // 参照する地域コードをまとめる
99- if ( areaCode.equals(allCode) ) {
100- // 「全国」
101- for ( Center cr : crlist ) {
102- if ( cr.getOrder() > 0 ) {
103- // 有効局の地域コードのみ集める
104- pages.put(cr.getAreaCode(),0);
105- }
106- }
107- }
108- else {
109- // 地域個別
110- pages.put(areaCode,0);
111- pages.put(bsCode,0);
112- }
113-
114- // トップの下に局ごとのリストを生やす
115- for ( String ac : pages.keySet() ) {
116- for ( Center cr : crlist ) {
117- if ( ac.equals(cr.getAreaCode()) ) {
118- ProgList pl = new ProgList();
119- pl.Area = cr.getAreaCode();
120- pl.SubArea = cr.getType();
121- pl.Center = cr.getCenter();
122- pl.BgColor = cr.getBgColor();
123-
124- // <TABLE>タグの列数を決め打ちで処理するので、設定上無効な局も内部的には列の1つとして必要
125- pl.enabled = (cr.getOrder()>0)?(true):(false);
126-
127- newplist.add(pl);
128-
129- int pg = Integer.valueOf(cr.getType());
130- if ( pl.enabled && pages.get(ac) < pg ) {
131- // 地域コードごとの最大参照ページ数を格納する
132- pages.put(ac,pg);
133- }
134- }
135- }
136- }
137-
138- // 局の下に日付ごとのリストを生やす
139- GregorianCalendar cal = new GregorianCalendar();
140- cal.setTime(new Date());
141- if ( CommonUtils.isLateNight(cal) ) {
142- // 4時までは当日扱いにする
143- cal.add(Calendar.DATE, -1);
144- }
145- GregorianCalendar cale = (GregorianCalendar) cal.clone();
146- for (int i=0; i<getDogDays(); i++) {
147- String date = CommonUtils.getDate(cale);
148- for ( ProgList pl : newplist ) {
149- ProgDateList cl = new ProgDateList();
150- cl.Date = date;
151- pl.pdate.add(cl);
152- }
153- cale.add(Calendar.DATE, 1);
154- }
155-
156- // 参照する総ページ数を計算
157- int counterMax = 0;
158- for ( String ac : pages.keySet() ) {
159- counterMax += pages.get(ac)*getDogDays();
160- }
161-
162- // 日付の下に番組情報ごとのリストを生やす(TVガイドシンプル版は1ページに複数局存在する)
163- int counter = 1;
164- for ( String ac : pages.keySet() ) {
165- cale = (GregorianCalendar) cal.clone();
166- for ( int i=0; i<getDogDays(); i++ ) {
167- String date = CommonUtils.getDateYMD(cale);
168- for ( int d=1; d<=pages.get(ac) && d<=REFPAGESMAX; d++ ) { // 最大{REFPAGESMAX}ページまでしか参照しない
169- String url;
170- if ( ac.equals(bsCode) ) {
171- url = "http://www.tvguide.or.jp/TF1101LS.php?mediaId=2&date="+date+"&time=05&dispflg=0&page="+String.valueOf(d)+"&time=24";
172- }
173- else {
174- url = "http://www.tvguide.or.jp/TF1101LS.php?regionId="+ac+"&mediaId=1&date="+date+"&time=05&dispflg=0&page="+String.valueOf(d)+"&time=24";
175- }
176- _loadProgram(ac, d, pages.get(ac), url, force, i, cale.get(Calendar.MONTH)+1, cale.get(Calendar.DATE), counter++, counterMax);
177- }
178-
179- cale.add(Calendar.DATE, 1);
180- }
181- }
182-
183- // 当日分のプログラムリストのみrowを再計算(現在時刻以前の情報がない関係で)
184- for ( ProgList pl : newplist ) {
185- if ( pl.enabled ) {
186- if ( pl.pdate.size() > 0 ) {
187- ProgDateList pcl = pl.pdate.get(0);
188- pcl.row = 0;
189- for ( ProgDetailList pdl : pcl.pdetail ) {
190- pcl.row += pdl.length;
191- }
192- }
193- }
194- }
195-
196- // 開始・終了日時を正しい値に計算しなおす
197- for ( ProgList pl : newplist ) {
198- setAccurateDate(pl.pdate);
199- }
200-
201- // 古いデータから補完できないかな?
202- CompensatesPrograms(newplist);
203-
204- // 古い番組データを置き換える
205- pcenter = newplist;
206- }
207-
208- /* ここまで */
209-
210-
211-
212- /*
213- * 非公開メソッド
214- */
215-
216- private void _loadProgram(String areacode, int page, int pmax, String url, boolean force, int wdaycol, int month, int day, int counter, int counterMax) {
217- // progfilesの読み出し
218- final String progCacheFile = String.format(getProgDir()+File.separator+"TVGuide_%s_%d_%s.html", areacode, day, page);
219- try {
220- File f = new File(progCacheFile);
221- if (force == true ||
222- (f.exists() == true && isCacheOld(progCacheFile) == true) ||
223- (f.exists() == false && isCacheOld(null) == true)) {
224- webToFile(url, progCacheFile, thisEncoding);
225- reportProgress(String.format("%s (オンライン)を取得しました: (%d/%d) %d日[%d/%d] %s",getTVProgramId(),counter,counterMax,day,page,pmax,url));
226- }
227- else if (CommonUtils.isFileAvailable(f,10)) {
228- reportProgress(String.format("%s (キャッシュ)を取得しました: (%d/%d) %d日[%d/%d] %s",getTVProgramId(),counter,counterMax,day,page,pmax,progCacheFile));
229- }
230- else {
231- reportProgress(String.format("%s (キャッシュ)がみつかりません: (%d/%d) %d日[%d/%d] %s",getTVProgramId(),counter,counterMax,day,page,pmax,progCacheFile));
232- return;
233- }
234-
235- // キャッシュファイルの読み込み
236- String response = CommonUtils.read4file(progCacheFile, true);
237-
238- // キャッシュが不整合を起こしていたら投げ捨てる
239- Matcher ma = Pattern.compile(String.format("class=\"txt01 display_now\">%d月%d日",month,day)).matcher(response);
240- if ( ! ma.find() ) {
241- reportProgress(String.format("%s (キャッシュ)が無効です: (%d/%d) %d日[%d/%d] %s",getTVProgramId(),counter,counterMax,day,page,pmax,progCacheFile));
242- return;
243- }
244-
245- // 番組リストの追加
246- getPrograms(areacode, String.valueOf(page), wdaycol, response);
247- }
248- catch (Exception e) {
249- // 例外
250- System.out.println("Exception: _loadProgram()");
251- e.printStackTrace();
252- }
253- }
254-
255- //
256- private void getPrograms(String areacode, String page, int wdaycol, String src) {
257-
258- HashMap<String,ProgGenre> genres = new HashMap<String, TVProgram.ProgGenre>();
259- genres.put("ccccff", ProgGenre.SPORTS);
260- genres.put("ccffcc", ProgGenre.MUSIC);
261- genres.put("ccffff", ProgGenre.ANIME);
262- genres.put("ffcccc", ProgGenre.MOVIE);
263- genres.put("ffffcc", ProgGenre.DORAMA);
264- genres.put("ffcc99", ProgGenre.VARIETY);
265- genres.put("", ProgGenre.NOGENRE);
266-
267- HashMap<String,Integer> marks = new HashMap<String,Integer>();
268- marks.put("26", 0); // 新番組
269- marks.put("30", 1); // 最終回
270- marks.put("29", 2); // 再放送
271- // 初回放送(みつからないよ)
272- marks.put("53", 4); // [PV]ペイパービュー
273- marks.put("54", 4); // [PV]ペイパービュー
274- marks.put("17", 5); // [字]文字多重放送
275- marks.put("12", 6); // [二]二か国語放送
276- marks.put("11", 7); // [多]音声多重放送
277- marks.put("52", 8); // [吹]吹き替え
278- marks.put("45", 9); // [デ]データ放送
279- marks.put("49", 10); // [生]生放送
280- marks.put("20", 11); // - ノースクランブル
281-
282- // 番組枠の開始位置を決定する
283- Matcher ma = Pattern.compile("<th rowspan=\"60\" class=\"txt02\"[\\s\\S]*?>\\s*(\\d+)\\s*</th>").matcher(src);
284- if ( ! ma.find() ) {
285- return;
286- }
287- int curHour = Integer.valueOf(ma.group(1));
288- if ( CommonUtils.isLateNight(curHour) ) {
289- curHour += 24;
290- }
291-
292- ma = Pattern.compile("<td\\s+rowspan=\"(\\d+?)\"\\s+valign=\"top\"\\s+(class=\"frame\"\\s+)?bgcolor=\"#(.*?)\">([\\s\\S]+?)</table>\\s*?</td>").matcher(src);
293- while (ma.find()) {
294- //
295- ProgDetailList pdl = new ProgDetailList();
296-
297- int hh = 0;
298- int mm = 0;
299-
300- int plen = pdl.length = Integer.valueOf(ma.group(1));
301-
302- String bgcolor = ma.group(3);
303-
304- if ( ma.group(4).indexOf("番組データがありません。") != -1 ) {
305- // 詳細がないよ
306- pdl.title = "番組情報がありません";
307- }
308- else {
309- Matcher mb = Pattern.compile("<div class=\"program_text_1\">\\s*(\\d+):(\\d+)\\s*</div>").matcher(ma.group(4));
310- if ( ! mb.find()) {
311- continue;
312- }
313-
314- // 開始・終了時刻
315- {
316- hh = Integer.valueOf(mb.group(1));
317- mm = Integer.valueOf(mb.group(2));
318- pdl.start = CommonUtils.getTime(hh, mm);
319-
320- int nn = mm + pdl.length;
321- mm = nn % 60;
322- hh = (hh + (nn-mm)/60) % 24;
323- pdl.end = CommonUtils.getTime(hh, mm);
324- }
325-
326- mb = Pattern.compile("javascript:popup\\('(.+?)'\\);return false;\">([\\s\\S]*?)</A>").matcher(ma.group(4));
327- if ( ! mb.find()) {
328- continue;
329- }
330-
331- // リンク
332- pdl.link = "http://www.tvguide.or.jp/"+mb.group(1);
333-
334- // タイトル
335- pdl.title = mb.group(2).replaceAll("<br>", "");
336-
337- // ジャンル
338- {
339- if (genres.containsKey(bgcolor)) {
340- pdl.genre = genres.get(bgcolor);
341- }
342- else {
343- System.err.println("unexpected genre code: "+bgcolor);
344- pdl.genre = ProgGenre.NOGENRE;
345- }
346- }
347-
348- mb = Pattern.compile("<div class=\"program_text_3\">(.*?)</div>").matcher(ma.group(4));
349- if ( ! mb.find()) {
350- continue;
351- }
352-
353- // 詳細
354- pdl.detail = mb.group(1).replaceAll("<br>", "\n").trim();
355-
356- // 各種マーク
357- mb = Pattern.compile("/image/icon/(\\d+?)\\.gif").matcher(ma.group(4));
358- while (mb.find()) {
359- if (marks.containsKey(mb.group(1))) {
360- switch (marks.get(mb.group(1))) {
361- case 0:
362- pdl.flag = ProgFlags.NEW;
363- break;
364- case 1:
365- pdl.flag = ProgFlags.LAST;
366- break;
367- case 2:
368- pdl.addOption(ProgOption.REPEAT);
369- break;
370- case 3:
371- pdl.addOption(ProgOption.FIRST);
372- break;
373- case 4:
374- pdl.addOption(ProgOption.PV);
375- break;
376- case 5:
377- pdl.addOption(ProgOption.SUBTITLE);
378- break;
379- case 6:
380- pdl.addOption(ProgOption.BILINGUAL);
381- break;
382- case 7:
383- pdl.addOption(ProgOption.MULTIVOICE);
384- break;
385- case 8:
386- pdl.addOption(ProgOption.STANDIN);
387- break;
388- case 9:
389- pdl.addOption(ProgOption.DATA);
390- break;
391- case 10:
392- pdl.addOption(ProgOption.LIVE);
393- break;
394- case 11:
395- pdl.noscrumble = ProgScrumble.NOSCRUMBLE;
396- break;
397- }
398- }
399- }
400-
401- // タイトルから各種フラグを分離する
402- doSplitFlags(pdl, nf);
403-
404- // サブタイトル分離
405- doSplitSubtitle(pdl);
406- }
407-
408- // 挿入位置
409- int col = -1;
410- int rowMin = 9999;
411- for ( int i=0; i<newplist.size(); i++ ) {
412- ProgList pl = newplist.get(i);
413- if ( ! (pl.Area.equals(areacode) && pl.SubArea.equals(page)) ) {
414- continue;
415- }
416- if (pl.pdate.get(wdaycol).row < rowMin) {
417- col = i;
418- rowMin = pl.pdate.get(wdaycol).row;
419- }
420- }
421- if (col < 0) {
422- continue;
423- }
424-
425- // 挿入…
426- ProgDateList pcl = newplist.get(col).pdate.get(wdaycol);
427-
428- // 1つめの番組は状態によって修正が必要
429- if ( pcl.pdetail.size() == 0 && curHour != getTimeBarStart() ) {
430- if ( pdl.start.length() == 0 ) {
431- // 番組情報がない、は伸ばすだけでよい
432- pdl.length += (curHour-getTimeBarStart())*60;
433- }
434- else {
435- // なにかの番組情報
436- if ( curHour >= 24 ) {
437- if ( CommonUtils.isLateNight(hh) ) {
438- hh += 24;
439- }
440- }
441- int ttop = getTimeBarStart() * 60;
442- int tcur = curHour*60;
443- int tstart = hh*60+mm;
444- if ( tstart <= ttop ) {
445- // 日をまたぐ番組()
446- pdl.length += (tcur-ttop); // 先頭時刻~現在時刻までのスペース分上に伸ばす
447- }
448- else {
449- // 直前までの情報がない番組
450- {
451- // ダミー挿入
452- ProgDetailList NullPdl = new ProgDetailList();
453- NullPdl.title = "番組情報がありません";
454- NullPdl.length = (tstart-ttop); // 先頭時刻~開始時刻までのスペースを確保
455- pcl.pdetail.add(NullPdl);
456- }
457- pdl.length += (tcur-tstart); // 開始時刻~現在時刻までのスペース分上に伸ばす
458- }
459- }
460- }
461-
462- // 挿入
463- pcl.pdetail.add(pdl);
464- pcl.row += plen;
465- }
466- }
467-
468-
469-
470- /*******************************************************************************
471- * 地域情報を取得する
472- ******************************************************************************/
473-
474- //
475- @Override
476- public String getDefaultArea() {return "東京";}
477-
478- //
479- public void loadAreaCode(){
480-
481- // 設定ファイルが存在していればファイルから
482- File f = new File(getAreaSelectedFile());
483- if (f.exists() == true) {
484- @SuppressWarnings("unchecked")
485- ArrayList<AreaCode> tmp = (ArrayList<AreaCode>) CommonUtils.readXML(getAreaSelectedFile());
486- if ( tmp != null ) {
487-
488- aclist = tmp;
489-
490- // 後方互換
491- for ( AreaCode ac : aclist ) {
492- String[] aid = ac.getCode().split(",",2);
493- ac.setCode(aid[0]);
494- }
495-
496- return;
497- }
498- else {
499- System.err.println(ERRID+"地域リストの読み込みに失敗しました: "+getAreaSelectedFile());
500- }
501- }
502-
503- // 地域一覧の作成
504- ArrayList<AreaCode> newaclist = new ArrayList<AreaCode>();
505-
506- // 存在していなければWeb上から
507- String uri = "http://www.tvguide.or.jp/TF1101LS.php";
508- String response = webToBuffer(uri,thisEncoding,true);
509- if ( response == null ) {
510- System.out.println(ERRID+"地域情報の取得に失敗しました: "+uri);
511- return;
512- }
513-
514- Matcher ma = Pattern.compile("<select name=\"area\"([\\s\\S]+?)</select>").matcher(response);
515- if ( ma.find() ) {
516- Matcher mb = Pattern.compile("&regionId=(.+?)\" (selected)?>(.+?)</option>").matcher(ma.group(1));
517- while (mb.find()) {
518- AreaCode ac = new AreaCode();
519- ac.setArea(mb.group(3));
520- ac.setCode(mb.group(1));
521- newaclist.add(ac);
522- }
523- }
524-
525- if ( newaclist.size() == 0 ) {
526- System.err.println(ERRID+"地域一覧の取得結果が0件だったため情報を更新しません");
527- return;
528- }
529-
530- {
531- {
532- AreaCode ac = new AreaCode();
533- ac.setArea("全国");
534- ac.setCode(allCode);
535- newaclist.add(0,ac);
536- }
537- {
538- AreaCode ac = new AreaCode();
539- ac.setArea("BS");
540- ac.setCode(bsCode);
541- newaclist.add(ac);
542- }
543- }
544-
545- aclist = newaclist;
546- saveAreaCode();
547- }
548-
549-
550- /*******************************************************************************
551- * 放送局情報を取得する
552- ******************************************************************************/
553-
554- // 設定ファイルがなければWebから取得
555- public void loadCenter(String code, boolean force) {
556-
557- if ( code == null ) {
558- System.out.println(ERRID+"地域コードがnullです.");
559- return;
560- }
561-
562- String centerListFile = getCenterListFile(getTVProgramId(), code);
563-
564- if (force) {
565- File f = new File(centerListFile);
566- f.delete();
567- }
568-
569- File f = new File(centerListFile);
570- if (f.exists() == true) {
571- @SuppressWarnings("unchecked")
572- ArrayList<Center> tmp = (ArrayList<Center>) CommonUtils.readXML(centerListFile);
573- if ( tmp != null ) {
574-
575- crlist = tmp;
576-
577- // 放送局名変換
578- attachChFilters();
579-
580- System.out.println(MSGID+"放送局リストを読み込みました: "+centerListFile);
581- return;
582- }
583- else {
584- System.out.println(MSGID+"放送局リストの読み込みに失敗しました: "+centerListFile);
585- }
586- }
587-
588- // 放送局をつくるよ
589- ArrayList<Center> newcrlist = new ArrayList<Center>();
590-
591- // 地上派・UHFは地域別に扱う
592-
593- int cntMax = ((code.equals(allCode))?(aclist.size()-2):(1)) + 1;
594- int cnt = 1;
595- for (AreaCode ac : aclist) {
596- if (ac.getCode().equals(bsCode)) {
597- continue;
598- }
599- else if (code.equals(allCode) && ac.getCode().equals(allCode)) {
600- continue;
601- }
602- else if ( ! code.equals(allCode) && ! ac.getCode().equals(code)) {
603- continue;
604- }
605-
606- // 地上波
607- String url = "http://www.tvguide.or.jp/TF1101LS.php?regionId="+ac.getCode()+"&mediaId=1";
608- if ( _loadCenter(newcrlist, ac.getCode(), url) ) {
609- reportProgress(MSGID+"放送局情報を取得しました: ("+cnt+"/"+cntMax+") "+url);
610- }
611- cnt++;
612- }
613-
614- // BS1・BS2は共通にする
615-
616- {
617- // BSデジタル
618- String url = "http://www.tvguide.or.jp/TF1101LS.php?mediaId=2";
619- if ( _loadCenter(newcrlist, bsCode, url) ) {
620- reportProgress(MSGID+"放送局情報を取得しました: ("+cnt+"/"+cntMax+") "+url);
621- }
622- cnt++;
623- }
624-
625- if ( newcrlist.size() == 0 ) {
626- System.err.println(ERRID+"放送局情報の取得結果が0件だったため情報を更新しません");
627- return;
628- }
629-
630- crlist = newcrlist;
631- attachChFilters(); // 放送局名変換
632- saveCenter();
633- }
634-
635- private boolean _loadCenter(ArrayList<Center> newcrlist, String code, String uri) {
636-
637- String response = webToBuffer(uri,null,null,null,thisEncoding,true);
638- if ( response == null ) {
639- System.out.println(ERRID+"放送局情報の取得に失敗しました: "+uri);
640- return false;
641- }
642-
643- // 局名リストに追加する
644-
645- Matcher ma = Pattern.compile("(<select name=\"ch\"[\\s\\S]+?</select>)").matcher(response);
646- if ( ma.find() ) {
647- Matcher mb = Pattern.compile("&stationId=(.+?)&page=(.+?)\" (selected)?>([\\s\\S]+?)</option>").matcher(ma.group(1));
648- while ( mb.find() ) {
649- String centerName = CommonUtils.unUniEscape(mb.group(4));
650- String centerId = mb.group(1);
651- String page = mb.group(2);
652-
653- // NHK総合・NHK教育
654- centerName = centerName.replaceFirst("^NHK総合", "NHK総合");
655- centerName = centerName.replaceFirst("^NHK Eテレ", "NHK Eテレ");
656- if ( ! code.startsWith(bsCode)) {
657- if (centerName.startsWith("NHK")) {
658- centerName = centerName.replaceFirst("・.*$", "");
659- centerName = centerName+"・"+getArea(code);
660- }
661- }
662- else {
663- if (centerName.equals("放送大学")) {
664- centerName = "放送大学BS1";
665- }
666- else if (centerName.equals("放送大学2")) {
667- centerName = "放送大学BS2";
668- }
669- else if (centerName.equals("放送大学3")) {
670- centerName = "放送大学BS3";
671- }
672- }
673-
674- Center cr = new Center();
675- cr.setAreaCode(code);
676- cr.setCenterOrig(centerName);
677- cr.setLink(centerId);
678- cr.setType(page);
679- cr.setEnabled(true);
680- newcrlist.add(cr);
681- }
682- }
683-
684- return true;
685- }
686-
687-}
Show on old repository browser