タイニー番組ナビゲータ本体
Révision | 339befc2961ed8da020b08a0e8b30a0ec9c68ab2 (tree) |
---|---|
l'heure | 2022-05-08 18:48:13 |
Auteur | Masahiko Kimura <mkimura@u01....> |
Commiter | Masahiko Kimura |
Ver.1.13.6 (2022/5/8)
1. [新聞形式]予約バーのツールチップで該当の時間帯の予約内容を表示する
2. [新聞形式]放送局別1週おき表示に対応する(ヘッダーの右クリックメニューで選択)
3. [しょぼかる]過去日に遡って番組情報を取得できるようにする(最大7日)
(env.txtでsyobocalPastDaysに日数を指定する)
4. [新聞形式][タイトル一覧][タイトルダイアログ]3.で取得したしょぼかるの番組情報を利用する
@@ -13,6 +13,8 @@ import java.awt.Graphics2D; | ||
13 | 13 | import java.awt.Point; |
14 | 14 | import java.awt.Rectangle; |
15 | 15 | import java.awt.Robot; |
16 | +import java.awt.event.ActionEvent; | |
17 | +import java.awt.event.ActionListener; | |
16 | 18 | import java.awt.event.ComponentAdapter; |
17 | 19 | import java.awt.event.ComponentEvent; |
18 | 20 | import java.awt.event.ComponentListener; |
@@ -37,7 +39,9 @@ import java.util.GregorianCalendar; | ||
37 | 39 | import javax.swing.JComponent; |
38 | 40 | import javax.swing.JLabel; |
39 | 41 | import javax.swing.JLayeredPane; |
42 | +import javax.swing.JMenuItem; | |
40 | 43 | import javax.swing.JPanel; |
44 | +import javax.swing.JPopupMenu; | |
41 | 45 | import javax.swing.JScrollPane; |
42 | 46 | import javax.swing.JSplitPane; |
43 | 47 | import javax.swing.JTree; |
@@ -57,6 +61,7 @@ import javax.swing.tree.TreeNode; | ||
57 | 61 | import javax.swing.tree.TreePath; |
58 | 62 | import javax.swing.tree.TreeSelectionModel; |
59 | 63 | |
64 | +import tainavi.TVProgram.ProgGenre; | |
60 | 65 | import tainavi.TVProgram.ProgType; |
61 | 66 | import tainavi.TVProgramIterator.IterationType; |
62 | 67 | import tainavi.VWMainWindow.MWinTab; |
@@ -287,6 +292,9 @@ public abstract class AbsPaperView extends JPanel implements TickTimerListener,H | ||
287 | 292 | // スクロール関係 |
288 | 293 | private int buttonPressed = 0; |
289 | 294 | |
295 | + // 放送局別表示の日数間隔 | |
296 | + private int byCenterModeDayInterval = 1; | |
297 | + | |
290 | 298 | /* |
291 | 299 | * ページャーのEnable/Disableを更新する |
292 | 300 | */ |
@@ -483,6 +491,7 @@ public abstract class AbsPaperView extends JPanel implements TickTimerListener,H | ||
483 | 491 | */ |
484 | 492 | public void jumpToNow() { |
485 | 493 | if ( nowNode != null ) { |
494 | + this.startDate = CommonUtils.getDate529(0, true); | |
486 | 495 | TreePath tp = new TreePath(nowNode.getPath()); |
487 | 496 | setSelectionPath(null); |
488 | 497 | setSelectionPath(tp); |
@@ -691,6 +700,7 @@ public abstract class AbsPaperView extends JPanel implements TickTimerListener,H | ||
691 | 700 | case PASSED: |
692 | 701 | PassedProgram passed = tvprograms.getPassed(); |
693 | 702 | if ( passed.loadAllCenters(value) ) { |
703 | + attachSyoboPassed(passed); | |
694 | 704 | redrawByDate(value, IterationType.PASSED); |
695 | 705 | } |
696 | 706 | else { |
@@ -1506,6 +1516,7 @@ public abstract class AbsPaperView extends JPanel implements TickTimerListener,H | ||
1506 | 1516 | System.err.println(ERRID+"過去ログの取得に失敗しました: "+date); |
1507 | 1517 | return null; |
1508 | 1518 | } |
1519 | + attachSyoboPassed(passed); | |
1509 | 1520 | |
1510 | 1521 | // 指定した日付のノードがツリーになければ作成する |
1511 | 1522 | addPassedNodeIfNotExist(date); |
@@ -1755,7 +1766,7 @@ public abstract class AbsPaperView extends JPanel implements TickTimerListener,H | ||
1755 | 1766 | |
1756 | 1767 | String today = CommonUtils.getDate529(0, true); |
1757 | 1768 | // 開始日が当日以降であれば現在の表を作成する |
1758 | - if (startDate.compareTo(today) >= 0){ | |
1769 | + if (this.byCenterModeDayInterval == 1 && startDate.compareTo(today) >= 0){ | |
1759 | 1770 | startDate = today; |
1760 | 1771 | redrawByCenterCurrent(center); |
1761 | 1772 | } |
@@ -1849,14 +1860,42 @@ public abstract class AbsPaperView extends JPanel implements TickTimerListener,H | ||
1849 | 1860 | * 放送局別に過去ログから表を作成する |
1850 | 1861 | */ |
1851 | 1862 | private void redrawByCenterPassed(String center){ |
1863 | + // 開始日を調整する | |
1864 | + String today = CommonUtils.getDate529(0, true); | |
1865 | + | |
1866 | + GregorianCalendar ct = CommonUtils.getCalendar(today); | |
1867 | + ct.add(GregorianCalendar.DAY_OF_MONTH, 7-(env.getDatePerPassedPage()-1)*this.byCenterModeDayInterval); | |
1868 | + String dateMax = CommonUtils.getDate(ct); | |
1869 | + | |
1870 | + while (startDate.compareTo(dateMax) > 0){ | |
1871 | + ct = CommonUtils.getCalendar(startDate); | |
1872 | + ct.add(GregorianCalendar.DAY_OF_MONTH, -this.byCenterModeDayInterval); | |
1873 | + startDate = CommonUtils.getDate(ct); | |
1874 | + } | |
1875 | + | |
1852 | 1876 | // 過去ログの取得 |
1853 | 1877 | PassedProgram tvp = tvprograms.getPassed(); |
1854 | 1878 | |
1855 | 1879 | // 開始日以降で指定日数分の番組情報を取得する |
1856 | - ProgList pl = tvp.loadByCenterDates(startDate, env.getDatePerPassedPage(), center); | |
1880 | + ProgList pl = tvp.loadByCenterDates(startDate, env.getDatePerPassedPage(), this.byCenterModeDayInterval, center); | |
1857 | 1881 | if (pl == null) |
1858 | 1882 | return; |
1859 | 1883 | |
1884 | + attachSyoboPassedProgList(pl); | |
1885 | + | |
1886 | + // 未来分の番組情報をマージする | |
1887 | + GregorianCalendar c2 = CommonUtils.getCalendar(startDate); | |
1888 | + for (int n=0; n<env.getDatePerPassedPage(); n++){ | |
1889 | + String date = CommonUtils.getDate(c2); | |
1890 | + if (date.compareTo(today) >= 0){ | |
1891 | + ProgDateList pcl = getProgDateListByCenterAndDate(center, date); | |
1892 | + if (pcl != null) | |
1893 | + pl.pdate.add(pcl); | |
1894 | + } | |
1895 | + | |
1896 | + c2.add(Calendar.DAY_OF_MONTH, this.byCenterModeDayInterval); | |
1897 | + } | |
1898 | + | |
1860 | 1899 | // 日付ヘッダを描画する |
1861 | 1900 | for (int centerid=0; centerid<pl.pdate.size(); centerid++) { |
1862 | 1901 | ProgDateList pcl = pl.pdate.get(centerid); |
@@ -1898,6 +1937,53 @@ public abstract class AbsPaperView extends JPanel implements TickTimerListener,H | ||
1898 | 1937 | } |
1899 | 1938 | |
1900 | 1939 | /** |
1940 | + * 指定された放送局の番組一覧を取得する | |
1941 | + * | |
1942 | + * @param center 対象の放送局 | |
1943 | + * @return 該当の番組一覧 | |
1944 | + */ | |
1945 | + private ProgList getProgListByCenter(String center){ | |
1946 | + for (int a=0; a<tvprograms.size(); a++) { | |
1947 | + // | |
1948 | + TVProgram tvp = tvprograms.get(a); | |
1949 | + // | |
1950 | + if (tvp.getType() != ProgType.PROG) { | |
1951 | + continue; | |
1952 | + } | |
1953 | + // | |
1954 | + for (ProgList pl : tvp.getCenters()) { | |
1955 | + if (pl.enabled == true && pl.Center.equals(center)) { | |
1956 | + return pl; | |
1957 | + } | |
1958 | + } | |
1959 | + } | |
1960 | + | |
1961 | + return null; | |
1962 | + } | |
1963 | + | |
1964 | + /** | |
1965 | + * 指定された放送局の本日の番組一覧を取得する | |
1966 | + * | |
1967 | + * @param center 対象の放送局 | |
1968 | + * @return 該当の番組一覧 | |
1969 | + */ | |
1970 | + private ProgDateList getProgDateListByCenterAndDate(String center, String date){ | |
1971 | + ProgList pl = getProgListByCenter(center); | |
1972 | + if (pl == null) | |
1973 | + return null; | |
1974 | + | |
1975 | + // 日付ヘッダを描画する | |
1976 | + for (int centerid=0; centerid<pl.pdate.size(); centerid++) { | |
1977 | + ProgDateList pcl = pl.pdate.get(centerid); | |
1978 | + | |
1979 | + if (pcl.Date.equals(date)) | |
1980 | + return pcl; | |
1981 | + } | |
1982 | + | |
1983 | + return null; | |
1984 | + } | |
1985 | + | |
1986 | + /** | |
1901 | 1987 | * 予約待機赤枠の描画(個々の枠) |
1902 | 1988 | * @see #updateReserveBorder(String) |
1903 | 1989 | */ |
@@ -1992,7 +2078,7 @@ public abstract class AbsPaperView extends JPanel implements TickTimerListener,H | ||
1992 | 2078 | continue; |
1993 | 2079 | } |
1994 | 2080 | |
1995 | - drawBorder(date,Center,topDateTime,bottomDateTime,tvd.startDateTime,tvd.endDateTime,tvd.length,tuner,env.getPickedColor(),false,q); | |
2081 | + drawBorder(date,Center,topDateTime,bottomDateTime,tvd.startDateTime,tvd.endDateTime,tvd.recmin,tuner,env.getPickedColor(),false,q); | |
1996 | 2082 | } |
1997 | 2083 | } |
1998 | 2084 | } |
@@ -2248,7 +2334,7 @@ public abstract class AbsPaperView extends JPanel implements TickTimerListener,H | ||
2248 | 2334 | // 予約枠を描画する |
2249 | 2335 | for (int j=0; j<starts.size(); j++) { |
2250 | 2336 | if (critDateTime.compareTo(ends.get(j)) <= 0) { |
2251 | - list.mergeResTimeItem("", starts.get(j), ends.get(j)); | |
2337 | + list.mergeResTimeItem("", starts.get(j), ends.get(j), r, recorder); | |
2252 | 2338 | } |
2253 | 2339 | } |
2254 | 2340 | } |
@@ -2312,6 +2398,7 @@ public abstract class AbsPaperView extends JPanel implements TickTimerListener,H | ||
2312 | 2398 | jLayeredPane_space_side_view.add(rb); |
2313 | 2399 | |
2314 | 2400 | rb.setVBounds(bounds.getTimebarColumnWidth(), row, length); |
2401 | + rb.setToolTipText("<html><table>" + item.getTooltip() + "</table></html>"); | |
2315 | 2402 | rb.setVisible(true); |
2316 | 2403 | |
2317 | 2404 | resTimeBorders.add(rb); |
@@ -2462,7 +2549,7 @@ public abstract class AbsPaperView extends JPanel implements TickTimerListener,H | ||
2462 | 2549 | public void moveToPrevDatePage(){ |
2463 | 2550 | PassedProgram passed = tvprograms.getPassed(); |
2464 | 2551 | |
2465 | - String date = passed.getPrevDate(startDate, env.getDatePerPassedPage()); | |
2552 | + String date = passed.getPrevDate(startDate, env.getDatePerPassedPage()*this.byCenterModeDayInterval); | |
2466 | 2553 | if (date == null) |
2467 | 2554 | return; |
2468 | 2555 |
@@ -2478,7 +2565,7 @@ public abstract class AbsPaperView extends JPanel implements TickTimerListener,H | ||
2478 | 2565 | public boolean isPrevDatePageEnabled(){ |
2479 | 2566 | PassedProgram passed = tvprograms.getPassed(); |
2480 | 2567 | |
2481 | - String date = passed.getPrevDate(startDate, env.getDatePerPassedPage()); | |
2568 | + String date = passed.getPrevDate(startDate, env.getDatePerPassedPage()*this.byCenterModeDayInterval); | |
2482 | 2569 | |
2483 | 2570 | return date != null; |
2484 | 2571 | } |
@@ -2492,7 +2579,7 @@ public abstract class AbsPaperView extends JPanel implements TickTimerListener,H | ||
2492 | 2579 | |
2493 | 2580 | PassedProgram passed = tvprograms.getPassed(); |
2494 | 2581 | |
2495 | - String date = passed.getNextDate(startDate, env.getDatePerPassedPage()); | |
2582 | + String date = passed.getNextDate(startDate, env.getDatePerPassedPage()*this.byCenterModeDayInterval); | |
2496 | 2583 | if (date == null) |
2497 | 2584 | date = CommonUtils.getDate529(0, true); |
2498 | 2585 |
@@ -2507,8 +2594,19 @@ public abstract class AbsPaperView extends JPanel implements TickTimerListener,H | ||
2507 | 2594 | */ |
2508 | 2595 | public boolean isNextDatePageEnabled(){ |
2509 | 2596 | String today = CommonUtils.getDate529(0, true); |
2597 | + if (this.byCenterModeDayInterval == 1){ | |
2598 | + return (startDate.compareTo(today) < 0); | |
2599 | + } | |
2600 | + | |
2601 | + GregorianCalendar ct = CommonUtils.getCalendar(today); | |
2602 | + ct.add(GregorianCalendar.DAY_OF_MONTH, 7); | |
2603 | + String dateMax = CommonUtils.getDate(ct); | |
2604 | + | |
2605 | + ct = CommonUtils.getCalendar(startDate); | |
2606 | + ct.add(GregorianCalendar.DAY_OF_MONTH, env.getDatePerPassedPage()*this.byCenterModeDayInterval); | |
2607 | + String date = CommonUtils.getDate(ct); | |
2510 | 2608 | |
2511 | - return startDate.compareTo(today) < 0; | |
2609 | + return (date.compareTo(dateMax) <= 0); | |
2512 | 2610 | } |
2513 | 2611 | |
2514 | 2612 | /* |
@@ -2522,6 +2620,68 @@ public abstract class AbsPaperView extends JPanel implements TickTimerListener,H | ||
2522 | 2620 | return path.getPathComponent(1) == centerNode; |
2523 | 2621 | } |
2524 | 2622 | |
2623 | + /** | |
2624 | + * しょぼかるの番組情報を過去番組表に反映する | |
2625 | + * | |
2626 | + * @param passed 対象の過去番組表 | |
2627 | + */ | |
2628 | + private void attachSyoboPassed(PassedProgram passed) { | |
2629 | + for ( ProgList tvpl : passed.getCenters() ) { | |
2630 | + attachSyoboPassedProgList(tvpl); | |
2631 | + } | |
2632 | + } | |
2633 | + | |
2634 | + /** | |
2635 | + * しょぼかるの番組情報を放送局別過去番組表に反映する | |
2636 | + * | |
2637 | + * @param tvpl 対象の過去番組表 | |
2638 | + */ | |
2639 | + private void attachSyoboPassedProgList(ProgList tvpl) { | |
2640 | + TVProgram syobo = tvprograms.getSyobo(); | |
2641 | + if (syobo == null) { | |
2642 | + return; | |
2643 | + } | |
2644 | + | |
2645 | + if ( ! tvpl.enabled) { | |
2646 | + return; | |
2647 | + } | |
2648 | + | |
2649 | + for ( ProgList svpl : syobo.getCenters() ) { | |
2650 | + if ( ! tvpl.Center.equals(svpl.Center)) { | |
2651 | + continue; | |
2652 | + } | |
2653 | + for ( ProgDateList tvc : tvpl.pdate ) { | |
2654 | + ProgDateList mSvc = null; | |
2655 | + for ( ProgDateList svc : svpl.pdate ) { | |
2656 | + if (tvc.Date.equals(svc.Date) ) { | |
2657 | + mSvc = svc; | |
2658 | + break; | |
2659 | + } | |
2660 | + } | |
2661 | + if (mSvc == null) | |
2662 | + continue; | |
2663 | + | |
2664 | + // しょぼかる側に該当する日付があるのでマッチング。アニメと映画と音楽 | |
2665 | + for ( ProgDetailList tvd : tvc.pdetail ) { | |
2666 | + if ( ! tvd.isEqualsGenre(ProgGenre.ANIME, null) && | |
2667 | + ! tvd.isEqualsGenre(ProgGenre.MOVIE, null) && | |
2668 | + ! tvd.isEqualsGenre(ProgGenre.MUSIC, null) ) { | |
2669 | + continue; | |
2670 | + } | |
2671 | + | |
2672 | + for ( ProgDetailList svd : mSvc.pdetail ) { | |
2673 | + if ( tvd.start.equals(svd.start) ) { | |
2674 | + tvd.linkSyobo = svd.link; | |
2675 | + break; | |
2676 | + } | |
2677 | + } | |
2678 | + } | |
2679 | + } | |
2680 | + | |
2681 | + break; | |
2682 | + } | |
2683 | + } | |
2684 | + | |
2525 | 2685 | /******************************************************************************* |
2526 | 2686 | * ハンドラ―メソッド |
2527 | 2687 | ******************************************************************************/ |
@@ -3069,12 +3229,17 @@ public abstract class AbsPaperView extends JPanel implements TickTimerListener,H | ||
3069 | 3229 | } |
3070 | 3230 | |
3071 | 3231 | public void mouseClicked(MouseEvent e) { |
3232 | + JTreeLabel.Nodes node = jLabel_tree.getNode(); | |
3233 | + String value = jLabel_tree.getValue(); | |
3234 | + if (node == null || value == null) | |
3235 | + return; | |
3236 | + | |
3237 | + // 右ダブルクリックで局表示に切り替え | |
3238 | + String center = ((JLabel)e.getSource()).getText(); | |
3239 | + | |
3072 | 3240 | if (e.getButton() == MouseEvent.BUTTON1) { |
3073 | 3241 | if (e.getClickCount() == 2) { |
3074 | - JTreeLabel.Nodes node = jLabel_tree.getNode(); | |
3075 | - String value = jLabel_tree.getValue(); | |
3076 | - if (node == null || value == null) | |
3077 | - return; | |
3242 | + byCenterModeDayInterval = 1; | |
3078 | 3243 | |
3079 | 3244 | // 過去ログノードの場合、選択されているノードを開始日とする |
3080 | 3245 | if (node == JTreeLabel.Nodes.PASSED) |
@@ -3082,14 +3247,51 @@ public abstract class AbsPaperView extends JPanel implements TickTimerListener,H | ||
3082 | 3247 | else |
3083 | 3248 | startDate = CommonUtils.getDate529(0, true); |
3084 | 3249 | |
3085 | - // 右ダブルクリックで局表示に切り替え | |
3086 | - String center = ((JLabel)e.getSource()).getText(); | |
3087 | 3250 | StdAppendMessage(MSGID+"一局表示に切り替え:"+center); |
3088 | - //redrawByCenter(center); | |
3089 | 3251 | jLabel_tree.setView(JTreeLabel.Nodes.BCAST, center); |
3090 | 3252 | reselectTree(); |
3091 | 3253 | } |
3092 | 3254 | } |
3255 | + else if (e.getButton() == MouseEvent.BUTTON3){ | |
3256 | + JPopupMenu pop = new JPopupMenu(); | |
3257 | + // ポインタの位置 | |
3258 | + Point p = e.getPoint(); | |
3259 | + | |
3260 | + JMenuItem menuItem = new JMenuItem(String.format("放送局別表示【%s】", center)); | |
3261 | + Font f = menuItem.getFont(); | |
3262 | + menuItem.setFont(f.deriveFont(f.getStyle()|Font.BOLD)); | |
3263 | + menuItem.addActionListener(new ActionListener() { | |
3264 | + public void actionPerformed(ActionEvent e) { | |
3265 | + byCenterModeDayInterval = 1; | |
3266 | + | |
3267 | + // 過去ログノードの場合、選択されているノードを開始日とする | |
3268 | + if (node == JTreeLabel.Nodes.PASSED) | |
3269 | + startDate = value; | |
3270 | + else | |
3271 | + startDate = CommonUtils.getDate529(0, true); | |
3272 | + | |
3273 | + jLabel_tree.setView(JTreeLabel.Nodes.BCAST, center); | |
3274 | + reselectTree(); | |
3275 | + } | |
3276 | + }); | |
3277 | + pop.add(menuItem); | |
3278 | + | |
3279 | + menuItem = new JMenuItem(String.format("放送局別1週おき表示【%s】", center)); | |
3280 | + menuItem.addActionListener(new ActionListener() { | |
3281 | + public void actionPerformed(ActionEvent e) { | |
3282 | + byCenterModeDayInterval = 7; | |
3283 | + | |
3284 | + // 過去ログノードの場合、選択されているノードを開始日とする | |
3285 | + startDate = value; | |
3286 | + | |
3287 | + jLabel_tree.setView(JTreeLabel.Nodes.BCAST, center); | |
3288 | + reselectTree(); | |
3289 | + } | |
3290 | + }); | |
3291 | + pop.add(menuItem); | |
3292 | + | |
3293 | + pop.show((Component)e.getSource(), p.x, p.y); | |
3294 | + } | |
3093 | 3295 | } |
3094 | 3296 | }; |
3095 | 3297 |
@@ -941,7 +941,7 @@ public abstract class AbsReserveListView extends JPanel implements TickTimerList | ||
941 | 941 | ca.add(Calendar.MINUTE, len); |
942 | 942 | String eDTa = CommonUtils.getDateTime(ca); |
943 | 943 | |
944 | - list.mergeResTimeItem(ra.recorder, sDTa, eDTa); | |
944 | + list.mergeResTimeItem(ra.recorder, sDTa, eDTa, null, null); | |
945 | 945 | } |
946 | 946 | } |
947 | 947 |
@@ -155,6 +155,7 @@ abstract class AbsTitleDialog extends JDialog { | ||
155 | 155 | private boolean folderOnly = false; |
156 | 156 | private TitleInfo info = null; |
157 | 157 | private ProgDetailList prog = null; |
158 | + private ProgDetailList progSyobo = null; | |
158 | 159 | private TVProgramList tvprograms = null; |
159 | 160 | |
160 | 161 | private boolean reg = false; |
@@ -216,14 +217,15 @@ abstract class AbsTitleDialog extends JDialog { | ||
216 | 217 | * @param t 編集対象のタイトル情報 |
217 | 218 | * @param tvs フォルダリスト |
218 | 219 | */ |
219 | - public void open(TitleInfo t, ProgDetailList l, String otitle) { | |
220 | + public void open(TitleInfo t, ProgDetailList l, ProgDetailList ls, String otitle) { | |
220 | 221 | info = t; |
221 | 222 | prog = l; |
223 | + progSyobo = ls; | |
222 | 224 | recorder = getSelectedRecorder(); |
223 | 225 | tvsFolder = recorder.getFolderList(); |
224 | 226 | |
225 | 227 | updateTitleLabel(); |
226 | - updateTitleInfo(t, prog, otitle); | |
228 | + updateTitleInfo(t, prog, progSyobo, otitle); | |
227 | 229 | |
228 | 230 | String device_name = "[" + t.getRec_device() + "]"; |
229 | 231 |
@@ -250,7 +252,7 @@ abstract class AbsTitleDialog extends JDialog { | ||
250 | 252 | /* |
251 | 253 | * タイトル情報を更新する |
252 | 254 | */ |
253 | - private void updateTitleInfo(TitleInfo t, ProgDetailList pdl, String titleOld){ | |
255 | + private void updateTitleInfo(TitleInfo t, ProgDetailList pdl, ProgDetailList pdlSyobo, String titleOld){ | |
254 | 256 | String title = t.getTitle(); |
255 | 257 | jTextField_title.setText(title); |
256 | 258 |
@@ -275,12 +277,33 @@ abstract class AbsTitleDialog extends JDialog { | ||
275 | 277 | } |
276 | 278 | } |
277 | 279 | |
280 | + if (pdlSyobo != null){ | |
281 | + String no = getProgramNo(title, pdlSyobo); | |
282 | + String subtitle = getSubtitle(title, pdlSyobo); | |
283 | + String ptitle = getProgramTitle(title); | |
284 | + String ptitleOld = getProgramTitle(titleOld); | |
285 | + | |
286 | + String cand = formatTitleFromOld(ptitleOld, no, subtitle, titleOld); | |
287 | + if (cand != null) | |
288 | + jComboBox_title.addItem(cand); | |
289 | + else{ | |
290 | + cand = formatDefaultTitle(ptitle, no, subtitle); | |
291 | + if (cand != null) | |
292 | + jComboBox_title.addItem(cand); | |
293 | + } | |
294 | + } | |
295 | + | |
278 | 296 | // 番組情報が見つかったら、タイトルと詳細をセットする |
297 | + String prog = ""; | |
279 | 298 | if (pdl != null){ |
280 | - jTextArea_prog.setText(pdl.prefix_mark + pdl.title + pdl.postfix_mark + "\r\n" + pdl.detail); | |
281 | - jTextArea_prog.setCaretPosition(0); | |
299 | + prog = pdl.prefix_mark + pdl.title + pdl.postfix_mark + "\r\n" + pdl.detail; | |
300 | + } | |
301 | + if (pdlSyobo != null){ | |
302 | + prog += "\r\n【しょぼかる】" + pdlSyobo.prefix_mark + pdlSyobo.title + pdlSyobo.postfix_mark + " " + pdlSyobo.detail; | |
282 | 303 | } |
283 | 304 | |
305 | + jTextArea_prog.setText(prog); | |
306 | + jTextArea_prog.setCaretPosition(0); | |
284 | 307 | } |
285 | 308 | |
286 | 309 | /* |
@@ -1130,8 +1130,10 @@ public abstract class AbsTitleListView extends JPanel { | ||
1130 | 1130 | int bes = tvd.endDateTime.compareTo(start); |
1131 | 1131 | |
1132 | 1132 | // 予約情報と時間が重なる場合はその番組情報を返す |
1133 | - if (bse * bes < 0) | |
1133 | + if (bse * bes < 0){ | |
1134 | + attachSyobocalToProgDetailList(t, tvd); | |
1134 | 1135 | return tvd; |
1136 | + } | |
1135 | 1137 | } |
1136 | 1138 | |
1137 | 1139 | break; |
@@ -1143,6 +1145,80 @@ public abstract class AbsTitleListView extends JPanel { | ||
1143 | 1145 | return null; |
1144 | 1146 | } |
1145 | 1147 | |
1148 | + /** | |
1149 | + * 番組情報にしょぼかるの番組詳細リンクをひもづける | |
1150 | + * | |
1151 | + * @param t タイトル情報 | |
1152 | + * @param tvd 番組情報 | |
1153 | + */ | |
1154 | + protected void attachSyobocalToProgDetailList(TitleInfo t, ProgDetailList tvd){ | |
1155 | + // すでに番組詳細リンクがある場合は何もしない | |
1156 | + if ( tvd.linkSyobo != null && !tvd.linkSyobo.isEmpty()) | |
1157 | + return; | |
1158 | + | |
1159 | + ProgDetailList tdl = getSyobocalProgDetailForTitle(t); | |
1160 | + if (tdl != null){ | |
1161 | + // 番組詳細リンクをひもづける | |
1162 | + tvd.linkSyobo = tdl.link; | |
1163 | + } | |
1164 | + } | |
1165 | + | |
1166 | + /* | |
1167 | + * 指定したタイトルと放送局が同じで時間が重なるしょぼかるの番組情報を取得する | |
1168 | + * | |
1169 | + * @param t タイトル情報 | |
1170 | + */ | |
1171 | + protected ProgDetailList getSyobocalProgDetailForTitle(TitleInfo t){ | |
1172 | + // ジャンルで絞り込む | |
1173 | + if ( ! t.containsGenre(ProgGenre.ANIME.toIEPG()) && | |
1174 | + ! t.containsGenre(ProgGenre.MOVIE.toIEPG()) && | |
1175 | + ! t.containsGenre(ProgGenre.MUSIC.toIEPG()) ) | |
1176 | + return null; | |
1177 | + | |
1178 | + TVProgramList tpl = getTVProgramList(); | |
1179 | + TVProgram syobo = tpl.getSyobo(); | |
1180 | + if (syobo == null) | |
1181 | + return null; | |
1182 | + | |
1183 | + // しょぼかるのチャンネル別番組表を取得する | |
1184 | + ProgList mSvpl = null; | |
1185 | + for ( ProgList svpl : syobo.getCenters() ) { | |
1186 | + if ( t.getCh_name().equals(svpl.Center)) { | |
1187 | + mSvpl = svpl; | |
1188 | + break; | |
1189 | + } | |
1190 | + } | |
1191 | + if (mSvpl == null) | |
1192 | + return null; | |
1193 | + | |
1194 | + // しょぼかるの日付別番組表を取得する | |
1195 | + String date = CommonUtils.getDate529(t.getStartDateTime(), true); | |
1196 | + ProgDateList mSvc = null; | |
1197 | + for ( ProgDateList svc : mSvpl.pdate ) { | |
1198 | + if (date.equals(svc.Date) ) { | |
1199 | + mSvc = svc; | |
1200 | + break; | |
1201 | + } | |
1202 | + } | |
1203 | + if (mSvc == null) | |
1204 | + return null; | |
1205 | + | |
1206 | + // しょぼかるの番組情報を取得する | |
1207 | + String time = t.getAhh() + ":" + t.getAmm(); | |
1208 | + ProgDetailList mSvd = null; | |
1209 | + for ( ProgDetailList svd : mSvc.pdetail ) { | |
1210 | + if ( time.equals(svd.start) ){ | |
1211 | + mSvd = svd; | |
1212 | + break; | |
1213 | + } | |
1214 | + } | |
1215 | + if (mSvd == null) | |
1216 | + return null; | |
1217 | + | |
1218 | + return mSvd; | |
1219 | + | |
1220 | + } | |
1221 | + | |
1146 | 1222 | /******************************************************************************* |
1147 | 1223 | * リスナー |
1148 | 1224 | ******************************************************************************/ |
@@ -1029,6 +1029,11 @@ public class Env { | ||
1029 | 1029 | public void setMaxSearchWordNum(int n){ maxSearchWordNum = n; } |
1030 | 1030 | private int maxSearchWordNum = MAX_SEARCH_WORD_NUM; |
1031 | 1031 | |
1032 | + // しょぼかるの過去取得日数(タイトル一覧用) | |
1033 | + public int getSyobocalPastDays(){ return syobocalPastDays; } | |
1034 | + public void setSyobocalPastDays(int n){ syobocalPastDays = n; } | |
1035 | + private int syobocalPastDays = 0; | |
1036 | + | |
1032 | 1037 | /******************************************************************************* |
1033 | 1038 | * 作ったけど使ってないもの |
1034 | 1039 | ******************************************************************************/ |
@@ -131,7 +131,7 @@ public class PassedProgram extends TVProgramUtils implements TVProgram,Cloneable | ||
131 | 131 | /* |
132 | 132 | * 指定した放送局の期間分の番組情報を読み込む |
133 | 133 | */ |
134 | - public ProgList loadByCenterDates(String startDate, int max, String center){ | |
134 | + public ProgList loadByCenterDates(String startDate, int max, int interval, String center){ | |
135 | 135 | ProgList pl = new ProgList(); |
136 | 136 | pl.Center = center; |
137 | 137 | pl.enabled = true; |
@@ -159,7 +159,7 @@ public class PassedProgram extends TVProgramUtils implements TVProgram,Cloneable | ||
159 | 159 | } |
160 | 160 | |
161 | 161 | // 日付を1日ずらす |
162 | - c.add(GregorianCalendar.DAY_OF_MONTH, 1); | |
162 | + c.add(GregorianCalendar.DAY_OF_MONTH, interval); | |
163 | 163 | } |
164 | 164 | |
165 | 165 | return pl; |
@@ -707,7 +707,7 @@ public class PassedProgram extends TVProgramUtils implements TVProgram,Cloneable | ||
707 | 707 | public String getNextDate(String dateArg, int count){ |
708 | 708 | int num = dd.length; |
709 | 709 | |
710 | - for (int n=0; n<num; n++){ | |
710 | + for (int n=0; n<num-1; n++){ | |
711 | 711 | String date = dd[num-1-n]; |
712 | 712 | |
713 | 713 | if (date.compareTo(dateArg) <= 0) |
@@ -416,7 +416,8 @@ public class PickedProgram extends TVProgramUtils implements TVProgram,Cloneable | ||
416 | 416 | } |
417 | 417 | |
418 | 418 | for (ProgDetailList tPdl : pcl.pdetail) { |
419 | - if (tPdl.title.equals(data.title) && tPdl.start.equals(data.start) && tPdl.end.equals(data.end)) { | |
419 | +// if (tPdl.title.equals(data.title) && tPdl.start.equals(data.start) && tPdl.end.equals(data.end)) { | |
420 | + if (tPdl.start.equals(data.start) && tPdl.end.equals(data.end)) { | |
420 | 421 | if (force) { |
421 | 422 | pcl.pdetail.remove(tPdl); |
422 | 423 | } |
@@ -8,27 +8,35 @@ public class ResTimeItem { | ||
8 | 8 | String start; |
9 | 9 | String end; |
10 | 10 | int count; |
11 | + String tooltip; | |
11 | 12 | |
12 | - public ResTimeItem(String r, String s, String e, int c){ | |
13 | + public ResTimeItem(String r, String s, String e, int c, String t){ | |
13 | 14 | this.recorder = r; |
14 | 15 | this.start = s; |
15 | 16 | this.end = e; |
16 | 17 | this.count = c; |
18 | + this.tooltip = t; | |
17 | 19 | } |
18 | 20 | |
19 | - public ResTimeItem(String r, String s, String e){ | |
21 | + public ResTimeItem(String r, String s, String e, String t){ | |
20 | 22 | this.recorder = r; |
21 | 23 | this.start = s; |
22 | 24 | this.end = e; |
23 | 25 | this.count = 1; |
26 | + this.tooltip = t; | |
24 | 27 | } |
25 | 28 | |
26 | 29 | public void setStart(String s){ start = s; } |
27 | 30 | public void setEnd(String e){ end = e; } |
28 | - public void addCount(){ count++; } | |
31 | + public void addCount(String t){ | |
32 | + count++; | |
33 | + tooltip = tooltip + t; | |
34 | + } | |
35 | + public void setTooltip(String t){ tooltip = t; } | |
29 | 36 | |
30 | 37 | public String getRecorder(){ return recorder; } |
31 | 38 | public String getStart(){ return start; } |
32 | 39 | public String getEnd(){ return end; } |
33 | 40 | public int getCount(){ return count; } |
41 | + public String getTooltip(){ return tooltip; } | |
34 | 42 | } |
@@ -25,13 +25,27 @@ public class ResTimeList extends ArrayList<ResTimeItem> { | ||
25 | 25 | /* |
26 | 26 | * ResTimeItemオブジェクト配列に予約時間枠をマージしながら追加する |
27 | 27 | */ |
28 | - public void mergeResTimeItem(String rec, String start, String end){ | |
28 | + public void mergeResTimeItem(String rec, String start, String end, ReserveList rl, HDDRecorder recorder){ | |
29 | 29 | Boolean b = false; |
30 | 30 | |
31 | 31 | // 長さ0の時間枠は無視する |
32 | 32 | if (start.equals(end)) |
33 | 33 | return; |
34 | 34 | |
35 | + StringBuilder sb = new StringBuilder(""); | |
36 | + | |
37 | + sb.append("<TR>"); | |
38 | + sb.append("<TD>" + start.substring(11) + "~" + end.substring(11) + "</TD>"); | |
39 | + if (rl != null){ | |
40 | + sb.append("<TD>" + rl.getCh_name() + "</TD>"); | |
41 | + String color = recorder != null ? recorder.getColor(rl.getTuner()) : "000000"; | |
42 | + sb.append("<TD><STRONG><FONT COLOR=" + color + ">" + rl.getTuner() + "</FONT></STRONG></TD>"); | |
43 | + sb.append("<TD><STRONG><FONT COLOR=BLUE><U>" + rl.getTitle() + "</U></FONT></STRONG></TD>"); | |
44 | + } | |
45 | + sb.append("</TR>"); | |
46 | + | |
47 | + String tooltip = sb.toString(); | |
48 | + | |
35 | 49 | // すでにある予約枠と順に比較する |
36 | 50 | for (ResTimeItem item2 : this){ |
37 | 51 | String start2 = item2.getStart(); |
@@ -60,7 +74,7 @@ public class ResTimeList extends ArrayList<ResTimeItem> { | ||
60 | 74 | // <- a ->|<-- item2 -->| |
61 | 75 | else if (start.compareTo(start2) < 0){ |
62 | 76 | // item2の開始時刻までの枠(a)を再帰呼出しにより追加する |
63 | - mergeResTimeItem(rec, start, start2); | |
77 | + mergeResTimeItem(rec, start, start2, rl, recorder); | |
64 | 78 | |
65 | 79 | // item2の終了時刻より後に終わる場合 |
66 | 80 | // start end |
@@ -68,10 +82,10 @@ public class ResTimeList extends ArrayList<ResTimeItem> { | ||
68 | 82 | // <- a ->|<-- item2 -->|<- b -> |
69 | 83 | if (end.compareTo(end2) >= 0){ |
70 | 84 | // item2のカウントを増やす |
71 | - item2.addCount(); | |
85 | + item2.addCount(tooltip); | |
72 | 86 | |
73 | 87 | // item2の終了時刻後の枠(b)を再帰呼出しにより追加する |
74 | - mergeResTimeItem(rec, end2, end); | |
88 | + mergeResTimeItem(rec, end2, end, rl, recorder); | |
75 | 89 | } |
76 | 90 | // item2の終了時刻より前に終わる場合 |
77 | 91 | // start end |
@@ -79,12 +93,12 @@ public class ResTimeList extends ArrayList<ResTimeItem> { | ||
79 | 93 | // <- a ->|<--- item2 -->| |
80 | 94 | else{ |
81 | 95 | // item2の終了時間までの枠(c)を追加する |
82 | - ResTimeItem itemT = new ResTimeItem(rec, end, end2, item2.getCount()); | |
96 | + ResTimeItem itemT = new ResTimeItem(rec, end, end2, item2.getCount(), item2.getTooltip()); | |
83 | 97 | addResTimeItem(itemT); |
84 | 98 | |
85 | 99 | // item2の時間を短くし、カウントを増やす |
86 | 100 | item2.setEnd(end); |
87 | - item2.addCount(); | |
101 | + item2.addCount(tooltip); | |
88 | 102 | } |
89 | 103 | } |
90 | 104 | // item2のの開始時刻より後に始まる場合 |
@@ -94,7 +108,7 @@ public class ResTimeList extends ArrayList<ResTimeItem> { | ||
94 | 108 | else{ |
95 | 109 | // item2の開始時刻からの枠(d)を追加する |
96 | 110 | if (start.compareTo(start2) > 0){ |
97 | - ResTimeItem itemH = new ResTimeItem(rec, start2, start, item2.getCount()); | |
111 | + ResTimeItem itemH = new ResTimeItem(rec, start2, start, item2.getCount(), item2.getTooltip()); | |
98 | 112 | addResTimeItem(itemH); |
99 | 113 | } |
100 | 114 |
@@ -106,10 +120,10 @@ public class ResTimeList extends ArrayList<ResTimeItem> { | ||
106 | 120 | // item2の開始時刻と長さを変更し、カウントを増やす |
107 | 121 | item2.setStart(start); |
108 | 122 | item2.setEnd(end2); |
109 | - item2.addCount(); | |
123 | + item2.addCount(tooltip); | |
110 | 124 | |
111 | 125 | // item2の終了時刻後の枠(e)を再帰呼出しにより追加する |
112 | - mergeResTimeItem(rec, end2, end); | |
126 | + mergeResTimeItem(rec, end2, end, rl, recorder); | |
113 | 127 | } |
114 | 128 | // item2の予約枠の終了時間より前に終わる場合 |
115 | 129 | // start end |
@@ -117,13 +131,13 @@ public class ResTimeList extends ArrayList<ResTimeItem> { | ||
117 | 131 | // |<----------- item2 ---------->| |
118 | 132 | else{ |
119 | 133 | // item2の終了時刻前の枠(f)を追加する |
120 | - ResTimeItem itemT = new ResTimeItem(rec, end, end2, item2.getCount()); | |
134 | + ResTimeItem itemT = new ResTimeItem(rec, end, end2, item2.getCount(), item2.getTooltip()); | |
121 | 135 | addResTimeItem(itemT); |
122 | 136 | |
123 | 137 | // item2の開始時刻と長さを変更し、カウントを増やす |
124 | 138 | item2.setStart(start); |
125 | 139 | item2.setEnd(end); |
126 | - item2.addCount(); | |
140 | + item2.addCount(tooltip); | |
127 | 141 | } |
128 | 142 | } |
129 | 143 |
@@ -133,9 +147,12 @@ public class ResTimeList extends ArrayList<ResTimeItem> { | ||
133 | 147 | |
134 | 148 | // 処理が完了しなかった場合は単に追加する |
135 | 149 | if (!b){ |
136 | - ResTimeItem item = new ResTimeItem(rec, start, end); | |
150 | + ResTimeItem item = new ResTimeItem(rec, start, end, tooltip); | |
137 | 151 | addResTimeItem(item); |
138 | 152 | } |
153 | + | |
154 | + // 開始時刻の昇順になるように並び替える | |
155 | + this.sort(new ResTimeItemComparator()); | |
139 | 156 | } |
140 | 157 | |
141 | 158 | /* |
@@ -5,7 +5,7 @@ import java.util.regex.Pattern; | ||
5 | 5 | |
6 | 6 | |
7 | 7 | public class VersionInfo { |
8 | - private static final String Version = "タイニー番組ナビゲータ for DBR-T2007 3.22.18β+1.13.5"; | |
8 | + private static final String Version = "タイニー番組ナビゲータ for DBR-T2007 3.22.18β+1.13.6"; | |
9 | 9 | |
10 | 10 | private static final String OSname = System.getProperty("os.name"); |
11 | 11 | private static final String OSvers = System.getProperty("os.version"); |
@@ -1034,6 +1034,7 @@ public class Viewer extends JFrame implements ChangeListener,TickTimerListener,H | ||
1034 | 1034 | HDDRecorder rec = getSelectedRecorder(); |
1035 | 1035 | TitleInfo o = rec.getTitleInfo(ttlId); |
1036 | 1036 | ProgDetailList prog = getProgDetailForTitle(o); |
1037 | + ProgDetailList progSyobo = getSyobocalProgDetailForTitle(o); | |
1037 | 1038 | |
1038 | 1039 | String ttlname = o.getTitle(); |
1039 | 1040 |
@@ -1043,7 +1044,7 @@ public class Viewer extends JFrame implements ChangeListener,TickTimerListener,H | ||
1043 | 1044 | rec.GetRdTitleDetail(o); |
1044 | 1045 | |
1045 | 1046 | VWTitleDialog dlg = new VWTitleDialog(false); |
1046 | - dlg.open(o.clone(), prog, otitle); | |
1047 | + dlg.open(o.clone(), prog, progSyobo, otitle); | |
1047 | 1048 | CommonSwingUtils.setLocationCenter(Viewer.this, dlg); |
1048 | 1049 | dlg.setVisible(true); |
1049 | 1050 |
@@ -1183,7 +1184,7 @@ public class Viewer extends JFrame implements ChangeListener,TickTimerListener,H | ||
1183 | 1184 | rec.GetRdTitleDetail(o0); |
1184 | 1185 | |
1185 | 1186 | VWTitleDialog dlg = new VWTitleDialog(true); |
1186 | - dlg.open(o0.clone(), null, null); | |
1187 | + dlg.open(o0.clone(), null, null, null); | |
1187 | 1188 | CommonSwingUtils.setLocationCenter(Viewer.this, dlg); |
1188 | 1189 | dlg.setVisible(true); |
1189 | 1190 |
@@ -5193,6 +5194,9 @@ public class Viewer extends JFrame implements ChangeListener,TickTimerListener,H | ||
5193 | 5194 | // 祝日情報 |
5194 | 5195 | if (env.getUseHolidayCSV()) |
5195 | 5196 | HolidayInfo.Load(env.getHolidayFetchURL(), env.getHolidayFetchInterval()); |
5197 | + | |
5198 | + // しょぼかるの過去日数 | |
5199 | + Syobocal.setPastDays(env.getSyobocalPastDays()); | |
5196 | 5200 | } |
5197 | 5201 | |
5198 | 5202 | // 二重起動チェック |
@@ -1,529 +1,567 @@ | ||
1 | -package tainavi.plugintv; | |
2 | - | |
3 | -import java.io.File; | |
4 | -import java.util.ArrayList; | |
5 | -import java.util.Calendar; | |
6 | -import java.util.GregorianCalendar; | |
7 | -import java.util.regex.Matcher; | |
8 | -import java.util.regex.Pattern; | |
9 | - | |
10 | -import tainavi.Center; | |
11 | -import tainavi.CommonUtils; | |
12 | -import tainavi.ContentIdSyobo; | |
13 | -import tainavi.ProgDateList; | |
14 | -import tainavi.ProgDetailList; | |
15 | -import tainavi.ProgList; | |
16 | -import tainavi.TVProgram; | |
17 | -import tainavi.TVProgramUtils; | |
18 | -import tainavi.TraceProgram; | |
19 | - | |
20 | -/** | |
21 | - * しょぼかるから番組表と放送局リストを取得する。プラグインではないよ。 | |
22 | - */ | |
23 | -public class Syobocal extends TVProgramUtils implements TVProgram,Cloneable { | |
24 | - | |
25 | - private final String thisEncoding = "UTF-8"; | |
26 | - | |
27 | - public void setDebug(boolean b) { debug = b; } | |
28 | - | |
29 | - private boolean debug = false; | |
30 | - | |
31 | - private boolean rss2 = false; | |
32 | - | |
33 | - /* 必須コード - ここから */ | |
34 | - | |
35 | - // 種族の特性 | |
36 | - private static final String tvProgId = "Syobocal"; | |
37 | - | |
38 | - //private final String progCacheFile = getProgDir()+File.separator+"syobocal.xml"; | |
39 | - private final String centerFile = "env"+File.separator+"center."+getTVProgramId()+".xml"; | |
40 | - | |
41 | - private final String MSGID = "[しょぼかる] "; | |
42 | - private final String ERRID = "[ERROR]"+MSGID; | |
43 | - private final String DBGID = "[DEBUG]"+MSGID; | |
44 | - | |
45 | - @Override | |
46 | - public String getTVProgramId() { return tvProgId; } | |
47 | - | |
48 | - @Override | |
49 | - public boolean isAreaSelectSupported() { return false; } | |
50 | - | |
51 | - @Override | |
52 | - public ProgType getType() { return ProgType.SYOBO; } | |
53 | - public ProgSubtype getSubtype() { return ProgSubtype.NONE; } | |
54 | - | |
55 | - @Override | |
56 | - public Syobocal clone() { | |
57 | - return (Syobocal) super.clone(); | |
58 | - } | |
59 | - | |
60 | - // 個体の特性 | |
61 | - | |
62 | - // | |
63 | - @Override | |
64 | - public int getTimeBarStart() {return 5;} | |
65 | - | |
66 | - private int getDogDays() { return ((getExpandTo8())?(8):(7)); } | |
67 | - | |
68 | - // | |
69 | - @Override | |
70 | - public boolean loadProgram(String areaCode, boolean force) { | |
71 | - | |
72 | - String progCacheFile = null; | |
73 | - if ( rss2 ) { | |
74 | - progCacheFile = getProgDir()+File.separator+"syobocal.xml"; | |
75 | - } | |
76 | - else { | |
77 | - progCacheFile = getProgDir()+File.separator+"syobocal.rss"; | |
78 | - } | |
79 | - | |
80 | - // 新しい番組データの入れ物を作る | |
81 | - ArrayList<ProgList> newplist = new ArrayList<ProgList>(); | |
82 | - | |
83 | - int cnt = 0; | |
84 | - | |
85 | - try { | |
86 | - String response = null; | |
87 | - | |
88 | - String cirtDateTimeYMD = CommonUtils.getCritDateTime().replaceAll("[/: ]", ""); | |
89 | - | |
90 | - File f = new File(progCacheFile); | |
91 | - if (force == true || | |
92 | - (f.exists() == true && isCacheOld(progCacheFile) == true) || | |
93 | - (f.exists() == false && isCacheOld(null) == true)) { | |
94 | - | |
95 | - String url = null; | |
96 | - if ( rss2 ) { | |
97 | - url = "http://cal.syoboi.jp/rss2.php?start="+cirtDateTimeYMD+"&days="+getDogDays()+"&titlefmt=$(Flag)^^^$(FlagW)^^^$(Cat)^^^$(ChName)^^^$(EdTime)^^^$(Title)^^^$(SubTitleB)"; | |
98 | - } | |
99 | - else { | |
100 | - url = "http://cal.syoboi.jp/rss.php?start=today&count=1500&days=8&days="+getDogDays()+"&titlefmt=$(Flag)^^^$(FlagW)^^^$(Cat)^^^$(ChName)^^^$(EdTime)^^^$(Title)^^^$(SubTitleB)"; | |
101 | - } | |
102 | - response = webToBuffer(url, thisEncoding, true); | |
103 | - if ( response == null ) { | |
104 | - reportProgress(ERRID+"RSS2.0(オンライン)の取得に失敗しました: "+url); | |
105 | - return false; | |
106 | - } | |
107 | - | |
108 | - reportProgress(MSGID+"RSS2.0(オンライン)を取得しました: "+url); | |
109 | - CommonUtils.write2file(progCacheFile, response); | |
110 | - } | |
111 | - else if (f.exists()) { | |
112 | - // | |
113 | - response = CommonUtils.read4file(progCacheFile, true); | |
114 | - if ( response == null ) { | |
115 | - reportProgress(ERRID+"RSS2.0(キャッシュ)の取得に失敗しました: "+progCacheFile); | |
116 | - return false; | |
117 | - } | |
118 | - reportProgress(MSGID+"RSS2.0(キャッシュ)を取得しました: "+progCacheFile); | |
119 | - } | |
120 | - else { | |
121 | - reportProgress(ERRID+"RSS2.0(キャッシュ)がみつかりません: "+progCacheFile); | |
122 | - return false; | |
123 | - } | |
124 | - | |
125 | - // 情報解析 | |
126 | - | |
127 | - Matcher ma = Pattern.compile("<item(.+?)</item>",Pattern.DOTALL).matcher(response); | |
128 | - while (ma.find()) { | |
129 | - | |
130 | - // 入れ物 | |
131 | - ProgDetailList pDetail = new ProgDetailList(); | |
132 | - | |
133 | - // <title>金曜ロードショー ヱヴァンゲリヲン新劇場版:破 TV版</title> | |
134 | - Matcher mb = Pattern.compile("<title>(.+?)</title>",Pattern.DOTALL).matcher(ma.group(1)); | |
135 | - if ( ! mb.find()) { | |
136 | - continue; | |
137 | - } | |
138 | - | |
139 | - String[] t = mb.group(1).split("\\^\\^\\^",7); | |
140 | - | |
141 | - if (t.length < 7) { | |
142 | - System.err.println(ERRID+"書式が不正: "+mb.group(1)); | |
143 | - } | |
144 | - | |
145 | - pDetail.title = CommonUtils.unEscape(t[5]); | |
146 | - | |
147 | - pDetail.detail = CommonUtils.unEscape(t[6]); | |
148 | - if ( pDetail.detail.matches("^#1$|^#1[^0-9].*$") ) { | |
149 | - // まあなにもしなくていいか | |
150 | - } | |
151 | - | |
152 | - if (t[0] != null && t[0].length() > 0) { | |
153 | - int flag = Integer.valueOf(t[0]); | |
154 | - if (flag != 0) { | |
155 | - if ((flag & 0x01) != 0x00) { | |
156 | - pDetail.addOption(ProgOption.SPECIAL); | |
157 | - flag ^= 0x01; | |
158 | - } | |
159 | - if ((flag & 0x02) != 0x00) { | |
160 | - pDetail.flag = ProgFlags.NEW; | |
161 | - flag ^= 0x02; | |
162 | - } | |
163 | - if ((flag & 0x04) != 0x00) { | |
164 | - pDetail.flag = ProgFlags.LAST; | |
165 | - flag ^= 0x04; | |
166 | - } | |
167 | - if ((flag & 0x08) != 0x00) { | |
168 | - pDetail.addOption(ProgOption.REPEAT); | |
169 | - flag ^= 0x08; | |
170 | - } | |
171 | - if (flag != 0) { | |
172 | - System.out.println(DBGID+"未対応のマーク: "+flag); | |
173 | - } | |
174 | - } | |
175 | - } | |
176 | - if (t[1] != null && t[1].length() > 0) { | |
177 | - int flagw = Integer.valueOf(t[1]); | |
178 | - if (flagw != 0) { | |
179 | - if ((flagw & 0x01) != 0x00) { | |
180 | - if (pDetail.flag != ProgFlags.NEW && ! pDetail.isOptionEnabled(ProgOption.SPECIAL)) { | |
181 | - pDetail.addOption(ProgOption.MOVED); // 新番組や特番なら(移)はいらんやろ | |
182 | - } | |
183 | - flagw ^= 0x01; | |
184 | - } | |
185 | - if (flagw != 0) { | |
186 | - System.out.println(DBGID+"未対応の警告フラグ: "+flagw); | |
187 | - } | |
188 | - } | |
189 | - } | |
190 | - // <tv:genre>アニメ(終了/再放送)</tv:genre> | |
191 | - pDetail.genre = null; | |
192 | - pDetail.subgenre = null; | |
193 | - pDetail.genrelist = new ArrayList<TVProgram.ProgGenre>(); | |
194 | - pDetail.subgenrelist = new ArrayList<TVProgram.ProgSubgenre>(); | |
195 | - boolean anime_etc = true; | |
196 | - | |
197 | - if (t[2] != null && t[2].length() > 0) { | |
198 | - // ジャンル | |
199 | - if (t[2].equals("1") || t[2].equals("10") || t[2].equals("5")) { | |
200 | - // 1:アニメ 10:アニメ(終了/再放送) 5:アニメ関連 | |
201 | - } | |
202 | - else if (t[2].equals("7")) { | |
203 | - // 7:OVA | |
204 | - pDetail.genre = ProgGenre.ANIME; | |
205 | - pDetail.subgenre = ProgSubgenre.ANIME_KOKUNAI; | |
206 | - pDetail.genrelist.add(ProgGenre.ANIME); | |
207 | - pDetail.subgenrelist.add(ProgSubgenre.ANIME_KOKUNAI); | |
208 | - anime_etc = false; | |
209 | - } | |
210 | - else if (t[2].equals("4")) { | |
211 | - // 4:特撮 | |
212 | - pDetail.genre = ProgGenre.ANIME; | |
213 | - pDetail.subgenre = ProgSubgenre.ANIME_TOKUSATSU; | |
214 | - pDetail.genrelist.add(ProgGenre.ANIME); | |
215 | - pDetail.subgenrelist.add(ProgSubgenre.ANIME_TOKUSATSU); | |
216 | - anime_etc = false; | |
217 | - } | |
218 | - else if (t[2].equals("8")) { | |
219 | - // 8:映画 | |
220 | - pDetail.genre = ProgGenre.MOVIE; | |
221 | - pDetail.subgenre = ProgSubgenre.MOVIE_ETC; | |
222 | - pDetail.genrelist.add(ProgGenre.MOVIE); | |
223 | - pDetail.subgenrelist.add(ProgSubgenre.MOVIE_ETC); | |
224 | - pDetail.removeOption(ProgOption.MOVED); // 映画なら(移)はいらんやろ | |
225 | - } | |
226 | - else if (t[2].equals("0")) { | |
227 | - // 0:その他 | |
228 | - pDetail.genrelist.add(ProgGenre.NOGENRE); | |
229 | - pDetail.subgenrelist.add(ProgSubgenre.NOGENRE_ETC); | |
230 | - } | |
231 | - else if (t[2].equals("3") || t[2].equals("2") || t[2].equals("6")) { | |
232 | - // 3:テレビ 2:ラジオ 6:メモ | |
233 | - } | |
234 | - else { | |
235 | - System.out.println(DBGID+"未対応のジャンル: "+t[2]); | |
236 | - } | |
237 | - | |
238 | - // 最後に | |
239 | - if (pDetail.genre == null) { | |
240 | - pDetail.genre = ProgGenre.ANIME; | |
241 | - pDetail.subgenre = ProgSubgenre.ANIME_ETC; | |
242 | - } | |
243 | - if (pDetail.genrelist.size() == 0 || anime_etc) { | |
244 | - pDetail.genrelist.add(ProgGenre.ANIME); | |
245 | - pDetail.subgenrelist.add(ProgSubgenre.ANIME_ETC); | |
246 | - } | |
247 | - } | |
248 | - | |
249 | - // <dc:publisher>日本テレビ</dc:publisher> | |
250 | - if ( t[3] == null || t[3].length() == 0) { | |
251 | - System.err.println(ERRID+"放送局名がない: "+mb.group(1)); | |
252 | - continue; | |
253 | - } | |
254 | - | |
255 | - // ベアな放送局名と、ChannelConvert.datを適用した結果の放送局名 | |
256 | - String location = CommonUtils.unEscape(t[3]); | |
257 | - String modifiedloc = getChName(location); | |
258 | - | |
259 | - // <tv:startDatetime>2011-08-29T00:00:00+09:00</tv:startDatetime> | |
260 | - if ( rss2 ) { | |
261 | - mb = Pattern.compile("<pubDate>(.+?)\\+09:00</pubDate>",Pattern.DOTALL).matcher(ma.group(1)); | |
262 | - } | |
263 | - else { | |
264 | - mb = Pattern.compile("<tv:startDatetime>(.+?)\\+09:00</tv:startDatetime>",Pattern.DOTALL).matcher(ma.group(1)); | |
265 | - } | |
266 | - if ( ! mb.find()) { | |
267 | - System.err.println(ERRID+"開始日時がない"); | |
268 | - continue; | |
269 | - } | |
270 | - GregorianCalendar ca = CommonUtils.getCalendar(mb.group(1)); | |
271 | - if ( ca == null ) { | |
272 | - System.err.println(ERRID+"開始日時が不正: "+mb.group(1)); | |
273 | - continue; | |
274 | - } | |
275 | - | |
276 | - pDetail.startDateTime = CommonUtils.getDateTime(ca); | |
277 | - pDetail.start = pDetail.startDateTime.substring(11, 16); | |
278 | - pDetail.accurateDate = CommonUtils.getDate(ca); | |
279 | - | |
280 | - if ( t[4] == null || t[4].length() == 0) { | |
281 | - System.err.println(ERRID+"終了時刻がない: "+mb.group(1)); | |
282 | - continue; | |
283 | - } | |
284 | - | |
285 | - GregorianCalendar cz = CommonUtils.getCalendar(CommonUtils.getDate(ca)+" "+t[4]); | |
286 | - if (ca.compareTo(cz) > 0) { | |
287 | - cz.add(Calendar.DAY_OF_MONTH, 1); | |
288 | - } | |
289 | - | |
290 | - pDetail.endDateTime = CommonUtils.getDateTime(cz); | |
291 | - pDetail.end = pDetail.endDateTime.substring(11, 16); | |
292 | - | |
293 | - // 24:00~28:59までは前日なんだニャー | |
294 | - if (CommonUtils.isLateNight(ca.get(Calendar.HOUR_OF_DAY))) { | |
295 | - ca.add(Calendar.DAY_OF_MONTH, -1); | |
296 | - } | |
297 | - | |
298 | - // 番組情報を入れるべき日付 | |
299 | - String progdate = CommonUtils.getDate(ca); | |
300 | - | |
301 | - // <description>HD放送</description> | |
302 | - mb = Pattern.compile("<description>(.+?)</description>").matcher(ma.group(1)); | |
303 | - if (mb.find()) { | |
304 | - pDetail.detail += " <" + CommonUtils.unEscape(mb.group(1)) + ">"; | |
305 | - if (pDetail.detail.contains("無料放送")) { | |
306 | - pDetail.noscrumble = ProgScrumble.NOSCRUMBLE; | |
307 | - } | |
308 | - if (pDetail.detail.contains("先行放送")) { | |
309 | - pDetail.addOption(ProgOption.PRECEDING); | |
310 | - } | |
311 | - if (pDetail.detail.contains("変更の可能性")) { | |
312 | - pDetail.extension = true; | |
313 | - } | |
314 | - if ( pDetail.detail.contains("繰り下げ") ) { | |
315 | - pDetail.extension = true; | |
316 | - } | |
317 | - if (pDetail.detail.contains("副音声")) { | |
318 | - pDetail.addOption(ProgOption.MULTIVOICE); | |
319 | - } | |
320 | - } | |
321 | - | |
322 | - // <link>http://cal.syoboi.jp/tid/44#198593</link> | |
323 | - mb = Pattern.compile("<link>(.+?)</link>",Pattern.DOTALL).matcher(ma.group(1)); | |
324 | - if (mb.find()) { | |
325 | - pDetail.link = mb.group(1); | |
326 | - if ( ! ContentIdSyobo.isValid(pDetail.link)) { | |
327 | - System.out.println(DBGID+"TIDとPIDが取得できない: "+pDetail.link); | |
328 | - } | |
329 | - } | |
330 | - | |
331 | - // 追加詳細 | |
332 | - pDetail.setGenreStr(); | |
333 | - | |
334 | - // 統合 | |
335 | - { | |
336 | - // 放送局が存在するか | |
337 | - ProgList prog = null; | |
338 | - for (ProgList pl : newplist) { | |
339 | - if (pl.Center.equals(modifiedloc)) { | |
340 | - prog = pl; | |
341 | - break; | |
342 | - } | |
343 | - } | |
344 | - if (prog == null) { | |
345 | - // 番組表 | |
346 | - prog = new ProgList(); | |
347 | - prog.Center = modifiedloc; | |
348 | - prog.enabled = true; | |
349 | - prog.pdate = new ArrayList<ProgDateList>(); | |
350 | - | |
351 | - newplist.add(prog); | |
352 | - } | |
353 | - | |
354 | - // 日付が存在するか | |
355 | - ProgDateList pCenter = null; | |
356 | - for (ProgDateList pcl : prog.pdate) { | |
357 | - if (pcl.Date.equals(progdate)) { | |
358 | - pCenter = pcl; | |
359 | - break; | |
360 | - } | |
361 | - } | |
362 | - if (pCenter == null) { | |
363 | - pCenter = new ProgDateList(); | |
364 | - pCenter.Date = progdate; | |
365 | - pCenter.pdetail = new ArrayList<ProgDetailList>(); | |
366 | - prog.pdate.add(pCenter); | |
367 | - } | |
368 | - | |
369 | - // 連結 | |
370 | - pCenter.pdetail.add(pDetail); | |
371 | - | |
372 | - cnt++; | |
373 | - } | |
374 | - | |
375 | - // | |
376 | - pDetail.splitted_title = pDetail.title; | |
377 | - pDetail.splitted_detail = pDetail.detail; | |
378 | - | |
379 | - // 詳細を登録する | |
380 | - pDetail.titlePop = TraceProgram.replacePop(pDetail.title); | |
381 | - pDetail.splitted_titlePop = pDetail.titlePop; | |
382 | - pDetail.detailPop = TraceProgram.replacePop(pDetail.detail); | |
383 | - pDetail.length = Integer.valueOf(CommonUtils.getRecMin(pDetail.start.substring(0,2),pDetail.start.substring(3,5),pDetail.end.substring(0,2),pDetail.end.substring(3,5))); | |
384 | - } | |
385 | - } | |
386 | - catch (Exception e) { | |
387 | - e.printStackTrace(); | |
388 | - return false; | |
389 | - } | |
390 | - | |
391 | - pcenter = newplist; | |
392 | - System.out.println(DBGID+"番組の数: "+cnt); | |
393 | - return true; | |
394 | - } | |
395 | - | |
396 | - /* ここまで */ | |
397 | - | |
398 | - /* | |
399 | - * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ | |
400 | - * ★★★★★ 放送地域を取得する(TVAreaから降格)-ここから ★★★★★ | |
401 | - * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ | |
402 | - */ | |
403 | - | |
404 | - @Override | |
405 | - public void loadAreaCode() { | |
406 | - } | |
407 | - | |
408 | - @Override | |
409 | - public void saveAreaCode() { | |
410 | - } | |
411 | - | |
412 | - @Override | |
413 | - public String getCode(String area) { | |
414 | - return "1"; | |
415 | - } | |
416 | - | |
417 | - @Override | |
418 | - public String getDefaultArea() { | |
419 | - return "しょぼかる"; | |
420 | - } | |
421 | - | |
422 | - @Override | |
423 | - public String getSelectedArea() { | |
424 | - return "しょぼかる"; | |
425 | - } | |
426 | - | |
427 | - @Override | |
428 | - public String getSelectedCode() { | |
429 | - return "1"; | |
430 | - } | |
431 | - | |
432 | - /* | |
433 | - * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ | |
434 | - * ★★★★★ 放送地域を取得する(TVAreaから降格)-ここまで ★★★★★ | |
435 | - * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ | |
436 | - */ | |
437 | - | |
438 | - /* | |
439 | - * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ | |
440 | - * ★★★★★ 放送局を選択する(TVCenterから降格)-ここから ★★★★★ | |
441 | - * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ | |
442 | - */ | |
443 | - | |
444 | - @Override | |
445 | - public void loadCenter(String code, boolean force) { | |
446 | - | |
447 | - if ( code == null ) { | |
448 | - System.out.println(ERRID+"地域コードがnullです."); | |
449 | - return; | |
450 | - } | |
451 | - | |
452 | - if ( ! force && new File(centerFile).exists() ) { | |
453 | - // NOT FORFCEならキャッシュからどうぞ | |
454 | - @SuppressWarnings("unchecked") | |
455 | - ArrayList<Center> tmp = (ArrayList<Center>) CommonUtils.readXML(centerFile); | |
456 | - if ( tmp != null ) { | |
457 | - crlist = tmp; | |
458 | - return; | |
459 | - } | |
460 | - } | |
461 | - | |
462 | - String uri = "http://cal.syoboi.jp/mng?Action=ShowChList"; | |
463 | - String response = webToBuffer(uri,thisEncoding,true); | |
464 | - if ( response == null ) { | |
465 | - System.err.println(ERRID+"放送局リストの取得に失敗: "+uri); | |
466 | - return; | |
467 | - } | |
468 | - System.out.println(MSGID+"放送局リストを取得: "+uri); | |
469 | - | |
470 | - Matcher ma = Pattern.compile("<table class=\"tframe output\".*?>(.+?)</table>",Pattern.DOTALL).matcher(response); | |
471 | - if ( ! ma.find() ) { | |
472 | - System.err.println(ERRID+"放送局情報がない: "+uri); | |
473 | - return; | |
474 | - } | |
475 | - | |
476 | - // 新しい放送局リストの入れ物を作る | |
477 | - ArrayList<Center> newcrlist = new ArrayList<Center>(); | |
478 | - | |
479 | - int cnt = 1; | |
480 | - Matcher mb = Pattern.compile("<tr>(.+?)</tr>",Pattern.DOTALL).matcher(ma.group(1)); | |
481 | - while ( mb.find() ) { | |
482 | - String[] d = mb.group(1).split("<.*?>",9); | |
483 | - if ( d.length != 9 ) { | |
484 | - System.err.println(ERRID+"書式不正(カラム数が足りない): "+d.length); | |
485 | - continue; | |
486 | - } | |
487 | - if ( ! d[1].matches("^\\d+$") ) { | |
488 | - continue; | |
489 | - } | |
490 | - | |
491 | - // 放送局リスト | |
492 | - Center cr = new Center(); | |
493 | - cr.setLink(d[5]); | |
494 | - cr.setAreaCode("1"); | |
495 | - cr.setCenterOrig(CommonUtils.unEscape(d[7])); | |
496 | - //cr.setCenter(this.chconv.get(cr.getCenterOrig())); // ChannelConvert.datで入れ替えたもの | |
497 | - cr.setType(""); | |
498 | - cr.setEnabled(true); | |
499 | - cr.setOrder(cnt++); | |
500 | - | |
501 | - newcrlist.add(cr); | |
502 | - | |
503 | - if (debug) System.out.println(MSGID+"放送局を追加: "+cr.getCenterOrig()+" -> "+cr.getCenter()); | |
504 | - } | |
505 | - | |
506 | - if ( newcrlist.size() == 0 ) { | |
507 | - System.err.println(ERRID+"放送局情報の取得結果が0件だったため情報を更新しません"); | |
508 | - return; | |
509 | - } | |
510 | - | |
511 | - System.out.println(DBGID+"放送局の数: "+newcrlist.size()); | |
512 | - | |
513 | - crlist = newcrlist; | |
514 | - attachChFilters(); | |
515 | - setSortedCRlist(); | |
516 | - CommonUtils.writeXML(centerFile, crlist); | |
517 | - } | |
518 | - | |
519 | - @Override | |
520 | - public boolean saveCenter() { | |
521 | - return false; | |
522 | - } | |
523 | - | |
524 | - /* | |
525 | - * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ | |
526 | - * ★★★★★ 放送局を選択する(TVCenterから降格)-ここまで ★★★★★ | |
527 | - * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ | |
528 | - */ | |
529 | -} | |
1 | +package tainavi.plugintv; | |
2 | + | |
3 | +import java.io.File; | |
4 | +import java.text.SimpleDateFormat; | |
5 | +import java.util.ArrayList; | |
6 | +import java.util.Calendar; | |
7 | +import java.util.GregorianCalendar; | |
8 | +import java.util.regex.Matcher; | |
9 | +import java.util.regex.Pattern; | |
10 | + | |
11 | +import tainavi.Center; | |
12 | +import tainavi.CommonUtils; | |
13 | +import tainavi.ContentIdSyobo; | |
14 | +import tainavi.ProgDateList; | |
15 | +import tainavi.ProgDetailList; | |
16 | +import tainavi.ProgList; | |
17 | +import tainavi.TVProgram; | |
18 | +import tainavi.TVProgramUtils; | |
19 | +import tainavi.TraceProgram; | |
20 | + | |
21 | +/** | |
22 | + * しょぼかるから番組表と放送局リストを取得する。プラグインではないよ。 | |
23 | + */ | |
24 | +public class Syobocal extends TVProgramUtils implements TVProgram,Cloneable { | |
25 | + private final String thisEncoding = "UTF-8"; | |
26 | + | |
27 | + public void setDebug(boolean b) { debug = b; } | |
28 | + | |
29 | + private boolean debug = false; | |
30 | + | |
31 | + private boolean rss2 = false; | |
32 | + | |
33 | + /* 必須コード - ここから */ | |
34 | + | |
35 | + // 種族の特性 | |
36 | + private static final String tvProgId = "Syobocal"; | |
37 | + | |
38 | + private static int pastDays = 0; | |
39 | + | |
40 | + public static void setPastDays(int n){ pastDays = n; } | |
41 | + | |
42 | + //private final String progCacheFile = getProgDir()+File.separator+"syobocal.xml"; | |
43 | + private final String centerFile = "env"+File.separator+"center."+getTVProgramId()+".xml"; | |
44 | + | |
45 | + private final String MSGID = "[しょぼかる] "; | |
46 | + private final String ERRID = "[ERROR]"+MSGID; | |
47 | + private final String DBGID = "[DEBUG]"+MSGID; | |
48 | + | |
49 | + @Override | |
50 | + public String getTVProgramId() { return tvProgId; } | |
51 | + | |
52 | + @Override | |
53 | + public boolean isAreaSelectSupported() { return false; } | |
54 | + | |
55 | + @Override | |
56 | + public ProgType getType() { return ProgType.SYOBO; } | |
57 | + public ProgSubtype getSubtype() { return ProgSubtype.NONE; } | |
58 | + | |
59 | + @Override | |
60 | + public Syobocal clone() { | |
61 | + return (Syobocal) super.clone(); | |
62 | + } | |
63 | + | |
64 | + // 個体の特性 | |
65 | + | |
66 | + // | |
67 | + @Override | |
68 | + public int getTimeBarStart() {return 5;} | |
69 | + | |
70 | + private int getDogDays() { return ((getExpandTo8())?(8):(7)); } | |
71 | + | |
72 | + // | |
73 | + @Override | |
74 | + public boolean loadProgram(String areaCode, boolean force) { | |
75 | + | |
76 | + String progCacheFile = null; | |
77 | + if ( rss2 ) { | |
78 | + progCacheFile = getProgDir()+File.separator+"syobocal.xml"; | |
79 | + } | |
80 | + else { | |
81 | + progCacheFile = getProgDir()+File.separator+"syobocal.rss"; | |
82 | + } | |
83 | + | |
84 | + // 新しい番組データの入れ物を作る | |
85 | + ArrayList<ProgList> newplist = new ArrayList<ProgList>(); | |
86 | + | |
87 | + int cnt = 0; | |
88 | + | |
89 | + try { | |
90 | + String response = null; | |
91 | + | |
92 | + String cirtDateTimeYMD = CommonUtils.getCritDateTime().replaceAll("[/: ]", ""); | |
93 | + | |
94 | + File f = new File(progCacheFile); | |
95 | + if (force == true || | |
96 | + (f.exists() == true && isCacheOld(progCacheFile) == true) || | |
97 | + (f.exists() == false && isCacheOld(null) == true)) { | |
98 | + | |
99 | + String url = null; | |
100 | + if ( rss2 ) { | |
101 | + url = "http://cal.syoboi.jp/rss2.php?start="+cirtDateTimeYMD+"&days="+getDogDays()+"&titlefmt=$(Flag)^^^$(FlagW)^^^$(Cat)^^^$(ChName)^^^$(EdTime)^^^$(Title)^^^$(SubTitleB)"; | |
102 | + } | |
103 | + else { | |
104 | +// url = "http://cal.syoboi.jp/rss.php?start=today&count=1500&days=8&days="+getDogDays()+"&titlefmt=$(Flag)^^^$(FlagW)^^^$(Cat)^^^$(ChName)^^^$(EdTime)^^^$(Title)^^^$(SubTitleB)"; | |
105 | + | |
106 | + GregorianCalendar c = new GregorianCalendar(); | |
107 | + if ( CommonUtils.isLateNight(c.get(Calendar.HOUR_OF_DAY)) ) { | |
108 | + c.add(Calendar.DAY_OF_MONTH, -1); | |
109 | + } | |
110 | + c.add(Calendar.DAY_OF_MONTH, -pastDays); | |
111 | + | |
112 | + String start = new SimpleDateFormat("yyyy-MM-dd").format(c.getTime()); | |
113 | + int days = getDogDays() + pastDays; | |
114 | + | |
115 | + url = "http://cal.syoboi.jp/rss.php?start="+start+"&count=1500&days="+days+"&titlefmt=$(Flag)^^^$(FlagW)^^^$(Cat)^^^$(ChName)^^^$(EdTime)^^^$(Title)^^^$(SubTitleB)"; | |
116 | + } | |
117 | + response = webToBuffer(url, thisEncoding, true); | |
118 | + if ( response == null ) { | |
119 | + reportProgress(ERRID+"RSS2.0(オンライン)の取得に失敗しました: "+url); | |
120 | + return false; | |
121 | + } | |
122 | + | |
123 | + reportProgress(MSGID+"RSS2.0(オンライン)を取得しました: "+url); | |
124 | + CommonUtils.write2file(progCacheFile, response); | |
125 | + } | |
126 | + else if (f.exists()) { | |
127 | + // | |
128 | + response = CommonUtils.read4file(progCacheFile, true); | |
129 | + if ( response == null ) { | |
130 | + reportProgress(ERRID+"RSS2.0(キャッシュ)の取得に失敗しました: "+progCacheFile); | |
131 | + return false; | |
132 | + } | |
133 | + reportProgress(MSGID+"RSS2.0(キャッシュ)を取得しました: "+progCacheFile); | |
134 | + } | |
135 | + else { | |
136 | + reportProgress(ERRID+"RSS2.0(キャッシュ)がみつかりません: "+progCacheFile); | |
137 | + return false; | |
138 | + } | |
139 | + | |
140 | + // 情報解析 | |
141 | + | |
142 | + Matcher ma = Pattern.compile("<item(.+?)</item>",Pattern.DOTALL).matcher(response); | |
143 | + while (ma.find()) { | |
144 | + | |
145 | + // 入れ物 | |
146 | + ProgDetailList pDetail = new ProgDetailList(); | |
147 | + | |
148 | + // <title>金曜ロードショー ヱヴァンゲリヲン新劇場版:破 TV版</title> | |
149 | + Matcher mb = Pattern.compile("<title>(.+?)</title>",Pattern.DOTALL).matcher(ma.group(1)); | |
150 | + if ( ! mb.find()) { | |
151 | + continue; | |
152 | + } | |
153 | + | |
154 | + String[] t = mb.group(1).split("\\^\\^\\^",7); | |
155 | + | |
156 | + if (t.length < 7) { | |
157 | + System.err.println(ERRID+"書式が不正: "+mb.group(1)); | |
158 | + } | |
159 | + | |
160 | + pDetail.title = CommonUtils.unEscape(t[5]); | |
161 | + | |
162 | + pDetail.detail = CommonUtils.unEscape(t[6]); | |
163 | + if ( pDetail.detail.matches("^#1$|^#1[^0-9].*$") ) { | |
164 | + // まあなにもしなくていいか | |
165 | + } | |
166 | + | |
167 | + if (t[0] != null && t[0].length() > 0) { | |
168 | + int flag = Integer.valueOf(t[0]); | |
169 | + if (flag != 0) { | |
170 | + if ((flag & 0x01) != 0x00) { | |
171 | + pDetail.addOption(ProgOption.SPECIAL); | |
172 | + flag ^= 0x01; | |
173 | + } | |
174 | + if ((flag & 0x02) != 0x00) { | |
175 | + pDetail.flag = ProgFlags.NEW; | |
176 | + flag ^= 0x02; | |
177 | + } | |
178 | + if ((flag & 0x04) != 0x00) { | |
179 | + pDetail.flag = ProgFlags.LAST; | |
180 | + flag ^= 0x04; | |
181 | + } | |
182 | + if ((flag & 0x08) != 0x00) { | |
183 | + pDetail.addOption(ProgOption.REPEAT); | |
184 | + flag ^= 0x08; | |
185 | + } | |
186 | + if (flag != 0) { | |
187 | + System.out.println(DBGID+"未対応のマーク: "+flag); | |
188 | + } | |
189 | + } | |
190 | + } | |
191 | + if (t[1] != null && t[1].length() > 0) { | |
192 | + int flagw = Integer.valueOf(t[1]); | |
193 | + if (flagw != 0) { | |
194 | + if ((flagw & 0x01) != 0x00) { | |
195 | + if (pDetail.flag != ProgFlags.NEW && ! pDetail.isOptionEnabled(ProgOption.SPECIAL)) { | |
196 | + pDetail.addOption(ProgOption.MOVED); // 新番組や特番なら(移)はいらんやろ | |
197 | + } | |
198 | + flagw ^= 0x01; | |
199 | + } | |
200 | + if (flagw != 0) { | |
201 | + System.out.println(DBGID+"未対応の警告フラグ: "+flagw); | |
202 | + } | |
203 | + } | |
204 | + } | |
205 | + // <tv:genre>アニメ(終了/再放送)</tv:genre> | |
206 | + pDetail.genre = null; | |
207 | + pDetail.subgenre = null; | |
208 | + pDetail.genrelist = new ArrayList<TVProgram.ProgGenre>(); | |
209 | + pDetail.subgenrelist = new ArrayList<TVProgram.ProgSubgenre>(); | |
210 | + boolean anime_etc = true; | |
211 | + | |
212 | + if (t[2] != null && t[2].length() > 0) { | |
213 | + // ジャンル | |
214 | + if (t[2].equals("1") || t[2].equals("10") || t[2].equals("5")) { | |
215 | + // 1:アニメ 10:アニメ(終了/再放送) 5:アニメ関連 | |
216 | + } | |
217 | + else if (t[2].equals("7")) { | |
218 | + // 7:OVA | |
219 | + pDetail.genre = ProgGenre.ANIME; | |
220 | + pDetail.subgenre = ProgSubgenre.ANIME_KOKUNAI; | |
221 | + pDetail.genrelist.add(ProgGenre.ANIME); | |
222 | + pDetail.subgenrelist.add(ProgSubgenre.ANIME_KOKUNAI); | |
223 | + anime_etc = false; | |
224 | + } | |
225 | + else if (t[2].equals("4")) { | |
226 | + // 4:特撮 | |
227 | + pDetail.genre = ProgGenre.ANIME; | |
228 | + pDetail.subgenre = ProgSubgenre.ANIME_TOKUSATSU; | |
229 | + pDetail.genrelist.add(ProgGenre.ANIME); | |
230 | + pDetail.subgenrelist.add(ProgSubgenre.ANIME_TOKUSATSU); | |
231 | + anime_etc = false; | |
232 | + } | |
233 | + else if (t[2].equals("8")) { | |
234 | + // 8:映画 | |
235 | + pDetail.genre = ProgGenre.MOVIE; | |
236 | + pDetail.subgenre = ProgSubgenre.MOVIE_ETC; | |
237 | + pDetail.genrelist.add(ProgGenre.MOVIE); | |
238 | + pDetail.subgenrelist.add(ProgSubgenre.MOVIE_ETC); | |
239 | + pDetail.removeOption(ProgOption.MOVED); // 映画なら(移)はいらんやろ | |
240 | + } | |
241 | + else if (t[2].equals("0")) { | |
242 | + // 0:その他 | |
243 | + pDetail.genrelist.add(ProgGenre.NOGENRE); | |
244 | + pDetail.subgenrelist.add(ProgSubgenre.NOGENRE_ETC); | |
245 | + } | |
246 | + else if (t[2].equals("3") || t[2].equals("2") || t[2].equals("6")) { | |
247 | + // 3:テレビ 2:ラジオ 6:メモ | |
248 | + } | |
249 | + else { | |
250 | + System.out.println(DBGID+"未対応のジャンル: "+t[2]); | |
251 | + } | |
252 | + | |
253 | + // 最後に | |
254 | + if (pDetail.genre == null) { | |
255 | + pDetail.genre = ProgGenre.ANIME; | |
256 | + pDetail.subgenre = ProgSubgenre.ANIME_ETC; | |
257 | + } | |
258 | + if (pDetail.genrelist.size() == 0 || anime_etc) { | |
259 | + pDetail.genrelist.add(ProgGenre.ANIME); | |
260 | + pDetail.subgenrelist.add(ProgSubgenre.ANIME_ETC); | |
261 | + } | |
262 | + } | |
263 | + | |
264 | + // <dc:publisher>日本テレビ</dc:publisher> | |
265 | + if ( t[3] == null || t[3].length() == 0) { | |
266 | + System.err.println(ERRID+"放送局名がない: "+mb.group(1)); | |
267 | + continue; | |
268 | + } | |
269 | + | |
270 | + // ベアな放送局名と、ChannelConvert.datを適用した結果の放送局名 | |
271 | + String location = CommonUtils.unEscape(t[3]); | |
272 | + String modifiedloc = getChName(location); | |
273 | + | |
274 | + // <tv:startDatetime>2011-08-29T00:00:00+09:00</tv:startDatetime> | |
275 | + if ( rss2 ) { | |
276 | + mb = Pattern.compile("<pubDate>(.+?)\\+09:00</pubDate>",Pattern.DOTALL).matcher(ma.group(1)); | |
277 | + } | |
278 | + else { | |
279 | + mb = Pattern.compile("<tv:startDatetime>(.+?)\\+09:00</tv:startDatetime>",Pattern.DOTALL).matcher(ma.group(1)); | |
280 | + } | |
281 | + if ( ! mb.find()) { | |
282 | + System.err.println(ERRID+"開始日時がない"); | |
283 | + continue; | |
284 | + } | |
285 | + GregorianCalendar ca = CommonUtils.getCalendar(mb.group(1)); | |
286 | + if ( ca == null ) { | |
287 | + System.err.println(ERRID+"開始日時が不正: "+mb.group(1)); | |
288 | + continue; | |
289 | + } | |
290 | + | |
291 | + pDetail.startDateTime = CommonUtils.getDateTime(ca); | |
292 | + pDetail.start = pDetail.startDateTime.substring(11, 16); | |
293 | + pDetail.accurateDate = CommonUtils.getDate(ca); | |
294 | + | |
295 | + if ( t[4] == null || t[4].length() == 0) { | |
296 | + System.err.println(ERRID+"終了時刻がない: "+mb.group(1)); | |
297 | + continue; | |
298 | + } | |
299 | + | |
300 | + GregorianCalendar cz = CommonUtils.getCalendar(CommonUtils.getDate(ca)+" "+t[4]); | |
301 | + if (ca.compareTo(cz) > 0) { | |
302 | + cz.add(Calendar.DAY_OF_MONTH, 1); | |
303 | + } | |
304 | + | |
305 | + pDetail.endDateTime = CommonUtils.getDateTime(cz); | |
306 | + pDetail.end = pDetail.endDateTime.substring(11, 16); | |
307 | + | |
308 | + // 24:00~28:59までは前日なんだニャー | |
309 | + if (CommonUtils.isLateNight(ca.get(Calendar.HOUR_OF_DAY))) { | |
310 | + ca.add(Calendar.DAY_OF_MONTH, -1); | |
311 | + } | |
312 | + | |
313 | + // 番組情報を入れるべき日付 | |
314 | + String progdate = CommonUtils.getDate(ca); | |
315 | + | |
316 | + // <description>HD放送</description> | |
317 | + mb = Pattern.compile("<description>(.+?)</description>").matcher(ma.group(1)); | |
318 | + if (mb.find()) { | |
319 | + pDetail.detail += " <" + CommonUtils.unEscape(mb.group(1)) + ">"; | |
320 | + if (pDetail.detail.contains("無料放送")) { | |
321 | + pDetail.noscrumble = ProgScrumble.NOSCRUMBLE; | |
322 | + } | |
323 | + if (pDetail.detail.contains("先行放送")) { | |
324 | + pDetail.addOption(ProgOption.PRECEDING); | |
325 | + } | |
326 | + if (pDetail.detail.contains("変更の可能性")) { | |
327 | + pDetail.extension = true; | |
328 | + } | |
329 | + if ( pDetail.detail.contains("繰り下げ") ) { | |
330 | + pDetail.extension = true; | |
331 | + } | |
332 | + if (pDetail.detail.contains("副音声")) { | |
333 | + pDetail.addOption(ProgOption.MULTIVOICE); | |
334 | + } | |
335 | + } | |
336 | + | |
337 | + // <link>http://cal.syoboi.jp/tid/44#198593</link> | |
338 | + mb = Pattern.compile("<link>(.+?)</link>",Pattern.DOTALL).matcher(ma.group(1)); | |
339 | + if (mb.find()) { | |
340 | + pDetail.link = mb.group(1); | |
341 | + if ( ! ContentIdSyobo.isValid(pDetail.link)) { | |
342 | + System.out.println(DBGID+"TIDとPIDが取得できない: "+pDetail.link); | |
343 | + } | |
344 | + } | |
345 | + | |
346 | + // 追加詳細 | |
347 | + pDetail.setGenreStr(); | |
348 | + | |
349 | + // 統合 | |
350 | + { | |
351 | + // 放送局が存在するか | |
352 | + ProgList prog = null; | |
353 | + for (ProgList pl : newplist) { | |
354 | + if (pl.Center.equals(modifiedloc)) { | |
355 | + prog = pl; | |
356 | + break; | |
357 | + } | |
358 | + } | |
359 | + if (prog == null) { | |
360 | + // 番組表 | |
361 | + prog = new ProgList(); | |
362 | + prog.Center = modifiedloc; | |
363 | + prog.enabled = true; | |
364 | + prog.pdate = new ArrayList<ProgDateList>(); | |
365 | + | |
366 | + newplist.add(prog); | |
367 | + } | |
368 | + | |
369 | + // 日付が存在するか | |
370 | + ProgDateList pCenter = null; | |
371 | + for (ProgDateList pcl : prog.pdate) { | |
372 | + if (pcl.Date.equals(progdate)) { | |
373 | + pCenter = pcl; | |
374 | + break; | |
375 | + } | |
376 | + } | |
377 | + if (pCenter == null) { | |
378 | + pCenter = new ProgDateList(); | |
379 | + pCenter.Date = progdate; | |
380 | + pCenter.pdetail = new ArrayList<ProgDetailList>(); | |
381 | + prog.pdate.add(pCenter); | |
382 | + } | |
383 | + | |
384 | + // 連結 | |
385 | + pCenter.pdetail.add(pDetail); | |
386 | + | |
387 | + cnt++; | |
388 | + } | |
389 | + | |
390 | + // | |
391 | + pDetail.splitted_title = pDetail.title; | |
392 | + pDetail.splitted_detail = pDetail.detail; | |
393 | + | |
394 | + // 詳細を登録する | |
395 | + pDetail.titlePop = TraceProgram.replacePop(pDetail.title); | |
396 | + pDetail.splitted_titlePop = pDetail.titlePop; | |
397 | + pDetail.detailPop = TraceProgram.replacePop(pDetail.detail); | |
398 | + pDetail.length = Integer.valueOf(CommonUtils.getRecMin(pDetail.start.substring(0,2),pDetail.start.substring(3,5),pDetail.end.substring(0,2),pDetail.end.substring(3,5))); | |
399 | + } | |
400 | + } | |
401 | + catch (Exception e) { | |
402 | + e.printStackTrace(); | |
403 | + return false; | |
404 | + } | |
405 | + | |
406 | + pcenter = newplist; | |
407 | + System.out.println(DBGID+"番組の数: "+cnt); | |
408 | + return true; | |
409 | + } | |
410 | + | |
411 | + /* ここまで */ | |
412 | + | |
413 | + /* | |
414 | + * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ | |
415 | + * ★★★★★ 放送地域を取得する(TVAreaから降格)-ここから ★★★★★ | |
416 | + * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ | |
417 | + */ | |
418 | + | |
419 | + @Override | |
420 | + public void loadAreaCode() { | |
421 | + } | |
422 | + | |
423 | + @Override | |
424 | + public void saveAreaCode() { | |
425 | + } | |
426 | + | |
427 | + @Override | |
428 | + public String getCode(String area) { | |
429 | + return "1"; | |
430 | + } | |
431 | + | |
432 | + @Override | |
433 | + public String getDefaultArea() { | |
434 | + return "しょぼかる"; | |
435 | + } | |
436 | + | |
437 | + @Override | |
438 | + public String getSelectedArea() { | |
439 | + return "しょぼかる"; | |
440 | + } | |
441 | + | |
442 | + @Override | |
443 | + public String getSelectedCode() { | |
444 | + return "1"; | |
445 | + } | |
446 | + | |
447 | + /* | |
448 | + * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ | |
449 | + * ★★★★★ 放送地域を取得する(TVAreaから降格)-ここまで ★★★★★ | |
450 | + * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ | |
451 | + */ | |
452 | + | |
453 | + /* | |
454 | + * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ | |
455 | + * ★★★★★ 放送局を選択する(TVCenterから降格)-ここから ★★★★★ | |
456 | + * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ | |
457 | + */ | |
458 | + | |
459 | + @Override | |
460 | + public void loadCenter(String code, boolean force) { | |
461 | + | |
462 | + if ( code == null ) { | |
463 | + System.out.println(ERRID+"地域コードがnullです."); | |
464 | + return; | |
465 | + } | |
466 | + | |
467 | + if ( ! force && new File(centerFile).exists() ) { | |
468 | + // NOT FORFCEならキャッシュからどうぞ | |
469 | + @SuppressWarnings("unchecked") | |
470 | + ArrayList<Center> tmp = (ArrayList<Center>) CommonUtils.readXML(centerFile); | |
471 | + if ( tmp != null ) { | |
472 | + crlist = tmp; | |
473 | + return; | |
474 | + } | |
475 | + } | |
476 | + | |
477 | + String uri = "http://cal.syoboi.jp/mng?Action=ShowChList"; | |
478 | + String response = webToBuffer(uri,thisEncoding,true); | |
479 | + if ( response == null ) { | |
480 | + System.err.println(ERRID+"放送局リストの取得に失敗: "+uri); | |
481 | + return; | |
482 | + } | |
483 | + System.out.println(MSGID+"放送局リストを取得: "+uri); | |
484 | + | |
485 | + Matcher ma = Pattern.compile("<table class=\"tframe output\".*?>(.+?)</table>",Pattern.DOTALL).matcher(response); | |
486 | + if ( ! ma.find() ) { | |
487 | + System.err.println(ERRID+"放送局情報がない: "+uri); | |
488 | + return; | |
489 | + } | |
490 | + | |
491 | + // 新しい放送局リストの入れ物を作る | |
492 | + ArrayList<Center> newcrlist = new ArrayList<Center>(); | |
493 | + | |
494 | + int cnt = 1; | |
495 | + Matcher mb = Pattern.compile("<tr>(.+?)</tr>",Pattern.DOTALL).matcher(ma.group(1)); | |
496 | + while ( mb.find() ) { | |
497 | + String[] d = mb.group(1).split("<.*?>",9); | |
498 | + if ( d.length != 9 ) { | |
499 | + System.err.println(ERRID+"書式不正(カラム数が足りない): "+d.length); | |
500 | + continue; | |
501 | + } | |
502 | + if ( ! d[1].matches("^\\d+$") ) { | |
503 | + continue; | |
504 | + } | |
505 | + | |
506 | + // 放送局リスト | |
507 | + Center cr = new Center(); | |
508 | + cr.setLink(d[5]); | |
509 | + cr.setAreaCode("1"); | |
510 | + cr.setCenterOrig(CommonUtils.unEscape(d[7])); | |
511 | + //cr.setCenter(this.chconv.get(cr.getCenterOrig())); // ChannelConvert.datで入れ替えたもの | |
512 | + cr.setType(""); | |
513 | + cr.setEnabled(true); | |
514 | + cr.setOrder(cnt++); | |
515 | + | |
516 | + newcrlist.add(cr); | |
517 | + | |
518 | + if (debug) System.out.println(MSGID+"放送局を追加: "+cr.getCenterOrig()+" -> "+cr.getCenter()); | |
519 | + } | |
520 | + | |
521 | + if ( newcrlist.size() == 0 ) { | |
522 | + System.err.println(ERRID+"放送局情報の取得結果が0件だったため情報を更新しません"); | |
523 | + return; | |
524 | + } | |
525 | + | |
526 | + System.out.println(DBGID+"放送局の数: "+newcrlist.size()); | |
527 | + | |
528 | + crlist = newcrlist; | |
529 | + attachChFilters(); | |
530 | + setSortedCRlist(); | |
531 | + CommonUtils.writeXML(centerFile, crlist); | |
532 | + } | |
533 | + | |
534 | + @Override | |
535 | + public boolean saveCenter() { | |
536 | + return false; | |
537 | + } | |
538 | + | |
539 | + /* | |
540 | + * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ | |
541 | + * ★★★★★ 放送局を選択する(TVCenterから降格)-ここまで ★★★★★ | |
542 | + * ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ | |
543 | + */ | |
544 | + | |
545 | + /** | |
546 | + * 日付変更線(29:00)をまたいだら過去のデータはカットする | |
547 | + * <B> PassedProgramでは使わない | |
548 | + */ | |
549 | + @Override | |
550 | + public void refresh() { | |
551 | + | |
552 | + String critDate = CommonUtils.getDate529(-60*60*24*pastDays, true); | |
553 | + for ( ProgList p : pcenter ) { | |
554 | + int i = 0; | |
555 | + for ( ProgDateList c : p.pdate ) { | |
556 | + if ( c.Date.compareTo(critDate) >= 0 ) { | |
557 | + break; | |
558 | + } | |
559 | + i++; | |
560 | + } | |
561 | + for ( int j=0; j<i; j++) { | |
562 | + p.pdate.remove(0); | |
563 | + } | |
564 | + } | |
565 | + } | |
566 | + | |
567 | +} |