Linux Media Center設置心得(MythTV)-MythTV EPG

常言道:『飲水思源』,在 Open Source 的世界裡,我們常常需要別人的幫助,但是在您有所心得的時候請記得分享給大家,『幫助人是快樂的喔』。歡迎您在使用 debian 的過程中的任何心得分享給大家。

Linux Media Center設置心得(MythTV)-MythTV EPG

文章ycfu » 週五 2月 02, 2007 11:15 am

2007-02-26修改,
這次改版比較多,中間改過好幾次,比較大的變更如下:
1.把程式順序排列一下,加上區段註解,比較容易看和找程式段。
2.加入擷取、解析ETTODAY的節目表(東森洋片、東森電影、東森幼幼、HBO、Cinemax共5台),原因很簡單,因為它這幾台節目表有節目介紹,而且節目介紹不需要另外開連結。
3.加入擷取、解析Discovery、動物星球的節目表,原因和ETTODAY差不多,Discovery的節目表有節目介紹,而動物星球的節目表和Discovery結構完全一樣,因此一起加了。

已知一個bug,長久以來有幾個頻道沒節目資訊,是有bug造成的,不過目前還不知道原因。
2007-02-22修改,改程式的2個bug。

不小心刪掉了,重發一次~

在M$的MCE上,去年已經有EPG可以使用了,MythTV一直都沒有台灣的EPG可以用,最近這幾周終於弄出來了,將說明和程式貼上來。

使用程式時請務必注意,因為我是用php以命令列模式寫的,要記得安裝php5-cil套件,不然不用說,一定是出現command not found,至於perl,因為我perl不會,因此用比較熟一點的php來寫。

另外,MythTV是有提供中文支援的,不過在選單中,它不是用Chinese、Traditional Chinese、正體中文、繁體中文、中文...etc,選單中它稱為「Hanzi (Traditional)」,中文是「漢語 (正體)」,不知道之前是誰中文化的,這樣的用法感覺上並不常見。

最後提一下,因為不知道版權上會不會有什麼問題,還是聲明一下。
這幾個程式在說明中有提到,部份區塊是參考其他人寫的。
而電視節目資訊目前是參考「開眼電影」的網站,所有節目資訊版權所有均屬「開眼電影」或它的來源所有。
本程式只用於學術研究與個人興趣,不會應用於任何商業行為。
如有問題或需要,本人願意將它拿掉、刪除。
至於程式和文章本身,隨便註明一下是我寫的就好了,反正難得我的文章有人有興趣,歡迎轉貼、轉載。
=======================================
MediaCenter-MythTVEPG:

MythTV和M$ MCE一樣,有EPG的功能,要實做它如下:

首先,我們要知道MythTV對電視設定的方式,我們也需要一些電視的基本資訊。

台灣的電視是屬於NTSC規格,可以參考「

http://zh.wikipedia.org/wiki/NTSC%E5%88%B6%E5%BC%8F」。

台灣的有線電視頻道表是走美國有線電視頻道表的格式,以Linux上的「tvtime」這套

電視軟體來看,
頻道表格式它有:
us-cable
us-cable100
us-broadcast
china-broadcast
southafrica
japan-cable
japan-broadcast
europe
australia
australia-optus
newzealand
france
russia
custom (first run tvtime-scanner)

我們的選擇就可以選「us-cable100」,我們的有線電視頻道表有用到超過100。

而在MythTV當中,我們選「us-cable」即可。

也許會說,我們可以選「custom」來掃描就好了,可是實際上來說,MythTV在設定好

頻道表之後,
frequency ID直接輸入頻道就可以了,以「TVBS-N」來說,目前「TVBS-N」是55頻道


則在frequency ID填入55即可。

如果用custom來掃描頻道的話,
第一個問題是會掃描到很多不是頻道,但訊號比較強的雜訊台,要手動去過濾它。
第二個問題是,掃出來的頻道表,它的頻道和實際的頻道有出入,以「TVBS-N」來說


它可能不會是55頻道。
第三個問題是,它掃出來的會是頻率,頻率在處理的時候不好處理,因為有線電視提

供的頻道表,
它會是「頻道->電視台」,而不會是「頻率->電視台」,在處理的時候會麻煩許多。

在了解設定之後,我們要說明一下MythTV電視的設定方式。
MythTV我們可以把它理解成Freevo,它也算是個MediaCenter的殼,
MythTV本身算是個類似tvtime這樣的看電視軟體,不一樣的地方在於,
它針對MediaCenter有很多不同的設計,像是它提供其他的模組,
每個模組都可以看作是獨立的,因此MythVideo的設定,和MythTV的設定就不同,
所以MythTV裡面的字型大小、格式之類的,和MythVideo並沒有太大關聯。

此外,MythTV將電視軟體做得很大,它的所有設定包括頻道資訊,都是以資料庫的方

式存在MySQL當中,
而且MythTV被分隔為MythTV-Backend和MythtvFrontend,
Mythtv-Backend負責控制電視的播放,因此電視卡的設定都是在Mythtv-Backend,
而介面部份,還有像是MythVideo模組,都是在Mythtv-Frontend上,
所以MythTV有能力做到跨電腦的電視播放。

因此,我們在透過「mythtv-setup」設定電視卡的時候,其實都是針對

Mythtv-backend設定的,
設定的資料都存入MySQL當中。
在這邊,我們有一個很重要的事情要注意,我們在設定電視卡的時候,不要讓它作頻

道掃描。
因為它的頻道掃描,和tvtime的custom一樣,掃描出來的frequency ID都是頻率,非

常不好處理,
我們在之後要手動自己建立自家的「頻道-電視台」列表。

再來,我們還不到動手的時候,我們要來說明MythTV上EPG的動作方式。
EPG全名是「Electronic Program Guide」,中文叫做「電子節目導覽」,
它其實是一種功能,就是提供電視的節目表以及節目介紹,
目前家裏完成的,只有節目表的功能,還沒有節目介紹,但是可以做到。

目前包括M$ MCE在內,一些電視軟體都有EPG的功能,大部分的電視軟體,EPG作法是


它們讀取一個稱之為「XMLTV」的電視節目表,這個表是以「XML」的方式儲存的,
以MythTV來說,它的檔案格式會是如下(格式來源:http://xmltv.org/wiki/xmltvfileformat.html):
代碼: 選擇全部
<tv generator-info-name="tv_grab_uk">
  <channel id="bbc2.bbc.co.uk">
     <display-name lang="en">BBC2</display-name>
  </channel>
  <channel id="channel4.com">
     <display-name lang="en">Channel 4</display-name>
  </channel>

  <programme channel="bbc2.bbc.co.uk" start="20010829000500 +0100">
     <title lang="en">The Phil Silvers Show</title>
     <desc lang="en">
        Bilko claims he's had a close encounter with an alien in order
        to be given some compassionate leave so he can visit an old
        flame in New York.
     </desc>
  </programme>

  <programme channel="channel4.com" start="20010829095500 +0100">
     <title lang="en">King of the Hill</title>
     <sub-title lang="en">Meet the Propaniacs</sub-title>
     <desc lang="en">
         Bobby tours with a comedy troupe who specialize in
         propane-related mirth.
     </desc>
     <credits>
        <actor>Mike Judge</actor>
        <actor>Lane Smith</actor>
     </credits>
     <category lang="en">animation</category>
  </programme>
</tv>

我們可以發現,它的格式非常完整,包括了電視台、節目時間、節目,甚至節目介紹

、演員表都有,
現階段,我們能夠做出節目表就阿彌陀佛了~

在這裡,我之前有一個問題,我們前面提過的「頻道表」,它是由「頻道-電視台」組

成的,
而「XMLTV格式」中,有「電視台」和「節目表」...等資訊,它們關聯是在哪裡?
畢竟都是存入MySQL,總要有關聯才可以。
我就遇到過,我將產生的xmltv直接匯入,結果MythTV竟然自創了一堆頻道出來,
這些頻道都沒有frequency ID(frequency ID為0),
不過我也發現,這些頻道的chanid和callsign都等於xmltv的channel id。

因此我大概猜到它們的關聯,它們的關聯是在「xmltvid」和「XMLTV的channel id」



MythTV儲存頻道是透過一個MySQL的table,叫做channel。
裡面比較有關系的欄位如下:
chanid 頻道ID(在這邊,MythTV習慣上會是1000起跳,我則是將「有線電視

頻道+1000」填入)
channum 頻道編號(在這邊,我直接填入「有線電視頻道」)
freqid frequency ID;頻率ID(在這邊,我直接填入「有線電視頻道」)


sourceid 來源編號(這裡是填上是Linux上第幾個電視卡裝置,基本上一張電視卡都

會是「1」)
callsign 電視台別名(在這邊,我參考TV Control,自己另外取了幾個頻道的

英文名,並填入)
name 電視台名稱(在這邊,我依「開眼電影」網站的電視台名稱

填入)
xmltvid XML ID(這裡我填入和callsign相同的英文名)
visible 可視(這裡設定的是,這個頻道要不要顯示,不要顯示的頻道我已經

挑掉了,因此都要顯示,都是「1」)

了解幾個主要欄位後,MythTV中XML TV的資訊另外存一個表,
這兩個表是靠「xmltvid」關聯在一起的,
因此我在XMLTV產生時,「XMLTV的channel id」也是填入「callsign」這樣的英文別

名。

了解這些後,我們可以實際動手了,首先我們要取得我們有線電視的頻道表,
以我家來說,我家是「新台北」,頻道表可以到「

http://www.cabletv.com.tw/login.aspx」取得。
「開眼電影」網站也可以取得「http://tv.atmovies.com.tw/」。

事實上,在MythTV當中,有提供日本的電視節目擷取程式,是用perl寫的,
我perl不熟,沒辦法寫好後放入MythTV中,不過他們的網站我去看過,
「開眼電影」提供的資訊,比它們的差一點點,日本的那個電視節目擷取程式,
真的寫的和M$ MCE一樣,直接輸入「郵遞區號」然後選「有線電視」業者,
就可以把頻道表直接抓好。
「開眼電影」有提供「有線電視業者」的頻道表下載,也有提供各電視台的節目表,
甚至節目介紹也有,但是幾個問題點:
1.沒有提供郵遞區號選擇(有提供區域,像基隆、台北...等)
2.有線電視業者頻道表的電視台名稱和「開眼電影」的電視台名稱不完全相同

不過我相信,這些問題最大的問題是,沒人寫程式.... :(

在取得了頻道表之後,我作成了Excel的表格,表格類似如下:
=======================================================
代碼: 選擇全部
頻道   MythTV頻率ID   簡稱   新台北頻道名稱   開眼
2   55250   -   節目表   -
3   61250   -   公用頻道   -
4   67250   -   地方自製頻道   -
5   77250   CNN   CNN   -
6   83250   FTV   民視   民視綜合台
7   175250   BLTV   人間   人間衛視
8   181250   TTV   台視   台灣電視台
9   187250   DAAI   大愛   大愛電視台
10   193250   CTV   中視   中視數位台
11   199250   CTS_IQ   華視教育頻道   華視教育頻道
12   205250   CTS   華視   華視 CTS
13   211250   PTS   公視   公共電視 PTS
15   127250   GOODTV   好消息   好消息Good TV
16   133250   ITV   原住民語頻道   原住民頻道
17   139250   HTV   客語頻道   客家電視 HTV
18   145250   NGC   國家地理頻道   國家地理頻道
19   151250   DISCOVERY   Discovery   DISCOVERY
20   157250   ASIATRAVEL   亞洲旅遊台   -
21   163250   TNL   旅遊生活頻道   旅遊生活頻道
22   169250   ANIMAL   動物星球   動物星球頻道
23   217250   DISNEY   迪士尼頻道   迪士尼頻道
24   223250   MOMO   MOMO親子台   MOMO親子台
25   229250   ET_YOYO   東森幼幼台   東森幼幼台

========================================================

比較麻煩的是在於,要一個一個去填入「開眼電影」的「電視台名稱」,而且要一模

一樣。
另一個麻煩則是要參考TV Control裡面的節目英文名填進去,沒有的自己查自己取。

這邊要注意的是,沒有名稱的,我就填入「-」,之後的程式也是去搜尋「-」作判斷



取好之後,我直接另存新檔,存成「.csv」的檔案,在這個.csv的檔案中,
我們需要稍微清理一下,幾個清潔動作:
1.把第一行「頻道 MythTV頻率ID 簡稱 新台北頻道名稱 開眼」拿掉


2.把不要的頻道拿掉,像是一堆討厭的購物台、節目表...之類的
3.另存新檔為Channels.txt

之後我們用第一個我寫的php程式把它寫入到MySQL中,
正因為這邊會把頻道、電視台名稱...等資料直接寫入MySQL,
因此在前面,我們不需要透過mythtv-setup來搜尋頻道。

直接執行「mythtv_freq_export.php」即可。
檔案內容列在最後面。

接著我們要取得節目資訊。
取得節目資訊的方式,我主要是「參考」(開頭和網站分析是抄它的)TVControl寫的,
TVControl(http://sean.o4u.com/ap/TVControl/)是網路上幾個熱心的人寫的,它算

是M$ MCE的過渡期程式,
M$ MCE 2005在去年推出時,並沒有做好節目資訊,因此節目表也是空白的,
在去年2006年6月左右(看討論知道的),MCE 2005台灣的節目表才有可以使用。
因此就有一些人,寫了TVControl這樣的程式,除了方便看電視之外,
另一個很大的特色,就是提供MCE節目資訊用的XMLTV檔案。

一開始,我本來是考慮直接拿它套進MythTV,可是兩個問題:
1.它是用VBScript寫的,Linux不支援,可能要用WINE+IE攪半天才可能辦到
2.它出來的檔案,MythTV吃起來都會error,很奇怪

加上它事實上,節目表也要自己改,因此乾脆參考它的,然後整個自己寫,
自己寫的時候,因為對php比較熟,perl完全不懂,因此就用php來寫,
在TVControl裡面,它分析網頁時直接用RegEx,不知道是我RegEx不熟,
還是php的RegEx有問題,因此我後來還是用笨方法,用substr慢慢切。

確定Channles.txt和myprog.php放在同一個目錄,
它會下載「開眼電影」的節目表,然後比對Channles.txt的電視台名稱,
把它輸出成xmltv的檔案。

輸出的檔案我是設成myxmltv.xml

之後要做的,就是用MythTV的匯入程式,將檔案讀進去,如下:

mythfilldatabase --file 1 3 myxmltv.xml

--file 表示以XMLTV的檔案匯入
1 表示sourceid,正如前面說過的,如果只有一張

電視卡,則就是1
3 表示幾天份的節目資訊,要和myprog.php呼應,

目前是設成3天

幾個跟檔案格式有關的注意事項:
1.Channels.txt在這邊應該是ANSI標準格式,不用預先調整成UTF-8,myprog.php裡面

有透過iconv()調整。
2.myxmltv.xml是UTF-8格式的,這應該是XMLTV規定的格式,大家都一樣吧。

myprog.php的XMLTV我是參考http://www.akbkhome.com/svn/akpear/XML_Tv/Tv.php寫

的,
目前剛完成,因此應該還有些bug,而且寫的不好看。

2007-02-02
myprog.php程式經過修改,目前已經可以支援Proxy,
預設是開啟的(家裡網路不開Proxy,速度很慢,詳情可以參閱PCZONE,不多解釋了)
直接在myprog.php的最前面修改參數即可支援。

目前已經可以直接放入 MythTV 自動執行了,作法設定如下:
MythTV Frontend
工具/設定
設定
一般設定
Automatically run mythfilldatabase
mythfilldatabase Path: /usr/local/bin/myprog.php(看你是放在哪裡,我放在

/usr/local/bin/)
mythfilldatabase Arguments: 3 /home/mythtv/Channels.txt /tmp/tmpxml.xml
mythfilldatabase Log Path: /var/log/mythtv/mythfilldatabase.log
mythfilldatabase Run Frequency (Days): 2(比設定少一天,固定讓它多抓一天份)
mythfilldatabase Execution Start: 20(每 2 天固定執行的時間,會以隨機方式在

Start和End之間時間執行)
mythfilldatabase Execution End: 23

mythtv_freq_export.php
=======================================================
代碼: 選擇全部
#!/usr/bin/php -q
<?
$a = ParseChannelInfo(readChannelInfo("Channels.txt"));
ImportChannels($a);

function readChannelInfo($filename)
{
  echo("頻道表讀取中...\n");
  $fn = fopen($filename, r);
  while(!feof ($fn)) {
    $buffer = fgets($fn, 4096);
    $buffer = trim($buffer);
    $channeldata = $channeldata.$buffer."\n";
  }
  fclose($fn);
  return $channeldata;
}

function Big5ToUTF8($source)
{
  return iconv("big5", "UTF-8", $source);
}


function ParseChannelInfo($channelinfo)
{
  echo("頻道表解析中...\n");
  //目前格式
  //6,民視,FTV,民視綜合台
  //頻道編號,有線電視頻道名稱,頻道ID,開眼頻道名稱
  $channelinfo = Big5ToUTF8($channelinfo);
  $linearray = split("\n", $channelinfo);
  for($i = 0;$i < count($linearray);$i++)
  {
    if($linearray[$i] != "")                //去除空白
    {
      $line = split(',', $linearray[$i]);
      $ChannelInfo[$i][0] = $line[0];
      $ChannelInfo[$i][1] = $line[2];
      $ChannelInfo[$i][2] = $line[4];
    }
  }
  return $ChannelInfo;
}
function ImportChannels($ChannelInfo)
{
  for($i = 0;$i < count($ChannelInfo);$i++)
  {
    $link = mysql_connect('127.0.0.1', 'root', '') or die('Could not

connect: ' . mysql_error());
    mysql_select_db('mythconverg') or die('Could not select database');
    $chanid = $ChannelInfo[$i][0] + 1000;
    $channum = $ChannelInfo[$i][0];
    $sourceid = 1;
    $name = $ChannelInfo[$i][2];
    $xmltvid = $ChannelInfo[$i][1];
    $query = "INSERT INTO `channel` ( `chanid` , `channum` , `freqid` ,

`sourceid` , `callsign` , `name` , `xmltvid` , `visible`) VALUES

('$chanid', '$channum', '$channum', '$sourceid', '$xmltvid', '$name',

'$xmltvid', '1');";
    mysql_query($query);
    mysql_close($link);
  }
}
?>

=======================================================

myprog.php
=======================================================
代碼: 選擇全部
#!/usr/bin/php -q
<?
//版本 v1.8.1

$MythTV_update = true;
$XMLTV_delete = true;
$Proxy_Enable = true;

$days = 3;
$ChannelFile = 'Channels.txt';
$XMLTVFile = 'myxmltv.xml';
$mythfilldatabase = '/usr/bin/mythfilldatabase';
$mythfilldatabase_sourceid = 1;
$proxy_name = 'proxy.apol.com.tw';
$proxy_port = 8080;

//設定時區(因為後面直接用+0800表示時區,因此這邊強制設為Asia/Taipei)
date_default_timezone_set("Asia/Taipei");

if($argc < 2 || $argc > 4 || in_array($argv[1], array('--help', '-help', '-h', '-?')))
{
  echo("
這個程式是用來擷取節目資訊並輸出成 XMLTV 格式的檔案,
要執行它需要至少 1 個參數.
 
使用說明:
$argv[0] 3 [channels.txt] [myxmltv.xml]

$days\t\t表示要產生幾天份的節目資訊(預設為 3 天份)
$ChannelFile\t表示輸入的頻道列表路徑檔名
$XMLTVFile\t表示輸出的XMLTV檔案路徑檔名

====================================================
This program is used for fetch TV Program Information and export a XMLTV format file.
It need more than 1 parameter to run.

Usage:
$argv[0] 3 [channels.txt] [myxmltv.xml]

$days\t\tHow many days Program Information create(Default 3 days)
$ChannelFile\tIt means Input Channel List file name and path
$XMLTVFile\tIt means Output XMLTV format file name and path
");
  exit(0);
}

if($argc >= 2)
{
  $days = $argv[1];
}
if($argc >= 3)
{
  $ChannelFile = $argv[2];
}
if($argc == 4)
{
  $XMLTVFile = $argv[3];
}

$mythfilldatabase_args = "--file $mythfilldatabase_sourceid $days $XMLTVFile";

//錯誤檢查
if (!file_exists($ChannelFile))
{
  echo("錯誤: 輸入的頻道列表檔案 ".$ChannelFile." 不存在.\n");
  exit(0);
}
if (!is_readable($ChannelFile))
{
  echo("錯誤: 輸入的頻道列表檔案 ".$ChannelFile." 無法讀取.\n");
  exit(0);
}
if (!is_writable($XMLTVFile) && file_exists($XMLTVFile))
{
  echo("錯誤: 輸出的XMLTV檔案 ".$XMLTVFile." 無法寫入.\n");
  exit(0);
}
if(!ereg("^[0-9]*$",$days))
{
  echo("錯誤: 節目天數不是數字.\n");
  exit(0);
}

//取得頻道資訊
$ChInfo = ParseChannelInfo(readChannelInfo($ChannelFile));
for($i = 0;$i < $days;$i++)
{
  $DownloadDays .= DownloadDay($i);
  $DownloadETDays .= DownloadETDay($i);
  $DownloadDisAniDay .= DownloadDisAniDay($i);
}
//取得節目資訊
$ProgInfo = ParseProgramInfo($DownloadDays);
$ProgETInfo = ParseProgramInfo($DownloadETDays);
$ProgDisAniInfo = ParseProgramInfo($DownloadDisAniDay);
//合併兩個節目資訊表
$ProgInfo = DuplicateReplace($ProgInfo, $ProgETInfo);
$ProgInfo = DuplicateReplace($ProgInfo, $ProgDisAniInfo);
//輸出成XML檔案
writeXMLTV(ChToXMLTV($ChInfo,$ProgInfo),$XMLTVFile);

if($MythTV_update)
{
  echo($mythfilldatabase . " 執行中...\n");
  echo(system($mythfilldatabase . " " . $mythfilldatabase_args) . "\n");
}

if($XMLTV_delete)
{
  unlink($XMLTVFile);
  echo($XMLTVFile . "已刪除");
}

//=======函式列表======
function writeXMLTV($xmltv, $filename)
{
  $myFile = $filename;
  $fn = fopen($myFile, 'w');
  fwrite($fn, $xmltv);
  fclose($fn);
}

//抓取網頁
function GetHtml($URL)
{
   //http://tw.php.net/fopen(Proxy範例)

  echo($URL."下載中...");
 
  //抓取網頁開始
   if(!$Proxy_Enable)
   {
     $web = fopen($URL, 'rb');
     while(!feof ($web))
     {
         $buffer = fread($web, 8192);
         $webdata = $webdata.$buffer;
     }
     fclose($web);
    }
  else
  {
   $proxy_fp = fsockopen($proxy_name, $proxy_port);
   if (!$proxy_fp)
   {
      return false;
   }
     fputs($proxy_fp, "GET $URL HTTP/1.0\r\nHost: $proxy_name\r\n\r\n");

     while(!feof($proxy_fp))
   {
      $buffer = fread($proxy_fp,4000);
      $webdata = $webdata.$buffer;
   }
     fclose($proxy_fp);
     $webdata = substr($webdata, strpos($webdata,"\r\n\r\n")+4);
  }
  return $webdata;
}

function Big5ToUTF8($source)
{
  return iconv("big5", "UTF-8", $source);
}

//取得日期字串, 傳入: 昨日-1 今日0 明日1 後天2
function DayString($offset)
{
  $Day = mktime(0, 0, 0, date("m")  , date("d")+$offset, date("Y"));
  $DayString = date("Ymd", $Day);
  return $DayString;
}

//======下載一天節目======
//下載開眼 HTML
function DownloadDay($doff)
{
  $ActiveDay = DayString($doff);
  $a = ParseHTML(Big5ToUTF8(GetHtml(GetATURL("A",$ActiveDay))),$ActiveDay);
  $a .= ParseHTML(Big5ToUTF8(GetHtml(GetATURL("T",$ActiveDay))),$ActiveDay);
  $a .= ParseHTML(Big5ToUTF8(GetHtml(GetATURL("G",$ActiveDay))),$ActiveDay);
  $a .= ParseHTML(Big5ToUTF8(GetHtml(GetATURL("N",$ActiveDay))),$ActiveDay);
  $a .= ParseHTML(Big5ToUTF8(GetHtml(GetATURL("D",$ActiveDay))),$ActiveDay);
  $a .= ParseHTML(Big5ToUTF8(GetHtml(GetATURL("M",$ActiveDay))),$ActiveDay);
  $a .= ParseHTML(Big5ToUTF8(GetHtml(GetATURL("L",$ActiveDay))),$ActiveDay);
  $a .= ParseHTML(Big5ToUTF8(GetHtml(GetATURL("C",$ActiveDay))),$ActiveDay);
  $a .= ParseHTML(Big5ToUTF8(GetHtml(GetATURL("E",$ActiveDay))),$ActiveDay);
  $a .= ParseHTML(Big5ToUTF8(GetHtml(GetATURL("J",$ActiveDay))),$ActiveDay);
  $a .= ParseHTML(Big5ToUTF8(GetHtml(GetATURL("S",$ActiveDay))),$ActiveDay);
  $a .= ParseHTML(Big5ToUTF8(GetHtml(GetATURL("V",$ActiveDay))),$ActiveDay);
  $a .= ParseHTML(Big5ToUTF8(GetHtml(GetATURL("F",$ActiveDay))),$ActiveDay);
  $a .= ParseHTML(Big5ToUTF8(GetHtml(GetATURL("R",$ActiveDay))),$ActiveDay);
 
  return $a;
}
//下載 Discovery 和 動物星球 HTML
function DownloadDisAniDay($doff)
{
  $ActiveDay = DayString($doff);
  $a  = ParseDisAniHTML(GetHtml(GetDiscoveryURL($ActiveDay)),$doff,"DISCOVERY");
  $a .= ParseDisAniHTML(GetHtml(GetAnimalplanetURL($ActiveDay)),$doff,"動物星球頻道");
 
  return $a;
}
//下載 ETTODAY HTML
function DownloadETDay($doff)
{
//目前僅下載 4 個電影台(東森電影、東森洋片、HBO、Cinemax)和 1 個卡通台(東森幼幼台)
//因為僅這 5 台有節目介紹,其他的不如開眼詳盡
  $ActiveDay = DayString($doff);
  $a = ParseETHTML(Big5ToUTF8(GetHtml(GetETURL("62",$ActiveDay))),$ActiveDay,"東森電影台");
  $a .= ParseETHTML(Big5ToUTF8(GetHtml(GetETURL("66",$ActiveDay))),$ActiveDay,"東森洋片台");
  $a .= ParseETHTML(Big5ToUTF8(GetHtml(GetETURL("65",$ActiveDay))),$ActiveDay,"HBO電影台");
  $a .= ParseETHTML(Big5ToUTF8(GetHtml(GetETURL("71",$ActiveDay))),$ActiveDay,"Cinemax");
  $a .= ParseETHTML(Big5ToUTF8(GetHtml(GetETURL("25",$ActiveDay))),$ActiveDay,"東森幼幼台");

  return $a;
}

//======解析不同網站 URL======
//開眼 URL
function GetATURL($CHcode, $strDay)
{
  $URL = "http://tv.atmovies.com.tw/tv/attv.asp?action=todaytime&tvfile=".$strDay.$CHcode;  //開眼節目表下載
  return $URL;
}
//Discovery URL
function GetDiscoveryURL($strDay)
{
  $URL = "http://discoverychannel.com.tw/_listings/index.shtml?schedule_date=".$strDay;
  return $URL;
}
//動物星球 URL
function GetAnimalplanetURL($strDay)
{
  $URL = "http://www.animalplanet.com.tw/_listings/index.shtml?schedule_date=".$strDay;
  return $URL;
}
//ETTODAY URL
function GetETURL($CH, $strDay)
{
  $URL = "http://tgc.ettoday.com/index.htm?c_date=".$strDay."&sta_id=".$CH;
  return $URL;
}
       
//======解析不同網站 HTML======
//解析 Discovery 和 動物星球 HTML
function ParseDisAniHTML($HTML, $doff, $ChName)
{
  echo("HTML解析中...\n");
  preg_match_all('/tvtime">([0-9]{2}:[0-9]{2}) -<\/td>[\r|\n|\t| ]*.*[\r|\n|\t| ].*<b>(.*)<\/b>(.*)<\/a>.*[\r|\n|\t| ]*.*[\r|\n|\t| ]*.*[\r|\n|\t| ]*.*[\r|\n|\t| ]*.*[\r|\n|\t| ]*.*[\r|\n|\t| ]*.*[\r|\n|\t| ]*.*[\r|\n|\t| ]*.*row[0-9]{1,2}">(.*)<\/span>/',$HTML,$matches);
  for($i = 0;$i < count($matches[0]);$i++)
  {
//解決跨日節目的bug(Discovery節目表是今天6:00~隔天5:00)
    ereg('([0-9]{2}):([0-9]{2})', $matches[1][$i], $Program_Time_temp);
    if($Program_Time_temp[1] < 6)
      $ActiveDay = DayString($doff + 1);
    else
      $ActiveDay = DayString($doff);
    $Program_Time = $ActiveDay." ".$matches[1][$i];
    $StrRet = $StrRet.$ChName."\t".$Program_Time."\t";
    $ProgramClass = "";
    $Program = trim($matches[2][$i]);
    $ProgramSubInfo = substr(trim($matches[3][$i]),2);
    $ProgramDesc = trim($matches[4][$i]);
    if($ProgramDesc == "No Programme Details")
      $ProgramDesc = "";
    $StrRet = $StrRet.$ProgramClass."\t".$Program."\t".$ProgramSubInfo."\t".$ProgramDesc;
    $StrRet = $StrRet."\n";
  }
  return $StrRet;
}
//解析 ETTODAY HTML
function ParseETHTML($HTML,$ActiveDay,$ChName)
{
  echo("HTML解析中...\n");
  preg_match_all('/<td width="17%".*([0-9]{2}:[0-9]{2})<\/font><\/td>[\r\n\t| ]*<td width="49%".*top">(.*)<\/td>[\r\n\t| ]*[\s][\r\n\t| ]*.*[\r\n\t| ]*<td width="27%".*top">(.*)&nbsp;<\/td>/',$HTML,$matches);
  for($i = 0;$i < count($matches[0]);$i++)
  {
    ereg('([0-9]{2}):([0-9]{2})', $matches[1][$i], $Program_Time_Temp);
    $Program_Time = $ActiveDay." ".$Program_Time_Temp[1].":".$Program_Time_Temp[2];
    $StrRet = $StrRet.$ChName."\t".$Program_Time."\t";
    $ProgramClass = "";
    $Program = trim($matches[2][$i]);
    if(strpos($Program,'<br>') > 0)
    {
      preg_match("/<b>(.*)<\/b>/",$Program,$match);
      $ProgramSubInfo = $match[1];
      preg_match("/<font class='sub-c'>(.*)<\/font>/",$Program,$match);
      $ProgramDesc = $match[1];
      $Program = substr($Program,0,strpos($Program,'<br>'));
    }
    if(trim($matches[3][$i]) != '')
      $ProgramSubInfo = $ProgramSubInfo."(".trim($matches[3][$i]).")";
    $StrRet = $StrRet.$ProgramClass."\t".$Program."\t".$ProgramSubInfo."\t".$ProgramDesc;
    $StrRet = $StrRet."\n";
  }
  return $StrRet;
}
//解析開眼 HTML
function ParseHTML($HTML,$ActiveDay)
{
  echo("HTML解析中...\n");
  $ChArray = split('<a name="CH', $HTML);     //先依CH分割
 
  foreach($ChArray as $value)
  {
    //下面解析出頻道名稱,HTML原始碼如下:
//      <a name="CH06"></a> &nbsp;&nbsp;
//               <a class=at15b target="_self" href="/tv/attv.asp?action=channeltime&tvfile=20070118CH06">民視綜合台</a>
//
//   <table border="1" cellspacing="1" cellpadding="2" class=at9 width="90%" align="center" bordercolor=cddcaa>
    if(preg_match('/^[0-9]{2}"><\/a> &nbsp;&nbsp;[ |\r|\n]*[ |\t]*<a class=at15b.*>(.*)<\/a>/',$value,$matches))
    {
      $ChName = $matches[1];
    }

    //下面解析出節目、時間...等資訊,HTML原始碼如下:
//            <tr>
//            <td align="center" class=at9>03:00</td>
//            <td class=at9 width=80%><font color=ffffff> 
//           
//           
//            <a target="_self" href="http://app.atmovies.com.tw/tv/attv.cfm?action=tvdata&tvtimeid=ACH53200701310300&year=2007&month=1&day=31&channel_id=CH53">
//            <font class=at11>美食家家樂<font color=ffffff>H</font></font></a>N<font color=606060> </font>dP8</font>
//            </td>
    //或是
//            <tr>
//            <td align="center" class=at9>23:15</td>
//            <td class=at9 width=80%><font color=ffffff> <font color=2A5C8A>【大愛劇場】</font>
//           
//           
//            <a target="_self" href="http://app.atmovies.com.tw/tv/attv.cfm?action=tvdata&tvtimeid=RCH75200701302315&year=2007&month=1&day=31&channel_id=CH75">
//            <font class=at11>美麗晨曦<font color=ffffff>P</font></font></a>D<font color=606060> </font>PH99</font>
//            </td>
//
    //或是
//            <tr>
//            <td align="center" class=at9>04:00</td>
//            <td class=at9 width=80%><font color=ffffff> 
//           
//            <font color=303033>收播</font>N<font color=606060> </font>PD10</font>
//            </td>

    //preg_match($RegEx,$str,$matches)
    //$matches會是[],[0]表示符合的全部內容,[1~]以後的表示符合以()分隔的特定群組
    //preg_match_all($RegEx,$str,$matches)
    //$matches會是[][],
    //[0][0]表示找到第 1 個的符合的全部內容,[1~N][0]以後的表示找到第 1~N 個的符合以()分隔的特定群組,
    //[0][1]表示找到第 2 個的符合的全部內容,[1~N][1]以後的表示找到第 1~N 個的符合以()分隔的特定群組,   
    //[0][2]表示找到第 3 個的符合的全部內容,[1~N][2]以後的表示找到第 1~N 個的符合以()分隔的特定群組
    //.....
   
//    if(preg_match('/<td align="center" class=at9/',$value,$matches))
   
    preg_match_all('/<td\s[^>]+>(\d{2}:\d{2})<\/td>[\s]+<td\s[^>]+>.+(?:<font color=2A5C8A>(.+)<\/font>| )[\w\W\s]+?<font class=at11>(.+?)<font .+?<font color=606060>(.*?)<\/font>[\w\W\s]+?<\/td>/',$value,$matches);
//解決跨日節目的重複bug(放在迴圈前判斷,可以減少在迴圈中判斷的次數)
    $Program_Time = $matches[1][0];   //只找第一個節目
    ereg('([0-9]{2}):([0-9]{2})', $matches[1][0], $Program_Time);
    if($Program_Time[1] > 12)
      $i = 1;
    else
      $i = 0;
    for(;$i < count($matches[0]);$i++)
    {
        $Program_Time = $ActiveDay." ".$matches[1][$i];
        $StrRet = $StrRet.$ChName."\t".$Program_Time."\t";
        $Program = $matches[2][$i];
//上patch,解決「【華視威秀春節電影院】</font> <font color=ff0000>☆」這樣的bug
        if(strpos($Program,'</font>') > 0)
          $Program = substr($Program, 0, strpos($Program,'</font>'));

        $ProgramClass = trim($Program);
//判斷有沒有節目,如果沒有,表示$ProgramClass是「收播」,則把「收播」轉成節目名稱
        $Program = trim($matches[3][$i]);
        if($Program == "")
        {
          $Program = $ProgramClass;
          $ProgramClass = "";
        }
       
        $ProgramSubInfo = trim($matches[4][$i]);
        $StrRet = $StrRet.$ProgramClass."\t".$Program."\t".$ProgramSubInfo."\t";
        $StrRet = $StrRet."\n";
    }
  }
  return $StrRet;
}

//======頻道表處理======
//讀取頻道表
function readChannelInfo($filename)
{
  echo("頻道表讀取中...");
  $fn = fopen($filename, r);
  while(!feof ($fn)) {
    $buffer = fgets($fn, 4096);
    $buffer = trim($buffer);
    $channeldata = $channeldata.$buffer."\n";
  }   
  fclose($fn);
  return $channeldata;
}
//解析頻道表
function ParseChannelInfo($channelinfo)
{
  echo("頻道表解析中...\n");
  //目前格式
  //6,民視,FTV,民視綜合台
  //頻道編號,MythTV頻道ID,頻道簡稱,有線電視頻道名稱,開眼頻道名稱
  $channelinfo = Big5ToUTF8($channelinfo);
  $linearray = split("\n", $channelinfo);
  for($i = 0;$i < count($linearray);$i++)
  {
    if($linearray[$i] != "")                //去除空白
    {
      $line = split(',', $linearray[$i]);
      $ChannelInfo[$i][0] = $line[2];
      $ChannelInfo[$i][1] = $line[4];
      $ChannelInfo[$i][2] = $line[0];
    }   
  }
  return $ChannelInfo;   
}

//======節目表處理======
//解析節目資訊
function ParseProgramInfo($programinfo)
{
  echo("節目表解析中...\n");
  //目前格式
  //東森戲劇台      20070129 13:00  衝吧!阿達
  //開眼頻道名稱   (\t)日期(空格)時間   (\t)節目類型   (\t)節目名稱   (\t)節目子訊息   (\t)節目介紹
  //不用轉UTF8,已經轉過了
  $linearray = split("\n", $programinfo);
  for($i = 0;$i < count($linearray);$i++)
  {
    if($linearray[$i] != "")                //去除空白
    {
      $line = split("\t", $linearray[$i]);
      $ChannelName = $line[0];
      $ProgramTime = $line[1];
      $ProgramClass = $line[2];
      $ProgramName = $line[3];
      $ProgramSubInfo = $line[4];
      $ProgramDesc = $line[5];

      $count = count($ProgramInfo[$ChannelName]);
      $ProgramInfo[$ChannelName][$count][0] = $ProgramTime;
      $ProgramInfo[$ChannelName][$count][1] = $ProgramClass;
      $ProgramInfo[$ChannelName][$count][2] = $ProgramName;
      $ProgramInfo[$ChannelName][$count][3] = $ProgramSubInfo;
      $ProgramInfo[$ChannelName][$count][4] = $ProgramDesc;
    }   
  }
  return $ProgramInfo;   
}

//合併節目資訊表
//比較兩張ProgramInfo,把重複的以後面的覆蓋前面的
function DuplicateReplace($ProgramInfoA, $ProgramInfoB)
{
  foreach ($ProgramInfoB as $k => $v)
  {
    if(isset($ProgramInfoA[$k]))
      $ProgramInfoA[$k] = $ProgramInfoB[$k];
  }
  return $ProgramInfoA;
}

//======產生XMLTV======
function ChToXMLTV($ChannelInfo,$ProgramInfo)
{
  echo("XMLTV產生中...\n");
  $doc = new DomDocument('1.0', 'UTF-8');
  $tv = $doc->createElement('tv');
  $tv->setAttribute( 'generator-info-name','my_xml_tv');
  $doc->appendChild($tv);
  //$out = '<'.'?xml version="1.0" encoding="UTF-8"?.'>'."\n" .
  //       '<!DOCTYPE tv SYSTEM "xmltv.dtd">'."\n" ."\n" .
  //       '<tv generator-info-name="my_xml_tv">'."\n";
  for($i = 0;$i < count($ChannelInfo);$i++)
  {
    $ChannelID = $ChannelInfo[$i][0];
    $ChannelName = $ChannelInfo[$i][1];
    if(!ereg("^-$", $ChannelID))     //當發現頻道ID是「-」時跳過
    {
      $ch = $doc->createElement('channel');
      $ch->setAttribute('id', $ChannelID);
      $disp = $doc->createElement('display-name');
      $disp->setAttribute('lang', 'ZH_TW');
      $disp->appendChild($doc->createTextNode($ChannelName));
      $ch->appendChild($disp);
      $tv->appendChild($ch);
      //$out .=
      //    '<channel id="'. $ChannelID .'">
      //        <display-name lang="zh_tw">'. $ChannelName .'</display-name>
      //    </channel>'."\n";
    }
  }
  for($i = 0;$i < count($ChannelInfo);$i++)
  {
    $ChannelID = $ChannelInfo[$i][0];
    $ChannelName = $ChannelInfo[$i][1];
    if(!($ChannelID == "-"))
    {
      for($j = 0;$j < count($ProgramInfo[$ChannelName]);$j++)
      {
        $pg = $doc->createElement('programme');
        $pg->setAttribute('channel', $ChannelID);
       
        ereg('(^[0-9]{4})([0-9]{2})([0-9]{2}) ([0-9]{2}):([0-9]{2})',$ProgramInfo[$ChannelName][$j][0],$pgtime);
        $start = mktime($pgtime[4],$pgtime[5],0,$pgtime[2],$pgtime[3],$pgtime[1]);
        $start_str = date('YmdHis',$start) . ' +0800';       
        $pg->setAttribute('start', $start_str);
       
        $title = $doc->createElement('title');
        $title->setAttribute('lang', 'ZH_TW');
        $title->appendChild($doc->createTextNode($ProgramInfo[$ChannelName][$j][2]));
        $pg->appendChild($title);

        $subtitle = $doc->createElement('sub-title');
        $subtitle->setAttribute('lang', 'ZH_TW');
        $subtitle->appendChild($doc->createTextNode($ProgramInfo[$ChannelName][$j][3]));
        $pg->appendChild($subtitle);

        if(strpos($ProgramInfo[$ChannelName][$j][3],'重播') > 0 || strpos($ProgramInfo[$ChannelName][$j][3],'(重)') >0)
        {
                $repeat = $doc->createElement('previously-shown');
                $repeat->setAttribute('channel', $ChannelName);
                $pg->appendChild($repeat);
        }
       
        $desc = $doc->createElement('desc');
        $desc->setAttribute('lang', 'ZH_TW');
        $desc->appendChild($doc->createTextNode($ProgramInfo[$ChannelName][$j][4]));
        $pg->appendChild($desc);
       
        $tv->appendChild($pg);
        //$out.= '<programme channel="'.$ChannelID. '" start="'.$ProgramInfo[$ChannelID][$j][0]. '">
        //    <title lang="ZH_TW">'. $this->toTitle($description) .'</title>
        //    <sub-title lang="ZH_TW">'. $this->toTitle($subtitle) .'</sub-title>
        //      <desc lang="ZH_TW">'. $description .'</desc>
        //    </programme>'."\n";
      }
    }
  }
 
  $doc->formatOutput = true;
  //$out .= "</tv>\n";
  return $doc->saveXML();
}

//============================================================
//下載post的範例
//抓取網頁(ETTODAY)(這邊的$CH同頻道編號)
//function GetETHtml($CH, $strDay)
//{
//  $host = "tgc.ettoday.com";
//  $actionPage = "/index.htm";
//  $postData = "kind_id=10&sta_id=$CH&c_date=$strDay&c_date=0";
//  echo("頻道編號 $CH 在 $strDay 從 ETTODAY 下載中...");
//  $webdata = doPost($actionPage,$postData,$host);
//  return $webdata;
//}
//
////Function來源:
////http://tw.php.net/manual/tw/function.fsockopen.php
//function doPost($uri,$postdata,$host)
//{
//  $da = fsockopen($host, 80, $errno, $errstr);
//  if (!$da)
//  {
//    echo "$errstr ($errno)<br/>\n";
//    echo $da;
//  }
//  else
//  {
//    $salida ="POST $uri  HTTP/1.1\r\n";
//    $salida.="Host: $host\r\n";
//    $salida.="User-Agent: PHP Script\r\n";
//    $salida.="Content-Type: application/x-www-form-urlencoded\r\n";
//    $salida.="Content-Length: ".strlen($postdata)."\r\n";
//    $salida.="Connection: close\r\n\r\n";
//    $salida.=$postdata;
//    fwrite($da, $salida);
//    while (!feof($da))
//      $response.=fgets($da, 128);
//    fclose($da);
//    return $response;
//  }//else
//}//function-doPost
//============================================================
?>

=======================================================
Channels.txt
=======================================================
代碼: 選擇全部
5,77250,CNN,CNN,-
6,83250,FTV,民視,民視綜合台
7,175250,BLTV,人間,人間衛視
8,181250,TTV,台視,台灣電視台
9,187250,DAAI,大愛,大愛電視台
10,193250,CTV,中視,中視數位台
11,199250,CTS_IQ,華視教育頻道,華視教育頻道
12,205250,CTS,華視,華視 CTS
13,211250,PTS,公視,公共電視 PTS
15,127250,GOODTV,好消息,好消息Good TV
16,133250,ITV,原住民語頻道,原住民頻道
17,139250,HTV,客語頻道,客家電視 HTV
18,145250,NGC,國家地理頻道,國家地理頻道
19,151250,DISCOVERY,Discovery,DISCOVERY
20,157250,ASIATRAVEL,亞洲旅遊台,-
21,163250,TNL,旅遊生活頻道,旅遊生活頻道
22,169250,ANIMAL,動物星球,動物星球頻道
23,217250,DISNEY,迪士尼頻道,迪士尼頻道
24,223250,MOMO,MOMO親子台,MOMO親子台
25,229250,ET_YOYO,東森幼幼台,東森幼幼台
26,235250,VL,緯來綜合,緯來綜合台
27,241250,GTV_1,GTV第1台,GTV第一台
28,247250,GTV,GTV綜合台,GTV綜合台
29,253250,SET_TW,三立台灣台,三立台灣台
30,259250,SET_CITY,三立都會台,三立都會台
31,265250,STAR_C,衛視中文台,衛視中文台
32,271250,ET_TV,東森綜合台,東森綜合台
33,277250,STV,超視,超視
36,295250,CTI,中天綜合台,中天綜合台
37,301250,AZIOTV,東風衛視,東風衛視
38,307250,MUCHTV,MUCH TV,MUCH-TV
39,313250,CTI_G,中天娛樂台,中天娛樂台
40,319250,ET_DRAMA,東森戲劇台,東森戲劇台
41,325250,GTV_D,GTV戲劇台,GTV戲劇台
42,331250,TVBS-G,TVBS-G,TVBS-G
43,337250,VL_D,緯來戲劇台,緯來戲劇台
44,343250,TOPTV,高點電視台,高點電視台
45,349250,SUPERX,東森娛樂台,東森娛樂台
46,355250,STV_2,超視育樂台,超視娛樂台
50,379250,ERA_N,年代電視,ERA NEWS
51,385250,ET_NEWS,東森新聞台,東森新聞台
52,391250,CTI_N,中天新聞台,中天新聞台
53,397250,FTV_N,民視新聞台,民視新聞台
54,403250,SET_N,三立新聞台,三立SETN
55,409250,TVBS-N,TVBS-N,TVBS-N
56,415250,TVBS,TVBS,TVBS
57,421250,ET_NEWS_S,東森新聞S台,東森新聞S台
58,427250,USTV_N,非凡新聞,非凡新聞台
61,445250,STAR_M,衛視電影台,衛視電影台
62,451250,ET_MOVIE,東森電影台,東森電影台
63,457250,VL_M,緯來電影台,緯來電影台
64,463250,LSTIME,LS TIME電影台,LS TIME電影台
65,469250,HBO,HBO,HBO電影台
66,475250,ET_EMOVIE,東森洋片台,東森洋片台
67,481250,AXN,AXN,AXN動作台
68,487250,HOLLYWOOD,Hollywood,好萊塢電影台
69,493250,STAR_EM,衛視西片台,STAR MOVIES
70,499250,VL_W,緯來育樂台,緯來育樂台
71,505250,CINEMAX,Cinemax,Cinemax
72,511250,VL_S,緯來體育台,緯來體育台
73,517250,ESPN,ESPN,ESPN
74,523250,STAR_S,衛視體育台,衛視體育台
75,529250,CHV,【V】,Channel [V]
76,535250,MTV,MTV,MTV
78,547250,ANIMAX,ANIMAX,ANIMAX
81,565250,TW_MUSIC,台音,台灣音樂台
82,571250,VL_J,緯來日本台,緯來日本台
83,577250,JET,JET,JET日本台
84,583250,GOLDSUN,國興衛視,國興日本台
85,589250,PILI,霹靂台灣台,霹靂台灣台
86,595250,GTV_K,GTV娛樂K台,娛樂K台
88,607250,USTV,非凡商業,非凡商業台
89,613250,HANGSENG,恆生財經,恆生財經台
92,631250,CHINESE_C,華人商業,華人商業台
95,91250,CARTOON,Cartoon Network,卡通頻道
97,103250,ZCH,Z,Z頻道
110,709250,NHK,NHK,NHK世界台

=======================================================
最後由 ycfu 於 週一 2月 26, 2007 8:32 am 編輯,總共編輯了 2 次。
ycfu
可愛的小學生
可愛的小學生
 
文章: 28
註冊時間: 週一 4月 03, 2006 1:34 am

文章xfr » 週四 2月 08, 2007 9:09 pm

其實我稍微改了一下用在其他國家的程式,用Perl也寫出了tv_grab_tw,爲了減輕大家的負擔,我把抓到的一週之內的節目表,以xmltv格式放在

http://surg15.mc.ntu.edu.tw/xmltv/tw.xml

有興趣的可以取抓下來看一看。
目前我是每天半夜左右會更新...
有興趣的可以設 cron job 在半夜三點左右來 wget...:)
xfr
可愛的小學生
可愛的小學生
 
文章: 1
註冊時間: 週四 2月 08, 2007 8:59 pm

文章malego » 週一 4月 21, 2008 12:30 pm

感謝 ycfu 大大的文章

搞了半天 終於讓我的電視卡透過mythtv 跑起來了

但是遇到兩個問題

1.聲音不同步的問題還是沒能解決

2.如何從其他電腦登入mythtv server 來看電視??

請問有人知道怎處理嗎?有試過用 totem 但是連不上去 :p
malego
 

文章ycfu » 週四 4月 24, 2008 10:06 pm

能夠對 malego 有幫助,我也感到很高興。

1. 我這邊沒有遇到聲音不同步的問題,我想你可以先用xawtv,甚至是mplayer,先試試看播放時電視時聲音會不會有同步的問題,如果沒問題,可以把電視播放的部份排除,鎖定問題在mythtv上。
另外可以查看電視播放時的系統負載,因為用mythtv時,他時光平移是靠realtime錄影的方式達成的,沒用硬體壓縮卡,對系統有不小的負載量。

2. 遠端連到mythtv看電視,我本來想try,但是新買的電視卡太新了,Linux還不支援,這部份就先delay著~
不過就我所知道的,mythtv主要分為:
mythtv-backend
mythfrontend

這兩個部份,其他什麼mythvideo、mythdvd之類的,全部都是module,單就看電視這件事情來說,可以不用管他們。

原則上,插電視卡的電腦「必須」是mythtv-backend,因此只要有電視卡的電腦,都把它們設成mythtv-backend。
而在執行mythfrontend時,第一次執行他都會自動呼叫mythtv-setup,這個設定程式就是用來設定mythfrontend用的,裡面我們可以指定mythtv-backend有哪幾個IP、哪幾張電視卡...等。

最後總結:
要從其他電腦登入mythtv server看電視,原則上就是再其他電腦上安裝mythfrontend,然後用mythtv-setup設定,一切順利的話,他就能成為前端播放電視了。

至於totem之類的播放器要播放,可能需要找stream server相關的資訊,mythtv有module可以做stream server,透過它搭配Windows Media Player或mplayer可以用stream看電視,不過這部份我沒try成功。

PS: 前面為了減少說明的複雜,沒有提到SQL Server,mythtv所有的設定都放SQL Server中,所以mythtv-setup設定時,也會問你SQL Server的IP、帳號、密碼。加入SQL後整個架構可以類似如下:

mythfrontend:192.168.1.1, 192.168.1.2, 192.168.1.3
mythtv-backend(有電視卡的電腦):192.168.1.1
MySQL Server:192.168.1.1

以上架構,192.168.1.1可以看作伺服器,上面插個2、3張電視卡都可以;192.168.1.2、192.168.1.3則是純粹的多媒體終端機,他們只需要網路線、電腦、電源線,就可以直接看電視了。
ycfu
可愛的小學生
可愛的小學生
 
文章: 28
註冊時間: 週一 4月 03, 2006 1:34 am

文章malego » 週五 4月 25, 2008 9:46 am

感謝ycfu大大的回應:
我回報一下我的狀況

1.xawtv跑起來正常 是跑mythtv時才會 DELAY (我再去查一下系統負載狀況)

2.我的環境是

mythfrontend:192.168.1.1, 192.168.1.2
mythtv-backend(有電視卡的電腦):192.168.1.1
MySQL Server:192.168.1.1

192.168.1.1 本機跑都正常
192.168.1.2 就是連不進去,顯示訊息是連不到資料庫,為此我還特地去把mysql鎖在local的選項關閉,後來也看得到server那台的3306 port有開 但仍失敗
google了很久 都沒有相關的文章可看 不知道還有哪些方向可以try出問題在哪??
malego
 

文章lancas » 週五 6月 06, 2008 1:18 am

您好,請問我照著設定作,但是到了執行 /usr/local/bin/myprog.php 3 /usr/local/bin/Channels.txt /usr/local/bin/myxmltv.xml的地方,剛開始還會一個一個檔去抓,但跑到一半就開始回應一直跑不完的兩行字如下,
Warning: feof(): supplied argument is not a valid stream resource in /usr/local/bin/myprog.php on line 134

Warning: fread(): supplied argument is not a valid stream resource in /usr/local/bin/myprog.php on line 136
請問是何原因?
我看了這兩行字是

while(!feof ($web))
{
$buffer = fread($web, 8192);
麻煩您了,謝謝,!
lancas
可愛的小學生
可愛的小學生
 
文章: 1
註冊時間: 週五 6月 06, 2008 1:11 am

文章ycfu » 週一 8月 11, 2008 2:14 am

不好意思~
好陣子沒更新這程式了,目前幾個節目表的網頁都已更新,程式需要修改,
我會找時間更新程式,感謝你的提問。
ycfu
可愛的小學生
可愛的小學生
 
文章: 28
註冊時間: 週一 4月 03, 2006 1:34 am


回到 share

誰在線上

正在瀏覽這個版面的使用者:沒有註冊會員 和 1 位訪客