《電影記憶》-又拍雲比賽作品總結

發表於2019-05-11

首先,什麼話也不說,直接上效果圖。

檢視效果: 首頁

搜尋關鍵字

選擇觀看電影,日期

電影記憶》 外掛是在onethink 平臺上開發的一個用於記錄自己觀看電影、電視媒體的展示工具。

使用技術

  • bootstrap2.3.1 ui

  • onethink cmf框架

  • curl

  • QueryList php採集元件

  • 又拍雲端儲存

功能介紹

  1. 搜尋電影媒體

  2. 看了電影

  3. 後臺列表(搜尋、刪除)

  4. 編輯觀看狀態、觀看時間

使用方法

  1. 後臺外掛列表中安裝、啟用外掛 外掛列表

  2. 外掛配置中設定又拍雲賬號 配置外掛

  3. 在要顯示的單個頁面 呼叫single鉤子

    
    
    1. {:hook('single', array('name'=>'MovieLog'))}

4.0 後臺管理

4.1 後臺列表搜尋、刪除 《電影記憶》-又拍雲比賽作品總結

4.2 後臺編輯單條記錄 編輯記錄

4.3 後臺批量更新已看記錄的簡介《電影記憶》-又拍雲比賽作品總結

好了。下面開始從技術上講重點。

本外掛本人認為至少能夠起到的作用是:

  1. 作為一個onethink 最新帶後臺外掛的例子。

  2. 啟發upyun開發者如何對接介面。從採集圖片、上傳圖片、更新快取和批量進行資料管理更新。

  3. 啟發大家如何進行bootstrap的幾個外掛優雅的使用。

  4. 實時web進度條如何實現。

  5. SAE 上對又拍雲的策略。

  6. onethink 的介紹。大家看官網:http://www.onethink.cn/ 眾所周知,thinkphp是國內最流行的PHP框架。但是由於更新頻繁,使用者眾多。導致各種在此基礎上的產品太多,質量參差不齊。二次開發專案難度大、成本高。

    因此,thinkphp官方決定出一個產品,制定一個標準,解決這個問題。雖然只要會php,任何問題都是能解決和實現的。那樣開發就像高考自由作文。文體不限。雖然自由,但是奇葩零分作文也多。

    但是如果命個主題、限制個文體就容易多了。希望大家有空能研究下。

    本人在官方onethink的基礎上移植了typecho的風格,製作了自己的部落格。也是開源的。作為程式設計師,技術部落格怎麼能用他人的呢?

    接下來就一步步的講這次開發中的重點:

    1. 首先外掛的開發,大家可以參見onethink文件裡的外掛開發指南,和看本人錄製的外掛開發視訊

    2. 又拍雲上傳介面的使用。

    3.   thinkphp3.2裡面的上傳類改進成驅動形式了。支援上傳時指定各種型別比如local、ftp、upyun、qiniu、sae、bcs之類的。

      所以我就外掛裡面配置儲存了下驅動的必填項。然後用自己之前對接upyun的賬號裡又建了個空間bucket: movie-log。開始對接使用。

      config.php

      01return array(
      02    'host'=>array(
      03        'title'=>'又拍雲伺服器:',
      04        'type'=>'text',
      05        'value'=>'',
      06    ),
      07    'username'=>array(
      08        'title'=>'又拍雲使用者:',
      09        'type'=>'text',
      10        'value'=>'',
      11    ),
      12    'password'=>array(
      13        'title'=>'又拍雲密碼:',
      14        'type'=>'password',
      15        'value'=>'',
      16    ),
      17    'bucket'=>array(
      18        'title'=>'又拍雲空間名稱:',
      19        'type'=>'text',
      20        'value'=>'MovieLog',
      21    ),
      22    'timeout'=>array(
      23        'title'=>'又拍雲上傳超時時間:',
      24        'type'=>'text',
      25        'value'=>'90',
      26    ),
      27);

         開始準備使用Upload驅動類的,後來由於上傳驅動裡有check檔案方法,裡面 is_uploaded_file 始終無法通過,畢竟不是傳統表單上傳的。為了不改核心程式碼,我把upyun的驅動放到外掛根目錄裡並對其進行修改。用裡面的save方法足以。後來加了個更新快取的方法。

        /ThinkPHP/Library/Think/Upload.class.php 

    01    /**
    02     * 檢查上傳的檔案
    03     * @param array $file 檔案資訊
    04     */
    05    private function check($file) {
    06        /* 檔案上傳失敗,捕獲錯誤程式碼 */
    07        if ($file['error']) {
    08            $this->error($file['error']);
    09            return false;
    10        }
    11 
    12        /* 無效上傳 */
    13        if (empty($file['name'])){
    14            $this->error = '未知上傳錯誤!';
    15        }
    16 
    17        /* 檢查是否合法上傳 */
    18        if (!is_uploaded_file($file['tmp_name'])) {
    19            $this->error = '非法上傳檔案!';
    20            return false;
    21        }

    在我的外掛MovieLogModel裡寫了個方法,進行圖片的上傳。

    01        include_once ONETHINK_ADDON_PATH.'MovieLog/function.php';
    02        $dir = ONETHINK_ADDON_PATH.'MovieLog/Upload/';
    03        if(APP_MODE == 'sae')
    04            $dir = SAE_TMP_PATH;
    05        $UpyunConfig = get_addon_config('MovieLog');
    06        $uploader = new Upyun('/', $UpyunConfig);
    07        $name = strstr($this->data['alt'],'subject/');
    08        $name = ltrim($name,'subject/');
    09        $name = trim($name,'/');
    10        if(!is_dir($dir))
    11            @mkdir($dir);
    12        $images = array(
    13            's'=>$this->curl_download($images['small'],"{$dir}s_{$name}.jpg"),
    14            'm'=>$this->curl_download($images['medium'],"{$dir}m_{$name}.jpg"),
    15            'l'=>$this->curl_download($images['large'],"{$dir}l_{$name}.jpg")
    16        );
    17        foreach ($images as $key => $value) {
    18            $file = array(
    19                'name'   =>"{$key}_{$name}.jpg",
    20                'savepath'=>'',
    21                'savename'=>"{$key}_{$name}.jpg",
    22                'type'   =>"image/jpeg",
    23                'size'   =>filesize($value),
    24                'tmp_name' =>$value,
    25                'md5'=>md5_file($value),
    26                'error' =>0,
    27            );
    28            $info = $uploader->save($file);
    29            if($info)
    30                @unlink($value);
    31        }
    32        $refresh = array();
    33        $return = array('small'=>"s_{$name}.jpg",'medium'=>"m_{$name}.jpg",'large'=>"l_{$name}.jpg");
    34        foreach($return as $r){
    35            $refresh[] = movie_cover($r);
    36        }
    37         
    38        $uploader->refreshCache(join('\n', $refresh));
    39        return serialize($return);
    40    }

    所以外掛圖片實際上是通過儲存遠端圖片到本地,然後用驅動上傳到upyun空間裡,然後刪除的。大家都知道海量圖片佔用本地磁碟大,且訪問慢。這時候又拍雲就起到作用了。

    我首頁200多部電影的封面,依然開啟嗖嗖的。

    這裡有兩點要注意。一個是圖片重複上傳的問題,由於我的圖片採集下來規則是定的一個圖片不會重複,有個對應的電影id。所以無需判斷。正常為了節省流量和時間。先判斷空間上是否有同樣的圖片,有就返回圖片地址資訊,沒有就才上傳。判斷唯一通過md5_file和sha1_file函式判斷就可以了。

    curl 採集用的QueryList。注意選擇器正確,無法找到內容,去掉rang引數

    再一個就是圖片快取的問題。圖片上傳後,通過http://空間.b0.upaiyun.com/檔名 訪問,不一定立馬能訪問到。這個需要手動去重新整理它。雖然又拍雲管理空間裡有傳多個連結(換行)然後更新快取的工具。從人性化的角度來說,這應該是自動的。或者訪問時後觸發的。因此我擴充套件裡onethink的Upyun驅動類加上了重新整理的方法。然後開始是在外掛訪問的前臺首頁,繫結圖片error事件,去ajax重新整理的。

    01                //重新整理upaiyun圖片快取
    02                $('img[src*="http://{$config.bucket}"]').error(function(e){
    03                    setTimeout(function () {
    04                        var url = "{:addons_url('MovieLog://MovieLog/refreshImg')}";
    05                        var _this = this;
    06                        this.src = '';
    07                        $(this).parents('.post-li').addClass('mega-loading');
    08                        $.ajax({
    09                            url: url,
    10                            data: {file : this.src},
    11                            success:function(data){
    12                                if(data.status)
    13                                    _this.src = _this.src;
    14                                $(this).parents('.post-li').removeClass('mega-loading');
    15                            }
    16                        });
    17                    }, 1000);
    18 
    19                });

    但是由於圖太多了,不斷ajax 有可能導致瀏覽器卡死。後來在除錯sae上上傳的時候傳完手動重新整理了一次。上面程式碼中

    1$uploader->refreshCache(join('\n', $refresh));

    就是呼叫介面重新整理。

    批量進行電影簡介更新。首先批量只是小批量,只選取了觀看後的記錄,並且要更新的summary欄位is null or = ''的記錄。因為本外掛是在搜尋時候採集資料,更新觀看狀態欄位時候採集圖片和寫如簡介的。為了效果,手動加入記錄後。已經有3000條了。全部更新的話太慢。想想一個記錄查curl都要2s左右。

    然後就是通過一個按鈕彈出更新的視窗。進行第一次查詢總更新記錄集合,快取主,在返回的第一次查詢裡返回更新的table裡的tr 的 process js函式。用eval 執行一次。然後執行的js函式裡再呼叫ajax重新請求下一個和改進度條寬度。最後一次返回判斷是否結束,將進度條寬度直接設滿。

    js端:

    01('#batch_update_btn').click(function(){
    02            var url = $(this).attr('url');
    03            $('#myModal').html($('#loading_tpl').html());
    04            var $btn = $(this);
    05            $btn.button('loading');
    06            $('#myModal').modal('show');
    07            $.ajax({
    08                url: url,
    09                success:function(data){
    10                    eval(data);
    11                },
    12                error:function(XMLHttpRequest, textStatus, errorThrown){
    13                    $('#myModal').html('網路出錯了');
    14                }
    15            });
    16            $('#myModal').modal('show');
    17            return false;
    18        });

            

01function process(id, msg){
02        var $btn = $('#batch_update_btn');
03        if(id != 0){
04            var url = $btn.attr('url');
05            $('#myModal .progress .bar').width(function(n,c){
06                return c+5;
07            });
08            $('#file_list tbody').prepend(msg);
09            $.ajax({
10                url: url,
11                data: {id: id},
12                success:function(data){
13                    eval(data);
14                },
15                error:function(XMLHttpRequest, textStatus, errorThrown){
16                    $('#myModal').html('網路出錯了');
17                }
18            });
19        }else{
20            $('#myModal .progress .bar').width('670');
21            $('#file_list').before('<p>全部更新完畢</p>');
22            $btn.button('reset');
23        }
24    }

php端方法

01    //批量更新簡介
02    public function update_batch(){
03        $id = I('id', 0);
04        include_once ONETHINK_ADDON_PATH.'MovieLog/DoubanMovie.class.php';
05        $obj = new \DoubanMovie();
06        if($id == 0){
07            $movie = D('Addons://MovieLog/Movie');
08            $list = $movie->where("(summary is null OR summary = '') AND is_published = 1")->getField('id,id,title');
09            $record = array_pop($list);
10            $id = $record['id'];
11        }else{
12            $list = session('batch_list');
13            $record = $list[$id];
14            unset($list[$id]);
15        }
16        $msg = "<tr><td>{$record['id']}</td><td>{$record['title']}</td><td class='success'> √</td></tr>";
17 
18          $detail = $obj->subject($id);
19        $movie = D('Addons://MovieLog/Movie');
20        if($detail['summary'] && $movie->save(array('id'=>$id, 'summary'=>$detail['summary'])) !== false)
21            $result = "<td class='success'> √</td>";
22        else
23            $result = "<td class='error'> X</td>";
24        $msg = "<tr><td>{$record['id']}</td><td>{$record['title']}</td>{$result}</tr>";
25        if(count($list)){
26            $new = array_slice($list, 0 ,1);
27            echo "process({$new[0]['id']}, \"{$msg}\");";
28            session('batch_list', $list);
29        }else{
30            session('batch_list', null);
31            exit("process(0,'');");
32        }
33    }

c bootstrap外掛使用:

  首先用了ScrollSpy 這個js元件。用於首頁月份隨內容高度變化而高亮的。這個效果是參考 點點網的 archive歸檔效果。這個外掛注意點是他高亮的元素必須是.nav 的li 並且加的是active類名。在監聽容器上可以指定偏移高度。

  然後是popover元件。預設的在移動到浮動窗上的容易消失。找了段別人寫好的manual 事件的

  

01//下方圖片牆提示
02                $('#mega-content .post-li').popover({
03                    trigger:'manual',
04                    delay:{show:1000, hide: 1000},
05                    content:function(e){
06                        var src = $(this).attr('src');
07                        var summary = $(this).attr('summary');
08                        return "<div class='cover_popover'><img src='"+src+"'><p>"+summary+"</p></div>";
09                    },
10                    html : true,
11                    title: this.title
12                }).on("mouseover", function () {
13                    var _this = this;
14                    $(this).popover("show");
15                    $(this).siblings(".popover").on("mouseleave", function () {
16                        $(_this).popover('hide');
17                    });
18                }).on("mouseleave", function () {
19                    var _this = this;
20                    setTimeout(function () {
21                        if (!$(".popover:hover").length) {
22                            $(_this).popover("hide")
23                        }
24                    }, 100);
25                });

  最後是彈窗。bootstrap的彈窗美觀,但是提供的介面少。就那麼幾個方法。不過在我的努力下實現了動態載入內容。

  一種是指定remote屬性。但是這種不能動態傳引數。

 第二種就是我用的,先頁面上放容器,然後彈出時候ajax返回頁面內容。

  注意:1.彈窗樣式 頁面上控制。2.預設彈窗會快取住,繫結hide事件,將載入的頁面刪除掉。

1$('#myModal').on('shown.bs.modal', function (e) {
3}).on('hidden.bs.modal',function(e){
4     $(this).removeData('bs.modal');
5});

d 實時進度條程式碼上面有了,就是輪詢ajax 設定進度條寬度。

e sae 上開始參考官方手冊說有wrapper saekv://、 saemc 都試了沒用。最後發現有臨時目錄常量 判斷環境sae時改下臨時儲存目錄就行了。本來還準備曲線救國用ftp介面呢!話說sae第三方服務有又拍雲,結果不能開通。怒了。

1        if(APP_MODE == 'sae')
2            $dir = SAE_TMP_PATH;

之前自己寫測試寫入可以 ajax訪問就不行了。最後發現是快取的問題。最後上傳完就重新整理快取,什麼疑難雜症都沒了。O(∩_∩)O哈哈~ 

好了,總結就這麼多,希望大家多給我投票 http://upyun.gitcafe.com/projects?category=top50  onethink-MovieLog-for-upyun 那個。“深度雲服務,編譯新未來”,歡迎大家關注比賽。

評論(1)

相關文章