Răsfoiți Sursa

other users' adds will show up; temp crappy internet fixes

raylu 14 ani în urmă
părinte
comite
8f85f1a74c
8 a modificat fișierele cu 249 adăugiri și 106 ștergeri
  1. 2 2
      Makefile
  2. 90 39
      main.go
  3. 6 1
      static/base.css
  4. 2 0
      static/jquery.hive.pollen.min.js
  5. 33 0
      static/poller.js
  6. 52 35
      static/script.js
  7. 13 29
      templates/p.html
  8. 51 0
      updates.go

+ 2 - 2
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

+ 90 - 39
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)

+ 6 - 1
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;

Fișier diff suprimat deoarece este prea mare
+ 2 - 0
static/jquery.hive.pollen.min.js


+ 33 - 0
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();
+});

+ 52 - 35
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();
 				});
 			}

+ 13 - 29
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>

+ 51 - 0
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
+}

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff