Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

closed β publish version #35

Merged
merged 8 commits into from
Commits on Apr 3, 2013
  1. add movie evaluation btn

    authored
Commits on Apr 4, 2013
  1. anable kick api server

    authored
  2. enable like and unlike API

    authored
  3. improve sort and filtering

    authored
  4. filter unlike

    authored
  5. improve control pannel

    authored
This page is out of date. Refresh to see the latest.
View
3  .gitmodules
@@ -22,3 +22,6 @@
[submodule "fuel/packages/log"]
path = fuel/packages/log
url = git://github.com/fuel/log.git
+[submodule "crawler"]
+ path = crawler
+ url = git@github.com:otiai10/anicatchCrawler.git
View
2  crawler/.gitignore
@@ -0,0 +1,2 @@
+conf.rb
+log/
View
10 crawler/crawler.rb
@@ -0,0 +1,10 @@
+require 'gmailAccessor'
+require 'dbAccessor'
+
+db = AnimeDBAccessor.new
+ga = GmailAccessor.new(:unread)
+ga.getAnimeList.each do |anime|
+ db.regist(anime)
+end
+
+p Time.now
View
60 crawler/dbAccessor.rb
@@ -0,0 +1,60 @@
+require 'rubygems'
+require 'mysql'
+require 'conf' # ただの設定ファイル
+
+class AnimeDBAccessor
+
+ attr_accessor :client, :tb_definition
+ def initialize
+ @tb_definition = "CREATE TABLE `animes` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `title` varchar(128) NOT NULL,
+ `url` text,
+ `likes` bigint(20) DEFAULT '0',
+ `unlikes` bigint(20) DEFAULT '0',
+ `info` binary(1) DEFAULT NULL,
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ `created_at` datetime DEFAULT NULL,
+ `deleted` tinyint(1) DEFAULT '0',
+ PRIMARY KEY (`title`),
+ UNIQUE KEY `id` (`id`)
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8"
+ #@client = Mysql.connect(DB_HOST, DB_USER, DB_PASS, DB_NAME)
+ @client = Mysql.connect('localhost', DB_USER, DB_PASS, DB_NAME)
+ end
+
+ def init_table
+ drop_st = 'DROP TABLE IF EXISTS animes'
+ @client.query(drop_st)
+ @client.query(@tb_definition)
+ end
+
+ def regist(anime=nil)
+ unless anime.nil?
+ insert_st = "INSERT IGNORE INTO animes (title, url, created_at) VALUE ('" + anime['title'] + "', '" + anime['url'] + "', NOW())"
+ @client.query(insert_st)
+ end
+ end
+
+ # pagingとかサポートしたい
+ def find(options=nil)
+ select_st = "SELECT * FROM animes"
+ @client.query(select_st).each do |row|
+ p row
+ end
+ end
+
+ def find_all
+ select_st = "SELECT * FROM animes ORDER BY unlikes, likes"
+ return @client.query(select_st)
+ end
+end
+
+# test
+=begin
+model = AnimeDBAccessor.new
+res = model.find_all
+res.each do |anime|
+ p anime
+end
+=end
View
55 crawler/gmailAccessor.rb
@@ -0,0 +1,55 @@
+require 'rubygems'
+require 'gmail' # sudo gem install ruby-gmail
+require 'conf' # ただの設定ファイル
+require 'kconv'
+
+MAIL_DELIMITER = "------------------------------------------------\r\n"
+
+class GmailAccessor
+ attr_accessor :gmail, :opt
+ def initialize(opt=:read)
+ @gmail = Gmail.new(USERNAME,PASSWORD)
+ @opt = opt
+ end
+
+ def getAnimeList
+ list = []
+ mails = @gmail.inbox.emails(@opt).map do |mail|
+ #本文処理
+ if !mail.text_part && !mail.html_part
+ entirebody = Kconv.toutf8(mail.body.decoded)
+ #entirebody = mail.body.decoded
+ splited = entirebody.split(MAIL_DELIMITER)
+ splited.each_with_index do |elm, i|
+ if /[0-9]+:[0-9]+/ =~ elm
+ val = splited[i + 1].split("\n")
+ info = {
+ "channel" => val[0],
+ "title" => val[1],
+ "sprint" => val[2],
+ "url" => val[3]
+ }
+ list.push(info);
+ end
+ #puts elm
+ end
+ elsif mail.text_part
+ #puts "text: " + Kconv.toutf8(mail.text_part.decoded)
+ elsif mail.html_part
+ #puts "html: " + Kconv.toutf8(mail.html_part.decoded)
+ end
+ end
+ return list
+ end
+end
+
+# test
+=begin
+ga = GmailAccessor.new()
+ga.getAnimeList.each do |anime|
+ puts 'CHANNEL :' + anime['channel']
+ puts 'TITLE :' + anime['title']
+ puts 'SPRINT :' + anime['sprint']
+ puts 'URL :' + anime['url']
+end
+=end
View
7 crawler/sampleapp.rb
@@ -0,0 +1,7 @@
+require 'dbAccessor'
+
+db = AnimeDBAccessor.new
+db.find_all.each do |anime|
+ p '=========='
+ puts anime
+end
View
39 fuel/app/classes/controller/api/anime.php
@@ -11,8 +11,13 @@ public function action_like()
'params' => $params,
);
if($this->_isValidParams($params)){
- $res['result'] = "true";
+ $anime = $this->getAnimeById($params['id']);
+ $likes = $anime['likes'] + 1;
+ if($this->updateAnimeLikesUnlikesById($params['id'], array('likes'=>$likes))){
+ $res['result'] = true;
+ }
}
+
$this->response(json_encode($res));
}
@@ -25,8 +30,13 @@ public function action_unlike()
'params' => $params,
);
if($this->_isValidParams($params)){
- $res['result'] = "true";
+ $anime = $this->getAnimeById($params['id']);
+ $unlikes = $anime['unlikes'] + 1;
+ if($this->updateAnimeLikesUnlikesById($params['id'], array('unlikes'=>$unlikes))){
+ $res['result'] = true;
+ }
}
+
$this->response(json_encode($res));
}
@@ -37,4 +47,29 @@ private function _isValidParams($params)
}
return true;
}
+
+ private function getAnimeById($id)
+ {
+ $query = 'SELECT * FROM animes WHERE id=' . $id . ' LIMIT 1';
+ $animes = DB::query($query)->execute()->as_array();
+ if(count($animes) === 1){
+ return array_shift($animes);
+ }
+ return null;
+ }
+
+ private function updateAnimeLikesUnlikesById($id, $params)
+ {
+ if(isset($params['likes'])){
+ $query = 'UPDATE animes SET likes=' . $params['likes'] .' WHERE id='.$id;
+ $success = DB::query($query)->execute();
+ }else if(isset($params['unlikes'])){
+ $query = 'UPDATE animes SET unlikes=' . $params['unlikes'] .' WHERE id='.$id;
+ $success = DB::query($query)->execute();
+ }
+ if($success){
+ return true;
+ }
+ return false;
+ }
}
View
17 fuel/app/classes/controller/stream.php
@@ -10,16 +10,21 @@ public function action_index()
$page = 1;
}
$offset = $page -1;
- $query = 'SELECT * FROM animes ORDER BY unlikes DESC, created_at, likes LIMIT '.($limit*$offset).', '.$limit;
+ $query = 'SELECT * FROM animes ORDER BY unlikes, created_at DESC, likes LIMIT '.($limit*$offset).', '.$limit;
$list = DB::query($query)->execute()->as_array();
+ $animes = array();
foreach($list as $k => $anime){
$video_info = $this->_getVideoFromYouTube($anime['title']);
- $list[$k] = array_merge($list[$k], $video_info);
+ if(empty($video_info)){
+ unset($list[$k]);
+ continue;
+ }
+ $animes[] = array_merge($list[$k], $video_info);
}
$this->template->content = View::forge('stream/index');
- $this->template->content->animes = $list;
+ $this->template->content->animes = $animes;
$this->template->content->page = $page;
}
@@ -38,8 +43,14 @@ private function _getVideoFromYouTube($anime_title, $class='OP')
$rows = json_decode($res->getBody(), true);
+ if(empty($rows['feed']) || empty($rows['feed']['entry'])){
+ return null;
+ }
$info = $this->_chooseAptYouTubeVideo($rows['feed']['entry']);
+ if(empty($info['id'])){
+ return null;
+ }
$elms = explode('/',$info['id']['$t']);
$vhash = array_pop($elms);
View
13 fuel/app/views/stream/index.php
@@ -6,9 +6,9 @@
<div class="span6">
<blockquote style="word-break: break-word;">
<h3 id="anime-title">hoge</h3>
- <small><a id="anime-url">hgoe</a></small>
+ <small><a id="anime-url" target="_blank">hgoe</a></small>
<h1 id="video-title">fuga</h1>
- <small><a id="video-url">hgoe</a></small>
+ <small><a id="video-url" target="_blank">hgoe</a></small>
</blockquote>
<div id="anime-evaluation">
<a tabindex='1' id="like-anime" anime-id="" class="btn btn-large btn-primary">好き</a>
@@ -17,10 +17,11 @@
</div>
</div>
<div class="row">
- <div class="span12">
- <a tabindex='1' id="cont-prev" class="play-prev btn btn-large">Prev</a>
- <!-- a tabindex='1' id="cont-pause" class="switch-pause btn btn-large">Pause</a -->
- <a tabindex='1' id="cont-next" class="play-next btn btn-large">Next</a>
+ <div id="control-pannel" class="span12">
+ <a tabindex='1' id="cont-prev" class="btn btn-large play-prev">PREV</a>
+ <a tabindex='1' id="cont-pause" class="btn btn-large switch-pause btn-inverse" state="0">PLAY</a>
+ <a tabindex='1' id="cont-next" class="btn btn-large play-next">NEXT</a>
+ <a tabindex='1' id="cont-hide" class="btn btn-large hide-cont" state="1">hide</a>
</div>
</div>
<div class="row streaming-contents">
View
12 public/assets/css/common.css
@@ -162,3 +162,15 @@ div#sage-face-hidden {
font-weight: bold;
text-shadow: 0 0 10px #000;
}
+
+object#player {
+ /*
+ position: fixed;
+ top: -500px;
+ */
+}
+
+div#control-pannel {
+ padding-top: 5px;
+ border-top: thin solid #ddd;
+}
View
30 public/assets/js/ajax.js
@@ -2,11 +2,13 @@
* ajax method
**/
var xhr = {};
+var API_HOST_URL = 'http://api.anicatch.net';
+var CONFIRM_SERIF = "これ押しちゃうとこのアニメがリストに戻ってくるのはけっこう絶望的ですが、マジすか?";
var ajax = {
call : function(func, param, callback){
var method = 'POST';
- var url = 'http://anicatch.net';
+ var url = API_HOST_URL;
var async = true;
var data = {};
switch(func){
@@ -22,8 +24,8 @@ var ajax = {
}
xhr = new XMLHttpRequest();
xhr.open(method, url, async, data);
- xhr.setRequestHeader('Pragma', 'no-cache');
- xhr.setRequestHeader('Cache-Control', 'no-cache');
+ //xhr.setRequestHeader('Pragma', 'no-cache');
+ //xhr.setRequestHeader('Cache-Control', 'no-cache');
//xhr.setRequestHeader('If-Modified-Since', 'Thu, 01 Jun 1970 00:00:00 GMT');
//xhr.responseType = 'json';
xhr.onreadystatechange = function(){
@@ -63,16 +65,18 @@ function registAjaxBtns(){
});
var unlikeAnimeBtn = document.getElementById('unlike-anime');
unlikeAnimeBtn.addEventListener('click',function(){
- var self = this;
- ajax.call('unlikeAnime', this.getAttribute('anime-id'), function(res){
- console.log('Ajax is back -> ', res);
- if(Boolean(res.result)){
- sageAction(function(){
- //replaceInnerHTML(self, '<h1>(´・ω・`)</h1>', { color : '#aaa'});
- replaceInnerHTML(self, '<div></div>');
- });
- }
- });
+ if(window.confirm(CONFIRM_SERIF)){
+ var self = this;
+ ajax.call('unlikeAnime', this.getAttribute('anime-id'), function(res){
+ console.log('Ajax is back -> ', res);
+ if(Boolean(res.result)){
+ sageAction(function(){
+ //replaceInnerHTML(self, '<h1>(´・ω・`)</h1>', { color : '#aaa'});
+ replaceInnerHTML(self, '<div></div>');
+ });
+ }
+ });
+ }
});
}
View
78 public/assets/js/player.js
@@ -6,6 +6,8 @@ var __index = 0;
var __player = {};
var btnHTML = '<a tabindex="1" id="like-anime" anime-id="" class="btn btn-large btn-primary">好き</a><a tabindex="1" id="unlike-anime" anime-id="" class="btn btn-large btn-inverse">これ今期アニメじゃない</a>';
+var defPauseBtnClass = "btn btn-large switch-pause btn-inverse",
+ pauseBtnChangeClass = "btn-inverse";
// see : https://developers.google.com/youtube/js_api_reference?hl=ja#Events
var STATE = {
@@ -44,6 +46,16 @@ function registControleBtns(){
});
}
+ var pauseBtn = document.getElementById('cont-pause');
+ pauseBtn.addEventListener('click', function(){
+ togglePauseBtnValue();
+ switchPause();
+ });
+
+ var toggleHideBtn = document.getElementById('cont-hide');
+ toggleHideBtn.addEventListener('click', function(){
+ toggleHide();
+ });
}
function initPlaylist(__playlist, is_sub){
@@ -97,6 +109,7 @@ function stateDispatcher(state){
playNext();
break;
case STATE.PLAYING:
+ togglePauseBtnValue(STATE.PLAYING);
break;
case STATE.STOPED:
break;
@@ -120,12 +133,15 @@ function displayInfo(){
atitle.innerHTML = __playlist[__index]['atitle'];
var vtitle = document.getElementById('video-title');
- vtitle.innerHTML = __playlist[__index]['vtitle'];
+ vtitle.innerHTML = __playlist[__index]['vtitle'] + '<a class="btn btn-small <!--btn-inverse-->">これ違う動画</a>';
var str = 'http://www.youtube.com/watch?v=' + __playlist[__index]['hash'];
var vurl = document.getElementById('video-url');
vurl.innerHTML = str;
vurl.setAttribute('href', str);
+ vurl.addEventListener('click', function(){
+ pause();
+ });
var str = __playlist[__index]['aurl'];
var aurl = document.getElementById('anime-url');
@@ -190,11 +206,71 @@ function playDirect(seq){
_playThis();
}
+function toggleHide(){
+ var btn = document.getElementById('cont-hide');
+ console.log(__player.style);
+ switch(btn.getAttribute('state')){
+ case "1":
+ __player.style.position = "fixed";
+ __player.style.top = "-500px";
+ btn.innerHTML = "show";
+ btn.setAttribute('state', '0');
+ break;
+ case "0":
+ default:
+ __player.style.position = "";
+ __player.style.top = "";
+ btn.innerHTML = "hide";
+ btn.setAttribute('state', '1');
+ }
+}
+
+function togglePauseBtnValue(state){
+ var btn = document.getElementById('cont-pause');
+ if(state == STATE.PLAYING){
+ btn.setAttribute('state', '0');
+ }
+ switch(btn.getAttribute('state')){
+ case "0":
+ btn.setAttribute('state', '1');
+ btn.innerHTML = 'PAUSE';
+ removeClass(btn, pauseBtnChangeClass);
+ break;
+ case "1":
+ default:
+ btn.setAttribute('state', '0');
+ btn.setAttribute('class', defPauseBtnClass);
+ btn.innerHTML = 'PLAY';
+ }
+}
+
function switchPause(){
+ switch(__player.getPlayerState()){
+ case STATE.STOPED:
+ case STATE.READY:
+ play();
+ break;
+ case STATE.PLAYING:
+ default:
+ pause();
+ break;
+ }
+}
+function pause(){
+ __player.pauseVideo();
+}
+function play(){
+ __player.playVideo();
}
function _playThis(){
__player.loadVideoById(__playlist[__index]['hash']);
displayInfo();
}
+
+function removeClass(el, c) {
+ var triml = /^\s+/,
+ trimr = /\s+$/;
+ el.className = (' ' + el.className + ' ').replace(' ' + c + ' ', '').replace(triml, '').replace(trimr, '');
+}
Something went wrong with that request. Please try again.