summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--main.go129
-rw-r--r--static/base.css7
-rw-r--r--static/jquery.hive.pollen.min.js3
-rw-r--r--static/poller.js33
-rw-r--r--static/script.js87
-rw-r--r--templates/p.html42
-rw-r--r--updates.go51
8 files changed, 250 insertions, 106 deletions
diff --git a/Makefile b/Makefile
index 47cbb29..b3a5966 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
all: aa
-main.6: main.go
- 6g main.go
+main.6: main.go updates.go
+ 6g main.go updates.go
aa: main.6
6l -o aa main.6
diff --git a/main.go b/main.go
index c139b99..965e000 100644
--- a/main.go
+++ b/main.go
@@ -6,6 +6,9 @@ import (
"exp/template"
mysql "github.com/Philio/GoMySQL"
"os"
+ "json"
+ "strconv"
+ "time"
)
type Song struct {
@@ -15,11 +18,10 @@ type Song struct {
}
type Playlist struct {
Id string
- Songs []*Song
}
var templates map[string]*template.Template
-const debug = false
+const debug = true
var db *mysql.Client
// given an id ('abcd1234'), return the pid (1)
@@ -59,41 +61,7 @@ func playlist(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/", 303)
return
}
- query, err := db.Prepare("SELECT `yid`,`title`,`user` FROM `playlist` JOIN `song` WHERE `id` = ?;")
- if err != nil {
- http.Error(w, err.String(), http.StatusInternalServerError)
- return
- }
- err = query.BindParams(id)
- if err != nil {
- http.Error(w, err.String(), http.StatusInternalServerError)
- return
- }
- err = query.Execute()
- if err != nil {
- http.Error(w, err.String(), http.StatusInternalServerError)
- return
- }
-
- playlist := Playlist{Id: id, Songs: make([]*Song, 0, 2)}
- for {
- song := new(Song)
- query.BindResult(&song.Yid, &song.Title, &song.User)
- eof, err := query.Fetch()
- if err != nil {
- http.Error(w, err.String(), http.StatusInternalServerError)
- return
- }
- if eof {
- break
- }
- playlist.Songs = append(playlist.Songs, song)
- }
- err = query.FreeResult()
- if err != nil {
- http.Error(w, err.String(), http.StatusInternalServerError)
- return
- }
+ playlist := Playlist{Id: id}
if debug {
t, err := template.ParseFile("templates/p.html")
@@ -108,7 +76,7 @@ func playlist(w http.ResponseWriter, r *http.Request) {
return
}
} else {
- err = templates["p"].Execute(w, playlist)
+ err := templates["p"].Execute(w, playlist)
if err != nil {
fmt.Fprintln(os.Stderr, err.String())
}
@@ -133,7 +101,10 @@ func add(w http.ResponseWriter, r *http.Request) {
http.Error(w, err.String(), http.StatusInternalServerError)
return
}
+
w.Write([]byte("1"))
+ addUpdate(pid, addAction,
+ &Song{Yid: q.Get("yid"), Title: q.Get("title"), User: q.Get("user")})
}
func remove(w http.ResponseWriter, r *http.Request) {
@@ -151,7 +122,85 @@ func remove(w http.ResponseWriter, r *http.Request) {
http.Error(w, err.String(), http.StatusInternalServerError)
return
}
+
w.Write([]byte("1"))
+ addUpdate(pid, removeAction, &Song{Yid: q.Get("yid")})
+}
+
+func poll(w http.ResponseWriter, r *http.Request) {
+ q := r.URL.Query()
+ timestamp := q.Get("timestamp")
+ if timestamp == "0" {
+ query, err := db.Prepare("SELECT `yid`,`title`,`user` FROM `playlist` JOIN `song` WHERE `id` = ?;")
+ if err != nil {
+ http.Error(w, err.String(), http.StatusInternalServerError)
+ return
+ }
+ err = query.BindParams(q.Get("pid"))
+ if err != nil {
+ http.Error(w, err.String(), http.StatusInternalServerError)
+ return
+ }
+ err = query.Execute()
+ if err != nil {
+ http.Error(w, err.String(), http.StatusInternalServerError)
+ return
+ }
+
+ updates := make([]Update, 0, 2)
+ for {
+ song := new(Song)
+ query.BindResult(&song.Yid, &song.Title, &song.User)
+ eof, err := query.Fetch()
+ if err != nil {
+ http.Error(w, err.String(), http.StatusInternalServerError)
+ return
+ }
+ if eof {
+ break
+ }
+ updates = append(updates, Update{Song: song, Action: addAction, Timestamp: time.Nanoseconds()})
+ }
+ err = query.FreeResult()
+ if err != nil {
+ http.Error(w, err.String(), http.StatusInternalServerError)
+ return
+ }
+
+ output, err := json.MarshalForHTML(updates)
+ if err != nil {
+ http.Error(w, err.String(), http.StatusInternalServerError)
+ return
+ }
+ w.Write(output)
+ } else {
+ timestamp, err := strconv.Atoi64(q.Get("timestamp"))
+ if err != nil {
+ http.Error(w, err.String(), http.StatusInternalServerError)
+ return
+ }
+ var update *Update
+ for i := 0; i < 30; i++ {
+ update = getUpdates(getpid(q.Get("pid")), timestamp)
+ if update != nil {
+ w.Write([]byte("["))
+ for update != nil {
+ output, err := json.MarshalForHTML(update)
+ if err == nil {
+ w.Write(output)
+ }
+ update = update.Next
+ if update != nil {
+ w.Write([]byte(","))
+ }
+ }
+ w.Write([]byte("]"))
+ return
+ }
+ time.Sleep(1e9) // 1 second
+ }
+ w.Write([]byte("[]"))
+ }
}
func main() {
@@ -166,7 +215,8 @@ func main() {
}
var err os.Error
- db, err = mysql.DialTCP("raylu.net", "audio", "audio", "audio")
+ //db, err = mysql.DialTCP("raylu.net", "audio", "audio", "audio")
+ db, err = mysql.DialTCP("173.228.31.111", "audio", "audio", "audio")
if err != nil {
fmt.Println(err)
os.Exit(1)
@@ -176,6 +226,7 @@ func main() {
http.HandleFunc("/p/", playlist)
http.HandleFunc("/add/", add)
http.HandleFunc("/remove/", remove)
+ http.HandleFunc("/poll/", poll)
err = http.ListenAndServe("localhost:8000", nil)
if err != nil {
fmt.Println(err)
diff --git a/static/base.css b/static/base.css
index c932d6f..00ad6f1 100644
--- a/static/base.css
+++ b/static/base.css
@@ -63,6 +63,7 @@ header label[for="user"] {
}
header input#user {
left: 570px;
+ top: 0px;
}
header label[for="song"] {
left: 300px;
@@ -137,7 +138,7 @@ section.song div.user {
}
section.song div.remove {
position: absolute;
- top: 0px;
+ top: 0;
right: 5px;
font-weight: bold;
cursor: pointer;
@@ -145,8 +146,12 @@ section.song div.remove {
section.song div.thumb {
float: left;
width: 150px;
+ height: 90px;
overflow: hidden;
}
+section.song div.thumb img {
+ height: 90px;
+}
section.song canvas, section.song > img {
position: relative;
top: 20px;
diff --git a/static/jquery.hive.pollen.min.js b/static/jquery.hive.pollen.min.js
new file mode 100644
index 0000000..e2557b3
--- /dev/null
+++ b/static/jquery.hive.pollen.min.js
@@ -0,0 +1,3 @@
+// https://github.com/rwldrn/jquery-hive
+// http://dev.pollenjs.com
+if(!Array.prototype.forEach){Array.prototype.forEach=function(a){var b=this.length||0,c=0,d=arguments[1];if(typeof a!=="function"){throw new TypeError}for(;c<b;c++){if(c in this){a.call(d,this[c],c,this)}}}}(function(WorkerGlobalScope){var Pollen=function(){this[0]=WorkerGlobalScope;return this},each=Array.prototype.forEach,indexOf=Array.prototype.indexOf,push=Array.prototype.push,slice=Array.prototype.slice,hasOwn=Object.prototype.hasOwnProperty,toStr=Object.prototype.toString,trim=String.prototype.trim;Pollen.prototype={identity:0,identify:{identify:function(){return Pollen.identity}},date:{now:function(a){return a?Math.round((new Date).getTime()/1e3):+(new Date)}},func:{noop:function(){},bind:function(a,b,c){if(a===null){return b}if(b&&a){return function(){return a.apply(b,c)}}}},evaluate:{isObj:function(a){if(!a){return false}if(a.constructor&&!hasOwn.call(a,"constructor")&&!hasOwn.call(a.constructor.prototype,"isPrototypeOf")){return false}var b;for(b in a){}return b===undefined||hasOwn.call(a,b)},isArr:function(a){return a!==null&&typeof a=="object"&&"splice"in a&&"join"in a},isRegExp:function(a){if(a){if((new RegExp(/([[\]\/\\])/g)).test(a)===false){return false}return(new RegExp(a)).test(null)||toStr.call(a)=="[object RegExp]"}return false},isFn:function(a){return a!==null&&toStr.call(a)==="[object Function]"&&typeof a=="function"},isStr:function(a){return a!==null&&typeof a=="string"&&isNaN(a)},isNum:function(a){return a!==null&&typeof a=="number"},isJson:function(a){if(a===null)return false;var b=Pollen.evaluate.isObj(a)?JSON.stringify(a):a;return(new RegExp('^("(\\\\.|[^"\\\\\\n\\r])*?"|[,:{}\\[\\]0-9.\\-+Eaeflnr-u \\n\\r\\t])+?$')).test(b)},isDef:function(a){if(!a||a===null||typeof a==="undefined"||Pollen.evaluate.isEmpty(a)){return false}return true},isNull:function(a){return a===null},isEmpty:function(a){return a==null||a==""},eq:function(a,b){var c=0,d=b.length,e=false;for(;c<d;c++){if(a===b[c]){e=true;break}}return e}},string:{trim:function(a){if(typeof a==="undefined"||a==null)return"";a=a+"";return a==""?"":a.replace(/^\s\s*/,"").replace(/\s\s*$/,"")},inStr:function(a,b){if(!a){return false}if(a.indexOf(b)>=0||(new RegExp(b,"ig")).test(a)){return true}return false},_regExpEscape:function(a){if((new RegExp(/([[\]\/\\])/g)).test(a)===false){return String(a).replace(/([.*+?^=!:${}()|[\]\/\\])/g,"\\$1")}return a}},array:{each:function(a,b){var c=0,d=a.length;if(Pollen.evaluate.isArr(a)){for(;c<d;c++){b.call(a,c,a[c])}}if(Pollen.evaluate.isObj(a)){for(var e in a){if(a[e]){b.call(a[e],e,a[e],c++)}}}},toArray:function(a){if(!a){return[]}if(Pollen.evaluate.isArr(a)){return a}if(Pollen.evaluate.isStr(a)){return a.split("")}var b=a.length||0,c=[];while(b--){c[b]=a[b]}return c},isAtIndex:function(a,b,c){if(a[b]==c){return true}return false},inArray:function(a,b){var c;for(c in a){if(a[c]==b){return true}}return false},clone:function(a){if(Pollen.evaluate.isArr(a)){return[].concat(a)}var b=Pollen.evaluate.isArr(a)?[]:{};for(var c in obj){if(hasOwn.call(obj,c)){b[c]=this.clone(obj[c])}}return b},last:function(a){return a[a.length-1]},first:function(a){return a[0]},unique:function(a){var b=0,c=[],d=[];for(var e in a){if(!Pollen.array.inArray(d,JSON.stringify(a[e]))){c[c.length]=a[e];d[d.length]=JSON.stringify(a[e])}}return c},merge:function(a){var b=a,c=0;for(;c<arguments.length;c++){b=Pollen.evaluate.isArr(arguments[c])?b.concat(arguments[c]):Pollen.object.extend(b,arguments[c])}return Pollen.evaluate.isArr(b)?this.unique(b):b},combine:function(a,b){var c=0,d=a.length,e={};if(!a||!b||!Pollen.evaluate.isArr(a)||!Pollen.evaluate.isArr(b)){return false}if(d!=b.length){throw"Cannot combine arrays, key length does not match value length"}for(;c<d;c++){e[a[c]]=b[c]}return e},filter:function(a,b,c){var d=0,e=a.length,f=[];if(!Pollen.evaluate.isArr(a)){f={};for(var g in a){if(b(a[g],d)){f[g]=a[g]}}return f}for(;d<e;d++){if(b(a[d],d)){f[f.length]=a[d]}}return f},map:function(a,b){var c=[],d=0,e=a.length;for(;d<e;d++){var f=b(a[d],d);if(f!==null){c[c.length]=f}}return c.concat.apply([],c)},grep:function(a,b,c){var d=[],e;if(Pollen.evaluate.isFn(b)){return Pollen.array.filter(a,b)}e=!Pollen.evaluate.isRegExp(b)?Pollen.string._regExpEscape(b):b;Pollen.array.each(a,function(b,f){if(typeof f==="number"){f=f+""}if(f.match(e)){d[d.length]=c?c.call(a,f,b):f}});return d},size:function(a){if(Pollen.evaluate.isArr(a)||Pollen.evaluate.isStr(a)){return Pollen.array.toArray(a).length}if(Pollen.evaluate.isObj(a)){var b=0;for(var c in a){if(!Pollen.evaluate.isNull(a[c])){b++}}return b}return Pollen.array.toArray(a).length},pick:function(a,b){var c=[];Pollen.array.each(a,function(a,d){c[c.length]=d[b]});return c},sortBy:function(a,b,c){return Pollen.array.map(a,function(a,d){return{value:a,criteria:b.call(c,a,d)}}).sort(function(a,b){var c=a.criteria,d=b.criteria;return c<d?-1:c>d?1:0}).pick("value")},compact:function(a){var b=[undefined,null,false],c=Pollen.evaluate.isArr(a)?[]:{},d=function(a){var b=a.length,e="";for(var f in a){e=a[f];if(Pollen.evaluate.isArr(e)){d(e)}else{if(!Pollen.evaluate.eq(e,[undefined,null,false])){if(Pollen.evaluate.isArr(c)){c[c.length]=e}else{c[e]=e}}}}return true};d(a);return c}},object:{keys:function(a){var b=[];for(var c in a){if(a[c]){b[b.length]=c}}return b},values:function(a){var b=[];for(var c in a){if(a[c]){b[b.length]=a[c]}}return b},extend:function(a,b){if(Pollen.evaluate.isNull(a)&&Pollen.evaluate.isDef(b)){return b}for(var c in b){if(hasOwn.call(b,c)){var d=b[c],e=a[c];if(!Pollen.evaluate.isNull(d)){a[c]=e&&typeof d=="object"&&typeof e=="object"?Pollen.array.merge(e,d):d}}}return a}},ajax:{_options:{url:"",data:"",dataType:"",success:Pollen.noop,type:"GET",sync:navigator.userAgent.toLowerCase().indexOf("safari/")!=-1?false:true,xhr:function(){return new XMLHttpRequest}},get:function(a){a.type="GET";this._ajax(a)},post:function(a){a.type="POST";this._ajax(a)},_ajax:function(a){var b=Pollen.object.extend(this._options,a),c=b.dataType=="json"?true:false,d=b.type.toLowerCase(),e=b.xhr(),f=b.success;if(!Pollen.evaluate.isStr(b.data)){b.data=Pollen.data.param(b.data)}if(d=="get"&&b.data.length){b.url+=((new RegExp(/\?/)).test(b.url)?"&":"?")+b.data}if(e){Pollen.ajax._confXHR(e,b,c,f);e.open(b.type,b.url,b.sync);e.setRequestHeader("X-Requested-With","Worker-XMLHttpRequest");e.setRequestHeader("X-Worker-Hive","Pollen-JS");if(Pollen.evaluate.isDef(Pollen.identity)){e.setRequestHeader("X-Pollen-Thread-Id",Pollen.identity)}if(d=="post"){e.setRequestHeader("Content-Type","application/x-www-form-urlencoded")}e.send(d=="post"?b.data:null)}},_confXHR:function(a,b,c,d){function h(){if(d){d.call(a,e)}}var e,f;var g=a.onreadystatechange=function(){if(a.readyState==4){f=Pollen.evaluate.isJson(a.responseText)?JSON.parse(a.responseText):null;e=c?f:{text:a.responseText,xml:a.responseXML,json:f};h()}};return a}},data:{param:function(a){function c(a,c){c=Pollen.evaluate.isFn(c)?c():c;b[b.length]=encodeURIComponent(a)+"="+encodeURIComponent(c)}var b=[];Pollen.array.each(a,function(a,b){c(a,b)});if(arguments.length==2&&arguments[1]===true){c("WORKER_ID",Pollen.identity)}return b.join("&").replace(/%20/g,"+")},cache:{pollen:+(new Date)},storage:function(a,b){if(a&&b===undefined){return Pollen.data.cache[a]?Pollen.data.cache[a]:false}Pollen.data.cache[a]=b;return Pollen.data.cache[a]},query:function(){function distinctFilter(a,b){var c=[],d={},e=a.length,f=0;for(;f<e;++f){var g=a[f];if(b(g,f,a)){if(typeof g=="object"&&g){if(!g.__included){g.__included=true;c[c.length]=g}}else if(!d[g+typeof g]){d[g+typeof g]=true;c[c.length]=g}}}for(f=0,e=c.length;f<e;++f){if(c[f]){delete c[f].__included}}return c}function expand(a,b){function d(a){if(b){if(b===true&&!(a instanceof Array)){c[c.length]=a}else if(a[b]){c[c.length]=a[b]}}for(var e in a){var f=a[e];if(!b){c[c.length]=f}else if(f&&typeof f=="object"){d(f)}}}var c=[];if(Pollen.evaluate.isArr(b)){if(b.length==1){return a[b[0]]}for(var e=0;e<b.length;e++){c[c.length]=a[b[e]]}}else{d(a)}return c}function slice(a,b,c,d){var e=a.length,f=[];c=c||e;b=b<0?Math.max(0,b+e):Math.min(e,b);c=c<0?Math.max(0,c+e):Math.min(e,c);for(var g=b;g<c;g+=d){f[f.length]=a[g]}return f}return function(query,obj){function makeRegex(a,b,c,d,e){return strs[e].match(/[\*\?]/)||d=="~"?"/^"+strs[e].substring(1,strs[e].length-1).replace(/\\([btnfr\\"'])|([^\w\*\?])/g,"\\$1$2").replace(/([\*\?])/g,".$1")+(d=="~"?"$/i":"$/")+".test("+b+")":a}function pcall(a){prefix=a+"("+prefix}var depth=0,strs=[],prefix="",executor="";query=query.replace(/"(\\.|[^"\\])*"|'(\\.|[^'\\])*'|[\[\]]/g,function(a){depth+=a=="["?1:a=="]"?-1:0;return a=="]"&&depth>0?"`]":a.charAt(0)=='"'||a.charAt(0)=="'"?"`"+(strs.push(a)-1):a}).replace(/([^<>=]=)([^=])/g,"$1=$2").replace(/@|(\.\s*)?[a-zA-Z\$_]+(\s*:)?/g,function(a){return a.charAt(0)=="."?a:a=="@"?"$obj":(a.match(/:|^(\$|Math|true|false|null)$/)?"":"$obj.")+a}).replace(/\.?\.?\[(`\]|[^\]])*\]|\?.*|\.\.([\w\$_]+)|\.\*/g,function(a,b,c){var d=a.match(/^\.?\.?(\[\s*\^?\?|\^?\?|\[\s*==)(.*?)\]?$/);if(d){var e="";if(a.match(/^\./)){pcall("expand");e=",true)"}pcall(d[1].match(/\=/)?"Pollen.array.map":d[1].match(/\^/)?"distinctFilter":"Pollen.array.filter");return e+",function($obj){return "+d[2]+"})"}d=a.match(/^\[\s*([\/\\].*)\]/);if(d){return".concat().sort(function(a,b){"+d[1].replace(/\s*,?\s*([\/\\])\s*([^,\\\/]+)/g,function(a,b,c){return"var av= "+c.replace(/\$obj/,"a")+",bv= "+c.replace(/\$obj/,"b")+";if(av>bv||bv==null){return "+(b=="/"?1:-1)+";}\n"+"if(bv>av||av==null){return "+(b=="/"?-1:1)+";}\n"})+"})"}d=a.match(/^\[(-?[0-9]*):(-?[0-9]*):?(-?[0-9]*)\]/);if(d){pcall("slice");return","+(d[1]||0)+","+(d[2]||0)+","+(d[3]||1)+")"}if(a.match(/^\.\.|\.\*|\[\s*\*\s*\]|,/)){pcall("expand");return(a.charAt(1)=="."?",'"+c+"'":a.match(/,/)?","+a:"")+")"}return a}).replace(/(\$obj\s*(\.\s*[\w_$]+\s*)*)(==|~)\s*`([0-9]+)/g,makeRegex).replace(/`([0-9]+)\s*(==|~)\s*(\$obj(\s*\.\s*[\w_$]+)*)/g,function(a,b,c,d,e){return makeRegex(a,d,e,c,b)});query=prefix+(query.charAt(0)=="$"?"":"$")+query.replace(/`([0-9]+|\])/g,function(a,b){return b=="]"?"]":strs[b]});executor=eval("1&&function($,$1,$2,$3,$4,$5,$6,$7,$8,$9){var $obj=$;return "+query+"}");for(var i=0;i<arguments.length-1;i++){arguments[i]=arguments[i+1]}return obj?executor.apply(this,arguments):executor}}()},worker:{send:function(a){var b=a,c;if(!Pollen.evaluate.isDef(a)){return}if(!Pollen.evaluate.isObj(a)){b={message:a}}if(a.SEND_TO){b.SEND_FROM=Pollen.identity}b.WORKER_ID=Pollen.identity;return postMessage(b)},reply:function(a){return Pollen.worker.send(a)},receive:function(a){return addEventListener("message",function(b){var c=b.data;if(Pollen.identity==""){Pollen.identity=c.WORKER_ID}return a.call(b,c)},false)}},json:{encode:JSON.parse,decode:JSON.stringify}};Pollen=new Pollen;p=$=new function WorkerOnMessage(){if(arguments.length){if(Pollen.evaluate.isFn(arguments[0])){return Pollen.worker.receive(arguments[0])}}return WorkerOnMessage};p.ajax=$.ajax=Pollen.ajax;"identify date string evaluate reflection array func object data json worker".split(" ").forEach(function(a){for(var b in Pollen[a]){p[b]=$[b]=Pollen[a][b]}})})(this)
diff --git a/static/poller.js b/static/poller.js
new file mode 100644
index 0000000..31d6799
--- /dev/null
+++ b/static/poller.js
@@ -0,0 +1,33 @@
+importScripts('/static/jquery.hive.pollen.min.js');
+
+var pid;
+var timestamp = '0';
+
+function getUpdates() {
+ $.ajax.get({
+ url: '/poll/',
+ dataType: 'json',
+ data: {pid: pid, timestamp: timestamp},
+ timeout: 1000 * 30,
+ success: handleUpdates
+ });
+}
+function handleUpdates(data) {
+ var updates = [];
+ for (var i = 0; i < data.length; i++) {
+ updates.push({
+ 'action': data[i].Action,
+ 'yid': data[i].Song.Yid,
+ 'title': data[i].Song.Title,
+ 'user': data[i].Song.User
+ });
+ timestamp = data[i].Timestamp;
+ }
+ $.send({updates: updates});
+ getUpdates();
+}
+
+$(function (data) {
+ pid = data.pid;
+ getUpdates();
+});
diff --git a/static/script.js b/static/script.js
index d4e24ab..9407689 100644
--- a/static/script.js
+++ b/static/script.js
@@ -11,6 +11,18 @@ $(document).ready(function () {
for (var i = 0; i < ids.length; i++) {
drawBar(ids[i]);
}
+ var poller = new Worker('/static/poller.js');
+ poller.onmessage = function (e) {
+ for (var i = 0; i < e.data.updates.length; i++) {
+ update = e.data.updates[i];
+ switch (update.action) {
+ case 0:
+ drawAdd(update);
+ break;
+ }
+ }
+ }
+ poller.postMessage({'pid': pid});
});
function drawBar(id) {
@@ -42,6 +54,7 @@ function drawBar(id) {
}
}
+// function name is defined by youtube player api
function onYouTubePlayerReady(playerId) {
player = document.getElementById('player');
player.addEventListener('onStateChange', 'onStateChange');
@@ -49,16 +62,16 @@ function onYouTubePlayerReady(playerId) {
function onStateChange(state) {
switch (state) {
- case 1: //playing
- interval = setInterval(drawBar, 100, current_id);
- break;
- case 0: //ended
- showPlay(current_id);
- case -1: //unstarted
- case 2: //paused
- case 3: //buffering
- case 5: //cued
- clearInterval(interval);
+ case 1: //playing
+ interval = setInterval(drawBar, 100, current_id);
+ break;
+ case 0: //ended
+ showPlay(current_id);
+ case -1: //unstarted
+ case 2: //paused
+ case 3: //buffering
+ case 5: //cued
+ clearInterval(interval);
}
}
@@ -118,7 +131,7 @@ function search(query) {
'key': 'AI39si7SaaRqtvAZTa8lePOq6XC5r7S5Xzp3AB6oYPfeCArPbA4dIq7tSVeuIDwAkcFFDeI3rzNmYxkyN_fg8X_7w800pIvVOA'
}
$.getJSON('https://gdata.youtube.com/feeds/api/videos', params,
- function(data) {
+ function (data) {
var entries = data.feed.entry;
var items = [];
for (var i = 0; i < entries.length; i++) {
@@ -147,34 +160,38 @@ function add(id, title) {
'user': user
}
$.getJSON('/add/', params,
- function(data) {
+ function (data) {
if (data != 1)
return;
- $('article').append('\
- <section class="song" id="' + id + '">\
- <div class="info">\
- <a href="http://www.youtube.com/watch?v=' + id + '">' + title + '</a>\
- </div>\
- <div class="user">' + user + '</div>\
- <div class="remove" onclick="remove(\'' + id + '\')">×</div>\
- <br class="clear">\
- <div class="thumb">\
- <img src="http://i.ytimg.com/vi/' + id + '/1.jpg" alt="' + id + '">\
- </div>\
- <canvas id="c_' + id + '" width="700" height="20"></canvas>\
- <br>\
- <img src="/static/player_play.png" alt="Play" onclick="play(\'' + id + '\')" id="play_' + id + '">\
- <img src="/static/player_pause.png" alt="Pause" onclick="pause(\'' + id + '\')" id="pause_' + id + '">\
- <img src="/static/player_stop.png" alt="Stop" onclick="stop(\'' + id + '\')">\
- <br class="clear">\
- </section>\
- ');
- ids.push(id);
- drawBar(id);
+ drawAdd(params);
}
);
}
+function drawAdd(s) {
+ $('article').append('\
+ <section class="song" id="' + s.yid + '">\
+ <div class="info">\
+ <a href="http://www.youtube.com/watch?v=' + s.yid + '">' + s.title + '</a>\
+ </div>\
+ <div class="user">' + s.user + '</div>\
+ <div class="remove" onclick="remove(\'' + s.yid + '\')">×</div>\
+ <br class="clear">\
+ <div class="thumb">\
+ <img src="http://i.ytimg.com/vi/' + s.yid + '/1.jpg" alt="' + s.yid + '">\
+ </div>\
+ <canvas id="c_' + s.yid + '" width="700" height="20"></canvas>\
+ <br>\
+ <img src="/static/player_play.png" alt="Play" onclick="play(\'' + s.yid + '\')" id="play_' + s.yid + '">\
+ <img src="/static/player_pause.png" alt="Pause" onclick="pause(\'' + s.yid + '\')" id="pause_' + s.yid + '">\
+ <img src="/static/player_stop.png" alt="Stop" onclick="stop(\'' + s.yid + '\')">\
+ <br class="clear">\
+ </section>\
+ ');
+ ids.push(s.yid);
+ drawBar(s.yid);
+}
+
function remove(id) {
var user = $('#user').val();
params = {
@@ -182,10 +199,10 @@ function remove(id) {
'yid': id,
}
$.getJSON('/remove/', params,
- function(data) {
+ function (data) {
if (data == 1) {
var element = $('#' + id);
- element.slideUp(100, function() {
+ element.slideUp(100, function () {
element.remove();
});
}
diff --git a/templates/p.html b/templates/p.html
index 8f7557f..f63c673 100644
--- a/templates/p.html
+++ b/templates/p.html
@@ -3,7 +3,10 @@
<head>
<meta charset="UTF-8">
<title>Audio Axis</title>
+ <!--
<link href='http://fonts.googleapis.com/css?family=Cantarell' rel='stylesheet'>
+ -->
+ <link href="/static/cantarell.css" rel="stylesheet">
<link href="/static/base.css" rel="stylesheet">
</head>
@@ -22,43 +25,24 @@
</ul></div>
</header>
<article>
- {{range .Songs}}
- <section class="song" id="{{.Yid}}">
- <div class="info">
- <a href="http://www.youtube.com/watch?v={{.Yid}}">{{.Title}}</a>
- </div>
- <div class="user">
- {{.User}}
- </div>
- <div class="remove" onclick="remove('{{.Yid}}')">×</div>
- <br class="clear">
- <div class="thumb">
- <img src="http://i.ytimg.com/vi/{{.Yid}}/1.jpg" alt="{{.Yid}}">
- </div>
- <canvas id="c_{{.Yid}}" width="700" height="20"></canvas>
- <br>
- <img src="/static/player_play.png" alt="Play" onclick="play('{{.Yid}}')" id="play_{{.Yid}}">
- <img src="/static/player_pause.png" alt="Pause" onclick="pause('{{.Yid}}')" id="pause_{{.Yid}}">
- <img src="/static/player_stop.png" alt="Stop" onclick="stop('{{.Yid}}')">
- <br class="clear">
- </section>
- {{else}}
- No songs found
- {{end}}
</article>
- {{$first := index .Songs 0}}
+ {{$first := "82KEVKGRAhI"}}
<script>
var pid = '{{.Id}}';
- var current_id = '{{$first.Yid}}';
- var ids = [{{range .Songs}}'{{.Yid}}',{{end}}];
+ var current_id = '';
+ var ids = [];
</script>
+ <script src="/static/jquery.min.js"></script>
+ <script src="/static/script.js"></script>
+ <!--
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
<script src="/static/script.js"></script>
- <object data="http://www.youtube.com/v/{{$first.Yid}}?version=3&amp;enablejsapi=1" id="player" width="1" height="1" type="application/x-shockwave-flash">
- <param name="movie" value="http://www.youtube.com/v/{{$first.Yid}}?version=3&amp;enablejsapi=1">
+ <object data="http://www.youtube.com/v/{{$first}}?version=3&amp;enablejsapi=1" id="player" width="1" height="1" type="application/x-shockwave-flash">
+ <param name="movie" value="http://www.youtube.com/v/{{$first}}?version=3&amp;enablejsapi=1">
<param name="allowScriptAccess" value="always">
- <embed src="http://www.youtube.com/v/{{$first.Yid}}?version=3&amp;enablejsapi=1" allowScriptAccess="always">
+ <embed src="http://www.youtube.com/v/{{$first}}?version=3&amp;enablejsapi=1" allowScriptAccess="always">
</object>
+ -->
</body>
</html>
diff --git a/updates.go b/updates.go
new file mode 100644
index 0000000..c36bda8
--- /dev/null
+++ b/updates.go
@@ -0,0 +1,51 @@
+package main
+
+import (
+ "time"
+)
+
+const (
+ addAction = 0
+ removeAction = 1
+)
+type Update struct {
+ Song *Song
+ Action uint8
+ Timestamp int64
+ Next *Update
+}
+var headUpdates map[int]*Update
+var tailUpdates map[int]*Update
+
+func init() {
+ headUpdates = make(map[int]*Update)
+ tailUpdates = make(map[int]*Update)
+}
+
+func addUpdate(pid int, action uint8, song *Song) {
+ update := new(Update)
+ update.Song = song
+ update.Action = action
+ update.Timestamp = time.Nanoseconds()
+ pup, ok := tailUpdates[pid]
+ if ok {
+ pup.Next = update
+ } else {
+ headUpdates[pid] = update
+ }
+ tailUpdates[pid] = update
+}
+
+func getUpdates(pid int, timestamp int64) *Update {
+ pup, ok := headUpdates[pid]
+ if !ok {
+ return nil
+ }
+ for pup != nil {
+ if pup.Timestamp > timestamp {
+ return pup
+ }
+ pup = pup.Next
+ }
+ return nil
+}