chiark / gitweb /
Limit rescan/recheck messages to one every 10 seconds (and at most one
[disorder] / server / queue-ops.c
1 /*
2  * This file is part of DisOrder.
3  * Copyright (C) 2004-2008 Richard Kettlewell
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18  * USA
19  */
20 #include "disorder-server.h"
21
22 static int find_in_list(struct queue_entry *needle,
23                         int nqs, struct queue_entry **qs) {
24   int n;
25
26   for(n = 0; n < nqs; ++n)
27     if(qs[n] == needle)
28       return 1;
29   return 0;
30 }
31
32 static int id_in_use(const char *id) {
33   struct queue_entry *q;
34
35   for(q = qhead.next; q != &qhead; q = q->next)
36     if(!strcmp(id, q->id))
37       return 1;
38   return 0;
39 }
40
41 static void queue_id(struct queue_entry *q) {
42   const char *id;
43
44   id = random_id();
45   while(id_in_use(id))
46     id = random_id();
47   q->id = id;
48 }
49
50 struct queue_entry *queue_add(const char *track, const char *submitter,
51                               int where) {
52   struct queue_entry *q, *beforeme;
53
54   q = xmalloc(sizeof *q);
55   q->track = xstrdup(track);
56   q->submitter = submitter ? xstrdup(submitter) : 0;
57   q->state = playing_unplayed;
58   queue_id(q);
59   time(&q->when);
60   switch(where) {
61   case WHERE_START:
62     queue_insert_entry(&qhead, q);
63     break;
64   case WHERE_END:
65     queue_insert_entry(qhead.prev, q);
66     break;
67   case WHERE_BEFORE_RANDOM:
68     /* We want to find the point in the queue before the block of random tracks
69      * at the end. */
70     beforeme = &qhead;
71     while(beforeme->prev != &qhead
72           && beforeme->prev->state == playing_random)
73       beforeme = beforeme->prev;
74     queue_insert_entry(beforeme->prev, q);
75     break;
76   }
77   /* submitter will be a null pointer for a scratch */
78   if(submitter)
79     notify_queue(track, submitter);
80   eventlog_raw("queue", queue_marshall(q), (const char *)0);
81   return q;
82 }
83
84 int queue_move(struct queue_entry *q, int delta, const char *who) {
85   int moved = 0;
86   char buffer[20];
87
88   /* not the most efficient approach but hopefuly relatively comprehensible:
89    * the idea is that for each step we determine which nodes are affected, and
90    * fill in all the links starting at the 'prev' end and moving towards the
91    * 'next' end. */
92   
93   while(delta > 0 && q->prev != &qhead) {
94     struct queue_entry *n, *p, *pp;
95
96     n = q->next;
97     p = q->prev;
98     pp = p->prev;
99     pp->next = q;
100     q->prev = pp;
101     q->next = p;
102     p->prev = q;
103     p->next = n;
104     n->prev = p;
105     --delta;
106     ++moved;
107   }
108
109   while(delta < 0 && q->next != &qhead) {
110     struct queue_entry *n, *p, *nn;
111
112     p = q->prev;
113     n = q->next;
114     nn = n->next;
115     p->next = n;
116     n->prev = p;
117     n->next = q;
118     q->prev = n;
119     q->next = nn;
120     nn->prev = q;
121     ++delta;
122     --moved;
123   }
124
125   if(moved) {
126     info("user %s moved %s", who, q->id);
127     notify_queue_move(q->track, who);
128     sprintf(buffer, "%d", moved);
129     eventlog("moved", who, (char *)0);
130   }
131   
132   return delta;
133 }
134
135 void queue_moveafter(struct queue_entry *target,
136                      int nqs, struct queue_entry **qs,
137                      const char *who) {
138   struct queue_entry *q;
139   int n;
140
141   /* Normalize */
142   if(!target)
143     target = &qhead;
144   else
145     while(find_in_list(target, nqs, qs))
146       target = target->prev;
147   /* Do the move */
148   for(n = 0; n < nqs; ++n) {
149     q = qs[n];
150     queue_delete_entry(q);
151     queue_insert_entry(target, q);
152     target = q;
153     /* Log the individual tracks */
154     info("user %s moved %s", who, q->id);
155     notify_queue_move(q->track, who);
156   }
157   /* Report that the queue changed to the event log */
158   eventlog("moved", who, (char *)0);
159 }
160
161 void queue_remove(struct queue_entry *which, const char *who) {
162   if(who) {
163     info("user %s removed %s", who, which->id);
164     notify_queue_move(which->track, who);
165   }
166   eventlog("removed", which->id, who, (const char *)0);
167   queue_delete_entry(which);
168 }
169
170 void queue_played(struct queue_entry *q) {
171   while(pcount && pcount >= config->history) {
172     eventlog("recent_removed", phead.next->id, (char *)0);
173     queue_delete_entry(phead.next);
174     pcount--;
175   }
176   if(config->history) {
177     eventlog_raw("recent_added", queue_marshall(q), (char *)0);
178     queue_insert_entry(phead.prev, q);
179     ++pcount;
180   }
181 }
182
183 /*
184 Local Variables:
185 c-basic-offset:2
186 comment-column:40
187 fill-column:79
188 indent-tabs-mode:nil
189 End:
190 */