ตัวอย่างรวบยอดของการใช้งาน ionic framework ร่วมกับ YouTube API V3 ในการดึงข้อมูล Playlist รายการต่างๆ มาแสดงผลเป็นแอพพลิเคชันดูหนัง
ตัวอย่างนี้ผมจะทำแอพพลิเคชันดูหนังจีน แบบซีรีย์ตอนๆ
เราจะเริ่มต้นด้วยการสมัคร Google Developer ก่อนหลังจากนั้นต้องไปเปิดสิทธิ์ของ YouTube API ที่ตอนนี้เป็น Version 3 แล้ว บทความก่อนหน้านี้ที่เคยเขียนมาต้องโละออกให้หมดครับ
เริ่มต้นครับให้เราสมัคร Google Developer Account ถ้ามีแล้วไปที่ URL นี้ครับ https://console.developers.google.com/ เพื่อเข้าไปเปิดสิทธิ์ในการเข้าถึง YouTube API V3
ทำการสร้าง New Project ขึ้นมาครับ ตั้งชื่อให้ตรงกับแอพพลิเคชันที่เราจะทำ
เมื่อสร้างแล้วหน้า Dashboard จะบอกให้เราไปเปิดใช้งาน API ครับ ที่ Enable and manage APIs คลิกเข้าไปที่นั่นเลย
เรื่องแปลกในการเปิดใช้งาน APIs ของ YouTube Data API นั่นก็คือถ้าเปิดสิทธิมันอย่างเดียว เราจะใช้งาน GET RESTFUL APIs ไม่ได้ครับ ต้องเปิดสิทธิของ Contacts API และ YouTube Analytics API ด้วยถึงจะใช้งานได้ครับไม่งั้นจะเจอแค่ LimitedUsage แล้วงง (ต้องไปงมใน StackOverflow นานมาก)
เปิดสิทธิไปให้ครบทั้ง 3 ส่วน แล้วมันจะบอกให้เราไป สร้าง credentials ขึ้นมาก่อน คลิกที่ Go to Credentials ซะก็จะเข้าไปสร้าง API Keys สำหรับใช้งานครับ
สร้าง Credentials ก็กรอกข้อมูลตามจริงครับ Platform เป็น Client Browser ก่อนนะครับให้เหมือนตัวอย่างนี้ เราจะได้ API Keys มาใช้งานละ ช่องของ Accept requests from these HTTP referrers (web site) นั้นถ้าเราไม่ระบุ Domain ที่เราจะใช้เรียกก็ปล่อยว่างไว้ครับ มันจะเตือนเราว่า ไม่ดีนาถ้าไม่ระบุ เพราะใครรู้ก็แอบไปใช้ได้ ถ้าเรารับได้ก็โอเค ซึ่งผมก็รับได้ครับ
สุดท้ายเราก็จะได้ Key มาใช้สักที
ทีนี้วิธีการที่เราจะเรียกใช้นั้น ผมออกแบบแอพพลิเคชันของผมดังนี้ คือ หน้าแรกเป็น Playlist กดรายการก็จะเข้าไปที่รายการของ Video ดังนั้น APIs จะมีการเรียกใช้ 2 ส่วนคือ PlayLists และ Video ครับ การเรียกใช้ API ให้เรียกตรงๆ ผ่าน Browser ได้เลยมันจะแสดงผลแบบนี้
ส่วน Id ของ Playlist เหรอ อย่าแกล้งโง่เลยครับผมรู้ว่าคุณรู้ดีว่าหาได้จากที่ไหน ตัวอย่างของผมก็ Playlist นี้
การเรียกก็จะใช้ 2 APIs คือ
ส่วน API ของ videos ก็ใช้รูปแบบนี้ครับ
ทีนี้ก็ถึงเวลาของการสร้างแอพพลิเคชัน ionic framework ละ เปิด command line หรือ terminal ขึ้นมา สร้างแอพแรกของเรา
ionic start AsianSeries blank -a AsianSeries -i com.daydev.asianseries
เราจะได้ Project Blank ขึ้นมาครับ ผมจะละการออกแบบไปก่อนเพราะผมคิดว่าเราคงออกแบบกันได้ จากการศึกษาบทเรียนนี้:
เอาง่ายๆ คือให้เปิดไฟล์ index.html ขึ้นมาครับ แก้ไขเป็น
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width" /> <meta http-equiv="Content-Security-Policy" content="default-src *; script-src 'self' 'unsafe-inline' 'unsafe-eval' *; style-src 'self' 'unsafe-inline' *"> <title>Asian Series</title> <link href="lib/ionic/css/ionic.css" rel="stylesheet"/> <script src="lib/ionic/js/ionic.bundle.js"></script> <link href="css/style.css" rel="stylesheet"/> <script src="js/app.js"></script> </head> <body ng-app="myApp"> <ion-nav-view animation="slide-left-right"> </ion-nav-view> </body> </html>
สร้าง Template ใหม่ขึ้นมา 2 หน้า โดยการเพิ่ม Folder ชื่อว่า “views” และสร้างไฟล์ชื่อว่า views/main.html และ views/live.html แก้ไข code ดังนี้ครับ
<div ng-controller="mainController"> <ion-view view-title="ซีรีย์ หนังจีน"> <ion-side-menus> <ion-pane ion-side-menu-content> <ion-nav-bar class="bar-dark nav-title-slide-ios7"> <ion-nav-buttons side="left"> <button class="button button-icon button-clear ion-navicon" ng-click="openMenu()"></button> </ion-nav-buttons> </ion-nav-bar> <ion-nav-view> <ion-content> <!--Content--> <ion-list> <a class="item item-thumbnail-left" ng-repeat="item in playlists" ng-if="item.snippet.title != 'Deleted video'" href="#/live/{{item.snippet.resourceId.videoId}}"> <img class="homelist" ng-cache ng-src="{{item.snippet.thumbnails.medium.url}}" onerror="this.src = 'http://placehold.it/350x150';"> <h2 class="title">{{item.snippet.title}}</h2> <p>คลิกเพื่อรับชม</p> </a> </ion-list> </ion-content> <!--Content--> </ion-nav-view> </ion-pane> <ion-side-menu side="left"> <ion-header-bar class="bar bar-header bar-dark" > </ion-header-bar> <ion-content has-header="true"> <a class="item item-icon-left" ng-click="openMenu()"> <i class="icon ion-easel"></i> ดูทีวีออนไลน์ </a> <a class="item item-icon-left" href="#history/{{id_member}}"> <i class="icon ion-closed-captioning"></i> ช่องรายการโปรด </a> </div> </ion-content> </ion-side-menu> </ion-side-menus> </ion-view> </div>
<div ng-controller="tvController"> <ion-view view-title="เรื่อง"> <ion-side-menus> <ion-pane ion-side-menu-content> <ion-nav-bar class="bar-dark nav-title-slide-ios7"> <ion-nav-buttons side="left"> <button class="button button-icon button-clear ion-navicon" ng-click="openMenu()"></button> </ion-nav-buttons> </ion-nav-bar> <ion-nav-view> <ion-content> <!--Content--> <div class="list card" ng-repeat="item in videos_detail"> <div class="item item-avatar"> <h2>{{item.snippet.title}}</h2> <p>{{item.snippet.publishedAt}}</p> </div> <div class="item item-body"> <div class="video-container"> <iframe ng-src="{{getIframeSrc(video_id) | trusted}}" frameborder="0" class="tv" allowfullscreen></iframe> </div> <p> {{item.snippet.description}} </p> <p> <a href="#" class="subdued">{{item.statistics.viewCount}} Views</a> <a href="#" class="subdued">{{item.statistics.likeCount}} Likes</a> </p> </div> </div> <!--Content--> </ion-nav-view> </ion-pane> <ion-side-menu side="left"> <ion-header-bar class="bar bar-header bar-dark" > </ion-header-bar> <ion-content has-header="true"> <a class="item item-icon-left" ng-click="openMenu()"> <i class="icon ion-easel"></i> ดูทีวีออนไลน์ </a> <a class="item item-icon-left" href="#history/{{id_member}}"> <i class="icon ion-closed-captioning"></i> ช่องรายการโปรด </a> </div> </ion-content> </ion-side-menu> </ion-side-menus> </ion-view> </div>
แก้ไข js/app.js ดังนี้
var app = angular.module('myApp', ['ionic']); var url_playlist_api = "https://www.googleapis.com/youtube/v3/playlistItems"; var url_video_api = "https://www.googleapis.com/youtube/v3/videos"; var playlist_id = "PL7DVjg1sAwC6q2UuWgMNAXrd7gDbE9ypx"; var api_key = "YOU KEY"; app.run(function($ionicPlatform) { $ionicPlatform.ready(function() { if(window.cordova && window.cordova.plugins.Keyboard) { cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true); cordova.plugins.Keyboard.disableScroll(true); } if(window.StatusBar) { StatusBar.styleDefault(); } }); }); app.config(function($stateProvider, $urlRouterProvider) { $stateProvider .state('main', { url: '/main', templateUrl: 'views/main.html', controller: 'mainController' }) $stateProvider .state('live', { url: '/live/:id', templateUrl: 'views/live.html', controller: 'tvController' }) $urlRouterProvider.otherwise('/main'); }); app.filter('trusted', ['$sce', function ($sce) { return function(url) { return $sce.trustAsResourceUrl(url); }; }]); app.controller('mainController', function($scope, $ionicSideMenuDelegate, $http, $stateParams,$ionicPlatform,$window) { $scope.openMenu = function () { $ionicSideMenuDelegate.toggleLeft(); }; $scope.greaterThan = function(fieldName){ return function(item){ return item[fieldName] > $scope.selected.score; } } $http.get(""+url_playlist_api+"?part=snippet&playlistId="+playlist_id+"&key="+api_key+"&maxResults=50") .success(function (response) { $scope.playlists = response.items; }); }); app.controller('tvController', function($scope, $ionicSideMenuDelegate, $http, $stateParams) { $scope.video_id = $stateParams.id; $scope.getIframeSrc = function (videoId) { return 'https://www.youtube.com/embed/' + videoId; }; $http.get(""+url_video_api+"?id="+$scope.video_id+"&key="+api_key+"&&part=snippet,contentDetails,statistics,status") .success(function (response) { $scope.videos_detail = response.items; }); });
ผมแอบใช้ Font สวยๆ มาช่วยแต่งหน้า Layout บน style.css ด้วย Font
ส่วนไฟล์ css/style.css นั้นผมใช้ ชุด css ดังนี้
@font-face { font-family: Bangna; src: url(../.../../fonts/WDB_Bangna.ttf); } .cateheader{padding-top:50px;} .cate_left{color:#000; font-size:20px; font-family: Bangna;} .platform-android .bar .title{font-size:16px; font-family: Bangna;} .item{font-size:16px; font-family: Bangna;} .title{font-size:16px; font-family: Bangna;} .tv{width:100%; height:250px;} .homelist{width:300px; height:auto;}
คราวนี้ก็จะมาอธิบายง่ายๆครับ
app.controller('mainController', function($scope, $ionicSideMenuDelegate, $http, $stateParams,$ionicPlatform,$window) { $scope.openMenu = function () { $ionicSideMenuDelegate.toggleLeft(); }; $scope.greaterThan = function(fieldName){ return function(item){ return item[fieldName] > $scope.selected.score; } } $http.get(""+url_playlist_api+"?part=snippet&playlistId="+playlist_id+"&key="+api_key+"&maxResults=50") .success(function (response) { $scope.playlists = response.items; }); });
เป็นการเรียก JSON จาก YouTube API ส่วนของ PlayList ไปเก็บใน Scope ที่ชื่อว่า playlists ผ่าน mainController ให้หน้า main.html เรียกไปใช้ จาก $stateParams
$stateProvider .state('main', { url: '/main', templateUrl: 'views/main.html', controller: 'mainController' })
การแสดงผลก็จะเป็นดังนี้
เมื่อมีการกดรายการของวีดีโอมันจะวิ่งไปที่หน้า live ผ่าน a href ที่ #/live/ ตามด้วยระหัสของวีดีโอ ผ่าน $stateParam คือ
$stateProvider .state('live', { url: '/live/:id', templateUrl: 'views/live.html', controller: 'tvController' })
ส่งค่าไปยัง scope ที่ชื่อ video_id ของ Controller ชื่อ tvController ครับ
app.controller('tvController', function($scope, $ionicSideMenuDelegate, $http, $stateParams) { $scope.video_id = $stateParams.id; $scope.getIframeSrc = function (videoId) { return 'https://www.youtube.com/embed/' + videoId; }; $http.get(""+url_video_api+"?id="+$scope.video_id+"&key="+api_key+"&&part=snippet,contentDetails,statistics,status") .success(function (response) { $scope.videos_detail = response.items; }); });
ซึ่งส่วนของ tvController ต้องมีการเรียก รายละเอียดผ่าน Video APIs ด้วย ส่วนของ $scope.video_id นั้นใช้กับ iframe หน้า live.html เท่านั้น แต่เราจะพบกับปัญหาเรื่อง sce หรือ Securities ครับให้เราเพิ่มส่วนของ filter ใน app.js ตามตัวอย่างข้างบน
app.filter('trusted', ['$sce', function ($sce) { return function(url) { return $sce.trustAsResourceUrl(url); }; }]);
รายการก็จะเล่นวีดีโอได้ครับผ่าน iframe ที่ส่วนของ การแสดงผล Directive
<div class="video-container"> <iframe ng-src="{{getIframeSrc(video_id) | trusted}}" frameborder="0" class="tv" allowfullscreen></iframe> </div>
ทดสอบเมื่อกดรายการดู
ลองรันผ่าน อุปกรณ์จริงของเราครับ หยิบ Android ขึ้นมาทดสอบดูจะได้แบบที่ผมทดสอบ เลย