Cosmetics only
authorvolpol <volpol@packet-gain.de>
Fri, 13 Sep 2013 22:51:14 +0000 (22:51 +0000)
committervolpol <volpol@packet-gain.de>
Fri, 13 Sep 2013 22:51:14 +0000 (22:51 +0000)
curly.c
itemq.c

diff --git a/curly.c b/curly.c
index b8ad046e00bcaed3e30f5b986beb3fb1bf24e240..a7850aafb94da6ac5b6f75789ed84df49312b2bf 100644 (file)
--- a/curly.c
+++ b/curly.c
@@ -29,106 +29,106 @@ static unsigned bufsize;
 #ifdef USE_TCP
 
 static void simple_http(int sock) {
-       const char *RSP =
-                       "HTTP/1.0 200 OK\r\nContent-Type:  video/mp2t\r\nConnection: close\r\n\r\n\r\n";
-       char drain[1024] = "";
-       int err;
-
-       WHOAMI;
-       //TODO POLL
-       do {
-               err = read(sock, drain, sizeof drain);
-               if (err <= 0)
-                       return;
-               drain[err] = 0;
-               DPRINT("%s\n", drain);
-       } while (!strstr(drain, "\r\n\r\n"));
-
-       send(sock, RSP, strlen(RSP), MSG_NOSIGNAL);
-
-       DPRINT ("simple http response sent\n");
+    const char *RSP =
+            "HTTP/1.0 200 OK\r\nContent-Type:  video/mp2t\r\nConnection: close\r\n\r\n\r\n";
+    char drain[1024] = "";
+    int err;
+
+    WHOAMI;
+    //TODO POLL
+    do {
+        err = read(sock, drain, sizeof drain);
+        if (err <= 0)
+            return;
+        drain[err] = 0;
+        DPRINT("%s\n", drain);
+    } while (!strstr(drain, "\r\n\r\n"));
+
+    send(sock, RSP, strlen(RSP), MSG_NOSIGNAL);
+
+    DPRINT ("simple http response sent\n");
 }
 
 size_t fetch_send(void *ptr, size_t size, size_t nmemb, void *stream) {
-       size_t bytesize = size * nmemb;
+    size_t bytesize = size * nmemb;
 
-       int sent;
+    int sent;
 
-       WHOAMI;
+    WHOAMI;
 
-       if (conn < 0)
-               conn = accept(sock, NULL, NULL);
+    if (conn < 0)
+        conn = accept(sock, NULL, NULL);
 
-       if (conn >= 0 && !flag_conn) {
-               DPRINT("Connection accepted\n");
-               flag_conn = 1;
-               simple_http(conn);
-       }
+    if (conn >= 0 && !flag_conn) {
+        DPRINT("Connection accepted\n");
+        flag_conn = 1;
+        simple_http(conn);
+    }
 
-       if (flag_conn) {
-               sent = send(conn, ptr, bytesize, MSG_NOSIGNAL);
-               if (sent <= 0) {
-                       DPRINT("Pious Teardown!\n");
-                       shutdown(conn, SHUT_RDWR);
-                       close(conn);
-                       conn = -1;
-                       flag_conn = 0;
-               }
-       }
+    if (flag_conn) {
+        sent = send(conn, ptr, bytesize, MSG_NOSIGNAL);
+        if (sent <= 0) {
+            DPRINT("Pious Teardown!\n");
+            shutdown(conn, SHUT_RDWR);
+            close(conn);
+            conn = -1;
+            flag_conn = 0;
+        }
+    }
 
     (void)stream;
-       return bytesize;
+    return bytesize;
 
 }
 
 
 static int prepare_tcp_dream(const char *ip, unsigned short port) {
-       int err = -1;
-       struct sockaddr_in lob;
-       WHOAMI;
+    int err = -1;
+    struct sockaddr_in lob;
+    WHOAMI;
 
-       sock = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
-       if (sock < 0)
-               goto ERR_SOCK;
+    sock = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
+    if (sock < 0)
+        goto ERR_SOCK;
 
-       lob.sin_family = AF_INET;
-       lob.sin_port = htons(port);
-       lob.sin_addr.s_addr = inet_addr(ip);
+    lob.sin_family = AF_INET;
+    lob.sin_port = htons(port);
+    lob.sin_addr.s_addr = inet_addr(ip);
 
-       err = bind(sock, (const struct sockaddr*) &lob, sizeof lob);
+    err = bind(sock, (const struct sockaddr*) &lob, sizeof lob);
 
-       if (err < 0)
-               goto ERR_BIND;
+    if (err < 0)
+        goto ERR_BIND;
 
-       err = listen(sock, 5);
+    err = listen(sock, 5);
 
-       if (err < 0)
-               goto ERR_LSTN;
+    if (err < 0)
+        goto ERR_LSTN;
 
-       flag_conn = 0;
-       conn = -1;
-       err = 0;
+    flag_conn = 0;
+    conn = -1;
+    err = 0;
 
-       goto ERR_SUCC;
+    goto ERR_SUCC;
 
 ERR_LSTN:
 ERR_BIND:
-               close(sock);
+    close(sock);
 
 ERR_SOCK:
 ERR_SUCC:
-               return err;
+    return err;
 }
 
 static void cleanup_tcp_dream(void){
-       WHOAMI;
-       if (conn>=0){
-               shutdown(conn, SHUT_RDWR);
-               close(conn);
-               conn = -1;
-               flag_conn = 0;
-       }
-       close(sock);
+    WHOAMI;
+    if (conn>=0){
+        shutdown(conn, SHUT_RDWR);
+        close(conn);
+        conn = -1;
+        flag_conn = 0;
+    }
+    close(sock);
 }
 
 #else
@@ -138,52 +138,52 @@ static void cleanup_tcp_dream(void){}
 static void prepare_tcp_dream(void){}
 
 size_t fetch_send(void *ptr, size_t size, size_t nmemb, void *stream) {
-       return (size * nmemb);
+    return (size * nmemb);
 }
 
 #endif
 
 int curly_init(void) {
-       CURLcode cc;
-       WHOAMI;
+    CURLcode cc;
+    WHOAMI;
 
-       cc = curl_global_init(CURL_GLOBAL_NOTHING);
-       if (cc != CURLE_OK)
-               return -1;
-       return 0;
+    cc = curl_global_init(CURL_GLOBAL_NOTHING);
+    if (cc != CURLE_OK)
+        return -1;
+    return 0;
 }
 
 void curly_cleanup(void) {
-       WHOAMI;
-       curl_global_cleanup();
+    WHOAMI;
+    curl_global_cleanup();
 }
 
 static CURL *sch;
 
 int curly_stream_init(const char *ip, unsigned short port) {
-       int err;
+    int err;
 
-       WHOAMI;
+    WHOAMI;
 
-       sch = curl_easy_init();
-       bufsize = BSIZE;
+    sch = curl_easy_init();
+    bufsize = BSIZE;
 
     //TODO error handling
 
-       err = prepare_tcp_dream(ip, port);
+    err = prepare_tcp_dream(ip, port);
 
-       return (sch != NULL && 0 == err);
+    return (sch != NULL && 0 == err);
 
 }
 
 void curly_stream_cleanup(void) {
-       WHOAMI;
+    WHOAMI;
 
-       if (sch)
-               curl_easy_cleanup(sch);
+    if (sch)
+        curl_easy_cleanup(sch);
 
-       cleanup_tcp_dream();
-       sch = NULL;
+    cleanup_tcp_dream();
+    sch = NULL;
 }
 
 #ifdef USE_TC7200_WORKAROUND
@@ -192,51 +192,54 @@ void curly_stream_cleanup(void) {
 #endif
 int curly_stream(const char *from_url, unsigned long duration) {
 
-       CURLcode cc = CURLE_COULDNT_CONNECT;
-       int err = -1;
-       double abps, size;
+    CURLcode cc = CURLE_COULDNT_CONNECT;
+    int err = -1;
+    double abps, size;
+#ifdef USE_TC7200_WORKAROUND
+    static int tc7200_deathcounter = 0;
+#endif
 #ifdef USE_TC7200_WORKAROUND
     static int tc7200_deathcounter = 0;
 #endif
 
-       WHOAMI;
+    WHOAMI;
 
 #ifdef USE_TCP
-       //when we don't have a client don't actually stream anything
-       //but try to take just as long
-       time_t st = time(NULL);
+    //when we don't have a client don't actually stream anything
+    //but try to take just as long
+    time_t st = time(NULL);
 
     while (conn < 0 && (unsigned long)(time(NULL)-st) < duration) {
-               conn = accept(sock, NULL, NULL);
-               usleep(1);
-       }
+        conn = accept(sock, NULL, NULL);
+        usleep(1);
+    }
 
-       if (conn < 0){
-               abps = 0;
-               size = 0;
-               cc = CURLE_OK;
-               goto FAKED;
-       }
+    if (conn < 0){
+        abps = 0;
+        size = 0;
+        cc = CURLE_OK;
+        goto FAKED;
+    }
 
 #endif
 
-       if (!sch)
-               goto OUT;
+    if (!sch)
+        goto OUT;
 
-       cc = curl_easy_setopt(sch, CURLOPT_URL, from_url);
-       if (CURLE_OK != cc)
-               goto OUT;
+    cc = curl_easy_setopt(sch, CURLOPT_URL, from_url);
+    if (CURLE_OK != cc)
+        goto OUT;
 
 #ifdef USE_TCP
-       cc = curl_easy_setopt(sch, CURLOPT_WRITEFUNCTION, fetch_send);
+    cc = curl_easy_setopt(sch, CURLOPT_WRITEFUNCTION, fetch_send);
 #else
-       cc = curl_easy_setopt(sch, CURLOPT_WRITEDATA, stdout);
+    cc = curl_easy_setopt(sch, CURLOPT_WRITEDATA, stdout);
 #endif
 
-       if (CURLE_OK != cc)
-               goto OUT;
+    if (CURLE_OK != cc)
+        goto OUT;
 
-       curl_easy_setopt(sch, CURLOPT_BUFFERSIZE, bufsize);
+    curl_easy_setopt(sch, CURLOPT_BUFFERSIZE, bufsize);
 
 #ifdef USE_TC7200_WORKAROUND
     //this is to work around a fucked up tc7200 router
@@ -250,28 +253,28 @@ int curly_stream(const char *from_url, unsigned long duration) {
 #endif
 
 #ifdef DEBUG
-       curl_easy_setopt(sch, CURLOPT_VERBOSE, 1L);
+    curl_easy_setopt(sch, CURLOPT_VERBOSE, 1L);
 #endif
 
-       curl_easy_setopt(sch, CURLOPT_TIMEOUT, 6*duration); //better than never timing out
+    curl_easy_setopt(sch, CURLOPT_TIMEOUT, 6*duration); //better than never timing out
 
-       cc = curl_easy_perform(sch);
+    cc = curl_easy_perform(sch);
 
 
-       if (CURLE_OK != cc)
-               goto OUT;
+    if (CURLE_OK != cc)
+        goto OUT;
 
-       cc = curl_easy_getinfo(sch,CURLINFO_SIZE_DOWNLOAD, &size);
-       cc |= curl_easy_getinfo(sch,CURLINFO_SPEED_DOWNLOAD, &abps);
+    cc = curl_easy_getinfo(sch,CURLINFO_SIZE_DOWNLOAD, &size);
+    cc |= curl_easy_getinfo(sch,CURLINFO_SPEED_DOWNLOAD, &abps);
 
 FAKED:
 
-       if (CURLE_OK == cc)
-               printf("%8.0f bytes @ %4.2f KB/s (%lu real seconds)\n", size, abps / 1000.0, time(NULL)-st);
+    if (CURLE_OK == cc)
+        printf("%8.0f bytes @ %4.2f KB/s (%lu real seconds)\n", size, abps / 1000.0, time(NULL)-st);
 
-       err = 0;
+    err = 0;
 OUT:
-       return err;
+    return err;
 }
 
 
@@ -290,37 +293,37 @@ int curly_refresh_m3u8(const char *from_url, MFILE *f) {
 
 #endif
 
-       CURL *ch = NULL;
-       CURLcode cc;
+    CURL *ch = NULL;
+    CURLcode cc;
 
 #ifdef USE_STREAM
-       FILE *f;
+    FILE *f;
 #endif
 
-       int err = -1;
-       WHOAMI;
+    int err = -1;
+    WHOAMI;
 
 #ifdef USE_STREAM
-       f = fopen(to_file, "w");
+    f = fopen(to_file, "w");
 
-       if (!f)
-               goto OUT;
+    if (!f)
+        goto OUT;
 #endif
 
-       /*
-        if (sch)
-        ch = sch;
-        else
-        */
+    /*
+     if (sch)
+     ch = sch;
+     else
+     */
 
-       ch = curl_easy_init();
+    ch = curl_easy_init();
 
-       if (!ch)
-               goto OUT;
+    if (!ch)
+        goto OUT;
 
-       cc = curl_easy_setopt(ch, CURLOPT_URL, from_url);
-       if (CURLE_OK != cc)
-               goto OUT;
+    cc = curl_easy_setopt(ch, CURLOPT_URL, from_url);
+    if (CURLE_OK != cc)
+        goto OUT;
 
 
     WHOAMI;
@@ -342,31 +345,31 @@ int curly_refresh_m3u8(const char *from_url, MFILE *f) {
 
 
     cc = curl_easy_perform(ch);
-       if (CURLE_OK != cc)
-               goto OUT;
+    if (CURLE_OK != cc)
+        goto OUT;
 
-       err = 0;
+    err = 0;
 
 
 OUT:
 
 #ifdef USE_STREAM
     if (f)
-               fclose(f);
+        fclose(f);
 #endif
-       //if (ch && ch!=sch)    curl_easy_cleanup(ch);
+    //if (ch && ch!=sch)       curl_easy_cleanup(ch);
 
-       if (ch)
-               curl_easy_cleanup(ch);
+    if (ch)
+        curl_easy_cleanup(ch);
 
-       return err;
+    return err;
 }
 
 int curly_is_connected(void){
-       WHOAMI;
+    WHOAMI;
 #ifdef USE_TCP
-                       return flag_conn;
+    return flag_conn;
 #else
-                       return 1;
+    return 1;
 #endif
 }
diff --git a/itemq.c b/itemq.c
index a5005d0bb3ab2979aa01c74bff4854e2f6f8aeb6..e00f83b8fb0628a286c6d22ead6e910360392427 100644 (file)
--- a/itemq.c
+++ b/itemq.c
@@ -34,30 +34,30 @@ static void handle_signal(int sig){
 }
 
 struct item {
-       char url[1024];
-       unsigned int hash;
-       //will be set to 1 after streamed
-       int done;
-       // will be set to 1 when it can be purged from the list
-       // this is true when done is 1 and after the last refresh round
-       // this hash was no longer present in the m3u8
-       int purge;
-       struct item *next;
-       unsigned long duration;
-       int is_streamlist;
-       int bandwidth;
+    char url[1024];
+    unsigned int hash;
+    //will be set to 1 after streamed
+    int done;
+    // will be set to 1 when it can be purged from the list
+    // this is true when done is 1 and after the last refresh round
+    // this hash was no longer present in the m3u8
+    int purge;
+    struct item *next;
+    unsigned long duration;
+    int is_streamlist;
+    int bandwidth;
 };
 
 static void *zalloc(size_t size) {
-       void *ptr;
+    void *ptr;
 
-       WHOAMI;
+    WHOAMI;
 
-       ptr = malloc(size);
-       if (ptr)
-               memset(ptr, 0, size);
+    ptr = malloc(size);
+    if (ptr)
+        memset(ptr, 0, size);
 
-       return ptr;
+    return ptr;
 
 }
 
@@ -65,122 +65,122 @@ static void *zalloc(size_t size) {
 static void print_list(void) {
 
 #ifdef DEBUG
-       struct item *n = head;
-       int i = 0;
+    struct item *n = head;
+    int i = 0;
 
-       WHOAMI;
+    WHOAMI;
 
-       while (n != NULL) {
-               DPRINT("[%d] %s:%lu:%X:%d:%d\n", ++i, n->url, n->duration, n->hash, n->done,
-                               n->purge);
-               n = n->next;
-       }
+    while (n != NULL) {
+        DPRINT("[%d] %s:%lu:%X:%d:%d\n", ++i, n->url, n->duration, n->hash, n->done,
+               n->purge);
+        n = n->next;
+    }
 #endif
 
 }
 
 struct item *find_hash(unsigned int hash) {
 
-       struct item *n = head;
+    struct item *n = head;
 
-       WHOAMI;
+    WHOAMI;
 
-       while (n != NULL) {
-               if (n->hash == hash)
-                       break;
-               n = n->next;
-       }
-       return n;
+    while (n != NULL) {
+        if (n->hash == hash)
+            break;
+        n = n->next;
+    }
+    return n;
 }
 
 static int compute_hash(const char *s) {
-       int hash = 0;
-       unsigned char bcc = 0;
-
-       WHOAMI;
-
-       while (*s) {
-               bcc ^= *s;
-               hash ^= bcc;
-               hash <<= 2;
-               s++;
-       }
-       return hash;
+    int hash = 0;
+    unsigned char bcc = 0;
+
+    WHOAMI;
+
+    while (*s) {
+        bcc ^= *s;
+        hash ^= bcc;
+        hash <<= 2;
+        s++;
+    }
+    return hash;
 }
 
 static void purge_run(int killemall) {
-       struct item *n;
+    struct item *n;
 
-       WHOAMI;
+    WHOAMI;
 
     //purge here
     while (head && (head->purge || killemall)) {
-               DPRINT("Purging %s:%X:%d:%d\n", head->url, head->hash, head->done,
-                               head->purge);
-               n = head;
-               head = head->next;
-               free(n);
-       }
+        DPRINT("Purging %s:%X:%d:%d\n", head->url, head->hash, head->done,
+               head->purge);
+        n = head;
+        head = head->next;
+        free(n);
+    }
 
 }
 
 static void purge_prepare(void) {
-       struct item *n;
+    struct item *n;
 
-       WHOAMI;
+    WHOAMI;
 
-       //mark done entries as ok to purge
-       //don't mark curr as ok to purge because we might
-       //still need it to advance to its next in emulate_stream()
-       for (n = head; n && n->done && n!=curr; n = n->next){
-                       n->purge = 1;
-       }
+    //mark done entries as ok to purge
+    //don't mark curr as ok to purge because we might
+    //still need it to advance to its next in emulate_stream()
+    for (n = head; n && n->done && n!=curr; n = n->next){
+        n->purge = 1;
+    }
 
 }
 
 void emulate_stream(void) {
 
-       int err;
-
-       WHOAMI;
-
-       if (!curr) {
-               //this should never happen, no reasonable way to recover
-               fprintf(stderr,"curr is NULL, bailing out\n");
-               in_game = 0;
-               return;
-       }
-
-       if (curr->done){
-               if (curr->next){
-                       curr = curr->next;
-               } else {
-                       //we end up here if we are faster than the server can produce
-                       if (!live) {
-                               in_game = 0;
-                       } else {
-                               DPRINT("sleeping\n");
-                               sleep(1);
-                       }
-                       return;
-               }
-       }
-
-       do {
-               printf("Streaming %s (%lu)\n", curr->url, curr->duration);
+    int err;
+
+    WHOAMI;
+
+    if (!curr) {
+        //this should never happen, no reasonable way to recover
+        fprintf(stderr,"curr is NULL, bailing out\n");
+        in_game = 0;
+        return;
+    }
+
+    if (curr->done){
+        if (curr->next){
+            curr = curr->next;
+        } else {
+            //we end up here if we are faster than the server can produce
+            if (!live) {
+                in_game = 0;
+            } else {
+                DPRINT("sleeping\n");
+                sleep(1);
+            }
+            return;
+        }
+    }
+
+    do {
+        printf("Streaming %s (%lu)\n", curr->url, curr->duration);
 #if 1
-               err = curly_stream(curr->url, curr->duration);
+        err = curly_stream(curr->url, curr->duration);
 #else
-               err = -1; curly_fake_stream();
+        err = -1; curly_fake_stream();
 #endif
 
-               if (err){
-                       DPRINT("Streaming failed\n");
-               }
+        if (err){
+            DPRINT("Streaming failed\n");
+        }
 
-       } while (0);
+    } while (0);
 
-       curr->done = 1;
+    curr->done = 1;
 
 }
 #ifdef USE_STREAM
@@ -190,216 +190,216 @@ int reload_m3u8(MFILE *f, const char *urlbase) {
 #endif
 
 #ifdef USE_STREAM
-       FILE *f;
+    FILE *f;
 #endif
-       char buf[1024];
-       struct item *n;
-       struct item *p;
-       unsigned int thash;
-       unsigned long lval;
+    char buf[1024];
+    struct item *n;
+    struct item *p;
+    unsigned int thash;
+    unsigned long lval;
 
 
-       int plist,pid,bw;
+    int plist,pid,bw;
 
-       const char *v;
-       MTAG m;
-       int urloff;
+    const char *v;
+    MTAG m;
+    int urloff;
 
-       WHOAMI;
+    WHOAMI;
 
 
-       plist = pid = bw = 0;
+    plist = pid = bw = 0;
 
-       DPRINT("Reloading M3U8\n");
+    DPRINT("Reloading M3U8\n");
 #ifdef USE_STREAM
     f = fopen(from_file, "r");
 #endif
-       if (!f)
-               return -1;
+    if (!f)
+        return -1;
 #ifdef USE_STREAM
-       while (fgets(buf, sizeof buf, f)) {
+    while (fgets(buf, sizeof buf, f)) {
 #else
-        while (mgets(buf, sizeof buf, f)) {
+    while (mgets(buf, sizeof buf, f)) {
 #endif
-               if (buf[strlen(buf) - 1] == '\n')
-                       buf[strlen(buf) - 1] = 0;
-               if (buf[strlen(buf) - 1] == '\r')
-                       buf[strlen(buf) - 1] = 0;
-
-               m = m3u8_parse(buf, &v);
-
-               if (M_EXTINF == m){
-                       m3u8_get_property(P_DURATION, v, &lval);
-               }
-               if (M_X_ENDLIST == m){
-                       printf("This is not a live stream!\n");
-                       live = 0;
-               }
-               if (M_X_STREAM_INF == m){
-                       //playlist entry detected;
-                       plist = 1;
-                       m3u8_get_property(P_BANDWIDTH, v, &lval);
-                       bw = lval;
-                       m3u8_get_property(P_PROGRAM_ID, v, &lval);
-                       pid = lval;
-                       printf ("PID: %d BW:%d\n",pid, bw);
-               }
-
-               if (M_URL != m) continue;
-
-               /*
-                position to add will be determined by the hash of new entry vs hashes already in the list
-                that is...all new hashes will be added at tail unless this entry's hash is already in the list
-                the entry is not then not added but the next new one will be added after this one
-                this will in degenerate into adding at tail if m3u8 refresh interval is too long (old entries purged)
-                */
-
-               thash = compute_hash(buf);
-
-               if ((p = find_hash(thash))) {
-                       //element is still in the newest m3u8
-                       //hold onto it some longer
-                       p->purge = 0;
-                       continue;
-               }
-
-               n = zalloc(sizeof(struct item));
-               n->hash = thash;
-               n->is_streamlist = plist;
-               n->bandwidth = bw;
-
-               urloff = 0;
-
-               if (strncmp(buf,"http://",7)){
-                       strcpy(n->url,urlbase);
-                       urloff = strlen(urlbase);
-               }
-
-               strcpy(n->url+urloff, buf);
-               n->duration = lval;
-
-               if (!head) {
-                       //XXX curr is always first, which is not what we want in certain scenarios
-                       head = tail = curr = n;
-               } else {
-                       if (!p || p == tail) { //hash not found
-                               tail->next = n;
-                               tail = n;
-                       } else {
-                               n->next = p->next;
-                               p->next = n;
-                       }
-               }
-       }
+        if (buf[strlen(buf) - 1] == '\n')
+            buf[strlen(buf) - 1] = 0;
+        if (buf[strlen(buf) - 1] == '\r')
+            buf[strlen(buf) - 1] = 0;
+
+        m = m3u8_parse(buf, &v);
+
+        if (M_EXTINF == m){
+            m3u8_get_property(P_DURATION, v, &lval);
+        }
+        if (M_X_ENDLIST == m){
+            printf("This is not a live stream!\n");
+            live = 0;
+        }
+        if (M_X_STREAM_INF == m){
+            //playlist entry detected;
+            plist = 1;
+            m3u8_get_property(P_BANDWIDTH, v, &lval);
+            bw = lval;
+            m3u8_get_property(P_PROGRAM_ID, v, &lval);
+            pid = lval;
+            printf ("PID: %d BW:%d\n",pid, bw);
+        }
+
+        if (M_URL != m) continue;
+
+        /*
+         position to add will be determined by the hash of new entry vs hashes already in the list
+         that is...all new hashes will be added at tail unless this entry's hash is already in the list
+         the entry is not then not added but the next new one will be added after this one
+         this will in degenerate into adding at tail if m3u8 refresh interval is too long (old entries purged)
+         */
+
+        thash = compute_hash(buf);
+
+        if ((p = find_hash(thash))) {
+            //element is still in the newest m3u8
+            //hold onto it some longer
+            p->purge = 0;
+            continue;
+        }
+
+        n = zalloc(sizeof(struct item));
+        n->hash = thash;
+        n->is_streamlist = plist;
+        n->bandwidth = bw;
+
+        urloff = 0;
+
+        if (strncmp(buf,"http://",7)){
+            strcpy(n->url,urlbase);
+            urloff = strlen(urlbase);
+        }
+
+        strcpy(n->url+urloff, buf);
+        n->duration = lval;
+
+        if (!head) {
+            //XXX curr is always first, which is not what we want in certain scenarios
+            head = tail = curr = n;
+        } else {
+            if (!p || p == tail) { //hash not found
+                tail->next = n;
+                tail = n;
+            } else {
+                n->next = p->next;
+                p->next = n;
+            }
+        }
+    }
 #ifdef USE_STREAM
-       fclose(f);
+    fclose(f);
 #endif
-       return 0;
+    return 0;
 }
 
 const char *choose_url(void){
-       struct item *n;
-       const char *u;
-       int bw = 0;
-
-       WHOAMI;
-
-       n = head;
-       u = head->url;
-       while (n){
-               //choose first matching url, >= to choose last, but could lead to problems, allow user selection!
-               if (n->bandwidth>bw) {u = n->url; bw=n->bandwidth; }
-               n->done = 1;
-               n->purge = 1;
-               n=n->next;
-       }
-
-       printf ("Final BW: %d | URL: %s\n",bw, u);
-       return u;
+    struct item *n;
+    const char *u;
+    int bw = 0;
+
+    WHOAMI;
+
+    n = head;
+    u = head->url;
+    while (n){
+        //choose first matching url, >= to choose last, but could lead to problems, allow user selection!
+        if (n->bandwidth>bw) {u = n->url; bw=n->bandwidth; }
+        n->done = 1;
+        n->purge = 1;
+        n=n->next;
+    }
+
+    printf ("Final BW: %d | URL: %s\n",bw, u);
+    return u;
 }
 
 static void reset_base(char *base, char *url){
 
-       WHOAMI;
+    WHOAMI;
 
-       strcpy(base,url);
-       //TODO risky dice
-       *(strrchr(base, '/')+1) = 0;
+    strcpy(base,url);
+    //TODO risky dice
+    *(strrchr(base, '/')+1) = 0;
 }
 int main(int argc, char *argv[]) {
 
-       time_t last, now;
+    time_t last, now;
 
-       int refreshed;
-       int refresh_period = 20;
-       char url[1024];
-       char base[1024];
+    int refreshed;
+    int refresh_period = 20;
+    char url[1024];
+    char base[1024];
 
-       if (argc>1)
-               strcpy(url, argv[1]);
-       else
-               strcpy(url, QVC_MASTER_M3U8);
+    if (argc>1)
+        strcpy(url, argv[1]);
+    else
+        strcpy(url, QVC_MASTER_M3U8);
 
-       printf ("Master URL: %s\n",url);
+    printf ("Master URL: %s\n",url);
 
-       reset_base(base, url);
+    reset_base(base, url);
 
-       curly_init();
+    curly_init();
     curly_stream_init("0.0.0.0",7120);
 
 
-       last = now = 0;
-       head = tail = curr = NULL;
-       live = in_game = 1;
+    last = now = 0;
+    head = tail = curr = NULL;
+    live = in_game = 1;
 
     signal(SIGTERM, handle_signal);
     signal(SIGINT,  handle_signal);
 
-       while (in_game) {
-               now = time(NULL);
-               if (live && now-last>=refresh_period) {
-                       DPRINT("Refreshing M3U8 after %d real seconds\n",(int)(last?now-last:0));
+    while (in_game) {
+        now = time(NULL);
+        if (live && now-last>=refresh_period) {
+            DPRINT("Refreshing M3U8 after %d real seconds\n",(int)(last?now-last:0));
 #ifdef USE_STREAM
-                       refreshed = (0 == curly_refresh_m3u8(url, PLS));
+            refreshed = (0 == curly_refresh_m3u8(url, PLS));
 #else
             MFILE *f = mopen(NULL, 0, "w+");
 
             refreshed = (0 == curly_refresh_m3u8(url, f));
 #endif
-                       if (refreshed) {
-                               last = now = time(NULL);
-                               purge_prepare();
+            if (refreshed) {
+                last = now = time(NULL);
+                purge_prepare();
 #ifdef USE_STREAM
-                               if (0 == reload_m3u8(PLS, base)) {
+                if (0 == reload_m3u8(PLS, base)) {
 #else
                 if (0 == reload_m3u8(f, base)) {
                     mclose(f);
 #endif
-                                       refreshed = 0;
+                    refreshed = 0;
                     purge_run(0);
-                                       print_list();
+                    print_list();
 
-                                       if (head->is_streamlist){
-                                               strcpy (url, choose_url());
-                                               reset_base(base, url);
-                                               curr = NULL; //so purge will not spare it
+                    if (head->is_streamlist){
+                        strcpy (url, choose_url());
+                        reset_base(base, url);
+                        curr = NULL; //so purge will not spare it
                         purge_run(0);
-                                               last = 0;
-                                               continue;
-                                       }
-                               }
-                       } else {
-                               DPRINT ("Could not load M3U8 from %s!\n",url);
-                               sleep (1);
-                       }
-               }
+                        last = 0;
+                        continue;
+                    }
+                }
+            } else {
+                DPRINT ("Could not load M3U8 from %s!\n",url);
+                sleep (1);
+            }
+        }
 
-                       emulate_stream();
+        emulate_stream();
 
 
-       }
+    }
     purge_run(1);
-       curly_stream_cleanup();
-       curly_cleanup();
-       return 0;
+    curly_stream_cleanup();
+    curly_cleanup();
+    return 0;
 }