summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnton Luka Šijanec <anton@sijanec.eu>2020-12-28 14:42:10 +0100
committerAnton Luka Šijanec <anton@sijanec.eu>2020-12-28 14:42:10 +0100
commita67365b43a446e33311e9e18b755200fb8dbf031 (patch)
treee12d2f2ca511eb474fd28a6ee8b8a35231a21eee
parentrazličica 0.0.2 sedaj prenese samo najboljši videoposnetek (diff)
parentizdaja 0.0.3, pripravljen na združitev v master (diff)
downloadrtv4d-dl-0.0.3.tar
rtv4d-dl-0.0.3.tar.gz
rtv4d-dl-0.0.3.tar.bz2
rtv4d-dl-0.0.3.tar.lz
rtv4d-dl-0.0.3.tar.xz
rtv4d-dl-0.0.3.tar.zst
rtv4d-dl-0.0.3.zip
-rw-r--r--Makefile5
-rw-r--r--README.md45
-rwxr-xr-xrtv4d-dlbin35272 -> 52776 bytes
-rw-r--r--rtv4d-dl.c762
-rw-r--r--test.c9
5 files changed, 600 insertions, 221 deletions
diff --git a/Makefile b/Makefile
index 952c7e4..62d67b2 100644
--- a/Makefile
+++ b/Makefile
@@ -3,6 +3,7 @@ default:
@echo - če še niste, preberite README.md in se pozanimajte o uporabi
@echo - če še niste, z \`make prepare\` namestite C \(potrebuje sudo in apt\)
@echo - če še niste, z \`make compile\` izdelajte binarne programe
+ @echo - če pe niste, z \`make install\` namesti v ~/.local/bin/ prej compilej!
@echo rtv4d-dl dela samo na GNU/Linux ... na oknih poskusi cygwin.
@echo to je vse, hvala.
@@ -11,3 +12,7 @@ prepare:
compile:
gcc rtv4d-dl.c -o rtv4d-dl -Wall -lm -I.
+
+install:
+ mkdir -p ~/.local/bin
+ cp ./rtv4d-dl ~/.local/bin/
diff --git a/README.md b/README.md
index 35e762f..0260c12 100644
--- a/README.md
+++ b/README.md
@@ -6,11 +6,15 @@ z uporabo programa se strinjate z naslednjimi stavki:
* program uporabljate na lastno odgovornost.
* če ni kje drugje avtor napisal drugače ali če to ni zakonsko drugače:
- ne smete distribuirati programa in izdelovali kopij.
+ - razlog: da lahko RTV v teoriji zahteva izbris programa iz Interneta
- smete ga uporabljati samo za zasebno nekomercialno uporabo.
+ - ne smete spreminjate izvorne kode
+ - razlog: da lahko RTV kadarkoli blokira program prek user-agent niza.
## funkcije
* prenašanje videoposnetkov iz arhiva kot odklenjene videodatoteke
-* [**novo!**] z različico 0.0.1 tudi prenašanje avdioposnetkov!
+* z različico 0.0.1 tudi prenašanje avdioposnetkov!
+* [**novo**]: z različico 0.0.3 tudi prenašanje televizijskih prenosov v živo
## možnosti uporabe programa
* prenos oddaje: `rtv4d-dl oddaja <URL/ID oddaje> [izhodna datoteka]`
@@ -21,19 +25,27 @@ z uporabo programa se strinjate z naslednjimi stavki:
- opomba: nekateri metapodatki veljajo omejeno časa (video URL)
* prenos sličice oddaje: `rtv4d-dl slicica-oddaja <URL> [datoteka]`
- primer: `rtv4d-dl slicica-oddaja 89614963 89614963.jpg`
+* prenos zadnjih dveh ur prenosa v živo: `rtv4d-dl živo [2] [3] [4] [5]`
+ - primer: `rtv4d-dl živo slo1 slo1 9999999 9999999` (prenese vse)
+ - arg. 2 je program, 3 je izhodni direktorij,
+ 4 je število sekund v preteklost, 5 je število sekund v prihodnost
+* prenos podnapisov oddaje: `rtv4d-dl podnapisi <url> [datoteka]`
+ - primer: `rtv4d-dl podnapisi 15486024 15486024.vtt`
# dodatne informacije:
* pisanje v STDOUT: kot pot datoteke napišite `/dev/stdout`
* program se poveže na \*.rtvslo.si, spremenite izvorno kodo za drugo
infrastrukturo
+* **živo**: za možne programe in razlago dolžine glej *dodatno o prenosu v živo*
# trenutna izdaja programa:
* program je bil nazadnje ročno testiran 13. decembra 2020 in takrat je DELOVAL.
-* različica: 0.0.2
+* različica: 0.0.3
## dnevnik sprememb:
* 0.0.2 - 13. december 2020: sedaj pravilno naloži samo največjo kvaliteto, pred
tem se naloži naključna kvaliteta.
+* 0.0.3 - 24. december 2020: dodano prenašanje VTT podnapisov in prenosov v živo
# o
* program je spisan 100% v C programskem jeziku
@@ -47,8 +59,7 @@ z uporabo programa se strinjate z naslednjimi stavki:
naj mi pošlje `Makefile`
## formatiranje kode
-* K&R komentarji
-* GNUC
+* K&R komentarji, GNUC
* levi zaviti oklepaj na isti vrstici kot funkcija, desni na svoji vrstici
* vrstica max. 80 znakov, upoštevajoč, da tabulator šteje za dva
* presledek za imenom funkcije in argumenti, vendar le ob deklaraciji
@@ -67,6 +78,32 @@ z uporabo programa se strinjate z naslednjimi stavki:
* ker predvajanje v živo na RTVSLO trenutno potrebuje Javascript, bi bilo
uporabno narediti minimalističen HTTP/RTP strežnik, ki bi delal zahteve na RTV
in kot izhod uporabniku ponudil pretok.
+ - opomba: seveda predvajanje v živo deluje na VLC predvajalniku v formatu m3u8
+ + primer: [https://ž.ga/tvslo1](https://ž.ga/tvslo1) v VLC network stream
* RTV za avdio/radio v živo že ponuja možnost poslušanja brez javascripta, imajo
namreč icecast2 strežnik na [mp3.rtvslo.si](mp3.rtvslo.si), tako da tega po
mojem ni potrebno izdelati še v rtv4d-dl.
+* RTV4D arhiv ponuja samo videokvalitete do 720p (1280x720 pikslov). Pri
+ prenosu v živo pa je maksimalna velikost 1080p (1920x1080 pisklov). Če torej
+ hočemo dobiti kvalitetno vsebino, jo moramo posneti, preden gre v arhiv.
+
+### dodatno o prenosu v živo
+* ne vemo, koliko sekund posnetkov hrani strežnik, zato predvidevamo, da je
+ vsak kos dolg toliko, kot tisti v kazalu, če pa imajo tisti v kazalu različne
+ dolžine, pa se izbere najkrajša in se zaokroži na celo sekundo na dol.
+* za avtomatsko pridobitev vseh videoprogramov, ki so na voljo kot prenosi v
+ živo, bi bilo potrebno narediti podporo za HTTPS, zato je treba poznati
+ kratice programov na pamet: `slo1`, `slo2`, `slo3`, `kp1`, `mb1`, `mmctv`.
+* če je število sekund v preteklost večje od vsebine, ki jo ima strežnik v
+ kazalu, bo shranjena vsa vsebina, ki je na strežniku za nazaj (~10 ur).
+* če je število sekund v prihodnost večje od 0, bo program čakal, da izide nov
+ delček pretoka, in ga naložil sproti, vse do izpolnjene kvote.
+* program najprej naloži v preteklost, nato v prihodnost, med nalaganjem v
+ prihodnost ga sicer lahko prekinete, vendar to naredite med tem, ko poteka
+ čakanje na nov segment, ne med nalaganjem segmenta ali tik po nalaganju.
+* prenos v živo se shrani kot m3u8 playlist in mpeg ts datoteke. te datoteke
+ se lahko normalno združi v eno z ukazom `cat *.ts > zdruzene.ts` in se odpre
+ kar zdruzene.ts v VLC predvajalniku. VLC podpira tudi direktno odprtje
+ playlist.m3u8 datoteke in branje po kosih.
+* če program ni bil prekinjen, bo po končanem prenosu v stdout napisal
+ metapodatke pretoka v živo.
diff --git a/rtv4d-dl b/rtv4d-dl
index e2343a1..0c62ff1 100755
--- a/rtv4d-dl
+++ b/rtv4d-dl
Binary files differ
diff --git a/rtv4d-dl.c b/rtv4d-dl.c
index 69442e0..6da6a61 100644
--- a/rtv4d-dl.c
+++ b/rtv4d-dl.c
@@ -4,6 +4,12 @@
#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>
+#include <time.h>
#define NIZ_DODATEK(a) #a
#define NIZ(a) NIZ_DODATEK(a)
#define RTV_CLIENT_ID "82013fb3a531d5414f478747c1aca622" /* enak za vse */
@@ -27,8 +33,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 +55,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_VER "0.0.2"
-
+#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 +152,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 +241,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 +271,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 +309,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 +326,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 +336,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 +411,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,33 +437,201 @@ 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;
+ FILE * fd2;
+ unsigned int i;
+ time_t * casi = NULL;
+ time_t cas;
+ 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':
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.");
@@ -464,13 +650,16 @@ 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;
}
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.");
@@ -493,16 +682,18 @@ 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 */
+ case 'S':
if (rtv_meta_izpolni(m) != 0) {
RTV_NAPISI(NAPAKA, "Ni uspelo pridobiti metapodatkov oddaje.");
returnstatus = 4;
@@ -520,21 +711,162 @@ 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 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, 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;
+ }
+ fclose(fd2);
+ 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 */
diff --git a/test.c b/test.c
index d24517d..191d22a 100644
--- a/test.c
+++ b/test.c
@@ -2,8 +2,13 @@
#include <stdlib.h>
#include <string.h>
int main (int argc, char ** argv) {
- char * metavalues[] = { "abc", "def", "ghi", "jkl" };
- fprintf(stdout, "%s\n", { "a", "b", "c", "d" }[3]);
+ char aaa[] = "chunk_1234.ts";
+ char bbb[] = "chunk_%u.ts";
+ unsigned int ccc;
+ sscanf(aaa, bbb, &ccc);
+ fprintf(stdout, "%u\n", ccc);
+ // char * metavalues[] = { "abc", "def", "ghi", "jkl" };
+ // fprintf(stdout, "%s\n", { "a", "b", "c", "d" }[3]);
// const char b[5] = "aaaaa";
// const char a[5] = "aaaaa";
// fprintf(stdout, "%d\n", strncasecmp(a, b, 325432));