chiark / gitweb /
Consistency check for finished tracks.
[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;
4857234e
RK
107 case WHERE_NOWHERE:
108 return q;
05b75f8d
RK
109 }
110 /* submitter will be a null pointer for a scratch */
111 if(submitter)
112 notify_queue(track, submitter);
113 eventlog_raw("queue", queue_marshall(q), (const char *)0);
114 return q;
115}
116
117int queue_move(struct queue_entry *q, int delta, const char *who) {
118 int moved = 0;
119 char buffer[20];
120
121 /* not the most efficient approach but hopefuly relatively comprehensible:
122 * the idea is that for each step we determine which nodes are affected, and
123 * fill in all the links starting at the 'prev' end and moving towards the
124 * 'next' end. */
125
126 while(delta > 0 && q->prev != &qhead) {
127 struct queue_entry *n, *p, *pp;
128
129 n = q->next;
130 p = q->prev;
131 pp = p->prev;
132 pp->next = q;
133 q->prev = pp;
134 q->next = p;
135 p->prev = q;
136 p->next = n;
137 n->prev = p;
138 --delta;
139 ++moved;
140 }
141
142 while(delta < 0 && q->next != &qhead) {
143 struct queue_entry *n, *p, *nn;
144
145 p = q->prev;
146 n = q->next;
147 nn = n->next;
148 p->next = n;
149 n->prev = p;
150 n->next = q;
151 q->prev = n;
152 q->next = nn;
153 nn->prev = q;
154 ++delta;
155 --moved;
156 }
157
158 if(moved) {
2e9ba080 159 disorder_info("user %s moved %s", who, q->id);
05b75f8d
RK
160 notify_queue_move(q->track, who);
161 sprintf(buffer, "%d", moved);
162 eventlog("moved", who, (char *)0);
163 }
164
165 return delta;
166}
167
168void queue_moveafter(struct queue_entry *target,
169 int nqs, struct queue_entry **qs,
170 const char *who) {
171 struct queue_entry *q;
172 int n;
173
174 /* Normalize */
175 if(!target)
176 target = &qhead;
177 else
178 while(find_in_list(target, nqs, qs))
179 target = target->prev;
180 /* Do the move */
181 for(n = 0; n < nqs; ++n) {
182 q = qs[n];
183 queue_delete_entry(q);
184 queue_insert_entry(target, q);
185 target = q;
186 /* Log the individual tracks */
2e9ba080 187 disorder_info("user %s moved %s", who, q->id);
05b75f8d
RK
188 notify_queue_move(q->track, who);
189 }
190 /* Report that the queue changed to the event log */
191 eventlog("moved", who, (char *)0);
192}
193
194void queue_remove(struct queue_entry *which, const char *who) {
195 if(who) {
2e9ba080 196 disorder_info("user %s removed %s", who, which->id);
05b75f8d
RK
197 notify_queue_move(which->track, who);
198 }
199 eventlog("removed", which->id, who, (const char *)0);
200 queue_delete_entry(which);
201}
202
203void queue_played(struct queue_entry *q) {
204 while(pcount && pcount >= config->history) {
205 eventlog("recent_removed", phead.next->id, (char *)0);
206 queue_delete_entry(phead.next);
207 pcount--;
208 }
209 if(config->history) {
210 eventlog_raw("recent_added", queue_marshall(q), (char *)0);
211 queue_insert_entry(phead.prev, q);
212 ++pcount;
213 }
214}
215
216/*
217Local Variables:
218c-basic-offset:2
219comment-column:40
220fill-column:79
221indent-tabs-mode:nil
222End:
223*/