diff options
author | raylu <raylu@mixpanel.com> | 2011-08-06 19:55:57 -0700 |
---|---|---|
committer | raylu <raylu@mixpanel.com> | 2011-08-06 19:55:57 -0700 |
commit | 8f85f1a74cb9f8796638a00c5b78541d027b9845 (patch) | |
tree | 709f50a0d15106ed62e0d2aa7be64d95b7646fc8 | |
parent | 082514b9ed2071f21e75a735830741d3f319cf50 (diff) | |
download | audioaxis-8f85f1a74cb9f8796638a00c5b78541d027b9845.tar.xz |
other users' adds will show up; temp crappy internet fixes
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | main.go | 129 | ||||
-rw-r--r-- | static/base.css | 7 | ||||
-rw-r--r-- | static/jquery.hive.pollen.min.js | 3 | ||||
-rw-r--r-- | static/poller.js | 33 | ||||
-rw-r--r-- | static/script.js | 87 | ||||
-rw-r--r-- | templates/p.html | 42 | ||||
-rw-r--r-- | updates.go | 51 |
8 files changed, 250 insertions, 106 deletions
@@ -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 @@ -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&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&enablejsapi=1"> + <object data="http://www.youtube.com/v/{{$first}}?version=3&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&enablejsapi=1"> <param name="allowScriptAccess" value="always"> - <embed src="http://www.youtube.com/v/{{$first.Yid}}?version=3&enablejsapi=1" allowScriptAccess="always"> + <embed src="http://www.youtube.com/v/{{$first}}?version=3&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 +} |