[Chrome extension] 新北市/台北市圖書館 – 多重帳戶登入

[Chrome extension] 新北市/台北市圖書館 – 多重帳戶登入

icon_webstore.png

最近迷上了寫 Google Chrome extension,也就是擴充功能…

因為發現它實在蠻容易寫的,也很容易上手~~

 

這次想要解決的問題是關於新北市圖書館多重登入的問題~ 

因為家人每個人都有一張借書證,因此通常我們就會各自拿別人的去用,

這樣就可以一次借很多本書回來一起看…

只是新北市圖書館的網頁上,並沒有辦法支援多個帳號登入,

因此如果想要看看家人是否有哪幾本書快到期了,或是是否有通閱和預約的書到館的話,

就必須一一登入每個人的帳號,然後才能檢視,

其實是蠻不方便的…

 

因此,這次的想法就是做一個 chrome extension,

當按下這個 extension 的時候,就會自動登入所有家人的帳號,

將相關的借書、預約、通閱等等狀態全部一次取回來顯示~~

當然這個東西直接作成一個網頁 .html 也是可以的,

不過作成 chrome extension 有兩個好處:

1. Google 會自動雲端同步有安裝的 chrome extensions,因此每台電腦都會裝上。

2. Chrome extension 可以有選項頁,這樣可以更方便的選擇一些選項(像是加帳號等等)。

 

這次就不太多提上次已經提過的,製作 chrome extension 的一些基本概念,

只提一些較重要的部分了~~

 

Manifest.json

這次的 manifest.json 裡面,我們並沒有用到 background_page,

因為我們只需要在按下按鈕時,直接顯示一個頁面就好,

就不需要一個背景頁面在那邊佔 chrome 的資源了~

{
"name":             "新北市圖書館 - 多重帳戶登入",
"version":          "1.2",
"description":      "如果你的家庭裡有多張新北市圖書館證時,本程式可以幫助你登入所有的帳戶,一次檢視全部的借書狀況。",
"icons":            {
"16": "icon16.png",
"48": "icon48.png",
"128": "icon128.png"
},
"options_page":     "options.html",
"browser_action":   {
"default_icon"  : "icon128.png",
"default_title" : "新北市圖書館 - 多重帳戶登入",
"default_popup" : "baloon.html"
},
"permissions":      [
"http://library.tphcc.gov.tw/*"
]
}

 

baloon.html

正常來說,chrome 會把 default_popup 指向的網頁顯示在它的一個氣泡框裡面,

不過因為這個氣泡框只要點一下就會消失,

對於需要檢視各帳號借書狀態的我來說,覺得不太方便,

因此這邊的實作方式是開一個新的分頁 popup.html,

然後就直接用 window.close() 把不必要的氣泡窗關了~

<html>
<head>
<script>
chrome.tabs.create({ url: "popup.html" });
window.close();
</script>
</head>
<body>
</body>
</html>

 

popup.html

基本上這個網頁的架構很簡單,就是登入帳號 -> 查詢借書狀況 -> 查詢通閱狀況 -> 查詢xxx …

如果有多個帳號的話,就重覆上面的步驟~

最後,再把查詢完的結果整合起來顯示就可以了~~

不過,在實作的時候,發現如果用同步 (sync) 的方式來做登入與查詢的動作,

整個網頁在查詢完成之前是無法回應的,

這在有多個帳號的時候問題更明顯,實在不是很好,

一般人可能會以為網頁當掉了,然後再按一次重新整理 =_=…

因此,後來對網頁作了大翻修,全部改用非同步 (async) 的方式作登入與查詢,

不過僅限於同一帳號而言才能這麼做,

只有等到同一帳號的借書、通閱、預約狀態等等都查詢完了,

才能去登入下一個帳號,

不然 server 那邊的 session 是會阻止我們直接用帳號 A 的 session 去查帳號 B 的資訊的!!

 

下面這段程式,簡而言之,就是將所支援的每個服務(借書、通閱等等),

都顯示在一個 jQuery tab 分頁裡面,每個分頁裡面都是空的,

接著就執行 jsLoginAccount(0) 開始登入第一個帳號~

function jsOnload()
{
if (g_arrayAccounts != null && g_arrayAccounts.length > 0)
{
// Initialize tab html
$("#divResult").html('<div id="divResultTabCollection"><ul id="ulTabLinks"></ul></div>');
for (var iService = 0; iService < g_arrayServices.length; iService++)
{
// Check if this service is enabled
if (g_arrayServices[iService].enable != false)
{
$("#ulTabLinks").append("<li><a href='#divResultTab" + g_arrayServices[iService].output + "'>" + g_arrayServices[iService].tab + "</a></li>");
$("#divResultTabCollection").append("<div id='divResultTab" + g_arrayServices[iService].output + "'><div class='classLoading'><img src='ajax-loader.gif'> 正在查詢相關資訊,請稍候...</div></div>");
}
}
// Show result tabs
$("#divResultTabCollection").tabs();
// Login first account
jsLoginAccount(0);
}
}

 

下面這段程式主要就是先看看是否所有的帳號都已登入過,

如果還沒有的話就進去執行,

首先是去呼叫登入的 URL,如果登入成功了,

就會用非同步的方式,同時用 jsQueryService() 去查詢所有的服務狀態(借書、通閱、預約等等),

每回來一筆服務結果,就會用 jsAppendQueriedServiceInfo() 將結果加到 jQuery 分頁上,

同時也呼叫 jsIncQueriedServiceCount() 去累計目前已經完成查詢的服務數目。

當所有的服務結果都回來之後,就再呼叫 jsLoginAccount() 去登入下一個帳號,

直到所有的帳號都處理完成為止~~

function jsLoginAccount(iAccount)
{
// Check if this account index is valid
if (iAccount < g_arrayAccounts.length)
{
// Check if this account is enabled
if (jsIsAccountEnable(iAccount))
{
g_bAnyAccountEnable = true;
jQuery.ajax({
url:        g_sCGIURL,
type:       "POST",
data:       {
"PG_NAME":  "BRW",
"UMODE":    "FIRST",
"ULG":      "CHI",
"UCODE":    "BIG5",
"BRWID":    g_arrayAccounts[iAccount].name,
"BRWPWD":   g_arrayAccounts[iAccount].pass
},
async:      true,
success:    function(html)
{
if (html.indexOf("<hr ") >= 0)
{
// After login, the first page is the currently borrowed books,
// so we can save this into array first.
jsAppendQueriedServiceInfo(0, html);
g_nNumQueriedServices = 1;
// Search for all CGI links
g_arrayCGILinks = html.match(/<a href="/cgi-bin/spydus.+">/gi);
if (g_arrayCGILinks != null)
{
// Query every listed service info in async mode at the same time
for (var iService = 1; iService < g_arrayServices.length; iService++)
{
// Check if the service link index is valid
if (g_arrayServices[iService].index >= 0 && g_arrayServices[iService].index < g_arrayCGILinks.length && g_arrayServices[iService].enable != false)
{
// Query the service
jsQueryService(g_sWebRoot + g_arrayCGILinks[g_arrayServices[iService].index].replace(/<a href="(.+)">/gi, "$1"), iService, iAccount);
}
else
{
// Does not query this service, but still accumulate queried service count
jsIncQueriedServiceCount(iAccount);
}
}
}
}
else
{
alert("無法成功登入帳號 " + g_arrayAccounts[iAccount].name + (g_arrayAccounts[iAccount].desc != "" ? "("+g_arrayAccounts[iAccount].desc+")" : "") + "!n請檢查一下帳號密碼是不是輸入正確喔!");
// Login failed. Login next account
jsLoginAccount(iAccount+1);
}
},
error:      function(jqXHR, textStatus, errorThrown)
{
// Login failed. Login next account
jsLoginAccount(iAccount+1);
}
});
}
else
{
// This account is not enabled. Continue login next account
jsLoginAccount(iAccount+1);
}
}
else if (!g_bAnyAccountEnable)
{
$("#divResult").html("您尚未輸入或啟用任何的帳號!<br>請到<a href='options.html' target='_blank'>選項頁</a>輸入至少一個圖書館的帳號,謝謝!");
}
else
{
// Hide the loading div after all data is loaded
$(".classLoading").hide();
}
}
function jsIsAccountEnable(iAccount)
{
return (g_arrayAccounts[iAccount].enable != false);
}
function jsAppendQueriedServiceInfo(iService, sHtml)
{
// Extract html
var iPos = sHtml.indexOf("<hr ");
if (iPos >= 0)
{
sHtml = sHtml.substr(iPos);
}
// Replace links of library to absolute links
sHtml = sHtml.replace(/"(/cgi-bin/.+)"/gi, '"' + g_sWebRoot + '$1"');
// Add the output to tab
$("#divResultTab" + g_arrayServices[iService].output).append(sHtml);
}
function jsQueryService(sURL, iService, iAccount)
{
// Query the link to get output
jQuery.ajax({
url:        sURL,
type:       "GET",
async:      true,
success:    function(html)
{
// Append queried service info for this account for this service
jsAppendQueriedServiceInfo(iService, html);
},
complete:   function(jqXHR, textStatus)
{
jsIncQueriedServiceCount(iAccount);
}
});
}
function jsIncQueriedServiceCount(iAccount)
{
// Check if all services for this account are queried
if (++g_nNumQueriedServices >= g_arrayServices.length)
{
// Login next account
setTimeout("jsLoginAccount(" + (iAccount+1) + ")", 0);
}
}

 

有興趣的人,可以到這裡下載回去試用看看喔~

也歡迎給我任何的意見或建議~ ^^

(本頁面已被瀏覽過 312 次)

3 thoughts on “[Chrome extension] 新北市/台北市圖書館 – 多重帳戶登入

  1. 請問帳戶是否限定輸入的借書證數量~~日前輸入8張借書證後只顯示7張借書證的資料??
    版主回覆:(05/02/2013 03:55:44 PM)
    沒有限制耶,有可能是 bug…
    最近有空再來找找看,真抱歉 =_=…

    1. 謝謝您的支持,
      但目前暫時還沒有打算出付費版…
      因為付費版的話,
      使用者對 app 的 bug 忍受力會降低。
      像我只是業餘偶爾改善一下 app,
      可能對於付費版的使用者,
      會比較不好交待… 😛

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料