$ git clone http://tcclient.ion.nu/tc_client.git
commit 427ed28210834c5ed62a8a2d78997320f72cf5ee
Author: Alicia <...>
Date: Tue Apr 7 09:27:34 2015 +0200
Removed files which were moved throughout the versions but where the originals were apparently not automatically removed in the import process.
diff --git a/irchack.c b/irchack.c
deleted file mode 100644
index fa527f8..0000000
--- a/irchack.c
+++ /dev/null
@@ -1,414 +0,0 @@
-/*
- irchack, a simple application to reuse IRC clients as user interfaces for tc_client
- Copyright (C) 2014-2015 alicia@ion.nu
- Copyright (C) 2015 Jade Lea
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, version 3 of the License.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-#include <netinet/in.h>
-#include <unistd.h>
-#include <poll.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <sys/socket.h>
-#include <ctype.h>
-#include <signal.h>
-
-#ifdef __ANDROID__
-// Android has no dprintf, so we make our own
-#include <stdarg.h>
-size_t dprintf(int fd, const char* fmt, ...)
-{
- va_list va;
- va_start(va, fmt);
- int len=vsnprintf(0, 0, fmt, va);
- va_end(va);
- char buf[len+1];
- va_start(va, fmt);
- vsnprintf(buf, len+1, fmt, va);
- va_end(va);
- buf[len]=0;
- write(fd, buf, len);
- return len;
-}
-#endif
-
-// ANSI colors and their IRC equivalents
-struct color{const char* ansi; const char* irc;};
-struct color colortable[]={
- {"31", "\x03""05"},
- {"31;1", "\x03""04"},
- {"33", "\x03""07"},
- {"33", "\x03""07"},
- {"33;1", "\x03""08"},
- {"32;1", "\x03""09"},
- {"32;1", "\x03""09"},
- {"32", "\x03""03"},
- {"36", "\x03""10"},
- {"34;1", "\x03""12"},
- {"34;1", "\x03""12"},
- {"34", "\x03""02"},
- {"35", "\x03""06"},
- {"35;1", "\x03""13"},
- {"35;1", "\x03""13"},
- {"35;1", "\x03""13"}
-};
-
-const char* findcolor_irc(const char* ansi)
-{
- int len;
- for(len=0; ansi[len]&&ansi[len]!='m'; ++len);
- int i;
- for(i=0; i<16; ++i)
- {
- if(!strncmp(colortable[i].ansi, ansi, len) && !colortable[i].ansi[len])
- {
- return colortable[i].irc;
- }
- }
- return 0;
-}
-
-int findcolor_ansi(char* irc, char** end)
-{
- char color[4];
- strncpy(color, irc, 3);
- color[3]=0;
- if(!isdigit(color[1])){*end=&irc[1]; return -1;}
- if(!isdigit(color[2])){*end=&irc[2]; color[2]=color[1]; color[1]='0';}else{*end=&irc[3];}
- int i;
- for(i=0; i<16; ++i)
- {
- if(!strcmp(colortable[i].irc, color))
- {
- return i;
- }
- }
- return -1;
-}
-
-extern char session(int sock, const char* nick, const char* channel, const char* pass, const char* acc_user, const char* acc_pass);
-
-int main(int argc, char** argv)
-{
- int port=(argc>1?atoi(argv[1]):6667);
- struct sockaddr_in addr;
- memset(&addr, 0, sizeof(addr));
- addr.sin_family=AF_INET;
- addr.sin_addr.s_addr=htonl(0x7f000001); // 127.0.0.1
- addr.sin_port=htons(port);
- int lsock=socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
- if(bind(lsock, (struct sockaddr*)&addr, sizeof(addr))){perror("bind"); return 1;}
- listen(lsock, 1);
- printf("Done! Open an IRC client and connect to localhost on port %i\n", port);
- signal(SIGCHLD, SIG_IGN);
- int sock;
- while((sock=accept(lsock, 0, 0))>-1)
- {
- if(fork()){continue;}
- char buf[2048];
- char* nick=0;
- char* channel=0;
- char* pass=0;
- char* acc_user=0;
- char* acc_pass=0;
- int len;
- while(1)
- {
- len=0;
- int r;
- while(len<2047)
- {
- if((r=read(sock, &buf[len], 1))!=1 || buf[len]=='\r' || buf[len]=='\n'){break;}
- ++len;
- }
- if(r!=1){break;}
- buf[len]=0;
- if(!strncmp(buf, "USER ", 5))
- {
- acc_user=&buf[5];
- char* end=strchr(acc_user, ' ');
- if(end){end[0]=0;}
- acc_user=strdup(acc_user);
- }
- else if(!strncmp(buf, "PASS ", 5))
- {
- acc_pass=&buf[5];
- if(acc_pass[0]==':'){acc_pass=&acc_pass[1];}
- acc_pass=strdup(acc_pass);
- }
- else if(!strncmp(buf, "NICK ", 5))
- {
- char* newnick=&buf[5];
- if(newnick[0]==':'){newnick=&nick[1];}
- if(!nick)
- {
- dprintf(sock, ":irchack 001 %s :Welcome\n", newnick);
- }else{
- dprintf(sock, ":%s!user@host NICK :%s\n", nick, newnick);
- }
- free(nick);
- nick=strdup(newnick);
- }
- else if(nick && !strncmp(buf, "JOIN ", 5))
- {
- free(channel);
- channel=&buf[5];
- if(channel[0]==':'){channel=&channel[1];}
- free(pass);
- pass=strchr(channel, ' ');
- if(pass)
- {
- pass[0]=0;
- pass=&pass[1];
- if(pass[0]==':'){pass=strdup(&pass[1]);}
- }
- if(channel[0]=='#'){channel=&channel[1];}
- channel=strdup(channel);
- if(!session(sock, nick, channel, pass, acc_user, acc_pass)){break;}
- }
- else if(!strncmp(buf, "PING ", 5))
- {
- dprintf(sock, ":irchack PONG %s\n", &buf[5]);
- }
- }
- shutdown(sock, SHUT_RDWR);
- _exit(0);
- }
- close(lsock);
- return 0;
-}
-
-char session(int sock, const char* nick, const char* channel, const char* pass, const char* acc_user, const char* acc_pass)
-{
- printf("Nick: %s\n", nick);
- printf("Channel: %s\n", channel);
- printf("Password: %s\n", pass);
- int tc_in[2];
- int tc_out[2];
- pipe(tc_in);
- pipe(tc_out);
- if(!fork())
- {
- close(tc_in[1]);
- close(tc_out[0]);
- dup2(tc_in[0], 0);
- dup2(tc_out[1], 1);
- if(acc_user && acc_pass)
- {
- execl("./tc_client", "./tc_client", "-u", acc_user, "-p", acc_pass, channel, nick, pass, (char*)0);
- }else{
- execl("./tc_client", "./tc_client", channel, nick, pass, (char*)0);
- }
- perror("Failed to exec tc_client");
- _exit(1);
- }
- close(tc_in[0]);
- close(tc_out[1]);
- struct pollfd pfd[2];
- pfd[0].fd=tc_out[0];
- pfd[0].events=POLLIN;
- pfd[0].revents=0;
- pfd[1].fd=sock;
- pfd[1].events=POLLIN;
- pfd[1].revents=0;
- char buf[2048];
- int len;
- char joins=0;
- while(1)
- {
- poll(pfd, 2, -1);
- if(pfd[0].revents)
- {
- pfd[0].revents=0;
- len=0;
- int r;
- while(len<2047)
- {
- if((r=read(tc_out[0], &buf[len], 1))!=1 || buf[len]=='\r' || buf[len]=='\n'){break;}
- ++len;
- }
- if(r!=1){break;}
- buf[len]=0;
-printf("Got from tc_client: '%s'\n", buf);
- if(!strncmp(buf, "Currently online: ", 18))
- {
- dprintf(sock, ":irchack 353 %s = #%s :", nick, channel);
- char* user=&buf[18];
- while(user)
- {
- char* next=strchr(user, ',');
- if(next){next[0]=0; next=&next[2];}
- dprintf(sock, "%s%s", user, next?" ":"");
- user=next;
- }
- write(sock, "\n", 1);
- joins=1;
- continue;
- }
- else if(joins)
- {
- dprintf(sock, ":irchack 366 %s #%s :End of /NAMES list.\n", nick, channel);
- joins=0;
- }
- if(!strncmp(buf, "Room topic: ", 12))
- {
- dprintf(sock, ":irchack 332 %s #%s :%s\n", nick, channel, &buf[12]);
- continue;
- }
- if(!strcmp(buf, "Password required"))
- {
- dprintf(sock, ":irchack 475 %s :Cannot join %s without the correct password\n", channel, channel);
- close(tc_in[1]);
- close(tc_out[0]);
- return 1;
- }
- if(!strncmp(buf, "Guest ID: ", 10))
- {
- dprintf(sock, ":%s!user@host NICK :guest-%s\n", nick, &buf[10]);
- continue;
- }
- if(!strncmp(buf, "No such nick: ", 14))
- {
- dprintf(sock, ":irchack 401 %s %s :No such nick/channel\n", nick, &buf[14]);
- continue;
- }
- char* space=strchr(buf, ' ');
- if(space && !strcmp(space, " is a moderator."))
- {
- space[0]=0;
- dprintf(sock, ":irchack MODE #%s +o %s\n", channel, buf);
- continue;
- }
- if(space && !strcmp(space, " is no longer a moderator."))
- {
- space[0]=0;
- dprintf(sock, ":irchack MODE #%s -o %s\n", channel, buf);
- continue;
- }
- if(buf[0]!='['){continue;} // Beyond this we only care about timestamped lines
- // Translate ANSI escape codes to IRC color code instead
- char* ansi;
- const char* color="";
- while((ansi=strstr(buf, "\x1b[")))
- {
- int len;
- for(len=0; ansi[len]&&ansi[len]!='m'; ++len);
- if(ansi[len]=='m'){++len;}
- const char* c=findcolor_irc(&ansi[2]);
- if(c){color=c;}
- memmove(ansi, &ansi[len], strlen(&ansi[len])+1);
- }
-
- char* name=strchr(buf, ' ');
- if(!name){continue;}
- name[0]=0;
- name=&name[1];
- char* msg=name;
- while(msg[0]&&msg[0]!=':'&&msg[0]!=' '){msg=&msg[1];}
- if(msg[0]==':') // message
- {
- msg[0]=0;
- msg=&msg[2];
- if(!strncmp(msg, "/msg ", 5)) // PM
- {
- msg=strchr(&msg[5], ' ');
- if(!msg){continue;}
- msg=&msg[1];
- dprintf(sock, ":%s!user@host PRIVMSG %s :%s%s\n", name, nick, color, msg);
- }else{ // Regular channel message
- dprintf(sock, ":%s!user@host PRIVMSG #%s :%s%s\n", name, channel, color, msg);
- }
- }else{ // action, parse the actions and send them as JOINs, NICKs and QUITs etc. instead
- msg[0]=0;
- msg=&msg[1];
- if(!strcmp(msg, "entered the channel"))
- {
- dprintf(sock, ":%s!user@host JOIN #%s\n", name, channel);
- }
- else if(!strncmp(msg, "changed nickname to ", 20))
- {
- dprintf(sock, ":%s!user@host NICK :%s\n", name, &msg[20]);
- }
- else if(!strcmp(msg, "left the channel"))
- {
- dprintf(sock, ":%s!user@host QUIT :left the channel\n", name);
- }
- else // Unhandled action
- {
- dprintf(sock, ":%s!user@host PRIVMSG #%s :\x01""ACTION %s\x01\n", name, channel, msg);
- }
- }
- }
- if(pfd[1].revents)
- {
- pfd[1].revents=0;
- len=0;
- int r;
- while(len<2047)
- {
- if((r=read(sock, &buf[len], 1))!=1 || buf[len]=='\r' || buf[len]=='\n'){break;}
- ++len;
- }
- if(r!=1){break;}
- buf[len]=0;
-printf("Got from IRC client: '%s'\n", buf);
- if(!strncmp(buf, "PRIVMSG ", 8))
- {
- char* target=&buf[8];
- char* msg=strchr(&buf[8], ' ');
- if(!msg){continue;}
- msg[0]=0;
- msg=&msg[1];
- if(msg[0]==':'){msg=&msg[1];}
- char* color;
- while((color=strchr(msg, '\x03')))
- {
- char* end;
- int c=findcolor_ansi(color, &end);
- if(c!=-1){dprintf(tc_in[1], "/color %i\n", c);}
- memmove(color, end, strlen(end)+1);
- }
- if(!strncmp(msg, "\x01""ACTION ", 8)) // Translate '/me'
- {
- msg=&msg[7];
- msg[0]='*';
- char* end=strchr(msg, '\x01');
- if(end){end[0]='*';}
- }
- if(target[0]=='#' && !strcmp(&target[1], channel))
- {
- dprintf(tc_in[1], "%s\n", msg);
- }else{
- dprintf(tc_in[1], "/msg %s %s\n", target, msg);
- }
- }
- else if(!strncmp(buf, "NICK ", 5))
- {
- char* nick=&buf[5];
- if(nick[0]==':'){nick=&nick[1];}
- dprintf(tc_in[1], "/nick %s\n", nick);
- }
- else if(!strncmp(buf, "PING ", 5))
- {
- dprintf(sock, ":irchack PONG %s\n", &buf[5]);
- }
- else if(!strncmp(buf, "QUIT ", 5)){break;}
- }
- }
-
- close(tc_in[1]);
- close(tc_out[0]);
- return 0;
-}
diff --git a/modbot.c b/modbot.c
deleted file mode 100644
index 5cffbb9..0000000
--- a/modbot.c
+++ /dev/null
@@ -1,578 +0,0 @@
-/*
- modbot, a bot for tc_client that queues and plays videos
- Copyright (C) 2015 alicia@ion.nu
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, version 3 of the License.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-#include <unistd.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <sys/wait.h>
-#include <stdarg.h>
-#include <time.h>
-
-struct list
-{
- char** items;
- unsigned int itemcount;
-};
-
-struct list mods={0,0};
-struct list queue={0,0};
-struct list goodvids={0,0}; // pre-approved videos
-struct list badvids={0,0}; // not allowed, essentially banned
-char* playing=0;
-time_t started=0;
-int tc_client;
-
-void list_del(struct list* list, const char* item)
-{
- unsigned int i;
- unsigned int len;
- while(item[0])
- {
- if(item[0]=='\r' || item[0]=='\n'){item=&item[1]; continue;} // Skip empty lines
- for(len=0; item[len] && item[len]!='\r' && item[len]!='\n'; ++len);
- for(i=0; i<list->itemcount; ++i)
- {
- if(!strncmp(list->items[i], item, len) && !list->items[i][len])
- {
- free(list->items[i]);
- --list->itemcount;
- memmove(&list->items[i], &list->items[i+1], sizeof(char*)*(list->itemcount-i));
- }
- }
- item=&item[len];
- }
-}
-
-void list_add(struct list* list, const char* item)
-{
- list_del(list, item);
- unsigned int len;
- while(item[0])
- {
- if(item[0]=='\r' || item[0]=='\n'){item=&item[1]; continue;} // Skip empty lines
- for(len=0; item[len] && item[len]!='\r' && item[len]!='\n'; ++len);
- ++list->itemcount;
- list->items=realloc(list->items, sizeof(char*)*list->itemcount);
- list->items[list->itemcount-1]=strndup(item, len);
- item=&item[len];
- }
-}
-
-void list_switch(struct list* list, char* olditem, char* newitem)
-{
- unsigned int i;
- for(i=0; i<list->itemcount; ++i)
- {
- if(!strcmp(list->items[i], olditem))
- {
- free(list->items[i]);
- list->items[i]=strdup(newitem);
- }
- }
-}
-
-int list_getpos(struct list* list, char* item)
-{
- int i;
- unsigned int len;
- while(item[0])
- {
- if(item[0]=='\r' || item[0]=='\n'){item=&item[1]; continue;} // Skip empty lines
- for(len=0; item[len] && item[len]!='\r' && item[len]!='\n'; ++len);
- for(i=0; i<list->itemcount; ++i)
- {
- if(!strncmp(list->items[i], item, len) && !list->items[i][len]){return i;}
- }
- item=&item[len];
- }
- return -1;
-}
-
-char list_contains(struct list* list, char* item)
-{
- return (list_getpos(list, item)!=-1);
-}
-
-void list_load(struct list* list, const char* file)
-{
- struct stat st;
- if(stat(file, &st)){return;}
- int f=open(file, O_RDONLY);
- char buf[st.st_size+1];
- read(f, buf, st.st_size);
- buf[st.st_size]=0;
- close(f);
- char* start=buf;
- char* end;
- while((end=strchr(start, '\n'))) // TODO: support \r?
- {
- end[0]=0;
- list_add(list, start);
- start=&end[1];
- }
- printf("Loaded %u lines from %s\n", list->itemcount, file);
-}
-
-void list_save(struct list* list, const char* file)
-{
- int f=open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600);
- unsigned int i;
- for(i=0; i<list->itemcount; ++i)
- {
- write(f, list->items[i], strlen(list->items[i]));
- write(f, "\n", 1);
- }
- close(f);
-}
-
-void list_movetofront(struct list* list, unsigned int pos)
-{
- if(pos>=list->itemcount){return;}
- char* move=list->items[pos];
- memmove(&list->items[1], list->items, sizeof(char*)*pos);
- list->items[0]=move;
-}
-
-void say(const char* pm, const char* fmt, ...)
-{
- va_list va;
- va_start(va, fmt);
- unsigned int len=vsnprintf(0,0,fmt,va);
- va_end(va);
- va_start(va, fmt);
- char buf[len+1+(pm?strlen("/msg ")+strlen(pm):0)];
- char* msg=buf;
- if(pm)
- {
- msg=&buf[strlen("/msg ")+strlen(pm)];
- sprintf(buf, "/msg %s ", pm);
- }
- vsprintf(msg, fmt, va);
- va_end(va);
- write(tc_client, buf, strlen(buf));
-}
-
-void getvidinfo(const char* vid, const char* type, char* buf, unsigned int len)
-{
- int out[2];
- pipe(out);
- if(!fork())
- {
- close(out[0]);
- dup2(out[1], 1);
- execlp("youtube-dl", "youtube-dl", "--default-search", "auto", type, "--", vid, (char*)0);
- perror("execlp(youtube-dl)");
- _exit(1);
- }
- wait(0);
- close(out[1]);
- len=read(out[0], buf, len-1);
- if(len<0){len=0;}
- while(len>0 && (buf[len-1]=='\r' || buf[len-1]=='\n')){--len;} // Strip newlines
- buf[len]=0;
- close(out[0]);
-}
-
-unsigned int getduration(const char* vid)
-{
- char timebuf[128];
- timebuf[0]=':'; // Sacrifice 1 byte to avoid having to deal with a special case later on, where no ':' is found and we go from the start of the string, but only once
- getvidinfo(vid, "--get-duration", &timebuf[1], 127);
- if(!timebuf[1]){printf("Failed to get video duration using youtube-dl, assuming 60s\n"); return 60;} // If using youtube-dl fails, assume videos are 1 minute long
- // youtube-dl prints it out in hh:mm:ss format, convert it to plain seconds
- unsigned int len;
- // Seconds
- char* sep=strrchr(timebuf, ':');
- if(sep){sep[0]=0; len=atoi(&sep[1]);}
- // Minutes
- sep=strrchr(timebuf, ':');
- if(sep){sep[0]=0; len+=atoi(&sep[1])*60;}
- // Hours
- sep=strrchr(timebuf, ':');
- if(sep){sep[0]=0; len+=atoi(&sep[1])*60;}
- // Days
- sep=strrchr(timebuf, ':');
- if(sep){sep[0]=0; len+=atoi(&sep[1])*24;}
- return len;
-}
-
-unsigned int waitskip=0;
-void playnextvid()
-{
- waitskip=0;
- playing=queue.items[0];
- --queue.itemcount;
- memmove(queue.items, &queue.items[1], sizeof(char*)*queue.itemcount);
- say(0, "/mbs youTube %s 0\n", playing);
- // Find out the video's length and schedule an alarm for then
- alarm(getduration(playing));
- started=time(0);
-}
-
-void playnext(int x)
-{
- free(playing);
- playing=0;
- if(queue.itemcount<1){alarm(0); printf("Nothing more to play\n"); return;} // Nothing more to play
- if(!list_contains(&goodvids, queue.items[0]))
- {
- if(!waitskip)
- {
- say(0, "Next video (http://youtube.com/watch?v=%s) is not yet approved by mods\n", queue.items[0]);
- unsigned int i;
- for(i=1; i<queue.itemcount; ++i)
- {
- if(list_contains(&goodvids, queue.items[i]))
- {
- waitskip=i;
- alarm(120);
- break;
- }
- }
- return;
- }else{
- say(0, "Skipping http://youtube.com/watch?v=%s because it is still not approved after 2 minutes\n", queue.items[0]);
- list_movetofront(&queue, waitskip);
- waitskip=0;
- }
- }
- playnextvid();
-}
-
-int main(int argc, char** argv)
-{
- int in[2];
- int out[2];
- pipe(in);
- pipe(out);
- if(!fork())
- {
- close(in[1]);
- close(out[0]);
- dup2(in[0], 0);
- dup2(out[1], 1);
- execv("./tc_client", argv);
- _exit(1);
- }
- close(in[0]);
- close(out[1]);
- tc_client=in[1];
- signal(SIGALRM, playnext);
- list_load(&goodvids, "goodvids.txt");
- list_load(&badvids, "badvids.txt");
- char buf[1024];
- int len=0;
- while(1)
- {
- if(read(out[0], &buf[len], 1)<1){break;}
- if(len<1023&&buf[len]!='\r'&&buf[len]!='\n'){++len; continue;}
- if(!len){continue;}
- buf[len]=0;
- char* esc;
- while((esc=strstr(buf, "\x1b["))) // Strip out ANSI colors
- {
- for(len=2; isdigit(esc[len])||esc[len]==';'; ++len);
- memmove(esc, &esc[len+1], strlen(&esc[len]));
- }
- len=0;
- // printf("Got line '%s'\n", buf);
- char* space=strchr(buf, ' ');
- if(!space){continue;}
- if(!strcmp(space, " is a moderator."))
- {
- // If there are not-yet-approved videos in the queue when a mod joins, ask them to review them
- space[0]=0;
- list_add(&mods, buf);
- continue;
- }
- if(!strcmp(space, " is no longer a moderator."))
- {
- space[0]=0;
- list_del(&mods, buf);
- continue;
- }
- space[0]=0;
- if(buf[0]=='['&&isdigit(buf[1])&&isdigit(buf[2])&&buf[3]==':') // Timestamp
- {
- char* nick=&space[1];
- space=strchr(nick, ' ');
- if(!space){continue;}
- if(space[-1]==':') // Sent a message
- {
- space[-1]=0;
- char* msg=&space[1];
- // Handle commands sent in PMs
- char* pm=0;
- if(!strncmp(msg, "/msg ", 5))
- {
- msg=strchr(&msg[5], ' ');
- if(!msg){continue;}
- msg=&msg[1];
- pm=nick;
- }
- if(!strncmp(msg, "!request ", 9))
- {
- char title[256];
- char vid[1024];
- getvidinfo(&msg[9], "--get-id", vid, 1024);
- if(!vid[0]){say(pm, "No video found, sorry\n"); continue;} // Nothing found
- char* plist;
- for(plist=vid; plist[0] && plist[0]!='\r' && plist[0]!='\n'; plist=&plist[1]);
- if(plist[0]) // Link was a playlist, do some trickery to get the title of the first video (instead of getting nothing)
- {
- strcpy(title, "Playlist, starting with ");
- plist[0]=0;
- getvidinfo(vid, "--get-title", &title[24], 256-24);
- plist[0]='\n';
- }else{
- plist=0;
- getvidinfo(vid, "--get-title", title, 256);
- }
- printf("Requested ID '%s' by '%s'\n", vid, nick);
- // Check if it's already queued and mention which spot it's in, or if it's marked as bad and shouldn't be queued
- int pos;
- if((pos=list_getpos(&queue, vid))>-1)
- {
- say(pm, "Video '%s' is already in queue (number %i)\n", title, pos);
- continue;
- }
- if(list_contains(&badvids, vid))
- {
- say(pm, "Video '%s' is marked as bad, won't add to queue\n", title);
- continue;
- }
- if(list_contains(&mods, nick)) // Auto-approve for mods
- {
- list_add(&goodvids, vid);
- list_del(&badvids, vid);
- list_save(&goodvids, "goodvids.txt");
- list_save(&badvids, "badvids.txt");
- }
-
- list_add(&queue, vid);
- if(!list_contains(&goodvids, vid))
- {
- if(plist)
- {
- say(pm, "Playlist '%s' is added to the queue but will need to be approved by a mod\n", title);
- }else{
- say(pm, "Video '%s' (%s) is added to the queue but will need to be approved by a mod\n", vid, title);
- }
- }
- else if(!playing){playnext(0);}
- else{say(pm, "Added to queue\n");}
- }
- else if(!strcmp(msg, "!queue"))
- {
- unsigned int notapproved=0;
- unsigned int len=0;
- unsigned int i;
- for(i=0; i<queue.itemcount; ++i)
- {
- if(!list_contains(&goodvids, queue.items[i])){++notapproved; len+=strlen(queue.items[i])+2;}
- }
- if(notapproved)
- {
- char buf[len];
- buf[0]=0;
- for(i=0; i<queue.itemcount; ++i)
- {
- if(!list_contains(&goodvids, queue.items[i]))
- {
- if(buf[0]){strcat(buf, ", ");}
- strcat(buf, queue.items[i]);
- }
- }
- say(pm, "%u videos in queue, %u of which are not yet approved by mods (%s)\n", queue.itemcount, notapproved, buf);
- }else{
- say(pm, "%u videos in queue\n", queue.itemcount);
- }
- }
- else if(!strcmp(msg, "!time")) // Debugging
- {
- unsigned int remaining=alarm(0);
- alarm(remaining);
- say(pm, "'%s' is scheduled to end in %u seconds\n", playing, remaining);
- }
- else if(!strcmp(msg, "!help"))
- {
- say(nick, "The following commands can be used:\n");
- usleep(100000);
- say(nick, "!request <link> = request a video to be played\n");
- usleep(100000);
- say(nick, "!queue = get the number of songs in queue and which (if any) need to be approved\n");
- usleep(100000);
- say(nick, "Mod commands:\n"); // TODO: don't bother filling non-mods' chats with these?
- usleep(100000);
- say(nick, "!playnext = play the next video in queue without approving it (to see if it's ok)\n");
- usleep(100000);
- say(nick, "!approve = mark the currently playing video as good, or if none is playing the next in queue\n");
- usleep(100000);
- say(nick, "!approve <link> = mark the specified video as okay\n");
- say(nick, "!approve next = mark the next not yet approved video as okay\n");
- say(nick, "!approve entire queue = approve all videos in queue (for playlists)\n");
- usleep(100000);
- say(nick, "!badvid = stop playing the current video and mark it as bad\n");
- usleep(100000);
- say(nick, "!badvid <link> = mark the specified video as bad, preventing it from ever being queued again\n");
- say(nick, "You can also just play videos manually and they will be marked as good.\n");
- }
- else if(list_contains(&mods, nick)) // Mods-only commands
- {
- if(!strcmp(msg, "!playnext"))
- {
- if(playing){say(pm, "A video (%s) is already playing\n", playing); continue;}
- if(queue.itemcount<1){say(pm, "There are no videos in queue, sorry\n"); continue;}
- playnextvid();
- }
- else if(!strcmp(msg, "!approve"))
- {
- if(playing)
- {
- if(list_contains(&goodvids, playing) && !list_contains(&badvids, playing)){say(pm, "'%s' is already approved, use !approve <ID> to approve another video (or 'next' instead of an ID to approve the next not-yet-approved video in queue)\n", playing); continue;}
- list_add(&goodvids, playing);
- list_del(&badvids, playing);
- list_save(&goodvids, "goodvids.txt");
- list_save(&badvids, "badvids.txt");
- }else if(queue.itemcount>0){
- if(list_contains(&goodvids, queue.items[0]) && !list_contains(&badvids, queue.items[0])){say(pm, "'%s' is already approved, use !approve <ID> to approve another video\n", queue.items[0]); continue;}
- list_add(&goodvids, queue.items[0]);
- list_del(&badvids, queue.items[0]);
- list_save(&goodvids, "goodvids.txt");
- list_save(&badvids, "badvids.txt");
- playnext(0);
- }else{say(pm, "Approve what? please specify a video\n");}
- }
- else if(!strncmp(msg, "!approve ", 9))
- {
- char* vid=&msg[9];
- if(!vid[0]){continue;} // No video specified
- char vidbuf[256];
- if(!strcmp(vid, "next"))
- {
- unsigned int i;
- for(i=0; i<queue.itemcount; ++i)
- {
- if(!list_contains(&goodvids, queue.items[i])){vid=queue.items[i]; break;}
- }
- if(i==queue.itemcount){say(pm, "Nothing more to approve :)\n"); continue;}
- }
- else if(!strcmp(vid, "entire queue"))
- {
- char approved=0;
- unsigned int i;
- for(i=0; i<queue.itemcount; ++i)
- {
- if(list_contains(&goodvids, queue.items[i])){continue;}
- list_add(&goodvids, queue.items[i]);
- approved=1;
- }
- if(approved)
- {
- list_save(&goodvids, "goodvids.txt");
- if(!playing){playnext(0);} // Next in queue just got approved, so play it
- }else{
- say(0, "%s: there is nothing in the queue that isn't already approved, please do not overuse this function\n", nick);
- }
- continue;
- }else{
- getvidinfo(vid, "--get-id", vidbuf, 256);
- vid=vidbuf;
- }
- list_add(&goodvids, vid);
- list_del(&badvids, vid);
- list_save(&goodvids, "goodvids.txt");
- list_save(&badvids, "badvids.txt");
- if(!playing && queue.itemcount>0 && !strcmp(vid, queue.items[0])){playnext(0);} // Next in queue just got approved, so play it
- }
- else if(!strcmp(msg, "!badvid") || !strncmp(msg, "!badvid ", 8))
- {
- if(!msg[7] && !playing){say(pm, "Nothing is playing, please use !badvid <URL/ID> instead\n"); continue;}
- char vid[1024];
- if(msg[7])
- {
- getvidinfo(&msg[8], "--get-id", vid, 256);
- }else{strncpy(vid, playing, 1023); vid[1023]=0;}
- if(!vid[0]){say(pm, "Video not found, sorry\n");}
- list_del(&queue, vid);
- list_del(&goodvids, vid);
- list_add(&badvids, vid);
- list_save(&goodvids, "goodvids.txt");
- list_save(&badvids, "badvids.txt");
- if(!strcmp(vid, playing)){say(0, "/mbc youTube\n"); playnext(0);}
- }
- else if(!strncmp(msg, "/mbs youTube ", 13))
- {
- // Someone manually started a video, mark that video as good, remove it from queue, and set an alarm for when it's modbot's turn to play stuff again
- char* vid=&msg[13];
- char* end=strchr(vid, ' ');
- if(end){end[0]=0;}
- list_del(&queue, vid);
- list_add(&goodvids, vid);
- list_save(&goodvids, "goodvids.txt");
- free(playing);
- playing=strdup(vid);
- unsigned int pos=(end?(strtol(&end[1], 0, 0)/1000):0);
- alarm(getduration(playing)-pos);
- started=time(0)-pos;
- }
- else if(!strcmp(msg, "/mbc youTube")){playnext(0);} // Video cancelled
- else if(!strncmp(msg, "/mbsk youTube ", 14)) // Seeking
- {
- unsigned int pos=strtol(&msg[14], 0, 0)/1000;
- alarm(getduration(playing)-pos);
- started=time(0)-pos;
- }
- // TODO: handle /mbpa (pause) and /mbpl (resume play)
- }
- }else{ // Actions
- if(!strncmp(space, " changed nickname to ", 21))
- {
- space[0]=0;
- if(list_contains(&mods, nick))
- {
- list_switch(&mods, nick, &space[21]);
- nick=&space[21];
- unsigned int i;
- for(i=0; i<queue.itemcount; ++i)
- {
- if(!list_contains(&goodvids, queue.items[i]))
- {
- say(nick, "there are 1 or more videos in queue that are not yet approved, please type !queue to review them\n");
- break;
- }
- }
- }
- continue;
- }
- else if(!strcmp(space, " entered the channel")) // Newcomer, inform about the currently playing video
- {
- if(playing)
- {
- space[0]=0;
- say(0, "/priv %s /mbs youTube %s %u\n", nick, playing, (time(0)-started)*1000);
- }
- }
- }
- }
- }
- return 0;
-}