作者TKyo.bbs@cpu.tfcis.org (暗黑貴公子) 看板: plan
標題[更新]即時查詢奇摩電影
時間動力核心 (2005/01/19 Wed 19:29:06) Updated: 2006/04/17
更新說明
1.此次更新修正事宜
(1) 掉字的 Bug (例 : 北極特快車/台北北區)
(2) 連線當掉的 Bug (例 : 功夫/台北東區)
2.此次更新部份
(1) ymovie.c:CGI_COMMAND3, 補上 \n\n
(2) ymovie.c:
write_file()
http_conn()
(2) 的部份由於更新幅度相當大, 所以請整個 function 更新即可
簡介 :
這隻小程式與原先精華區的 "奇摩電影" 功能大不相同
1.整合 xover 介面, 使用 pans 分頁介面
2.透過另一隻程式 (ymovie-open.c) 建立之電影資料檔
再即時查詢其電影的 "放映地區" 及 "放映時刻"
3.由於整合 xover 介面, 所以要新增/修改的地方很多 :-)
紀錄 :
1.2004/12/14 完成
2.2004/12/14 - 2004/12/20 實際上線測試
3.2004/12/26 - 更新 : ymovie.c:write_file()
更新 : ymovie.c:http_conn()
By CSZone Kyo 2004/12/24
: src/include/global.h : 適當位置加入
+ #ifdef HAVE_NETTOOL
+ #define FN_YMOVIE "etc/ymovie.dat" /* 奇摩電影檔 */
+ #endif
: src/include/modes.h : 假設 XO_ZONE 最後為精華區, 需跟 xz[] 同步
#define XZ_GEM (XO_ZONE + 13) /* 精華區 */
+ #ifdef HAVE_NETTOOL
+ #define XZ_YMOVIE (XO_ZONE + 14) /* 查詢電影 */
+ #endif
: src/include/struct.h
#define FILM_GEM 12 /* help message */
+ #ifdef HAVE_NETTOOL
+ #define FILM_YMOVIE 13
+ #endif
/* 適當位置加入 */
+ #ifdef HAVE_NETTOOL
+ #define MOVIE_NOW 0x01
+ #define MOVIE_DOWN 0x02
+ #define MOVIE_NORMAL 0x10
+ typedef struct
+ {
+ int mv_no; /* 電影編號 */
+ int playmode; /* 目前放映模式 */
+ char mv_title[30]; /* 電影名稱 */
+ char area_desc[128]; /* 放映地區 (以 ',' 分隔之集合字串) */
+ } YMOVIE;
+ #endif
: src/include/theme.h : 適當位置加入
+ #ifdef HAVE_NETTOOL
+ /* ----------------------------------------------------- */
+ /* 奇摩電影查詢顏色 */
+ /* ----------------------------------------------------- */
+ #define COLOR_NOW "\033[1;31m" /* 院線片 */
+ #define COLOR_DOWN "\033[1;32m" /* 將下檔片 */
+ #define COLOR_OTHER "\033[0;37m" /* 其他 */
+ #define CHAR_NOW "★"
+ #define CHAR_DOWN "▼"
+ #define CHAR_OTHER " "
+ #define NECKER_YMOVIE "[←]主選單 [→]電影查詢 [↑↓]選擇 [h]說明\n" \
+ COLOR3 " 編號 電影名稱 放映地區%*s" \
+ " \033[m"
+ #define FEETER_YMOVIE \
+ COLOR1 " 奇摩電影 " COLOR2 " (ENTER)電影查詢 (↑/↓)上下頁 (←)離開" \
+ " \033[m"
+ #endif
: etc/help/ym/ymovie.hlp 新增此目錄及檔案
☆【電影查詢操作說明】☆
【基本指令】─────────────────────────────
(Enter) 電影查詢
(h) 說明
: src/maple/xover.c : xz[]
- {NULL, NULL, M_GEM, FEETER_GEM} /* XZ_GEM */
+ {NULL, NULL, M_GEM, FEETER_GEM}, /* XZ_GEM */
+ {NULL, NULL, M_XMODE, FEETER_YMOVIE} /* XZ_YMOVIE */
: src/maple/menu.c : 適當選單
+ "bin/ymovie.so:ym_main", 0, - M_XMODE,
+ "Movie ♂ 奇摩電影 ♀",
:src/so/ymovie.c 新增這隻程式
/*-------------------------------------------------------*/
/* ymovie.c ( NTHU CS MapleBBS Ver 3.10 ) */
/*-------------------------------------------------------*/
/* target : Yahoo/奇摩電影查詢 */
/* author : kyo.bbs@cszone.org */
/* create : 04/12/14 */
/* update : / / */
/*-------------------------------------------------------*/
#if 0
1.本瀏覽程式需配合 bin/ymovie-open 去抓取資料並建立電影檔
2.根據電影檔資訊即時抓取該部電影放映時段及地點
3.本程式並不需要安裝 lynx
#endif
#include "bbs.h"
#ifdef HAVE_NETTOOL
#define HTTP_PORT 80
#define SERVER_YMOVIE "tw.movie.yahoo.com"
#define CGI_HTTP_TAG "http://"
#define CGI_COMMAND "GET " CGI_HTTP_TAG SERVER_YMOVIE \
"/mv_search.html?mname="
#define CGI_COMMAND2 "&area="
#define CGI_COMMAND3 " HTTP/1.0\n\n"
#define BR_PLAY "\033[m\n \033[1;36m"
#define BR_COLS 9
/* 注意事項 */
/* ------------------------------------------------------ */
/* 1.pans 分頁介面用, 表示一頁要顯示多少筆資料 */
/* 2.勿設定太多筆, 顯示超過畫面會當機 */
/* 3.MENU_PAGE 新增或減少時, menu_sub 也得相對新增或減少 */
/* ------------------------------------------------------ */
#define MENU_PAGE 10
extern XZ xz[];
extern char xo_pool[];
static void
url_encode(dst, src) /* URL encoding */
uschar *dst; /* Thor.990331: 要 src 的三倍空間 */
uschar *src;
{
for (; *src; src++)
{
if (*src == ' ')
*dst++ = '+';
else if (is_alnum(*src))
*dst++ = *src;
else
{
/* 原使用 register cc 於 W_ALL 會有警告, 故改成 int */
int cc = *src;
*dst++ = '%';
*dst++ = radix32[cc >> 4];
*dst++ = radix32[cc & 0xf];
}
}
*dst = '\0';
}
static int
write_file(sockfd, fp, ftmp)
int sockfd;
FILE *fp;
char *ftmp;
{
char pool[2048], buf_play[512] = {0};
int cc, i, j, k, fsize;
char *xhead, *fimage;
int show, start_show, bufplay;
char *start_str[] =
{
"<td align=\042center\042 class=\042sbody\042>",
"<td class=\042time\042>",
"<td class=\042sbody\042>",
NULL
};
char *stop_str[] =
{
"</td>",
"</td>",
"</a>",
NULL
};
char *insert_str[] =
{
"\033[1;37m分 級:\033[35m",
"\033[1;37m放映時間:\033[36m",
"\033[1;37m戲院名稱:\033[31m",
NULL
};
FILE *fpw;
/* Load HTML Page into memory (fimage) */
fpw = fopen(ftmp, "w");
while ((cc = read(sockfd, &pool, sizeof(pool))) > 0)
fwrite(&pool, cc, 1, fpw);
fclose(fpw);
close(sockfd);
fimage = f_map(ftmp, &fsize);
if (fimage == (char *) -1)
{
fclose(fp);
vmsg("目前無法開啟電影索引檔");
return -1;
}
/* parser HTML from memory (fimage) */
show = 1;
bufplay = 0;
start_show = 0;
i = 0;
for (xhead = fimage; *xhead; xhead++)
{
if (!start_show)
{
k = strlen(start_str[i]) ;
if (!str_ncmp(xhead, start_str[i], k))
{
start_show = 1;
fputs(insert_str[i], fp);
xhead += k;
if (i == 1)
{
bufplay = 1;
j = 0;
}
}
}
else if (start_show)
{
k = strlen(stop_str[i]);
if (!str_ncmp(xhead, stop_str[i], k))
{
start_show = 0;
switch (i)
{
case 0:
case 2:
fputs("\033[m\n", fp);
fputs("\033[1;34m" MSG_SEPERATOR "\033[m\n", fp);
break;
case 1:
{
char *phead, *pitem;
int plen, pcount;
bufplay = 0;
pcount = 0;
phead = pitem = buf_play;
while (pitem = strstr(phead, " "))
{
plen = pitem - phead;
if (plen <= 7) /* 一般/加註時刻 */
{
*pitem = '\0';
if (pcount == (BR_COLS + 1)) /* 到底時立刻換行 */
{
fputs(BR_PLAY, fp);
pcount = 0;
}
fputs(phead, fp);
while (plen < 7 && (pcount != BR_COLS)) /* 補空白 */
{
fputc(' ', fp);
plen++;
}
}
else
{
if (pcount) /* 已經換行就不需要再換行 */
{
fputs(BR_PLAY, fp);
pcount = 0;
}
fputs(phead, fp);
break;
}
pcount++;
phead = pitem + 2;
}
fputs("\033[m\n", fp);
memset(&buf_play, 0, sizeof(buf_play));
}
break;
}
if (++i > 2)
i = 1;
xhead += k;
}
}
if (!start_show)
continue;
/* 標籤略過 */
cc = *xhead;
switch(cc)
{
case '<':
show = 0;
continue;
case '>':
show = 1;
continue;
case '\n':
case '\r':
continue;
case ' ':
continue;
}
if (show)
{
if (bufplay)
buf_play[j++] = cc;
else
fputc(cc, fp);
}
}
munmap(fimage, fsize);
if (i == 0)
{
fputs("\033[1;34m" MSG_SEPERATOR "\033[m\n", fp);
fputs("\n沒有查詢到任何資料!\n", fp);
}
else
i = 1;
return i;
}
static int
http_conn(server, s, extdata)
char *server;
char *s;
char *extdata;
{
int sockfd, ret;
FILE *fp;
char fname[64], ftmp[64];
if ((sockfd = dns_open(server, HTTP_PORT)) < 0)
{
vmsg("無法與伺服器取得連結,查詢失敗");
return 0;
}
else
{
outz("正在連接伺服器,請稍後...");
refresh();
}
write(sockfd, s, strlen(s));
shutdown(sockfd, 1);
sprintf(fname, "tmp/%s.ymovie", cuser.userid);
fp = fopen(fname, "w");
sprintf(ftmp, "tmp/%s.ymovie.tmp", cuser.userid);
outz("擷取資料中,請稍後...");
refresh();
fputs("\033[1;34m" MSG_SEPERATOR "\033[m\n", fp);
fputs(extdata, fp);
ret = write_file(sockfd, fp, ftmp);
fclose(fp);
if (ret >= 0)
{
more(fname, NULL);
if (ret)
{
if (vans("將查詢結果寄回信箱?[N] ") == 'y')
mail_self(fname, cuser.userid, "[備 忘 錄] 電影查詢", MAIL_READ);
}
}
unlink(fname);
unlink(ftmp);
return 1;
}
static void
ym_item(num, ym)
int num;
YMOVIE *ym;
{
prints("%6d %s\033[m%-25.26s %-42.43s\n",
num,
(ym->playmode & MOVIE_NOW) ? COLOR_NOW CHAR_NOW :
(ym->playmode & MOVIE_DOWN) ? COLOR_DOWN CHAR_DOWN :
COLOR_OTHER CHAR_OTHER,
ym->mv_title, ym->area_desc);
}
static int
ym_query(xo)
XO *xo;
{
YMOVIE *ym;
int i, j, cc, top;
char *p, *s;
char buf[80];
char menu_sub[10][25] = {0};
ym = (YMOVIE *) xo_pool + (xo->pos - xo->top);
top = 0;
while (1)
{
char *menu[] = {"0N",
menu_sub[0], menu_sub[1], menu_sub[2],
menu_sub[3], menu_sub[4], menu_sub[5],
menu_sub[6], menu_sub[7], menu_sub[8],
menu_sub[9],
"Q 取消查詢", NULL};
s = p = ym->area_desc;
i = 0;
while (*p)
{
if (*p == ',')
{
*p = '\0';
j = (i % MENU_PAGE);
if (i >= top)
sprintf(menu_sub[j], "%c %-s", j + '0', s);
*p = ',';
i++;
s = p + 1;
if (i >= (top + MENU_PAGE))
break;
}
p++;
}
if (*p == 0)
{
j = (i % MENU_PAGE);
sprintf(menu_sub[j], "%c %-s", j + '0', s);
i++;
}
j = (i % MENU_PAGE);
if (j)
{
menu[++j] = menu[11];
menu[++j] = menu[12];
}
sprintf(buf,
"選擇放映地區 (←) 換頁║%c║",
(top / MENU_PAGE) + '1');
cc = pans(1, 25, buf, menu);
if ( cc == 'n')
{
top += MENU_PAGE;
if (*p == 0)
top = 0;
continue;
}
else if (cc == 'q')
{
break;
}
else
{
char uestr[90], sendform[512];
strcpy(sendform, CGI_COMMAND);
url_encode(uestr, ym->mv_title);
strcat(sendform, uestr);
strcat(sendform, CGI_COMMAND2);
url_encode(uestr, menu_sub[cc - '0'] + 3);
strcat(sendform, uestr);
strcat(sendform, CGI_COMMAND3);
sprintf(buf, "\033[1;37m電影名稱:\033[32m%s\033[m"
"\n\033[1;37m放映地區:\033[33m%s\033[m\n",
ym->mv_title, menu_sub[cc - '0'] + 3);
http_conn(SERVER_YMOVIE, sendform, buf);
return XO_HEAD;
}
}
return XO_NONE;
}
static int
ym_body(xo)
XO *xo;
{
YMOVIE *ym;
int max, num, tail;
max = xo->max;
if (max <= 0)
{
vmsg("尚未建立電影資料");
return XO_QUIT;
}
ym = (YMOVIE *) xo_pool;
num = xo->top;
tail = num + XO_TALL;
if (max > tail)
max = tail;
move(3, 0);
do
{
ym_item(++num, ym++);
} while (num < max);
clrtobot();
return XO_FOOT; /* itoc.010403: 把 b_lines 填上 feeter */
}
static int
ym_head(xo)
XO *xo;
{
vs_head("電影查詢", str_site);
prints(NECKER_YMOVIE, d_cols, "");
return ym_body(xo);
}
static int
ym_load(xo)
XO *xo;
{
xo_load(xo, sizeof(YMOVIE));
return ym_body(xo);
}
static int
ym_init(xo)
XO *xo;
{
xo_load(xo, sizeof(YMOVIE));
return ym_head(xo);
}
static int
ym_help(xo)
XO *xo;
{
/* xo_help("ym"); */ /* 沒有建 help 檔 */
more("etc/help/ym/ymovie.hlp", NULL);
return ym_head(xo);
}
static KeyFunc ym_cb[] =
{
XO_INIT, ym_init,
XO_LOAD, ym_load,
XO_HEAD, ym_head,
XO_BODY, ym_body,
'r', ym_query,
'h', ym_help
};
int
ym_main()
{
XO *xo;
xz[XZ_YMOVIE - XO_ZONE].xo = xo = xo_new(FN_YMOVIE);
xz[XZ_YMOVIE - XO_ZONE].cb = ym_cb;
xo->pos = 0;
xover(XZ_YMOVIE);
free(xo);
return 0;
}
#endif /* HAVE_NETTOOL */
: src/util/ymovie-open.c 新增這隻程式
/*-------------------------------------------------------*/
/* util/ymovie-open.c ( NTHU CS MapleBBS Ver 3.10 ) */
/*-------------------------------------------------------*/
/* target : 奇摩電影檔更新 */
/* create : 04/12/14 */
/* update : / / */
/* author : kyo.bbs@cszone.twbbs.org */
/*-------------------------------------------------------*/
#if 0
# 每天 5:30 AM 建立一次奇摩電影檔
5 30 * * * bin/ymovie-open > /dev/null 2>&1
#endif
#include "bbs.h"
#ifdef HAVE_NETTOOL
#define HTTP_PORT 80
#define SERVER_YMOVIE "tw.movie.yahoo.com"
#define CGI_HTTP_TAG "http://"
#define CGI_GET_YMOVIE CGI_HTTP_TAG SERVER_YMOVIE "/js/search_mv.js"
#define CGI_GET_AREA CGI_HTTP_TAG SERVER_YMOVIE "/mv_area_js.php?mname="
#undef DEBUG
void
url_encode(dst, src) /* URL encoding */
uschar *dst; /* Thor.990331: 要 src 的三倍空間 */
uschar *src;
{
for (; *src; src++)
{
if (*src == ' ')
*dst++ = '+';
else if (is_alnum(*src))
*dst++ = *src;
else
{
/* 原使用 register cc 於 W_ALL 會有警告, 故改成 int */
int cc = *src;
*dst++ = '%';
*dst++ = radix32[cc >> 4];
*dst++ = radix32[cc & 0xf];
}
}
*dst = '\0';
}
static char *
parser_work(sockfd)
int sockfd;
{
static char pool[2048];
static char buf[2048]; /* 所有電影檔及放映地區長字串暫放 */
int cc, i, j, reload;
char *xhead, *xtail, *xpos;
int start_get;
char *start_str[] =
{
"Thi_option0(\042",
"Thi_option('",
NULL
};
char *stop_str[] =
{
"\042);",
"')",
NULL
};
xhead = pool;
xtail = pool;
xpos = buf;
start_get = 0;
reload = 0;
memset(&buf, 0, sizeof(buf));
for (;;xhead++)
{
if (xhead >= xtail || reload)
{
if (reload)
{
reload = i = 0;
while (xhead < xtail)
{
pool[i] = *xhead;
xhead++;
i++;
}
xhead = pool;
cc = read(sockfd, xhead + i, sizeof(pool) - i - 1);
}
else
{
xhead = pool;
cc = read(sockfd, xhead, sizeof(pool));
}
if (cc <= 0)
break;
xtail = xhead + cc;
}
if (!start_get)
{
for (i = 0; start_str[i] != NULL; i++)
{
j = strlen(start_str[i]);
if ((xtail - xhead) < j)
{
xhead--;
reload = 1;
continue;
}
if (!str_ncmp(xhead, start_str[i], j))
{
start_get = 1;
xhead += j;
break;
}
}
if (xhead >= xtail) /* 因為 xhead += j; 的關係 */
continue; /* 所以再此再度判斷一次 */
}
else if (start_get)
{
for (i = 0; stop_str[i] != NULL; i++)
{
j = strlen(stop_str[i]);
if ((xtail - xhead) < j)
{
xhead--;
reload = 1;
continue;
}
if (!str_ncmp(xhead, stop_str[i], j))
{
start_get = 0;
xhead += j;
break;
}
}
if (xhead >= xtail) /* 因為 xhead += j; 的關係 */
continue; /* 所以再此再度判斷一次 */
}
if (!start_get)
continue;
*xpos++ = *xhead;
}
return buf;
}
static int
http_conn(server, s)
char *server;
char *s;
{
int sockfd;
sockfd = dns_open(server, HTTP_PORT);
if (sockfd < 0)
{
printf("無法與伺服器取得連結,查詢失敗\n");
return 0;
}
write(sockfd, s, strlen(s));
shutdown(sockfd, 1);
return sockfd;
}
int
main()
{
int sockfd, i;
char ue_word[90], sendform[512];
char *p, *str;
YMOVIE ym;
chdir(BBSHOME);
system("rm -f " FN_YMOVIE); /* 暴力法, 重新建立電影檔 */
sprintf(sendform, "GET %s HTTP/1.0\n\n", CGI_GET_YMOVIE);
/* 取電影名稱及模式 */
if ((sockfd = http_conn(SERVER_YMOVIE, sendform)))
{
/* 去掉 " ,,===請選擇電影==;" 及將 ';' 分隔為 '\0' */
p = strtok(parser_work(sockfd), " ,;");
close(sockfd);
i = 0;
while (p != NULL)
{
if ((str = strstr(p, ",,")))
{
str += 2;
memset(&ym, 0, sizeof(YMOVIE));
ym.mv_no = ++i;
if (strncmp(str, CHAR_NOW, strlen(CHAR_NOW)) == 0)
ym.playmode |= MOVIE_NOW;
else if (strncmp(str, CHAR_DOWN, strlen(CHAR_DOWN)) == 0)
ym.playmode |= MOVIE_DOWN;
else
ym.playmode |= MOVIE_NORMAL;
if ((ym.playmode & MOVIE_NOW) || (ym.playmode & MOVIE_DOWN))
str += 2;
strncpy(ym.mv_title, str, sizeof(ym.mv_title));
rec_add(FN_YMOVIE, &ym, sizeof(YMOVIE));
}
p = strtok (NULL, ";");
}
}
i = 0;
/* 經由電影名稱抓放映地點 */
while (!rec_get(FN_YMOVIE, &ym, sizeof(YMOVIE), i))
{
url_encode(ue_word, ym.mv_title);
sprintf(sendform, "GET %s%s HTTP/1.0\n\n", CGI_GET_AREA, ue_word);
sockfd = http_conn(SERVER_YMOVIE, sendform);
if ((sockfd = http_conn(SERVER_YMOVIE, sendform)))
{
memset(&sendform, 0, sizeof(sendform)); /* 借 sendform 暫存 */
p = strtok(parser_work(sockfd), ",");
close(sockfd);
while (p != NULL)
{
if ((str = strstr(p, ",")))
strcat(sendform, ++str);
p = strtok (NULL, ";");
}
strncpy(ym.area_desc, sendform, sizeof(ym.area_desc));
rec_put(FN_YMOVIE, &ym, sizeof(YMOVIE), i, NULL);
#ifdef DEBUG
printf("%s\n", sendform);
#endif
}
i++;
}
return 0;
}
#endif /* HAVE_NETTOOL */
--
◤◥ Origin: Maple-itoc˙動力核心 cpu.tfcis.org
◣◢ Author: TKyo 從 cszone.twbbs.org 發表