summaryrefslogtreecommitdiffstats
path: root/rtv4d-dl.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--rtv4d-dl.c692
1 files changed, 476 insertions, 216 deletions
diff --git a/rtv4d-dl.c b/rtv4d-dl.c
index 93ad919..4b46265 100644
--- a/rtv4d-dl.c
+++ b/rtv4d-dl.c
@@ -4,6 +4,11 @@
#include <string.h>
#include <math.h>
#include <tcp.c>
+#include <dirent.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <errno.h>
#define NIZ_DODATEK(a) #a
#define NIZ(a) NIZ_DODATEK(a)
#define RTV_CLIENT_ID "82013fb3a531d5414f478747c1aca622" /* enak za vse */
@@ -27,8 +32,9 @@
#define RTV_TEST_PROGRAM "SLO1"
#define RTV_TEST_OBJAVLJENO "2010-12-03 23:20:10"
#define RTV_TEST_PREDVAJANO "2010-12-03 23:20:10"
-#define RTV_TEST_TIP_POSNETKA 4D_VIDEO_TIP
-#define RTV_TEST_SLICICA "http://img.rtvslo.si/_up/ava/ava_misc/show_logos" \
+#define RTV_TEST_TIP_POSNETKA RTV_VIDEO_TIP
+#define RTV_SLD "rtvslo.si"
+#define RTV_TEST_SLICICA "http://img." RTV_SLD "/_up/ava/ava_misc/show_logos" \
"/VREME_VECERNO-980.jpg"
#define RTV_TEST_KONTROLNA_VREDNOST 1186735842
#define RTV_TEST_VELIKOST 9396765
@@ -48,18 +54,73 @@
"\r\nAccept: */*\r\nX-Requested-With: tcp.c (" __FILE__ ":" NIZ(__LINE__) \
")\r\nConnection: close\r\n\r\n"
#define RTV_HTTP_TIMEOUT 69 /* sekund */
-#define RTV_NE_BO_POSLAL NULL /* "ToJeMogočeBackdoor!" */ /* bere več znakov */
-#define RTV_API_META_URL "http://api.rtvslo.si/ava/getRecordingDrm/" \
+#define RTV_NE_BO_POSLAL NULL /* bere več znakov */
+#define RTV_API_META_URL "http://api." RTV_SLD "/ava/getRecordingDrm/" \
"%u?client_id=" RTV_CLIENT_ID
#define RTV_API_META_URL_SIZEOF 128 /* vključno z nul znakom */
-#define RTV_API_MEDIA_URL "http://api.rtvslo.si/ava/getMedia/%u/?client_id=" \
+#define RTV_API_MEDIA_URL "http://api." RTV_SLD "/ava/getMedia/%u/?client_id=" \
RTV_CLIENT_ID "&jwt=%s"
#define RTV_API_MEDIA_URL_SIZEOF 64 + RTV_CLIENT_ID_SIZEOF + RTV_JWT_SIZEOF
#define RTV_JWT_SIZEOF 43+1
-#define RTV_PREDVAJALNIK_URL "http://4d.rtvslo.si/arhiv/v/%u"
-#define RTV_PREDVAJALNIK_URL_SIZEOF 32+1 + 12
+#define RTV_PREDVAJALNIK_URL "http://4d." RTV_SLD "/arhiv/v/%u"
+#define RTV_PREDVAJALNIK_URL_SIZEOF (32+1 + 12)
#define RTV_VER "0.0.3"
-
+#define RTV_ZIVO_PROGRAM_SIZEOF 12
+#define RTV_API_ZIVO_URL \
+ "http://api." RTV_SLD "/ava/getLiveStream/tv.%." \
+ NIZ(RTV_ZIVO_PROGRAM_SIZEOF) "s?client_id=" RTV_CLIENT_ID
+#define RTV_API_ZIVO_URL_SIZEOF (64 + 32 + 1 + RTV_ZIVO_PROGRAM_SIZEOF)
+#define RTV_HTTPS_V_HTTP(url) \
+ if (url[4] == 's') { memmove((url)+4, (url)+5, strlen((url)+5)+1); }
+#define RTV_ZCARON 4294967237
+#define strtollu strtoull
+#define strtolu strtoul
+#define strtolld strtoll
+#define strtold strtol
+#define strtod strtol
+#define strtou strtoul
+#define RTV_JSON_INIT() \
+ char * RTV_JSON_cp; size_t RTV_JSON_i, RTV_JSON_globina; char RTV_JSON_c;
+#define RTV_JSON_VALUE(str, i, key) (str+i+strlen(key)+2)
+#define RTV_JSON_TIP_u unsigned int
+#define RTV_JSON_TIP_s char
+#define RTV_JSON_OBLIKA_s(imem, format, loc) \
+ RTV_JSON_c = RTV_JSON_cp[0]; \
+ RTV_JSON_cp[0] = '\0'; /* omejimo json string, ne potrebujemo strncpy */ \
+ imem##_sizeof = sizeof(char)*(strlen(loc)+1+RTV_P_SIZEOF); \
+ imem = realloc(imem, imem##_sizeof); \
+ strcpy(imem, loc); \
+ RTV_JSON_cp[0] = RTV_JSON_c; /* ponastavimo originalno vrednost */
+#define RTV_JSON_OBLIKA_u(imem, format, loc) /* -1: št niso v "" v JSON */ \
+ imem = strto##format(loc, NULL, 10);
+#define RTV_JSON_IZPOLNI(imem, format, splitter, loc) \
+ do { RTV_JSON_cp = strchr(loc, splitter); \
+ if ( RTV_JSON_cp == NULL) { \
+ RTV_NAPISI(OPOZORILO, "RTV_JSON: napaka pri: " #imem); \
+ } else { \
+ RTV_JSON_OBLIKA_##format(imem, format, loc) \
+ RTV_NAPISI(HROSC, "RTV_JSON: " #imem " => %" #format, \
+ imem); \
+ } } while (0);
+#define RTV_JSON(str, strl, key, out, fmt, spl, otr) /* strl je strlen */ \
+ do { \
+ for (RTV_JSON_i = 0; RTV_JSON_i < strl; RTV_JSON_i++) { /* keyss=sizeof */ \
+ if (otr != NULL) { \
+ if (str[RTV_JSON_i] == '}' && RTV_JSON_globina > 0) RTV_JSON_globina--;\
+ if (str[RTV_JSON_i] == '{') \
+ if (strncmp(otr, str+RTV_JSON_i-(2+strlen(otr)), strlen(otr)) == 0) \
+ RTV_JSON_globina++; \
+ } \
+ if ( (RTV_JSON_globina > 0 || otr == NULL) \
+ && strncmp(str+RTV_JSON_i, key, strlen(key)) == 0) { \
+ RTV_JSON_IZPOLNI(out, fmt, spl, RTV_JSON_VALUE(str, RTV_JSON_i, key)); \
+ break; \
+ } \
+ } \
+ } while (0);
+#define RTV_FREE(param) do { free(param); param = NULL; } while (0)
+#define RTV_HTTP_SUCCESS(koda) ((koda / 100) == 2) /* če je koda 2xx */
+#define RTV_ZIVO_P_DOLZINA 10
struct meta_oddaja {
size_t naslov_sizeof;
char * naslov; /* Vreme ob 22h */
@@ -90,37 +151,75 @@ struct meta_oddaja {
char predvajalnik_url[RTV_PREDVAJALNIK_URL_SIZEOF]; /* http://4d.rtvslo.... */
size_t posnetek_url_sizeof;
char * posnetek_url; /* http://progressive.rtvslo.si/encrypted00/2010/12... */
+ char * podnapisi_url; /* http://img.rtvslo.si/_up/ava/ava_misc/subs/2020... */
+ size_t podnapisi_url_sizeof; /* upam, da nikoli ni več kot ena datoteka. */
};
struct meta_oddaja * meta_oddaja_alloc () {
struct meta_oddaja * m = malloc(sizeof(struct meta_oddaja));
- m->naslov = malloc(sizeof(char)*RTV_P_SIZEOF);m->naslov_sizeof = RTV_P_SIZEOF;
- m->zanri = malloc(sizeof(char)*RTV_P_SIZEOF); m->zanri_sizeof = RTV_P_SIZEOF;
- m->opis = malloc(sizeof(char)*RTV_P_SIZEOF); m->opis_sizeof = RTV_P_SIZEOF;
- m->tip_oddaje_ime=malloc(sizeof(char)*RTV_P_SIZEOF);
- m->tip_oddaje_ime_sizeof = RTV_P_SIZEOF;
- m->program = malloc(sizeof(char)*RTV_P_SIZEOF);m->program_sizeof=RTV_P_SIZEOF;
- m->slicica = malloc(sizeof(char)*RTV_P_SIZEOF);m->slicica_sizeof=RTV_P_SIZEOF;
- m->jwt = malloc(sizeof(char)*RTV_P_SIZEOF); m->jwt_sizeof=RTV_P_SIZEOF;
- m->objavljeno = malloc(sizeof(char)*RTV_P_SIZEOF);
- m->objavljeno_sizeof = RTV_P_SIZEOF;
- m->predvajano = malloc(sizeof(char)*RTV_P_SIZEOF);
- m->predvajano_sizeof = RTV_P_SIZEOF;
- m->posnetek_url = malloc(sizeof(char)*RTV_P_SIZEOF);
- m->posnetek_url_sizeof = RTV_P_SIZEOF;
+#define RTV_META_ALLOC(param) \
+ param = malloc(sizeof(char)*RTV_P_SIZEOF); param##_sizeof = RTV_P_SIZEOF; \
+ param[0] = '\0'; /* da ga nastavimo na prazno vrednost, ne na fuckery*/
+ RTV_META_ALLOC(m->naslov);
+ RTV_META_ALLOC(m->zanri);
+ RTV_META_ALLOC(m->opis);
+ RTV_META_ALLOC(m->tip_oddaje_ime);
+ RTV_META_ALLOC(m->program);
+ RTV_META_ALLOC(m->slicica);
+ RTV_META_ALLOC(m->jwt);
+ RTV_META_ALLOC(m->objavljeno);
+ RTV_META_ALLOC(m->predvajano);
+ RTV_META_ALLOC(m->posnetek_url);
+ RTV_META_ALLOC(m->podnapisi_url);
return m;
}
int meta_oddaja_free (struct meta_oddaja * m) {
- free(m->naslov); m->naslov = NULL;
- free(m->zanri); m->zanri = NULL;
- free(m->opis); m->opis = NULL;
- free(m->tip_oddaje_ime); m->tip_oddaje_ime = NULL;
- free(m->program); m->program = NULL;
- free(m->slicica); m->slicica = NULL;
- free(m->jwt); m->jwt = NULL;
- free(m->objavljeno); m->objavljeno = NULL;
- free(m->predvajano); m->predvajano = NULL;
- free(m->posnetek_url); m->posnetek_url = NULL;
- free(m); m = NULL;
+ RTV_FREE(m->naslov);
+ RTV_FREE(m->zanri);
+ RTV_FREE(m->opis);
+ RTV_FREE(m->tip_oddaje_ime);
+ RTV_FREE(m->program);
+ RTV_FREE(m->slicica);
+ RTV_FREE(m->jwt);
+ RTV_FREE(m->objavljeno);
+ RTV_FREE(m->predvajano);
+ RTV_FREE(m->posnetek_url);
+ RTV_FREE(m->podnapisi_url);
+ RTV_FREE(m);
+ return 0;
+}
+struct rtv_zivo_meta {
+ char program[RTV_ZIVO_PROGRAM_SIZEOF]; /* slo1, slo2 */
+ unsigned int sedanjost; /* recimo 5580, številka zadnjega kosa */
+ unsigned int prvi; /* recimo 1234, številka prvega kosa, ki ga ima strežnik */
+ unsigned int dolzina; /* koliko dolg je en kos */
+ unsigned int diskrepanca; /* 1, če niso vsi kosi enako dolgi, 0 drugače */
+ unsigned int prenesenih_kosov_preteklost;
+ unsigned int prenesenih_kosov_prihodnost;
+ unsigned int preteklost; /* število sekund, ki naj jih prenesem za nazaj */
+ unsigned int prihodnost; /* število sekund, ki naj jih prenesem za naprej */
+ char * seznam_predvajanja_url; /* http://30-rtvslo-tv-slo1.../playlist.m3u8 */
+ size_t seznam_predvajanja_url_sizeof;
+ char * kazalo_url; /* http://30-rtvslo-tv-slo-tv.../chunklist_b4128000.m3u8 */
+ size_t kazalo_url_sizeof;
+ char * kos_format; /* http://30-rtvslo-tv-slo-tv-sl.../media_b4128000_%u.ts */
+ size_t kos_format_sizeof;
+ char * api_url; /* http://api.rtvslo.si/ava/getLiveStream/tv.slo1?client... */
+ size_t api_url_sizeof;
+};
+struct rtv_zivo_meta * rtv_zivo_meta_alloc () {
+ struct rtv_zivo_meta * m = malloc(sizeof(struct rtv_zivo_meta));
+ RTV_META_ALLOC(m->seznam_predvajanja_url);
+ RTV_META_ALLOC(m->kazalo_url);
+ RTV_META_ALLOC(m->kos_format);
+ RTV_META_ALLOC(m->api_url);
+ return m;
+}
+int rtv_zivo_meta_free (struct rtv_zivo_meta * m) {
+ RTV_FREE(m->seznam_predvajanja_url);
+ RTV_FREE(m->kazalo_url);
+ RTV_FREE(m->kos_format);
+ RTV_FREE(m->api_url);
+ RTV_FREE(m);
return 0;
}
int niz_realloc (char * s, size_t * v) {
@@ -141,6 +240,7 @@ int http_get (/* const */ char * u, FILE * r) { /* url ostane enak */
size_t header_sizeof = 0;
long long int contentlength = -69420;
char * request_buf; /* za request buffer */
+ int response_code = -69420;
#define RTV_URL_HOST (u+7)
if (u == NULL) {
RTV_NAPISI(NAPAKA, "URL je null!");
@@ -170,33 +270,36 @@ int http_get (/* const */ char * u, FILE * r) { /* url ostane enak */
}
t = *k;
*k = '\0';
- RTV_NAPISI(INFO, "Vzpostavljam TCP povezavo na http://%s:%d ...",
- RTV_URL_HOST, p);
+ RTV_NAPISI(HROSC, "http://%s:%d/%s",
+ RTV_URL_HOST, p, path);
c = spawn_conn(RTV_URL_HOST, p);
if (c < 0) {
RTV_NAPISI(NAPAKA, "TCP povezava ni uspela!");
returnstatus = 4;
goto http_get_returncleanly;
} else {
- RTV_NAPISI(INFO, "Povezan na strežnik.");
+ RTV_NAPISI(HROSC, "Povezan na strežnik.");
}
request_buf = malloc (sizeof(char) * ( sizeof(RTV_HTTP_GET)
+ strlen(RTV_URL_HOST)+ strlen(path) + 1 ));
sprintf(request_buf, RTV_HTTP_GET, path, RTV_URL_HOST); /* =dovolj prostora */
- RTV_NAPISI(INFO, "Pošiljam %lu bajtov ...", strlen(request_buf));
+ RTV_NAPISI(HROSC, "Pošiljam %lu bajtov ...", strlen(request_buf));
ret = sync_write(c, request_buf, strlen(request_buf), RTV_HTTP_TIMEOUT);
if (ret != 0) {
returnstatus = 5;
RTV_NAPISI(NAPAKA, "TCP časovna omejitev pri pošiljanju je potekla");
goto http_get_returncleanly;
} else {
- RTV_NAPISI(INFO, "Uspešno poslano.");
+ RTV_NAPISI(HROSC, "Uspešno poslano.");
}
headerstream = open_memstream(&header, &header_sizeof);
while (1) {
rewind(headerstream);
ret = read_until(c, headerstream, RTV_HTTP_TIMEOUT, "\n", -1); /* unsig!*/
fflush(headerstream);
+ if (response_code == -69420 && strchr(header, ' ') != NULL) {
+ response_code = atoi(strchr(header, ' ')+1);
+ }
if (ret != 0) {
returnstatus = 6;
RTV_NAPISI(NAPAKA, "Branje headerja ni uspelo!");
@@ -205,15 +308,15 @@ int http_get (/* const */ char * u, FILE * r) { /* url ostane enak */
if (strncasecmp("Content-Length: ", header, strlen("Content-Length: "))
== 0) {
contentlength = strtoll(header+16, NULL, 10);
- RTV_NAPISI(INFO, "Pridobil %lld bajtni odgovor.", contentlength);
+ RTV_NAPISI(HROSC, "Pridobil %lld bajtni odgovor.", contentlength);
}
if (strncmp("\r\n", header, 2) == 0 || header[0] == '\n')
break;
}
if (contentlength == -69420) {
- RTV_NAPISI(OPOZORILO, "Manjka Content-Length, berem do konca.");
+ RTV_NAPISI(HROSC, "Manjka Content-Length, berem do konca."); /* legalno */
} else {
- RTV_NAPISI(INFO, "Začetek telesa odgovora. Berem in pišem.");
+ RTV_NAPISI(HROSC, "Začetek telesa odgovora. Berem in pišem.");
}
fclose(headerstream);
ret = read_until(c, r, RTV_HTTP_TIMEOUT, RTV_NE_BO_POSLAL, contentlength);
@@ -222,7 +325,7 @@ int http_get (/* const */ char * u, FILE * r) { /* url ostane enak */
RTV_NAPISI(NAPAKA, "Branje in pisanje telesa odgovora ni uspelo!");
goto http_get_returncleanly;
}
- RTV_NAPISI(INFO, "Prejel in uspešno shranil/prebral HTTP odgovor.");
+ RTV_NAPISI(HROSC, "Prejel in uspešno shranil/prebral HTTP odgovor.");
http_get_returncleanly:
free(request_buf);
request_buf = NULL;
@@ -232,138 +335,72 @@ int http_get (/* const */ char * u, FILE * r) { /* url ostane enak */
RTV_NAPISI(OPOZORILO, "TCP povezave ni uspelo prekiniti");
*k = t;
u[6] = '/';
+ if (returnstatus == 0) {
+ returnstatus = response_code;
+ }
return returnstatus;
}
int rtv_meta_izpolni(struct meta_oddaja * m) {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wnonnull"
int returnstatus = 0;
FILE * odgstream;
char * odg;
size_t sizeloc;
- size_t i, j;
- unsigned short int nasel_addaptivemedia = 0; /* glej iskanje stream URLja */
- char * metakeys[] = {"\"title\"", "\"showId\"", "\"genre\"", \
- "\"description\"", "\"showDescription\"", "\"duration\"", "\"jwt\"", \
- "\"showName\"", "\"source\"", "\"publishDate\"", "\"mediaType\"", \
- "\"orig\"", "\"broadcastDate\"", /* getMedia query: */ "\"http\"", \
- "\"https\"", "\"addaptiveMedia\"" };
- char * cp;
-#define RTV_META_IZPOLNI_METAKEYS_SIZEOF 13 /* hkrati offset za getMedia */
-#define RTV_META_IZPOLNI_METAKEYS_GETMEDIA_FINAL \
- (RTV_META_IZPOLNI_METAKEYS_SIZEOF+3) /* zadnji+1 za getMedia */
-#define RTV_META_IZPOLNI_VALUE (odg+i+strlen(metakeys[j])+2)
-#define RTV_META_IZPOLNI_VALUE_INTERNAL RTV_META_IZPOLNI_VALUE
+ RTV_JSON_INIT();
snprintf(m->get_meta_url, RTV_API_META_URL_SIZEOF, RTV_API_META_URL, m->id);
snprintf(m->predvajalnik_url, RTV_PREDVAJALNIK_URL_SIZEOF, RTV_PREDVAJALNIK_URL, m->id);
odgstream = open_memstream(&odg, &sizeloc);
returnstatus = http_get(m->get_meta_url, odgstream); /* shranimo metapodat. */
- if (returnstatus != 0) {
- RTV_NAPISI(NAPAKA, "Zahteva za metapodatke iz API strežnika je spodletela");
+ if (!RTV_HTTP_SUCCESS(returnstatus)) {
+ RTV_NAPISI(NAPAKA, "API zahteva je spodletela s kodo %d", returnstatus);
goto rtv_meta_izpolni_returncleanly;
- }
+ } else returnstatus = 0;
fflush(odgstream);
- for (i = 0; i < sizeloc; i++) {
- for (j = 0; j < RTV_META_IZPOLNI_METAKEYS_SIZEOF; j++) {
- if (strncmp(odg+i, metakeys[j], strlen(metakeys[j])) == 0) {
- switch (j) {
- case 0: /* title */
-#define strtollu strtoull
-#define strtolu strtoul
-#define strtolld strtoll
-#define strtold strtol
-#define strtod strtol
-#define strtou strtoul
-#define RTV_META_IZPOLNI_V(imem, format, tip) /* za variabilne nize */ \
- cp[0] = '\0'; /* omejimo json string, ne potrebujemo strncpy */ \
- m->imem = realloc(m->imem, sizeof(tip) * \
- strlen(RTV_META_IZPOLNI_VALUE_INTERNAL)+1); \
- m->imem##_sizeof = strlen(RTV_META_IZPOLNI_VALUE_INTERNAL)+1; \
- strcpy(m->imem, RTV_META_IZPOLNI_VALUE_INTERNAL);
-#define RTV_META_IZPOLNI_I(imem, format, tip) /* za številke */ \
- m->imem = strto##format(RTV_META_IZPOLNI_VALUE_INTERNAL, NULL, 10);
-#define RTV_META_IZPOLNI(imem, oblika, format, splitter, tip) \
- do { cp = strchr(RTV_META_IZPOLNI_VALUE_INTERNAL, splitter); \
- if (cp == NULL) { \
- RTV_NAPISI(OPOZORILO, "Napaka pri iskanju podatka " #imem); \
- /* strcpy(m->imem, "Napaka pri pridobivanju."); */ /* ni vse s*/ \
- } else { \
- oblika(imem, format, tip) \
- RTV_NAPISI(HROSC, "Shranil metapodatek " #imem ": %" #format, \
- m->imem); \
- } } while (0)
-/* #pragma GCC diagnostic ignored "-Wint-conversion" */ /* surpressaš opozor. */
- RTV_META_IZPOLNI(naslov, RTV_META_IZPOLNI_V, s, '"', char);
- break;
- case 1: /* showId */
- RTV_META_IZPOLNI(tip_oddaje_id, RTV_META_IZPOLNI_I, u, '"', unsigned int);
- break;
- case 2: /* genre je "asdasd","asdasd","sdfsfd" */
- RTV_META_IZPOLNI(zanri, RTV_META_IZPOLNI_V, s, ']', char);
- memmove(m->zanri, (m->zanri)+1, strlen(m->zanri)+1);
- break;
- case 3: /* description */
- RTV_META_IZPOLNI(opis, RTV_META_IZPOLNI_V, s, '"', char);
- break;
- case 4: /* showDescription */
- if (m->opis[0] == '\0') { /* če je prejšnji spodletel */
- RTV_META_IZPOLNI(opis, RTV_META_IZPOLNI_V, s, '"', char);
- }
- break;
- case 5: /* duration */
-#undef RTV_META_IZPOLNI_VALUE_INTERNAL
-#define RTV_META_IZPOLNI_VALUE_INTERNAL RTV_META_IZPOLNI_VALUE-1
- RTV_META_IZPOLNI(dolzina, RTV_META_IZPOLNI_I, u, '"', unsigned int);
-#undef RTV_META_IZPOLNI_VALUE_INTERNAL
-#define RTV_META_IZPOLNI_VALUE_INTERNAL RTV_META_IZPOLNI_VALUE
- break;
- case 6: /* jwt */
- RTV_META_IZPOLNI(jwt, RTV_META_IZPOLNI_V, s, '"', char);
- if (RTV_JWT_SIZEOF != m->jwt_sizeof) {
- RTV_NAPISI(OPOZORILO, "Shranil nepričakovano dolg JWT! Je vdor?");
- }
- break;
- case 7: /* showName */
- RTV_META_IZPOLNI(tip_oddaje_ime, RTV_META_IZPOLNI_V, s, '"', char);
- break;
- case 8: /* source */
- RTV_META_IZPOLNI(program, RTV_META_IZPOLNI_V, s, '"', char);
- break;
- case 9: /* publishDate */
- RTV_META_IZPOLNI(objavljeno, RTV_META_IZPOLNI_V, s, '"', char);
- break;
- case 10: /* mediaType */
- switch (RTV_META_IZPOLNI_VALUE[0]) {
- case 'v':
- m->tip_posnetka = RTV_VIDEO_TIP;
- break;
- case 'a':
- m->tip_posnetka = RTV_AUDIO_TIP;
- break;
- default:
- m->tip_posnetka = RTV_NEPOZNAN_TIP;
- break;
- }
- break;
- case 11: /* orig */ /* sličica */
- RTV_META_IZPOLNI(slicica, RTV_META_IZPOLNI_V, s, '"', char);
- break;
- case 12: /* broadcastDate */
- RTV_META_IZPOLNI(predvajano, RTV_META_IZPOLNI_V, s, '"', char);
- break;
-/* #pragma GCC diagnostic warning "-Wint-conversion" */ /* undo */
- default:
- RTV_NAPISI(OPOZORILO, "Doseg nedefinirane kode!");
- }
- }
+ RTV_JSON(odg, sizeloc, "\"title\"", m->naslov, s, '"', NULL);
+ /* pri številkah je vseeno, kaj je spl */
+ RTV_JSON(odg, sizeloc, "\"showId\"", m->tip_oddaje_id, u, '"', NULL);
+ RTV_JSON(odg, sizeloc, "\"genre\"", m->zanri, s, ']', NULL);
+ memmove(m->zanri, (m->zanri)+1, strlen(m->zanri)+1);
+ RTV_JSON(odg, sizeloc, "\"description\"", m->opis, s, '"', NULL);
+ if (m->opis[0] == '\0') /* če je prejšnji spodletel */
+ RTV_JSON(odg, sizeloc, "\"showDescription\"", m->opis, s, '"', NULL);
+ RTV_JSON(odg, sizeloc, "\"duration\"", m->dolzina, u, '"', NULL);
+ RTV_JSON(odg, sizeloc, "\"jwt\"", m->jwt, s, '"', NULL);
+ if (RTV_JWT_SIZEOF != m->jwt_sizeof)
+ RTV_NAPISI(OPOZORILO, "Shranil nepričakovano dolg JWT! Je vdor?");
+ RTV_JSON(odg, sizeloc, "\"showName\"", m->tip_oddaje_ime, s, '"', NULL);
+ RTV_JSON(odg, sizeloc, "\"source\"", m->program, s, '"', NULL);
+ RTV_JSON(odg, sizeloc, "\"publishDate\"", m->objavljeno, s, '"', NULL);
+ /* uporabimo kar m->slicica za začasno shrambo mediaType (: */
+ RTV_JSON(odg, sizeloc, "\"mediaType\"", m->slicica, s, '"', NULL);
+ switch (m->slicica[0]) {
+ case 'v':
+ m->tip_posnetka = RTV_VIDEO_TIP;
+ break;
+ case 'a':
+ m->tip_posnetka = RTV_AUDIO_TIP;
+ break;
+ default:
+ m->tip_posnetka = RTV_NEPOZNAN_TIP;
+ break;
}
+ /* sedaj pa m->slicica napolnimo s pravilnim tekstom */
+ RTV_JSON(odg, sizeloc, "\"orig\"", m->slicica, s, '"', NULL);
+ RTV_JSON(odg, sizeloc, "\"broadcastDate\"", m->predvajano, s, '"', NULL);
+ m->podnapisi_url[0] = '\0';
+ RTV_JSON(odg, sizeloc, "\"file\"", m->podnapisi_url, s, '"', NULL);
+ if (m->podnapisi_url[0] != '\0') {
+ RTV_HTTPS_V_HTTP(m->podnapisi_url);
}
snprintf(m->get_media_url, RTV_API_MEDIA_URL_SIZEOF, RTV_API_MEDIA_URL, m->id, m->jwt);
rewind(odgstream);
fflush(odgstream);
returnstatus = http_get(m->get_media_url, odgstream); /* shranimo video url */
- if (returnstatus != 0) {
+ if (!RTV_HTTP_SUCCESS(returnstatus)) {
RTV_NAPISI(NAPAKA, "Zahteva za ključ videa iz API strežnika je spodletela");
goto rtv_meta_izpolni_returncleanly;
- }
+ } else returnstatus = 0;
fflush(odgstream);
/*
* sedaj pridobimo direktni URL do mp4 datoteke, ki ima keylockhash v GET
@@ -373,45 +410,25 @@ int rtv_meta_izpolni(struct meta_oddaja * m) {
* bo ta vedno največji, če pa obstaja samo en stream, pa addaptiveMedia
* podobjekta sploh ne bo. torej, če se je string addaptiveMedia pojavil
* tik pred tem URLjem, bo ta najboljši in lahko nehamo. */
- for (i = 0; i < ftell(odgstream); i++) {
- for (j = RTV_META_IZPOLNI_METAKEYS_SIZEOF;
- j < RTV_META_IZPOLNI_METAKEYS_GETMEDIA_FINAL; j++) {
- if (strncmp(odg+i, metakeys[j], strlen(metakeys[j])) == 0) {
- switch (j-RTV_META_IZPOLNI_METAKEYS_SIZEOF) {
- case 0: /* http */ /* videofile */
- RTV_META_IZPOLNI(posnetek_url, RTV_META_IZPOLNI_V, s, '"', char);
- if (nasel_addaptivemedia == 1) {
- RTV_NAPISI(HROSC, "Izmed več streamov izbral najboljšega.");
- goto rtv_meta_izpolni_naselnajboljsistream;
- }
- nasel_addaptivemedia = 0;
- break;
- case 1: /* https */
- if (m->posnetek_url[0] == '\0') {
- RTV_META_IZPOLNI(posnetek_url, RTV_META_IZPOLNI_V, s, '"',
- char);
- fprintf(stderr, "test: %s\n", m->posnetek_url);
- memmove((m->posnetek_url)+4, (m->posnetek_url)+5,
- strlen((m->posnetek_url)+5)+1);
- RTV_NAPISI(HROSC, "Popravil HTTPS URL na HTTP");
- if (nasel_addaptivemedia == 1) {
- RTV_NAPISI(HROSC, "Izmed več streamov izbral najboljšega.");
- goto rtv_meta_izpolni_naselnajboljsistream;
- }
- }
- nasel_addaptivemedia = 0;
- break;
- case 2: /* addaptiveMedia */
- nasel_addaptivemedia = 1;
- RTV_NAPISI(HROSC, "Naslednji najden pretok bo najboljši.");
- break;
- default:
- RTV_NAPISI(OPOZORILO, "Doseg nedefinirane kode; case=%lu",
- j-RTV_META_IZPOLNI_METAKEYS_SIZEOF);
- }
- }
- }
- } /* endfor: for (i = 0; i < ftell(odgstream); i++) */
+ m->posnetek_url[0] = '\0';
+ RTV_JSON(odg, sizeloc, "\"http\"", m->posnetek_url, s, '"',
+ "addaptiveMedia");
+ if (m->posnetek_url[0] != '\0')
+ goto rtv_meta_izpolni_naselnajboljsistream;
+ RTV_JSON(odg, sizeloc, "\"https\"", m->posnetek_url, s, '"',
+ "addaptiveMedia");
+ if (m->posnetek_url[0] != '\0') {
+ RTV_HTTPS_V_HTTP(m->posnetek_url);
+ goto rtv_meta_izpolni_naselnajboljsistream;
+ }
+ RTV_JSON(odg, sizeloc, "\"http\"", m->posnetek_url, s, '"', NULL);
+ if (m->posnetek_url[0] != '\0')
+ goto rtv_meta_izpolni_naselnajboljsistream;
+ RTV_JSON(odg, sizeloc, "\"https\"", m->posnetek_url, s, '"', NULL);
+ if (m->posnetek_url[0] != '\0') {
+ RTV_HTTPS_V_HTTP(m->posnetek_url);
+ goto rtv_meta_izpolni_naselnajboljsistream;
+ }
rtv_meta_izpolni_naselnajboljsistream:
rtv_meta_izpolni_returncleanly:
@@ -419,28 +436,191 @@ int rtv_meta_izpolni(struct meta_oddaja * m) {
free(odg);
odg = NULL;
return returnstatus;
+#pragma GCC diagnostic pop
}
+int rtv_zivo_izpolni(struct rtv_zivo_meta * m) {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wnonnull"
+ int returnstatus = 0;
+ FILE * odgstream;
+ char * odg;
+ size_t sizeloc;
+ size_t i = 0;
+ char * temp = malloc(sizeof(char)*6);
+ size_t temp_sizeof = 6;
+ char * e; /* char pointer for the memes */
+ int j; /* int for the memes */
+ RTV_JSON_INIT();
+ snprintf(m->api_url, RTV_API_ZIVO_URL_SIZEOF,
+ RTV_API_ZIVO_URL, m->program);
+ odgstream = open_memstream(&odg, &sizeloc);
+ returnstatus = http_get(m->api_url, odgstream);
+ if (!RTV_HTTP_SUCCESS(returnstatus)) {
+ RTV_NAPISI(NAPAKA, "Napaka %d pri zahtevi na API strežnik.", returnstatus);
+ returnstatus = 1;
+ goto rtv_zivo_izpolni_returncleanly;
+ } else returnstatus = 0;
+ fflush(odgstream);
+ RTV_JSON(odg, sizeloc, "\"streamer\"", m->seznam_predvajanja_url, s, '"',
+ NULL);
+ RTV_HTTPS_V_HTTP(m->seznam_predvajanja_url);
+ RTV_JSON(odg, sizeloc, "\"streamer\"", m->kazalo_url, s, '"', NULL);
+ RTV_JSON(odg, sizeloc, "\"streamer\"", m->kos_format, s, '"', NULL);
+ m->kazalo_url[strlen(m->kazalo_url)] = '/'; /* ja, allocata se dodaten ram */
+ m->kos_format[strlen(m->kos_format)] = '/'; /* ja, allocata se dodaten ram */
+ RTV_HTTPS_V_HTTP(m->kazalo_url);
+ RTV_JSON(odg, sizeloc, "\"file\"", temp, s, '"', NULL);
+ m->seznam_predvajanja_url_sizeof =
+ strlen(m->seznam_predvajanja_url)+strlen(temp)+1;
+ m->seznam_predvajanja_url = realloc(m->seznam_predvajanja_url,
+ sizeof(char) * m->seznam_predvajanja_url_sizeof);
+ strcat(m->seznam_predvajanja_url, temp); /* ja, je varno */
+ /* če obstaja ?DVR na koncu, bo vsebina gzipana, to nas samo moti */
+ strchrnul(m->seznam_predvajanja_url, '?')[0] = '\0'; /* odstrani parametre */
+ RTV_HTTPS_V_HTTP(m->seznam_predvajanja_url);
+ rewind(odgstream);
+ http_get(m->seznam_predvajanja_url, odgstream);
+ for (i = 0; i < ftell(odgstream); i++) {
+ if (odg[i] == '\n' && odg[i+1] != '#') {
+ e = strchr(odg+i+1, '\r');
+ if (strchr(odg+i+1, '\n') > e) /* 1080p je najvišja resolucija => */
+ e = strchr(odg+i+1, '\n'); /* prvo kazalo je najvišja resolucija */
+ if (e != NULL) {
+ j = e[0];
+ e[0] = '\0';
+ }
+ m->kazalo_url_sizeof = strlen(m->kazalo_url)+strlen(odg+i+1)+1;
+ m->kazalo_url = realloc(m->kazalo_url, sizeof(char)*m->kazalo_url_sizeof);
+ strcat(m->kazalo_url, odg+i+1); /* ja, je varno /\ */
+ if (e != NULL)
+ e[0] = j; /* popravimo nazaj */
+ break; /* spet, potrebujemo samo prvi t. i. "chunklist". */
+ }
+ }
+ RTV_NAPISI(HROSC, "kazalo_url => %s", m->kazalo_url);
+ rewind(odgstream);
+ returnstatus = http_get(m->kazalo_url, odgstream);
+ if (!RTV_HTTP_SUCCESS(returnstatus)) {
+ RTV_NAPISI(NAPAKA, "Napaka %d pri zahtevi na API strežnik.", returnstatus);
+ returnstatus = 1;
+ goto rtv_zivo_izpolni_returncleanly;
+ } else returnstatus = 0;
+ e = strstr(odg, "#EXT-X-TARGETDURATION:");
+ if (e != NULL) {
+ m->dolzina = atoi(e+strlen("#EXT-X-TARGETDURATION:"));
+ RTV_NAPISI(HROSC, "(v prvo) dolžina kosa je %u sekund", m->dolzina);
+ } else {
+ e = strstr(odg, "#EXTINF:");
+ if (e != NULL) {
+ m->dolzina = atoi(e+strlen("#EXTINF:"));
+ RTV_NAPISI(HROSC, "(v drugo) dolžina kosa je %u sekund", m->dolzina)
+ } else {
+ m->dolzina = RTV_ZIVO_P_DOLZINA;
+ RTV_NAPISI(OPOZORILO, "nisem našel dolžine kosa-uporabim %u", m->dolzina);
+ }
+ }
+ e = strstr(odg, "#EXT-X-MEDIA-SEQUENCE:");
+ if (e != NULL) {
+ m->prvi = atoi(e+strlen("#EXT-X-MEDIA-SEQUENCE:")); /* prvi v kazalu */
+ RTV_NAPISI(HROSC, "našel sekvenčno številko %u", m->prvi);
+ } else {
+ RTV_NAPISI(NAPAKA, "pri iskanju MEDIA-SEQUENCE: ne morem narediti formata"
+ ". poskusite znova nekajkrat. je RTV strežnik spet GZIPpal? :shrug:");
+ returnstatus = 2;
+ goto rtv_zivo_izpolni_returncleanly;
+ }
+ m->sedanjost = -69420;
+ m->prenesenih_kosov_preteklost = 0;
+ m->prenesenih_kosov_prihodnost = 0;
+ for (i = 0; i < ftell(odgstream); i++) {
+ if (odg[i+1] != '#' && odg[i] == '\n') {
+ e = strchr(odg+i+1, '\r');
+ if (strchr(odg+i+1, '\n') > e)
+ e = strchr(odg+i+1, '\n');
+ j = -69420;
+ if (e != NULL) {
+ j = e[0];
+ e[0] = '\0';
+ }
+ snprintf(temp, temp_sizeof, "%u", m->prvi);
+ e = strstr(odg+i+1, temp);
+ if (e != NULL) {
+ m->kos_format_sizeof = ((strchr(odg+i+1, '\n')
+ ?(odg+i+1)-strchr(odg+i+1, '\n'):strlen(odg+i+1))+1+RTV_P_SIZEOF
+ )*sizeof(char);
+ m->kos_format = realloc(m->kos_format, m->kos_format_sizeof);
+ strncat(m->kos_format, odg+i+1, m->kos_format_sizeof/sizeof(char));
+ if (strchr(m->kos_format, '\r')) strchr(m->kos_format, '\r')[0] = '\0';
+ if (strchr(m->kos_format, '\n')) strchr(m->kos_format, '\n')[0] = '\0';
+ e = strstr(m->kos_format, temp);
+ memmove(e+2, e+strlen(temp), strlen(temp)+1); /* naredimo prostor 2 */
+ e[0] = '%'; e[1] = 'u'; /* napišemo format v prostorček */
+ RTV_HTTPS_V_HTTP(m->kos_format);
+ RTV_NAPISI(HROSC, "m->kos_format => %s", m->kos_format);
+ }
+ e = strrchr(m->kos_format+strlen("http://"), '/')+1;
+ if (strchr(m->kos_format, '%') != NULL && e != NULL) {
+ sscanf(odg+i+1, e, &(m->sedanjost));
+ }
+ if (j != -69420)
+ *(odg+i+strlen(odg+i)) = j; /* popravimo */
+ }
+ }
+ if (m->sedanjost == -69420) {
+ RTV_NAPISI(NAPAKA, "ni uspelo pridobiti sedanjosti.");
+ returnstatus = 3;
+ goto rtv_zivo_izpolni_returncleanly;
+ } else {
+ RTV_NAPISI(HROSC, "sedanjost je %u", m->sedanjost);
+ }
+ rtv_zivo_izpolni_returncleanly:
+ RTV_FREE(temp);
+ fclose(odgstream);
+ free(odg);
+ odg = NULL;
+ return returnstatus;
+#pragma GCC diagnostic pop
+}
+
int main (int argc, char ** argv) {
if (argc < 1+1) {
- fprintf(stderr, "preberi README.md pred uporabo programa, saj vsebuje navodila in ostalo.\n");
+ fprintf(stderr, "preberi README.md pred uporabo programa, saj vsebuje"
+ "navodila in ostalo.\n");
return 1;
}
struct meta_oddaja * m = meta_oddaja_alloc();
- char fn[69]; /* <id>.txt / <id>.mp4 - NE USER INPUT */
+ struct rtv_zivo_meta * z = rtv_zivo_meta_alloc();
+ char fn[420]; /* <id>.txt / <id>.mp4 - NE USER INPUT */
char * e; /* char pointer for the memes */
FILE * fd;
+ unsigned int i;
+ DIR * dir;
unsigned short int returnstatus = 0;
- if (RTV_URL != NULL) {
- m->id = atoi(RTV_URL);
- if (strrchr(RTV_URL, '/') != NULL)
- m->id = atoi(strrchr(RTV_URL, '/')+1);
- if (m->id <= 0) {
- fprintf(stderr, "IDja oddaje ni uspelo dobiti. preverite vnos.\n");
- returnstatus = 3;
- goto returncleanly;
- }
- } else {
- m->id = RTV_TEST_ID;
+ switch (RTV_NACIN[0]) {
+ case 'O': /* za vse, kar potrebuje ID oddaje, nastavimo ID oddaje */
+ case 'o':
+ case 'M':
+ case 'm':
+ case 'T':
+ case 't':
+ case 'p':
+ case 'P':
+ case 's':
+ case 'S':
+ RTV_NAPISI(HROSC, "Ta način potrebuje ID oddaje, sedaj ga nastavljam.");
+ if (RTV_URL != NULL) {
+ m->id = atoi(RTV_URL);
+ if (strrchr(RTV_URL, '/') != NULL)
+ m->id = atoi(strrchr(RTV_URL, '/')+1);
+ if (m->id <= 0) {
+ fprintf(stderr, "IDja oddaje ni uspelo dobiti. preverite vnos.\n");
+ returnstatus = 3;
+ goto returncleanly;
+ }
+ } else {
+ m->id = RTV_TEST_ID;
+ }
+ break;
}
switch (RTV_NACIN[0]) {
case 'T':
@@ -466,9 +646,11 @@ int main (int argc, char ** argv) {
returnstatus = 5;
goto returncleanly;
}
- if (http_get(m->posnetek_url, fd) == 0) {
+ if (RTV_HTTP_SUCCESS(http_get(m->posnetek_url, fd))) {
+ fclose(fd);
RTV_NAPISI(INFO, "uspešno shranjeno.");
} else {
+ fclose(fd);
RTV_NAPISI(NAPAKA, "Nekaj je spodletelo pri http_get()");
returnstatus = 6;
}
@@ -496,13 +678,14 @@ int main (int argc, char ** argv) {
"dolzina: %u\njwt: %s\ntip_oddaje_ime: %s\nprogram: %s\n"
"objavljeno: %s\ntip_posnetka: %s\nslicica: %s\npredvajano: %s\n"
/* "velikost: %llu\n" */ "get_meta_url: %s\nget_media_url: %s\n"
- "predvajalnik_url: %s\nposnetek_url: %s\n", m->id, m->naslov,
- m->tip_oddaje_id, m->zanri, m->opis, m->dolzina, m->jwt,
- m->tip_oddaje_ime, m->program, m->objavljeno,
+ "predvajalnik_url: %s\nposnetek_url: %s\npodnapisi_url: %s\n",
+ m->id, m->naslov, m->tip_oddaje_id, m->zanri, m->opis, m->dolzina,
+ m->jwt, m->tip_oddaje_ime, m->program, m->objavljeno,
m->tip_posnetka == RTV_VIDEO_TIP ? "RTV_VIDEO_TIP" : \
m->tip_posnetka == RTV_AUDIO_TIP ? "RTV_AUDIO_TIP":"RTV_NEPOZNAN_TIP",
m->slicica, m->predvajano, /* m->velikost, */ m->get_meta_url,
- m->get_media_url, m->predvajalnik_url, m->posnetek_url);
+ m->get_media_url, m->predvajalnik_url, m->posnetek_url,
+ m->podnapisi_url);
fclose(fd);
break;
case 's': /* sličica - prenese sličico oddaje */
@@ -524,26 +707,103 @@ int main (int argc, char ** argv) {
returnstatus = 5;
goto returncleanly;
}
- if (http_get(m->slicica, fd) == 0) {
+ if (RTV_HTTP_SUCCESS(http_get(m->slicica, fd))) {
+ fclose(fd);
RTV_NAPISI(INFO, "uspešno shranjeno.");
} else {
+ fclose(fd);
+ RTV_NAPISI(NAPAKA, "Nekaj je spodletelo pri http_get()");
+ returnstatus = 6;
+ }
+ break;
+ case 'p': /* podnapisi */ /* F za Gašperja Tiča, voditelja otroške oddaje */
+ case 'P': /* Iz popotne torbe, ki je uporabljena kot primer v README.md */
+ if (rtv_meta_izpolni(m) != 0) {
+ RTV_NAPISI(NAPAKA, "Ni uspelo pridobiti metapodatkov oddaje.");
+ returnstatus = 4;
+ goto returncleanly;
+ }
+ if (argc < 4) {
+ e = strrchr(m->podnapisi_url, '.');
+ snprintf(fn, sizeof(fn), "%u%s", m->id, e);
+ fd = fopen(fn, "w");
+ } else {
+ fd = fopen(argv[3], "w");
+ }
+ if (fd == NULL) {
+ RTV_NAPISI(NAPAKA, "Ni uspelo odpreti datoteke za pisanje vanjo.");
+ returnstatus = 5;
+ goto returncleanly;
+ }
+ if (RTV_HTTP_SUCCESS(http_get(m->podnapisi_url, fd))) {
+ fclose(fd);
+ RTV_NAPISI(INFO, "uspešno shranjeno.");
+ } else {
+ fclose(fd);
RTV_NAPISI(NAPAKA, "Nekaj je spodletelo pri http_get()");
returnstatus = 6;
}
break;
case 'z': /* zivo */
case 'Z':
- case 0xC5: /* živo / Živo, ž = 0xc5be, Ž = 0xc5bd, tudi šivo dela! */
- RTV_NAPISI(NAPAKA, "pretakanje v živo še ni izdelano!");
+ case RTV_ZCARON: /* živo / Živo, ž = 0xc5be, Ž = 0xc5bd, tudi šivo dela! */
+ if (argc <= 2) {
+ strcpy(z->program, "slo1");
+ } else {
+ strncpy(z->program, RTV_URL, RTV_ZIVO_PROGRAM_SIZEOF);
+ }
+ z->preteklost = argc > 4 ? atoi(argv[4]) : 9999999;
+ z->prihodnost = argc > 5 ? atoi(argv[5]) : 9999999;
+ e = argc > 3 ? argv[3] : z->program; /* dirEktorij */
+ dir = opendir(e);
+ if (dir) {
+ closedir(dir); /* direktorij obstaja, hvala */
+ } else if (errno == ENOENT) {
+ if (mkdir(e, 0755) != 0) {
+ RTV_NAPISI(NAPAKA, "med izdelavo direktorija: %s", strerror(errno));
+ }
+ } else {
+ RTV_NAPISI(NAPAKA, "med iskanjem direktorija: %s",
+ strerror(errno));
+ returnstatus = 5;
+ goto returncleanly;
+ }
+ if (rtv_zivo_izpolni(z) != 0) {
+ RTV_NAPISI(NAPAKA, "Ni uspelo pridobiti metapodatkov pretoka.");
+ returnstatus = 4;
+ }
+ for (i = z->sedanjost; i >= 0; i--) {
+ snprintf(fn, sizeof(fn), "%s/%u%s",
+ e, i, strrchr(z->kos_format, '.')); /* printf je NULL safe */
+ fd = fopen(fn, "w");
+ snprintf(fn, sizeof(fn), z->kos_format, i);
+ if (!RTV_HTTP_SUCCESS(http_get(fn, fd))) { /* napaka je verjetno 404 */
+ i--;
+ RTV_NAPISI(INFO, "ni več kosov v preteklosti");
+ fclose(fd);
+ break;
+ }
+ RTV_NAPISI(INFO, "prenesel kos %u iz preteklosti", i);
+ fclose(fd);
+ }
+ snprintf(fn, sizeof(fn), "%s/seznam_predvajanja.m3u8", e);
+ fd = fopen(fn, "w");
+ fprintf(fd, "# generirano z rtv4d-dl " RTV_VER "\n");
+ for (i = i; i <= z->sedanjost; i++) {
+ fprintf(fd, "%u%s\n", i, strrchr(z->kos_format, '.'));
+ }
break;
default:
- fprintf(stderr, "opcija ne obstaja! poskusi test.\n");
+ RTV_NAPISI(NAPAKA, "opcija (%c/%u) ne obstaja!",
+ RTV_NACIN[0], RTV_NACIN[0]);
returnstatus = 2;
goto returncleanly;
break;
}
returncleanly:
- meta_oddaja_free(m);
- m = NULL;
+ meta_oddaja_free(m); m = NULL;
+ rtv_zivo_meta_free(z); z = NULL;
return returnstatus;
}
+/* VODILO ZA 80 znakovno omejitev - konec sledečega komentarja je 80. znak: */
+/* 4567890 (2)01234567890 (4)01234567890 (6)01234567890 */