You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1060 lines
38 KiB
1060 lines
38 KiB
#define _GNU_SOURCE |
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
#include <tcp.c> |
|
#include <dirent.h> |
|
#include <errno.h> |
|
#include <sys/stat.h> |
|
#include <sys/types.h> |
|
#include <errno.h> |
|
#include <time.h> |
|
#define NIZ_DODATEK(a) #a |
|
#define NIZ(a) NIZ_DODATEK(a) |
|
#define RTV_CLIENT_ID "82013fb3a531d5414f478747c1aca622" /* enak za vse */ |
|
#define RTV_CLIENT_ID_SIZEOF 32+1 |
|
#define RTV_VIDEO_TIP 1 |
|
#define RTV_AUDIO_TIP 2 |
|
#define RTV_NEPOZNAN_TIP 0 |
|
#define RTV_NACIN argv[1] |
|
#define RTV_URL argv[2] |
|
#define RTV_P_SIZEOF 128 /* privzeti sizeof */ |
|
#define RTV_TEST_NASLOV "Vreme ob 22h" |
|
#define RTV_TEST_ZANRI "\"INFORMATIVNE VSEBINE\"," \ |
|
"\"DNEVNO INFORMATIVNE ODDAJE\",\"Vremenska poročila\"" |
|
#define RTV_TEST_OPIS "Vreme je na sporedu vsak dan po Poročilih, pred in po" \ |
|
" Dnevniku ter po Odmevih. Napoved vremena pa vas čaka tudi vsak delavnik" \ |
|
" zjutraj v rubriki oddaje Dobro jutro. \\r\\n" |
|
#define RTV_TEST_ID 89614963 |
|
#define RTV_TEST_DOLZINA 155 |
|
#define RTV_TEST_TIP_ODDAJE_IME "Vreme" |
|
#define RTV_TEST_TIP_ODDAJE_ID 608 |
|
#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 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 |
|
#define RTV_NAPISI_NAPAKA 1 |
|
#define RTV_NAPISI_INFO 1 |
|
#define RTV_NAPISI_OPOZORILO 1 |
|
#define RTV_NAPISI_HROSC 1 |
|
#define RTV_NAPISI(kaj, frmt, ...) /* pazi na format string RCE! */ \ |
|
do { if ( RTV_NAPISI_ ##kaj ) fprintf(stderr, \ |
|
"[" #kaj "] %s@%s:" NIZ(__LINE__) " " frmt "\n", \ |
|
__func__, __FILE__, ##__VA_ARGS__ ); \ |
|
fflush(stderr); } while(0); |
|
#define RTV_VER "0.1.2" |
|
#define RTV_USER_AGENT "Mozilla/5.0 equivalent (rtv4d-dl " RTV_VER "; C " \ |
|
NIZ(__STDC_VERSION__) " GCC " __VERSION__ "; " __DATE__ " " __TIME__ "; " \ |
|
__FILE__ ":" NIZ(__LINE__) ")" |
|
#define RTV_HTTP_GET \ |
|
"GET /%s HTTP/1.0\r\nHost: %s\r\nUser-Agent: " RTV_USER_AGENT \ |
|
"\r\nAccept: */*\r\nX-Requested-With: tcp.c (" __FILE__ ":" NIZ(__LINE__) \ |
|
")\r\nConnection: close\r\n\r\n" |
|
#define RTV_HTTP_TIMEOUT 9999999 /* sekund */ |
|
#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." 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." RTV_SLD "/arhiv/v/%u" |
|
#define RTV_PREDVAJALNIK_URL_SIZEOF (32+1 + 12) |
|
#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 |
|
#define RTV_INT_V_SLO(niz) /* niz naj bo http url */ \ |
|
if (strstr(niz, "-int")) { /* je strstr-jati dvakrat potratno? */ \ |
|
strncpy(strstr(niz, "-int"), "-slo", strlen("-slo")); /* nast. pov. \/ */ \ |
|
niz[8]--; /* pri medn. je štev. ponav. za 1 večja */ /* kot mednarodno */ \ |
|
RTV_NAPISI(OPOZORILO, "izven Slovenije prenašate vsebino RTVSLO. Če ne " \ |
|
"plačujete RTV prispevka ali če za to niste pooblaščeni, KRŠITE " \ |
|
"AVTORSKE PRAVICE in STE V PREKRŠKU - v tem primeru nemudoma " \ |
|
"prenehajte uporabljati program s Ctrl-C! naslovi so bili spremenjeni, " \ |
|
"tako da bo prenos še vedno deloval, če pa ne, pa poglejte navodila."); \ |
|
} |
|
#define RTV_ZIVO_KAZ_POSK 12 |
|
#define RTV_ZIVO_KAZ_POSK_SPANJE 1 |
|
struct meta_oddaja { |
|
size_t naslov_sizeof; |
|
char * naslov; /* Vreme ob 22h */ |
|
unsigned int tip_oddaje_id; /* 608 */ |
|
size_t zanri_sizeof; |
|
char * zanri; /* INFORMATIVNE VSEBINE, DNEVNO INFORMATIVNE ODDAJE, Vrem... */ |
|
size_t opis_sizeof; |
|
char * opis; /* Vreme je na sporedu vsak dan po Poročilih, pred in po Dn... */ |
|
unsigned int id; /* 89614963 */ |
|
unsigned int dolzina; /* 155 */ |
|
size_t jwt_sizeof; /* 44 */ |
|
char * jwt; /* 1lKYcP7j8iNwqVQeQC8htsrBN47LpiHq3sm5bFlxRys */ |
|
size_t tip_oddaje_ime_sizeof; |
|
char * tip_oddaje_ime; /* Vreme */ |
|
size_t program_sizeof; |
|
char * program; /* SLO1 */ |
|
size_t objavljeno_sizeof; |
|
char * objavljeno; /* 2010-12-03 23:20:10 */ |
|
unsigned short int tip_posnetka; /* RTV_VIDEO_TIP */ |
|
size_t slicica_sizeof; |
|
char * slicica; /* http://img.rtvslo.si/_up/ava/ava_misc/show_logos/VREM... */ |
|
size_t predvajano_sizeof; |
|
char * predvajano; /* 2010-12-03 23:20:10 */ |
|
/* unsigned long long int kontrolna_vrednost; */ |
|
/* unsigned long long int velikost; */ /* število bajtov posnetka */ |
|
char get_meta_url[RTV_API_META_URL_SIZEOF]; /* http://api.rtvslo.si/ava/... */ |
|
char get_media_url[RTV_API_MEDIA_URL_SIZEOF]; /* http://api.rtvslo.si/av... */ |
|
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)); |
|
#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) { |
|
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) { |
|
*v = (*v)*2; |
|
s = realloc(s, sizeof(char)*(*v)); |
|
return 0; |
|
} |
|
int http_get (/* const */ char * u, FILE * r) { /* url ostane enak */ |
|
unsigned int p = 80; /* HTTP port ^~~~~~~~ glej man open_memstream, fmemopen*/ |
|
char * k; /* označuje konec imena gostitelja */ |
|
char t; /* začasna shramba za končni znak, ko je le-ta null */ |
|
int c = -42069; /* connection descriptor */ |
|
int ret; /* izhodni status write funkcij */ |
|
char * path; /* kaže na path requesta */ |
|
int returnstatus = 0; |
|
char * header; /* za headerje */ |
|
FILE * headerstream; |
|
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!"); |
|
return 1; |
|
} |
|
if (strncmp(u, "http://", 7) != 0) { |
|
RTV_NAPISI(NAPAKA, "URL ni podprt: %s", u); |
|
return 2; |
|
} |
|
k = strchr(RTV_URL_HOST, '/'); |
|
if (k - strchrnul(RTV_URL_HOST, ':') > 0) { /* pred pathom je PORT */ |
|
k = strchrnul(RTV_URL_HOST, ':'); |
|
p = atoi(k+1); |
|
} |
|
if (p > 65535) { /* port je nepodpisan, če gre v minus bo itak ZELO > 65535 */ |
|
RTV_NAPISI(NAPAKA, "port je neveljaven"); |
|
return 3; |
|
} |
|
if (k == NULL) |
|
k = strchrnul(RTV_URL_HOST, '/'); |
|
path = strchr(RTV_URL_HOST, '/'); |
|
if (path == NULL) { |
|
u[6] = '\0'; /* na koncu popravimo nazaj, izkoristimo ta memory xD */ |
|
path = u+5; |
|
} else { |
|
path++; |
|
} |
|
t = *k; |
|
*k = '\0'; |
|
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(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(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(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!"); |
|
goto http_get_returncleanly; |
|
} |
|
if (strncasecmp("Content-Length: ", header, strlen("Content-Length: ")) |
|
== 0) { |
|
contentlength = strtoll(header+16, NULL, 10); |
|
RTV_NAPISI(HROSC, "Pridobil %lld bajtni odgovor.", contentlength); |
|
} |
|
if (strncmp("\r\n", header, 2) == 0 || header[0] == '\n') |
|
break; |
|
} |
|
if (contentlength == -69420) { |
|
RTV_NAPISI(HROSC, "Manjka Content-Length, berem do konca."); /* legalno */ |
|
} else { |
|
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); |
|
if (ret != 0) { |
|
returnstatus = 7; |
|
RTV_NAPISI(NAPAKA, "Branje in pisanje telesa odgovora ni uspelo!"); |
|
goto http_get_returncleanly; |
|
} |
|
RTV_NAPISI(HROSC, "Prejel in uspešno shranil/prebral HTTP odgovor."); |
|
http_get_returncleanly: |
|
free(request_buf); |
|
request_buf = NULL; |
|
free(header); |
|
header = NULL; |
|
if(c != -69420 && kill_conn(c) < 0) /* kill_conn se ne izvede, če prvi ni 1.*/ |
|
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; |
|
char * c; |
|
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 (!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); |
|
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); |
|
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 (!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 |
|
* parametru. OPOMBA: treba je najti NAJKVALITETNEJŠO datoteko, ker RTVSLO |
|
* strežnik pošilja zmešan vrstni red JSON parametrov, bo treba najti drug |
|
* način. ugotovil sem, da, če je stream v addaptiveMedia JSON podobjektu, |
|
* 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. */ |
|
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; |
|
} |
|
/* očitno še nismo našli ustreznega naslova, poskusimo hardcore */ |
|
RTV_NAPISI(INFO, "nisem našel direktnega mp4 URLja, poskušam HLS."); |
|
RTV_JSON(odg, sizeloc, "\"hls\"", m->posnetek_url, s, '"', |
|
"addaptiveMedia"); /* addaptiveMedia je fuckery m3u8 fajlov */ |
|
if (m->posnetek_url[0] == '\0') { |
|
RTV_NAPISI(NAPAKA, "ni uspelo pridobiti HLS URLja."); |
|
returnstatus = 1; |
|
goto rtv_meta_izpolni_returncleanly; |
|
} |
|
/* na mojo srečo je tukaj sicer najboljši stream vedno prvi */ |
|
rewind(odgstream); |
|
fflush(odgstream); |
|
returnstatus = http_get(m->posnetek_url, odgstream); |
|
if (!RTV_HTTP_SUCCESS(returnstatus)) { |
|
RTV_NAPISI(NAPAKA, "zahteva za HLS naslov je spodletela."); |
|
goto rtv_meta_izpolni_returncleanly; |
|
} else returnstatus = 0; |
|
fflush(odgstream); |
|
for (i = 0; i < sizeloc && odg[i] != '\0'; i++) { |
|
if ((i == 0 && odg[i] != '#') |
|
|| (i != 0 && odg[i-1] == '\n' && odg[i] != '#')) { |
|
c = strrchr(m->posnetek_url, '/'); |
|
if (c == NULL) { |
|
RTV_NAPISI(NAPAKA, "napaka na tej vrstici, kontaktiraj razvijalce"); |
|
returnstatus = 1; |
|
goto rtv_meta_izpolni_returncleanly; |
|
} |
|
if (m->posnetek_url_sizeof-1 < /* če ni dovolj prostora */ |
|
((c+(strchrnul(odg+i, '\n')-(odg+i)))-m->posnetek_url)) { |
|
m->posnetek_url_sizeof = |
|
((c+(strchrnul(odg+i, '\n')-(odg+i)))-m->posnetek_url) + 25; |
|
m->posnetek_url = realloc(m->posnetek_url, m->posnetek_url_sizeof); |
|
} |
|
strncpy(c+1, odg+i, strchrnul(odg+i, '\n')-(odg+i)); |
|
break; |
|
} |
|
} |
|
rtv_meta_izpolni_naselnajboljsistream: |
|
rtv_meta_izpolni_returncleanly: |
|
fclose(odgstream); |
|
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" |
|
#pragma GCC diagnostic ignored "-Wstringop-truncation" /* za RTV_INT_V_SLO(u) */ |
|
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(); |
|
m->kazalo_url[0] = '\0'; |
|
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); |
|
i = strlen(m->kazalo_url); |
|
m->kazalo_url[i++] = '/'; /* ja, allocata se dodaten ram */ |
|
m->kazalo_url[i] = '\0'; |
|
i = strlen(m->kos_format); |
|
m->kos_format[i++] = '/'; /* ja, allocata se dodaten ram */ |
|
m->kos_format[i] = '\0'; |
|
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); |
|
#ifndef RTV_NASTAVITEV_BREZ_LOKACIJSKIH_SPREMEMB |
|
RTV_INT_V_SLO(m->seznam_predvajanja_url); |
|
#endif |
|
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". */ |
|
} |
|
} |
|
#ifndef RTV_NASTAVITEV_BREZ_LOKACIJSKIH_SPREMEMB |
|
RTV_INT_V_SLO(m->kazalo_url); |
|
#endif |
|
e = strstr(m->kazalo_url, "_DVR"); |
|
if (e != NULL) { |
|
memmove(e, e+strlen("_DVR"), strlen(e+strlen("_DVR"))+1); |
|
RTV_NAPISI(HROSC, "RTV je poslal DVR, čeprav ga nočemo. popravil sem."); |
|
} |
|
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"); |
|
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); |
|
#ifndef RTV_NASTAVITEV_BREZ_LOKACIJSKIH_SPREMEMB |
|
RTV_INT_V_SLO(m->kos_format); |
|
#endif |
|
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 rtv_prenesi_hls (char * url, char * datotecna_predpona) { |
|
int returnstatus; |
|
DIR * dir; |
|
size_t max_kos_fn = strlen("seznam_predvajanja.m3u8"); |
|
char * fn=malloc(sizeof(char)*(strlen(datotecna_predpona)+2+max_kos_fn)); |
|
char * odg; |
|
size_t sizeloc; |
|
FILE * odgstream = open_memstream(&odg, &sizeloc); |
|
size_t kosov = 0; |
|
size_t i = 0; |
|
size_t ti = 0; /* temp in temp intt */ |
|
char ** k /* kosi */ = malloc(sizeof(char *)*1); |
|
FILE * fd = NULL; |
|
FILE * fd2 = NULL; |
|
char * c; |
|
returnstatus = http_get(url, odgstream); /* shranimo m3u8 */ |
|
if (!RTV_HTTP_SUCCESS(returnstatus)) { |
|
RTV_NAPISI(NAPAKA, "ni uspelo prenesti HLS datoteke"); |
|
returnstatus = 1; |
|
goto returncleanly; |
|
} else returnstatus = 0; |
|
fflush(odgstream); |
|
dir = opendir(datotecna_predpona); |
|
if (dir) { |
|
closedir(dir); /* direktorij obstaja, hvala */ |
|
} else if (errno == ENOENT) { |
|
if (mkdir(datotecna_predpona, 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; |
|
} |
|
for (i = 0; i <= sizeloc && odg[i] != '\0'; i++) { |
|
if (odg[i] == '\n') |
|
odg[i] = '\0'; |
|
if ((i == 0 && odg[i] != '#') |
|
|| (i != 0 && odg[i-1] == '\0' /* == '\n' */ && odg[i] != '#')) { |
|
k = realloc(k, sizeof(char *)*i+2); |
|
k[kosov++] = odg+i; |
|
ti = strlen(odg+i); |
|
if (ti > max_kos_fn) |
|
max_kos_fn = ti; |
|
} |
|
} |
|
sprintf(fn, "%s/seznam_predvajanja.m3u8", datotecna_predpona); |
|
fd2 = fopen(fn, "w"); |
|
fprintf(fd2, "# generiral rtv4d-dl\n"); |
|
fn=realloc(fn,sizeof(char)*(strlen(datotecna_predpona)+1+1+max_kos_fn |
|
+strlen(url))); |
|
for (i = 0; i < kosov; i++) { |
|
c = strchrnul(k[i], '?'); |
|
c[0] = '\0'; |
|
sprintf(fn, "%s/%05lu%s", datotecna_predpona, i, strchrnul(k[i], '.')); |
|
fprintf(fd2, "%05lu%s\n", i, strchrnul(k[i], '.')); |
|
if (c != NULL) |
|
c[0] = '?'; |
|
RTV_NAPISI(HROSC, "prenašam %lu. kos oddaje od %lu v datoteko %s", |
|
i+1, kosov, fn); |
|
fd = fopen(fn, "w"); |
|
strcpy(fn, url); |
|
strcpy(strrchr(fn, '/')+1, k[i]); /* c'mon, url mora imeti / */ |
|
returnstatus = http_get(fn, fd); /* shranimo ts */ |
|
if (!RTV_HTTP_SUCCESS(returnstatus)) { |
|
RTV_NAPISI(NAPAKA, "ni uspelo prenesti TS datoteke"); |
|
returnstatus = 1; |
|
goto returncleanly; |
|
} else returnstatus = 0; |
|
fclose(fd); |
|
} |
|
fflush(fd2); |
|
fclose(fd2); |
|
returncleanly: |
|
fclose(odgstream); |
|
free(odg); |
|
odg = NULL; |
|
return returnstatus; |
|
} |
|
int main (int argc, char ** argv) { |
|
if (argc < 1+1) { |
|
fprintf(stderr, "preberi README.md pred uporabo programa, saj vsebuje " |
|
"navodila in ostalo.\n"); |
|
return 1; |
|
} |
|
struct meta_oddaja * m = meta_oddaja_alloc(); |
|
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; |
|
FILE * fd2; |
|
unsigned int i = 0; |
|
time_t * casi = NULL; |
|
time_t cas; |
|
DIR * dir; |
|
unsigned short int returnstatus = 0; |
|
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': |
|
case 't': /* test - program se preizkusi brez prenosa datotek */ |
|
RTV_NAPISI(NAPAKA, "samotestiranje še ni izdelano!"); |
|
break; |
|
case 'O': |
|
case 'o': /* oddaja - prenese oddajo v datoteko */ |
|
if (rtv_meta_izpolni(m) != 0) { |
|
RTV_NAPISI(NAPAKA, "Ni uspelo pridobiti metapodatkov oddaje."); |
|
returnstatus = 4; |
|
goto returncleanly; |
|
} |
|
if (strstr(m->posnetek_url, ".m3u8") != NULL) { |
|
if (argc < 4) |
|
snprintf(fn, 68, "%u", m->id); |
|
else |
|
strncpy(fn, argv[3], 419); |
|
e = strrchr(fn, '.'); |
|
if (e != NULL) |
|
e[0] = '\0'; |
|
if (rtv_prenesi_hls(m->posnetek_url, fn) != 0) |
|
RTV_NAPISI(NAPAKA, "nisem uspel narediti HLS prenosa."); |
|
RTV_NAPISI(INFO, "uspešno prenesel oddajo v mapo po kosih."); |
|
} else { |
|
if (argc < 4) { |
|
e = strrchr(m->posnetek_url, '.'); |
|
snprintf(fn, 68, "%u%.4s", 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->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; |
|
} |
|
} |
|
break; |
|
case 'M': |
|
case 'm': /* meta-oddaja - prenese metapodatke o oddaji */ |
|
if (rtv_meta_izpolni(m) != 0) { |
|
RTV_NAPISI(NAPAKA, "Ni uspelo pridobiti metapodatkov oddaje."); |
|
returnstatus = 4; |
|
goto returncleanly; |
|
} |
|
if (argc < 4) { |
|
/* e = strrchr(m->posnetek_url, '.'); */ |
|
snprintf(fn, 68, "%u%s", m->id, ".txt"); |
|
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; |
|
} |
|
fprintf(fd, "id: %u\nnaslov: %s\ntip_oddaje_id: %u\nzanri: %s\nopis: %s\n" |
|
"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\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->podnapisi_url); |
|
fclose(fd); |
|
break; |
|
case 's': /* sličica - prenese sličico oddaje */ |
|
case 'S': |
|
if (rtv_meta_izpolni(m) != 0) { |
|
RTV_NAPISI(NAPAKA, "Ni uspelo pridobiti metapodatkov oddaje."); |
|
returnstatus = 4; |
|
goto returncleanly; |
|
} |
|
if (argc < 4) { |
|
e = strrchr(m->slicica, '.'); |
|
snprintf(fn, 68, "%u%.4s", 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->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 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; |
|
} |
|
casi = realloc(casi, sizeof(time_t)*(z->sedanjost+1)); |
|
for (i = z->sedanjost; i >= 0; i--) { |
|
cas = time(NULL); |
|
casi[i] = cas; |
|
if ((z->prenesenih_kosov_preteklost)*(z->dolzina) >= z->preteklost) { |
|
i++; |
|
RTV_NAPISI(INFO, "končal preteklost: kosov: %u, sekund: %u.", |
|
z->prenesenih_kosov_preteklost, |
|
(z->prenesenih_kosov_preteklost)*(z->dolzina)); |
|
break; |
|
} |
|
snprintf(fn, sizeof(fn), "%s/%u-%lu%s", |
|
e, i, cas, 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); |
|
snprintf(fn, sizeof(fn), "%s/%u-%lu%s", |
|
e, i-1, cas, strrchr(z->kos_format, '.')); |
|
unlink(fn); |
|
break; |
|
} |
|
RTV_NAPISI(INFO, "prenesel kos %u iz preteklosti", i); |
|
fclose(fd); |
|
z->prenesenih_kosov_preteklost++; |
|
} |
|
snprintf(fn, sizeof(fn), "%s/seznam_predvajanja.m3u8", e); |
|
fd2 = fopen(fn, "w"); |
|
fprintf(fd2, "# generirano z rtv4d-dl " RTV_VER "\n"); |
|
for (i = i; i <= z->sedanjost; i++) { |
|
fprintf(fd2, "%u-%lu%s\n", i, casi[i], strrchr(z->kos_format, '.')); |
|
} |
|
free(casi); |
|
casi = NULL; |
|
for (i = (z->sedanjost)+1; 1 == 1; i++) { |
|
cas = time(NULL); |
|
if ((z->prenesenih_kosov_prihodnost)*(z->dolzina) >= z->prihodnost) { |
|
i++; |
|
RTV_NAPISI(INFO, "končal prihodnost: kosov: %u, sekund: %u.", |
|
z->prenesenih_kosov_prihodnost, |
|
(z->prenesenih_kosov_prihodnost)*(z->dolzina)); |
|
break; |
|
} |
|
snprintf(fn, sizeof(fn), "%s/%u-%lu%s", |
|
e, i, cas, strrchr(z->kos_format, '.')); |
|
fd = fopen(fn, "w"); |
|
snprintf(fn, sizeof(fn), z->kos_format, i); |
|
returnstatus = http_get(fn, fd); |
|
if (!RTV_HTTP_SUCCESS(returnstatus)) { |
|
if (returnstatus != 404) { |
|
RTV_NAPISI(NAPAKA, "strežnik odvrnil %u namesto 200/404.", |
|
returnstatus); |
|
returnstatus = 1; |
|
fclose(fd2); |
|
fclose(fd); |
|
snprintf(fn, sizeof(fn), "%s/%u-%lu%s", |
|
e, i, cas, strrchr(z->kos_format, '.')); |
|
unlink(fn); |
|
goto returncleanly; |
|
break; |
|
} |
|
RTV_NAPISI(INFO, "kos ne obstaja, čakam %u sekund.", (z->dolzina)-1); |
|
sleep(z->dolzina-1); |
|
snprintf(fn, sizeof(fn), "%s/%u-%lu%s", |
|
e, i, cas, strrchr(z->kos_format, '.')); |
|
fclose(fd); |
|
unlink(fn); |
|
i--; /* ponovno poskusimo ta kos */ |
|
continue; |
|
} |
|
fprintf(fd2, "%u-%lu%s\n", i, cas, strrchr(z->kos_format, '.')); |
|
RTV_NAPISI(INFO, "prenesel kos %u iz prihodnosti", i); |
|
z->prenesenih_kosov_prihodnost++; |
|
fclose(fd); |
|
returnstatus = 0; |
|
} |
|
fprintf(stdout, "program: %s\nsedanjost: %u\nprvi: %u\ndolzina: %u\n" |
|
"diskrepanca: %u\nprenesenih_kosov_preteklost: %u\n" |
|
"prenesenih_kosov_prihodnost: %u\npreteklost: %u\nprihodnost: %u\n" |
|
"seznam_predvajanja_url: %s\nkazalo_url: %s\nkos_format: %s\n" |
|
"api_url: %s\n", z->program, z->sedanjost, z->prvi, z->dolzina, |
|
z->diskrepanca, z->prenesenih_kosov_preteklost, |
|
z->prenesenih_kosov_prihodnost, z->preteklost, z->prihodnost, |
|
z->seznam_predvajanja_url, z->kazalo_url, z->kos_format, z->api_url); |
|
fclose(fd2); |
|
break; |
|
case 'r': /* skrivna funkcija za razhroščevanje/razvijanje */ |
|
if (argc <= 2) { |
|
strcpy(z->program, "slo1"); |
|
} else { |
|
strncpy(z->program, RTV_URL, RTV_ZIVO_PROGRAM_SIZEOF); |
|
} |
|
while (1) { |
|
if (rtv_zivo_izpolni(z) != 0) { |
|
RTV_NAPISI(NAPAKA, "Ni uspelo pridobiti metapodatkov pretoka."); |
|
returnstatus = 4; |
|
goto returncleanly; |
|
} |
|
if (i != z->prvi) { |
|
i = z->prvi; |
|
fprintf(stdout, "številka prvega kosa (z->prvi) je po novem %u\n", |
|
i); |
|
fflush(stdout); |
|
} |
|
sleep(9); |
|
} |
|
default: |
|
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; |
|
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 */
|
|
|