3
* Copyright (C) 2008 W. Xaver
4
* W.Xaver[at]googlemail.com
5
* http://zdfmediathk.sourceforge.net/
7
* This program is free software: you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License as published by
9
* the Free Software Foundation, either version 3 of the License, or
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with this program. If not, see <http://www.gnu.org/licenses/>.
20
package mSearch.filmeSuchen.sender;
22
import java.text.ParseException;
23
import java.text.SimpleDateFormat;
24
import java.util.ArrayList;
25
import java.util.Date;
26
import mSearch.Config;
28
import mSearch.daten.DatenFilm;
29
import mSearch.filmeSuchen.FilmeSuchen;
30
import mSearch.filmeSuchen.GetUrl;
31
import mSearch.tool.Log;
32
import mSearch.tool.MSStringBuilder;
34
public class MediathekZdf extends MediathekReader implements Runnable {
36
public final static String SENDERNAME = "ZDF";
37
private final MSStringBuilder seite = new MSStringBuilder(Const.STRING_BUFFER_START_BUFFER);
38
LinkedListUrl listeTage = new LinkedListUrl();
40
public MediathekZdf(FilmeSuchen ssearch, int startPrio) {
41
super(ssearch, SENDERNAME, 5 /* threads */, 150 /* urlWarten */, startPrio);
45
public void addToList() {
49
if (Config.getStop()) {
50
meldungThreadUndFertig();
51
} else if (listeThemen.isEmpty() && listeTage.isEmpty()) {
52
meldungThreadUndFertig();
54
meldungAddMax(listeThemen.size() + listeTage.size());
56
for (int t = 0; t < maxThreadLaufen; ++t) {
57
//new Thread(new ThemaLaden()).start();
58
Thread th = new Thread(new ThemaLaden());
59
th.setName(SENDERNAME + t);
65
private void addDay() {
66
//https://www.zdf.de/sendung-verpasst?airtimeDate=2016-10-26
68
for (long i = 0; i < (Config.loadLongMax() ? 300 : 20); ++i) {
69
date = new SimpleDateFormat("yyyy-MM-dd").format(new Date().getTime() - i * (1000 * 60 * 60 * 24));
70
String url = "https://www.zdf.de/sendung-verpasst?airtimeDate=" + date;
71
listeTage.addUrl(new String[]{url});
75
private class ThemaLaden implements Runnable {
77
private final GetUrl getUrl = new GetUrl(wartenSeiteLaden);
78
private MSStringBuilder seite1 = new MSStringBuilder(Const.STRING_BUFFER_START_BUFFER);
79
private MSStringBuilder seite2 = new MSStringBuilder(Const.STRING_BUFFER_START_BUFFER);
80
MSStringBuilder seiteDay = new MSStringBuilder(Const.STRING_BUFFER_START_BUFFER);
81
private final ArrayList<String> urlList = new ArrayList<>();
88
while (!Config.getStop() && (link = listeTage.getListeThemen()) != null) {
90
getUrlsDay(link[0]/* url */);
91
meldungProgress(link[0]);
93
} catch (Exception ex) {
94
Log.errorLog(496583200, ex);
96
meldungThreadUndFertig();
99
private void getUrlsDay(String url) {
100
final String MUSTER_URL = "data-plusbar-url=\"";
101
ArrayList<String> urls = new ArrayList<>();
103
seiteDay = getUrl.getUri(SENDERNAME, url, Const.KODIERUNG_UTF, 2 /* versuche */, seiteDay, "" /* Meldung */);
104
if (seiteDay.length() == 0) {
105
Log.errorLog(942031254, "Leere Seite für URL: " + url);
108
seiteDay.extractList(MUSTER_URL, "\"", urls);
109
for (String u : urls) {
110
if (Config.getStop()) {
117
private void addFilmePage(String url) {
119
seite1 = getUrl.getUri(SENDERNAME, url, Const.KODIERUNG_UTF, 1 /* versuche */, seite1, "" /* Meldung */);
120
if (seite1.length() == 0) {
121
Log.errorLog(945120365, "Leere Seite für URL: " + url);
124
String apiToken = seite1.extract("\"config\": \"", "\"");
125
String filmUrl = seite1.extract("\"content\": \"", "\"");
126
if (apiToken.isEmpty() || filmUrl.isEmpty()) {
127
Log.errorLog(461203789, "leeres token: " + url);
129
//apiToken = getToken("https://www.zdf.de" + apiToken);
130
apiToken = "d2726b6c8c655e42b68b0db26131b15b22bd1a32";
132
String thema = seite1.extract("<span class=\"teaser-cat\">", "<").trim();
133
String titel = seite1.extract("<title>", "<"); //<title>Kielings wilde Welt (1/3) - ZDFmediathek</title>
134
titel = titel.replace("- ZDFmediathek", "").trim();
135
if (thema.isEmpty()) {
138
if (thema.contains("|")) {
139
thema = thema.substring(thema.indexOf("|") + 1).trim();
140
//thema = thema.substring(0, thema.indexOf("|")).trim();
142
String dauer = seite1.extract("<dd class=\"video-duration defdesc m-border\">", "<");
143
dauer = dauer.replace("min", "").trim();
146
if (!dauer.equals("")) {
147
duration = Long.parseLong(dauer) * 60;
149
} catch (NumberFormatException ex) {
150
Log.errorLog(462310178, ex, url);
153
//<time datetime="2016-10-29T16:15:00.000+02:00">29.10.2016</time>
154
String date = seite1.extract("<time datetime=\"", "\"");
155
String time = convertTime(date);
156
date = convertDate(date);
158
String description = seite1.extract("<p class=\"item-description\" >", "<").trim();
159
addFilmeJson(filmUrl, url, apiToken, thema, titel, duration, date, time, description);
160
} catch (Exception ex) {
161
Log.errorLog(642130547, ex, url);
165
// private String getToken(String url) {
166
// String apiToken = "";
167
// seite = getUrl.getUri(SENDERNAME, url, Const.KODIERUNG_UTF, 1 /* versuche */, seite, "" /* Meldung */);
168
// if (seite.length() == 0) {
169
// Log.errorLog(461230147, "kein token für URL: " + url);
172
// apiToken = seite.extract("\"apiToken\": \"", "\"");
173
// if (apiToken.isEmpty()) {
174
// Log.errorLog(915263625, "leeres token: " + url);
178
private void addFilmeJson(String url, String urlSendung, String token, String thema, String titel,
179
long duration, String date, String time, String description) {
180
seite2 = getUrl.getUri(SENDERNAME, url, Const.KODIERUNG_UTF, 1 /* versuche */, seite2, "" /* Meldung */, token);
181
if (seite2.length() == 0) {
182
Log.errorLog(945120365, "Leere Seite für URL: " + url);
186
String s1 = seite2.extract(",\"uurl\":\"", "\"");
188
Log.errorLog(915263698, "Leere Seite für URL: " + url);
192
s1 = "https://api.zdf.de//tmd/2/portal/vod/ptmd/mediathek/" + s1;
195
seite2 = getUrl.getUri(SENDERNAME, s1, Const.KODIERUNG_UTF, 1 /* versuche */, seite2, "" /* Meldung */, token);
196
if (seite2.length() == 0) {
197
Log.errorLog(721548963, "Leere Seite für URL: " + url);
202
String subtitle = "";
204
seite2.extractList("https://utstreaming.zdf.de/mtt", "\"", urlList);
205
for (String s : urlList) {
206
if (s.endsWith(".xml")) {
207
subtitle = "https://utstreaming.zdf.de/mtt" + s;
208
} else if (subtitle.isEmpty()) {
209
subtitle = "https://utstreaming.zdf.de/mtt" + s;
212
if (!urlList.isEmpty() && subtitle.isEmpty()) {
213
Log.errorLog(912021459, "kein subtitle für URL: " + url);
216
// jetzt werden die Film-Urls gesucht
218
seite2.extractList("\"uri\" : \"", "\"", urlList);
219
String urlNormal = "";
223
for (String s : urlList) {
224
// mit den Sollwerten
225
// "uri" : "https://rodlzdf-a.akamaihd.net/none/zdf/16/10/161030_grossevoelker2_araber_v2_tex/2/161030_grossevoelker2_araber_v2_tex_1496k_p13v13.mp4" -> 852x
226
// "uri" : "https://nrodlzdf-a.akamaihd.net/none/zdf/16/10/161030_grossevoelker2_araber_v2_tex/2/161030_grossevoelker2_araber_v2_tex_229k_p7v13.mp4" -> 320x
227
// "uri" : "https://nrodlzdf-a.akamaihd.net/none/zdf/16/10/161030_grossevoelker2_araber_v2_tex/2/161030_grossevoelker2_araber_v2_tex_476k_p9v13.mp4" -> 480x
228
if (s.endsWith("2328k_p35v13.mp4") || s.endsWith("2328k_p35v12.mp4")) {
231
if (s.endsWith("476k_p9v13.mp4") || s.endsWith("436k_p9v12.mp4") || s.endsWith("436k_p9v11.mp4")
232
|| s.endsWith("tex_h.mp4") || s.endsWith("inf_h.mp4")) {
235
if (s.endsWith("3328k_p36v13.mp4") || s.endsWith("3328k_p36v12.mp4")) {
239
for (String s : urlList) {
240
// dann evtl. die schlechteren
241
if (urlNormal.isEmpty()
242
&& (s.endsWith("1496k_p13v13.mp4") || s.endsWith("1456k_p13v12.mp4") || s.endsWith("1456k_p13v11.mp4") || s.endsWith("tex_vh.mp4")
243
|| s.endsWith("1596k_p13v9.mp4") || s.endsWith("inf_vh.mp4"))) {
246
if (urlLow.isEmpty() && s.endsWith("229k_p7v13.mp4")) {
251
if (urlNormal.isEmpty()) {
255
if (urlNormal.isEmpty()) {
256
Log.errorLog(642130547, "Keine FilmURL: " + url);
258
DatenFilm film = new DatenFilm(SENDERNAME, thema, urlSendung /*urlThema*/, titel, urlNormal, "" /*urlRtmp*/,
259
date, time, duration, description);
260
urlTauschen(film, urlSendung, mSearchFilmeSuchen);
262
if (!urlHd.isEmpty()) {
263
film.addUrlHd(urlHd, "");
265
if (!urlLow.isEmpty()) {
266
film.addUrlKlein(urlLow, "");
268
if (!subtitle.isEmpty()) {
269
film.addUrlSubtitle(subtitle);
274
private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");//2016-10-29T16:15:00.000+02:00
275
private final SimpleDateFormat sdfOutTime = new SimpleDateFormat("HH:mm:ss");
276
private final SimpleDateFormat sdfOutDay = new SimpleDateFormat("dd.MM.yyyy");
278
private String convertDate(String datum) {
280
Date filmDate = sdf.parse(datum);
281
datum = sdfOutDay.format(filmDate);
282
} catch (ParseException ex) {
283
Log.errorLog(731025789, ex, "Datum: " + datum);
288
private String convertTime(String zeit) {
290
Date filmDate = sdf.parse(zeit);
291
zeit = sdfOutTime.format(filmDate);
292
} catch (ParseException ex) {
293
Log.errorLog(915423687, ex, "Time: " + zeit);
300
public static void urlTauschen(DatenFilm film, String urlSeite, FilmeSuchen mSFilmeSuchen) {
301
// manuell die Auflösung hochsetzen
302
changeUrl("1456k_p13v11.mp4", "2256k_p14v11.mp4", film, urlSeite, mSFilmeSuchen);
303
changeUrl("1496k_p13v13.mp4", "2328k_p35v13.mp4", film, urlSeite, mSFilmeSuchen);
305
changeUrl("2256k_p14v12.mp4", "2328k_p35v12.mp4", film, urlSeite, mSFilmeSuchen);
307
changeUrl("1456k_p13v12.mp4", "2328k_p35v12.mp4", film, urlSeite, mSFilmeSuchen);
308
//wenns nicht geht, dann vielleicht so
309
changeUrl("1456k_p13v12.mp4", "2256k_p14v12.mp4", film, urlSeite, mSFilmeSuchen);
311
// manuell die Auflösung für HD setzen
312
updateHd("1496k_p13v13.mp4", "3328k_p36v13.mp4", film, urlSeite);
313
updateHd("2256k_p14v12.mp4", "3256k_p15v12.mp4", film, urlSeite);
314
updateHd("2328k_p35v12.mp4", "3328k_p36v12.mp4", film, urlSeite);
317
private static void changeUrl(String from, String to, DatenFilm film, String urlSeite, FilmeSuchen mSFilmeSuchen) {
318
if (film.arr[DatenFilm.FILM_URL].endsWith(from)) {
319
String url_ = film.arr[DatenFilm.FILM_URL].substring(0, film.arr[DatenFilm.FILM_URL].lastIndexOf(from)) + to;
320
String l = mSFilmeSuchen.listeFilmeAlt.getFileSizeUrl(url_, film.arr[DatenFilm.FILM_SENDER]);
321
// zum Testen immer machen!!
323
film.arr[DatenFilm.FILM_GROESSE] = l;
324
film.arr[DatenFilm.FILM_URL] = url_;
325
} else if (urlExists(url_)) {
326
// dann wars wohl nur ein "403er"
327
film.arr[DatenFilm.FILM_URL] = url_;
329
Log.errorLog(945120369, "urlTauschen: " + urlSeite);
334
private static void updateHd(String from, String to, DatenFilm film, String urlSeite) {
335
if (film.arr[DatenFilm.FILM_URL_HD].isEmpty() && film.arr[DatenFilm.FILM_URL].endsWith(from)) {
336
String url_ = film.arr[DatenFilm.FILM_URL].substring(0, film.arr[DatenFilm.FILM_URL].lastIndexOf(from)) + to;
337
// zum Testen immer machen!!
338
if (urlExists(url_)) {
339
film.addUrlHd(url_, "");
341
Log.errorLog(945120147, "urlTauschen: " + urlSeite);
346
public static DatenFilm filmHolenId(GetUrl getUrl, MSStringBuilder strBuffer, String sender, String thema, String titel, String filmWebsite, String urlId) {
347
//<teaserimage alt="Harald Lesch im Studio von Abenteuer Forschung" key="298x168">http://www.zdf.de/ZDFmediathek/contentblob/1909108/timg298x168blob/8081564</teaserimage>
348
//<detail>Möchten Sie wissen, was Sie in der nächsten Sendung von Abenteuer Forschung erwartet? Harald Lesch informiert Sie.</detail>
349
//<length>00:00:34.000</length>
350
//<airtime>02.07.2013 23:00</airtime>
351
final String BESCHREIBUNG = "<detail>";
352
final String LAENGE_SEC = "<lengthSec>";
353
final String LAENGE = "<length>";
354
final String DATUM = "<airtime>";
355
final String THEMA = "<originChannelTitle>";
358
String beschreibung, subtitle, laenge, datum, zeit = "";
360
strBuffer = getUrl.getUri_Utf(sender, urlId, strBuffer, "URL-Filmwebsite: " + filmWebsite);
361
if (strBuffer.length() == 0) {
362
Log.errorLog(398745601, "url: " + urlId);
366
subtitle = strBuffer.extract("<caption>", "<url>http://", "<", "http://");
367
if (subtitle.isEmpty()) {
368
subtitle = strBuffer.extract("<caption>", "<url>https://", "<", "https://");
369
// if (!subtitle.isEmpty()) {
370
// System.out.println("Hallo");
373
beschreibung = strBuffer.extract(BESCHREIBUNG, "<");
374
if (beschreibung.isEmpty()) {
375
beschreibung = strBuffer.extract(BESCHREIBUNG, "</");
376
beschreibung = beschreibung.replace("<![CDATA[", "");
377
beschreibung = beschreibung.replace("]]>", "");
378
if (beschreibung.isEmpty()) {
379
Log.errorLog(945123074, "url: " + urlId);
382
if (thema.isEmpty()) {
383
thema = strBuffer.extract(THEMA, "<");
386
laenge = strBuffer.extract(LAENGE_SEC, "<");
387
if (!laenge.isEmpty()) {
388
laengeL = extractDurationSec(laenge);
390
laenge = strBuffer.extract(LAENGE, "<");
391
if (laenge.contains(".")) {
392
laenge = laenge.substring(0, laenge.indexOf("."));
394
laengeL = extractDuration(laenge);
397
datum = strBuffer.extract(DATUM, "<");
398
if (datum.contains(" ")) {
399
zeit = datum.substring(datum.lastIndexOf(" ")).trim() + ":00";
400
datum = datum.substring(0, datum.lastIndexOf(" ")).trim();
403
//============================================================================
404
// und jetzt die FilmURLs
405
final String[] QU_WIDTH_HD = {"1280"};
406
final String[] QU_WIDTH = {"1024", "852", "720", "688", "480", "432", "320"};
407
final String[] QU_WIDTH_KL = {"688", "480", "432", "320"};
408
String url, urlKlein, urlHd, tmp = "";
410
urlHd = getUrl(strBuffer, QU_WIDTH_HD, tmp, true);
411
url = getUrl(strBuffer, QU_WIDTH, tmp, true);
412
urlKlein = getUrl(strBuffer, QU_WIDTH_KL, tmp, false);
414
if (url.equals(urlKlein)) {
422
//===================================================
423
if (urlHd.isEmpty()) {
424
// MSLog.fehlerMeldung(912024587, "keine URL: " + filmWebsite);
426
if (urlKlein.isEmpty()) {
427
// MSLog.fehlerMeldung(310254698, "keine URL: " + filmWebsite);
430
Log.errorLog(397002891, "keine URL: " + filmWebsite);
433
DatenFilm film = new DatenFilm(sender, thema, filmWebsite, titel, url, "" /*urlRtmp*/, datum, zeit,
434
laengeL, beschreibung);
435
if (!subtitle.isEmpty()) {
436
film.addUrlSubtitle(subtitle);
438
film.addUrlKlein(urlKlein, "");
439
film.addUrlHd(urlHd, "");
444
private static String getUrl(MSStringBuilder strBuffer, String[] arr, String tmp, boolean hd) {
445
final String URL_ANFANG = "<formitaet basetype=\"h264_aac_mp4_http_na_na\"";
446
final String URL_ENDE = "</formitaet>";
447
final String URL = "<url>";
448
final String WIDTH = "<width>";
452
int posAnfang, posEnde;
454
for (String qual : arr) {
457
if ((posAnfang = strBuffer.indexOf(URL_ANFANG, posAnfang)) == -1) {
460
posAnfang += URL_ANFANG.length();
461
if ((posEnde = strBuffer.indexOf(URL_ENDE, posAnfang)) == -1) {
465
tmp = strBuffer.extract(URL, "<", posAnfang, posEnde);
466
if (strBuffer.extract(WIDTH, "<", posAnfang, posEnde).equals(qual)) {
468
ret = checkUrlHD(tmp);
472
if (!ret.isEmpty()) {
478
if (ret.startsWith("http://tvdl.zdf.de")) {
479
ret = ret.replace("http://tvdl.zdf.de", "http://nrodl.zdf.de");
484
private static String checkUrlHD(String url) {
486
if (url.startsWith("http") && url.endsWith("mp4")) {
488
if (ret.startsWith("http://www.metafilegenerator.de/ondemand/zdf/hbbtv/")) {
489
ret = ret.replaceFirst("http://www.metafilegenerator.de/ondemand/zdf/hbbtv/", "http://nrodl.zdf.de/");
495
private static String checkUrl(String url) {
497
if (url.startsWith("http") && url.endsWith("mp4")) {
498
if (!url.startsWith("http://www.metafilegenerator.de/")) {