summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--db.go60
-rw-r--r--main.go101
-rw-r--r--static/base.css25
-rw-r--r--static/down-arrow.pngbin0 -> 540 bytes
-rw-r--r--static/remove.pngbin0 -> 505 bytes
-rw-r--r--static/script.js58
-rw-r--r--static/up-arrow.pngbin0 -> 468 bytes
-rw-r--r--updates.go10
9 files changed, 213 insertions, 45 deletions
diff --git a/Makefile b/Makefile
index b3a5966..94e6269 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
all: aa
-main.6: main.go updates.go
- 6g main.go updates.go
+main.6: main.go db.go updates.go
+ 6g main.go db.go updates.go
aa: main.6
6l -o aa main.6
diff --git a/db.go b/db.go
new file mode 100644
index 0000000..f161c54
--- /dev/null
+++ b/db.go
@@ -0,0 +1,60 @@
+package main
+
+import (
+ "os"
+)
+
+func queryInt(sql string, params ...interface{}) (int, os.Error) {
+ query, err := db.Prepare(sql)
+ if err != nil {
+ return 0, err
+ }
+ err = query.BindParams(params...)
+ if err != nil {
+ return 0, err
+ }
+ err = query.Execute()
+ if err != nil {
+ return 0, err
+ }
+ var result int
+ query.BindResult(&result)
+ eof, err := query.Fetch()
+ if err != nil {
+ return 0, err
+ } else if eof {
+ return 0, os.EOF
+ }
+ err = query.FreeResult()
+ if err != nil {
+ return 0, err
+ }
+ return result, nil
+}
+
+// given an id ('abcd1234'), return the pid (1)
+func getpid(id string) int {
+ query, err := db.Prepare("SELECT `pid` FROM `playlist` WHERE `id` = ?")
+ if err != nil {
+ return -1
+ }
+ err = query.BindParams(id)
+ if err != nil {
+ return -1
+ }
+ err = query.Execute()
+ if err != nil {
+ return -1
+ }
+ var pid int
+ query.BindResult(&pid)
+ _, err = query.Fetch()
+ if err != nil {
+ return -1
+ }
+ err = query.FreeResult()
+ if err != nil {
+ return -1
+ }
+ return pid
+}
diff --git a/main.go b/main.go
index 29724b2..c5023f6 100644
--- a/main.go
+++ b/main.go
@@ -24,33 +24,6 @@ var templates map[string]*template.Template
const debug = true
var db *mysql.Client
-// given an id ('abcd1234'), return the pid (1)
-func getpid(id string) int {
- query, err := db.Prepare("SELECT `pid` FROM `playlist` WHERE `id` = ?;")
- if err != nil {
- return -1
- }
- err = query.BindParams(id)
- if err != nil {
- return -1
- }
- err = query.Execute()
- if err != nil {
- return -1
- }
- var pid int
- query.BindResult(&pid)
- _, err = query.Fetch()
- if err != nil {
- return -1
- }
- err = query.FreeResult()
- if err != nil {
- return -1
- }
- return pid
-}
-
func home(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "path is %s", r.URL.Path[1:])
}
@@ -91,7 +64,7 @@ func add(w http.ResponseWriter, r *http.Request) {
return
}
- sql :="INSERT INTO `song` (`pid`,`yid`,`title`,`user`) VALUES(%d,'%s','%s','%s')"
+ sql := "INSERT INTO `song` (`pid`,`yid`,`title`,`user`) VALUES(%d,'%s','%s','%s')"
sql = fmt.Sprintf(sql, pid,
db.Escape(q.Get("yid")),
db.Escape(q.Get("title")),
@@ -115,7 +88,7 @@ func remove(w http.ResponseWriter, r *http.Request) {
return
}
- sql :="DELETE FROM `song` WHERE `pid` = %d AND yid = '%s'"
+ sql := "DELETE FROM `song` WHERE `pid` = %d AND yid = '%s'"
sql = fmt.Sprintf(sql, pid, q.Get("yid"))
err := db.Query(sql)
if err != nil {
@@ -127,11 +100,78 @@ func remove(w http.ResponseWriter, r *http.Request) {
addUpdate(pid, removeAction, &Song{Yid: q.Get("yid")})
}
+func move(w http.ResponseWriter, r *http.Request) {
+ q := r.URL.Query()
+ pid := getpid(q.Get("pid"))
+ if pid == -1 {
+ http.Error(w, "invalid pid", http.StatusInternalServerError)
+ return
+ }
+
+ direction, err := strconv.Atoui(q.Get("direction"))
+ if err != nil {
+ http.Error(w, err.String(), http.StatusInternalServerError)
+ return
+ }
+
+ err = db.Start()
+ if err != nil {
+ http.Error(w, err.String(), http.StatusInternalServerError)
+ return
+ }
+
+ order, err := queryInt("SELECT `order` FROM `song` WHERE `yid` = ? AND `pid` = ?",
+ q.Get("yid"), pid)
+ if err != nil {
+ http.Error(w, err.String(), http.StatusInternalServerError)
+ return
+ }
+ newOrder := order
+ if direction == moveUpAction && order > 0 {
+ newOrder--
+ } else if direction == moveDownAction {
+ newOrder++
+ } else {
+ http.Error(w, "invalid direction or cannot move up", http.StatusInternalServerError)
+ return
+ }
+
+ sql := "UPDATE `song` SET `order` = %d WHERE `order` = %d AND pid = %d"
+ sql = fmt.Sprintf(sql, order, newOrder, pid)
+ err = db.Query(sql)
+ if err != nil {
+ http.Error(w, err.String(), http.StatusInternalServerError)
+ return
+ } else if db.AffectedRows != 1 {
+ db.Rollback()
+ http.Error(w, "invalid direction for this song", http.StatusInternalServerError)
+ return
+ }
+ // there are now two songs with that order, so also check yid
+ sql = "UPDATE `song` SET `order` = %d WHERE `order` = %d AND pid = %d AND yid = '%s'"
+ sql = fmt.Sprintf(sql, newOrder, order, pid, q.Get("yid"))
+ err = db.Query(sql)
+ if err != nil {
+ db.Rollback()
+ http.Error(w, err.String(), http.StatusInternalServerError)
+ return
+ }
+
+ err = db.Commit()
+ if err != nil {
+ http.Error(w, err.String(), http.StatusInternalServerError)
+ return
+ }
+
+ w.Write([]byte("1"))
+ addUpdate(pid, direction, &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` = ?;")
+ query, err := db.Prepare("SELECT `yid`,`title`,`user` FROM `playlist` JOIN `song` WHERE `id` = ? ORDER BY `order` ASC")
if err != nil {
http.Error(w, err.String(), http.StatusInternalServerError)
return
@@ -227,6 +267,7 @@ func main() {
http.HandleFunc("/p/", playlist)
http.HandleFunc("/add/", add)
http.HandleFunc("/remove/", remove)
+ http.HandleFunc("/move/", move)
http.HandleFunc("/poll/", poll)
err = http.ListenAndServe("localhost:8000", nil)
if err != nil {
diff --git a/static/base.css b/static/base.css
index fb01a40..438e4c1 100644
--- a/static/base.css
+++ b/static/base.css
@@ -136,14 +136,31 @@ section.song div.info {
}
section.song div.user {
float: right;
- margin-right: 8px;
+ margin-right: 20px;
}
section.song div.remove {
position: absolute;
top: 0;
right: 5px;
- font-weight: bold;
- cursor: pointer;
+}
+section.song div.remove img {
+ opacity: 0.6;
+}
+section.song div.remove img:hover {
+ opacity: 1.0;
+}
+section.song div.reorder {
+ position: absolute;
+ bottom: 0;
+ right: 5px;
+}
+section.song div.reorder img {
+ display: block;
+ margin-bottom: 5px;
+ opacity: 0.6;
+}
+section.song div.reorder img:hover {
+ opacity: 1.0;
}
section.song div.thumb {
float: left;
@@ -156,7 +173,7 @@ section.song div.thumb img {
}
section.song canvas, section.song > img {
position: relative;
- left: 10px;
+ left: 5px;
}
section.song > img[src$='pause.png'] {
display: none;
diff --git a/static/down-arrow.png b/static/down-arrow.png
new file mode 100644
index 0000000..00c106d
--- /dev/null
+++ b/static/down-arrow.png
Binary files differ
diff --git a/static/remove.png b/static/remove.png
new file mode 100644
index 0000000..a033c4e
--- /dev/null
+++ b/static/remove.png
Binary files differ
diff --git a/static/script.js b/static/script.js
index 3be5775..8687b0e 100644
--- a/static/script.js
+++ b/static/script.js
@@ -14,6 +14,10 @@ $(document).ready(function () {
case 1:
drawRemove(update.yid);
break;
+ case 2:
+ case 3:
+ drawMove(update.yid, update.action);
+ break;
}
}
}
@@ -167,12 +171,11 @@ function search(query) {
}
function add(id, title) {
- var user = $('#user').val();
params = {
pid: pid,
yid: id,
title: title,
- user: user
+ user: $('#user').val()
}
$.getJSON('/add/', params);
}
@@ -187,7 +190,19 @@ function drawAdd(s) {
<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>\
+ <div class="remove">\
+ <a href="javascript:remove(\'' + s.yid + '\')">\
+ <img src="/static/remove.png" alt="remove">\
+ </a>\
+ </div>\
+ <div class="reorder">\
+ <a href="javascript:move(\'' + s.yid + '\', 2)">\
+ <img src="/static/up-arrow.png" alt="up">\
+ </a>\
+ <a href="javascript:move(\'' + s.yid + '\', 3)">\
+ <img src="/static/down-arrow.png" alt="down">\
+ </a>\
+ </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 + '">\
@@ -201,7 +216,6 @@ function drawAdd(s) {
}
function remove(id) {
- var user = $('#user').val();
params = {
pid: pid,
yid: id,
@@ -211,8 +225,42 @@ function remove(id) {
function drawRemove(id) {
var element = $('#' + id);
+ stop(id);
element.slideUp(100, function () {
- stop(id);
element.remove();
});
}
+
+function move(id, dir) {
+ params = {
+ pid: pid,
+ yid: id,
+ direction: dir // see updates.go:moveUpAction
+ }
+ $.getJSON('/move/', params);
+}
+
+function drawMove(id, dir) {
+ var element1 = document.getElementById(id);
+ if (dir == 2) { //up
+ var element2 = element1.previousElementSibling;
+ if (!element2) return;
+ element1 = $('#' + id);
+ element2 = $('#' + element2.id);
+ element1.fadeOut(200, function () {
+ element1.detach();
+ element2.before(element1);
+ element1.fadeIn(200);
+ });
+ } else if (dir == 3) { //down
+ var element2 = element1.nextElementSibling;
+ if (!element2) return;
+ element1 = $('#' + id);
+ element2 = $('#' + element2.id);
+ element1.fadeOut(200, function () {
+ element1.detach();
+ element2.after(element1);
+ element1.fadeIn(200);
+ });
+ }
+}
diff --git a/static/up-arrow.png b/static/up-arrow.png
new file mode 100644
index 0000000..29ca702
--- /dev/null
+++ b/static/up-arrow.png
Binary files differ
diff --git a/updates.go b/updates.go
index c36bda8..33f12a9 100644
--- a/updates.go
+++ b/updates.go
@@ -5,12 +5,14 @@ import (
)
const (
- addAction = 0
- removeAction = 1
+ addAction = 0
+ removeAction = 1
+ moveUpAction = 2
+ moveDownAction = 3
)
type Update struct {
Song *Song
- Action uint8
+ Action uint
Timestamp int64
Next *Update
}
@@ -22,7 +24,7 @@ func init() {
tailUpdates = make(map[int]*Update)
}
-func addUpdate(pid int, action uint8, song *Song) {
+func addUpdate(pid int, action uint, song *Song) {
update := new(Update)
update.Song = song
update.Action = action