chiark / gitweb /
ogg decodes differently in different places l-(
[disorder] / server / queue-ops.c
CommitLineData
05b75f8d
RK
1/*
2 * This file is part of DisOrder.
3 * Copyright (C) 2004-2008 Richard Kettlewell
4 *
e7eb3a27 5 * This program is free software: you can redistribute it and/or modify
05b75f8d 6 * it under the terms of the GNU General Public License as published by
e7eb3a27 7 * the Free Software Foundation, either version 3 of the License, or
05b75f8d
RK
8 * (at your option) any later version.
9 *
e7eb3a27
RK
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
05b75f8d 15 * You should have received a copy of the GNU General Public License
e7eb3a27 16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
05b75f8d 17 */
132a5a4a
RK
18/** @file server/queue-ops.c
19 * @brief Track queues (server-specific code)
20 */
05b75f8d
RK
21#include "disorder-server.h"
22
23static int find_in_list(struct queue_entry *needle,
24 int nqs, struct queue_entry **qs) {
25 int n;
26
27 for(n = 0; n < nqs; ++n)
28 if(qs[n] == needle)
29 return 1;
30 return 0;
31}
32
33static int id_in_use(const char *id) {
34 struct queue_entry *q;
35
36 for(q = qhead.next; q != &qhead; q = q->next)
37 if(!strcmp(id, q->id))
38 return 1;
39 return 0;
40}
41
42static void queue_id(struct queue_entry *q) {
43 const char *id;
44
45 id = random_id();
46 while(id_in_use(id))
47 id = random_id();
48 q->id = id;
49}
50
7a853280
RK
51/** @brief Add a track to the queue
52 * @param track Track to add
53 * @param submitter Who added it, or NULL
54 * @param where Where to add it
55 * @param target ID to add after for @ref WHERE_AFTER
56 * @param origin Track origin
57 * @return New queue entry or NULL
58 *
59 * The queue is NOT saved to disk.
60 *
61 * NULL can only be returned if @ref WHERE_AFTER is used with an invalid
62 * queue ID.
63 */
05b75f8d 64struct queue_entry *queue_add(const char *track, const char *submitter,
7a853280
RK
65 int where, const char *target,
66 enum track_origin origin) {
67 struct queue_entry *q, *beforeme, *afterme;
05b75f8d
RK
68
69 q = xmalloc(sizeof *q);
70 q->track = xstrdup(track);
71 q->submitter = submitter ? xstrdup(submitter) : 0;
72 q->state = playing_unplayed;
2dc2f478 73 q->origin = origin;
3229ef83 74 q->pid = -1;
05b75f8d 75 queue_id(q);
4265e5d3 76 xtime(&q->when);
05b75f8d
RK
77 switch(where) {
78 case WHERE_START:
79 queue_insert_entry(&qhead, q);
80 break;
81 case WHERE_END:
82 queue_insert_entry(qhead.prev, q);
83 break;
84 case WHERE_BEFORE_RANDOM:
85 /* We want to find the point in the queue before the block of random tracks
86 * at the end. */
87 beforeme = &qhead;
88 while(beforeme->prev != &qhead
2dc2f478 89 && beforeme->prev->origin == origin_random)
05b75f8d
RK
90 beforeme = beforeme->prev;
91 queue_insert_entry(beforeme->prev, q);
92 break;
7a853280
RK
93 case WHERE_AFTER:
94 if(!*target)
95 /* Insert at start of queue */
96 afterme = &qhead;
97 else {
98 /* Insert after a specific track */
99 afterme = qhead.next;
100 while(afterme != &qhead && strcmp(afterme->id, target))
101 afterme = afterme->next;
102 if(afterme == &qhead)
103 return NULL;
104 }
105 queue_insert_entry(afterme, q);
106 break;
05b75f8d
RK
107 }
108 /* submitter will be a null pointer for a scratch */
109 if(submitter)
110 notify_queue(track, submitter);
111 eventlog_raw("queue", queue_marshall(q), (const char *)0);
112 return q;
113}
114
115int queue_move(struct queue_entry *q, int delta, const char *who) {
116 int moved = 0;
117 char buffer[20];
118
119 /* not the most efficient approach but hopefuly relatively comprehensible:
120 * the idea is that for each step we determine which nodes are affected, and
121 * fill in all the links starting at the 'prev' end and moving towards the
122 * 'next' end. */
123
124 while(delta > 0 && q->prev != &qhead) {
125 struct queue_entry *n, *p, *pp;
126
127 n = q->next;
128 p = q->prev;
129 pp = p->prev;
130 pp->next = q;
131 q->prev = pp;
132 q->next = p;
133 p->prev = q;
134 p->next = n;
135 n->prev = p;
136 --delta;
137 ++moved;
138 }
139
140 while(delta < 0 && q->next != &qhead) {
141 struct queue_entry *n, *p, *nn;
142
143 p = q->prev;
144 n = q->next;
145 nn = n->next;
146 p->next = n;
147 n->prev = p;
148 n->next = q;
149 q->prev = n;
150 q->next = nn;
151 nn->prev = q;
152 ++delta;
153 --moved;
154 }
155
156 if(moved) {
2e9ba080 157 disorder_info("user %s moved %s", who, q->id);
05b75f8d
RK
158 notify_queue_move(q->track, who);
159 sprintf(buffer, "%d", moved);
160 eventlog("moved", who, (char *)0);
161 }
162
163 return delta;
164}
165
166void queue_moveafter(struct queue_entry *target,
167 int nqs, struct queue_entry **qs,
168 const char *who) {
169 struct queue_entry *q;
170 int n;
171
172 /* Normalize */
173 if(!target)
174 target = &qhead;
175 else
176 while(find_in_list(target, nqs, qs))
177 target = target->prev;
178 /* Do the move */
179 for(n = 0; n < nqs; ++n) {
180 q = qs[n];
181 queue_delete_entry(q);
182 queue_insert_entry(target, q);
183 target = q;
184 /* Log the individual tracks */
2e9ba080 185 disorder_info("user %s moved %s", who, q->id);
05b75f8d
RK
186 notify_queue_move(q->track, who);
187 }
188 /* Report that the queue changed to the event log */
189 eventlog("moved", who, (char *)0);
190}
191
192void queue_remove(struct queue_entry *which, const char *who) {
193 if(who) {
2e9ba080 194 disorder_info("user %s removed %s", who, which->id);
05b75f8d
RK
195 notify_queue_move(which->track, who);
196 }
197 eventlog("removed", which->id, who, (const char *)0);
198 queue_delete_entry(which);
199}
200
201void queue_played(struct queue_entry *q) {
202 while(pcount && pcount >= config->history) {
203 eventlog("recent_removed", phead.next->id, (char *)0);
204 queue_delete_entry(phead.next);
205 pcount--;
206 }
207 if(config->history) {
208 eventlog_raw("recent_added", queue_marshall(q), (char *)0);
209 queue_insert_entry(phead.prev, q);
210 ++pcount;
211 }
212}
213
214/*
215Local Variables:
216c-basic-offset:2
217comment-column:40
218fill-column:79
219indent-tabs-mode:nil
220End:
221*/