Skip to content

Instantly share code, notes, and snippets.

@supersupermomonga
Created October 7, 2015 13:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save supersupermomonga/ffbadfaaf373c61eb199 to your computer and use it in GitHub Desktop.
Save supersupermomonga/ffbadfaaf373c61eb199 to your computer and use it in GitHub Desktop.
<script>
var factory = {
video: function() {
var setQuery = function (q) {
this.q = q;
}
var setToken = function (results) {
this.token = results.nextPageToken;
}
var setResults = function (results) {
this.total = results.pageInfo.totalResults;
this.items = results.items;
this.token = results.nextPageToken;
}
return {
q: '',
total: 0,
items: [],
token: {},
setQuery: setQuery,
setToken: setToken,
setResults: setResults
}
}
}
var controller = {
search: function($scope, $state, Video) {
$scope.q = Video.q;
$scope.submit = function () {
Video.setQuery(this.q);
google.script.run
.withSuccessHandler(function(results) {
Video.setResults(results);
var options = {};
if ($state.current.name == 'result') {
options['reload'] = true;
}
$state.go('result', { q: Video.q }, options);
})
.withFailureHandler(function(res) {
$state.go('error');
})
.searchByKeyword(Video.q)
}
},
main: function($scope, $state, Video) {
$scope.total = Video.total;
$scope.items = Video.items;
$scope.showPlayer = function(item) {
google.script.run.showPlayer(item.id.videoId);
}
$scope.outputable = (Video.total > 0) ? true : false;
$scope.outputToSpreadsheet = function() {
google.script.run.outputToSpreadsheet(Video.q, Video.items);
}
$scope.paginate = (Video.token != null) ? true : false;
$scope.addItems = function() {
google.script.run
.withSuccessHandler(function(results) {
Video.setToken(results);
for(var i in results.items) {
$scope.items.push(results.items[i]);
}
})
.withFailureHandler(function(res) {
$state.go('error');
})
.searchByKeyword(Video.q, Video.token)
}
}
}
var template = {
search: '<div class="search-container"><form ng-submit="submit()"><div class="input-group"><input type="text" ng-model="q" ng-value="q" class="form-control" placeholder="Search..." /><span class="input-group-btn"><button class="btn btn-default" type="submit"><span class="glyphicon glyphicon-search" aria-hidden="true"></span></button></span></div></form></div>',
result: '<div class="main-container"><div class="state-container">{{ total | number:0 }} results</div><div class="result-container"><div class="media" ng-repeat="item in items"><div class="media-left media-top"><a class="media-thumb" ng-click="showPlayer(item)"><img class="media-object" src="{{ item.snippet.thumbnails.default.url }}" width="120" height="90" alt="" /><span>{{ item.snippet.publishedAt | date: "mediumDate" }}</span></a></div><div class="media-body"><h6 class="media-heading"><a ng-click="showPlayer(item)">{{ item.snippet.title }}</a></h6><p class="media-caption">{{ item.snippet.description }}</p></div></div></div><div class="paginate" ng-if="paginate"><button type="button" class="btn btn-default btn-sm btn-block" ng-click="addItems()">More</button></div></div><div class="output-container" ng-if="outputable"><button type="button" class="btn btn-default btn-block" ng-click="outputToSpreadsheet()"><span class="glyphicon glyphicon-save-file"></span>Output to spreadsheet</button></div>',
error: '<div class="main-container"><div class="state-container">System Error</div></div>'
}
var routes = function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/search');
$stateProvider
.state('search', {
url: '/search',
views: {
search: {
template: template.search,
controller: 'SearchCtrl'
}
}
})
.state('result', {
url: '/result/:q',
views: {
search: {
template: template.search,
controller: 'SearchCtrl'
},
main: {
template: template.result,
controller: 'MainCtrl'
}
}
})
.state('error', {
url: '/error',
views: {
search: {
template: template.search,
controller: 'SearchCtrl'
},
main: {
template: template.error
}
}
})
}
var app = angular.module('app', ['ui.router']);
app.factory('Video', factory.video);
app.controller('SearchCtrl', controller.search);
app.controller('MainCtrl', controller.main);
app.config(routes);
</script>
<link rel="stylesheet" src="//normalize-css.googlecode.com/svn/trunk/normalize.css" />
<!--<link rel="stylesheet" href="//ssl.gstatic.com/docs/script/css/add-ons1.css" />-->
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" />
<style type="text/css">
html, body {
position: relative;
height: 100%;
font-family: "Helvetica Neue", Helvetica, Arial;
-webkit-font-smoothing: antialiased;
}
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
display: none !important;
}
a {
cursor: pointer;
}
.search-container {
position: fixed;
z-index: 10;
width: 100%;
padding: 15px;
background: #cc181e;
}
.output-container {
position: fixed;
left: 0;
bottom: 0;
z-index: 10;
width: 100%;
padding: 15px;
background: #0f9d58;
}
.main-container {
padding: 65px 0;
}
.state-container {
padding: 10px 15px;
border-bottom: 1px solid #f0f0f0;
font-size: 80%;
text-align: right;
}
.result-container {
width: 100%;
padding: 15px 15px 0 15px;
}
.media-thumb {
display: block;
position: relative;
width: 120px;
height: 68px;
overflow: hidden;
}
.media-thumb:hover {
opacity: .85;
}
.media-thumb img {
margin-top: -11px;
}
.media-thumb span {
display: inline-block;
position: absolute;
bottom: 2px;
right: 2px;
padding: 2px;
background: rgba(0, 0, 0, .75);
color: #fff;
font-size: 75%;
}
.media-caption {
color: #767676;
font-size: 75%;
}
.paginate {
padding: 15px;
}
</style>
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('YouTube')
.addItem('Search', 'showSidebar')
.addItem('Play', 'showModalDialog')
.addToUi();
}
function onInstall() {
onOpen();
}
function onEdit() {
onOpen();
}
function showSidebar() {
var html = HtmlService.createTemplateFromFile('sidebar').evaluate().setSandboxMode(HtmlService.SandboxMode.IFRAME).setTitle('YouTube::Search');
SpreadsheetApp.getUi().showSidebar(html);
}
function showModalDialog() {
var videoId = SpreadsheetApp.getActiveSheet().getActiveCell().getValue();
PropertiesService.getScriptProperties().setProperty('VIDEO_ID', videoId);
var html = HtmlService.createTemplateFromFile('player').evaluate().setSandboxMode(HtmlService.SandboxMode.IFRAME).setWidth(420).setHeight(315);
SpreadsheetApp.getUi().showModalDialog(html, 'YouTube::Play');
}
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename).getContent();
}
function searchByKeyword(q, nextPageToken) {
var options = {
q: q,
maxResults: 50,
type: 'video',
order: 'date'
};
if (nextPageToken != null) {
options['pageToken'] = nextPageToken;
}
return YouTube.Search.list('id,snippet', options);
}
function showPlayer(videoId) {
PropertiesService.getScriptProperties().setProperty('VIDEO_ID', videoId);
var html = HtmlService.createTemplateFromFile('player').evaluate().setSandboxMode(HtmlService.SandboxMode.IFRAME).setWidth(420).setHeight(315);
SpreadsheetApp.getUi().showModalDialog(html, 'YouTube::Play');
}
function getYouTubeUrl() {
var videoId = PropertiesService.getScriptProperties().getProperty('VIDEO_ID');
return 'https://www.youtube.com/embed/'+videoId+'?cc_load_policy=0&vq=highres&rel=0&loop=1&autoplay=1';
}
function outputToSpreadsheet(q, items) {
try {
var ss = SpreadsheetApp.getActiveSpreadsheet(),
sheet = ss.insertSheet(q, 0),
header = ['videoId', 'title', 'description', 'channelId', 'channelTitle', 'publishedAt', 'thumbnailsDefaultUrl', 'thumbnailsHighUrl', 'thumbnailsMediumUrl'];
sheet.appendRow(header);
sheet.setFrozenRows(1);
for(var i in items) {
var item = items[i];
sheet.appendRow([
item.id.videoId,
item.snippet.title,
item.snippet.description,
item.snippet.channelId,
item.snippet.channelTitle,
item.snippet.publishedAt,
item.snippet.thumbnails['default']['url'],
item.snippet.thumbnails['high']['url'],
item.snippet.thumbnails['medium']['url']
]);
}
ui.alert('Complete');
} catch(ex) {
ui.alert(ex.toString());
}
}
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<?!= include('_stylesheet'); ?>
</head>
<body>
<iframe width="420" height="315" src="<?!= getYouTubeUrl(); ?>" frameborder="0" allowfullscreen></iframe>
</body>
</html>
<!DOCTYPE html>
<html lang="en" ng-app="app">
<head>
<base target="_top">
<?!= include("_stylesheet"); ?>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.15/angular-ui-router.js"></script>
</head>
<body>
<div ui-view="search" ng-cloak></div>
<div ui-view="main" ng-cloak></div>
<?!= include("_app"); ?>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment