├── .mvn └── wrapper │ ├── maven-wrapper.jar │ ├── maven-wrapper.properties │ └── MavenWrapperDownloader.java ├── src ├── main │ ├── resources │ │ └── .gitignore │ └── java │ │ └── de │ │ └── mediathekview │ │ └── mlib │ │ ├── tool │ │ ├── InputStreamProgressMonitor.java │ │ ├── MVHttpClient.java │ │ ├── FileSize.java │ │ ├── GermanStringSorter.java │ │ ├── MSLong.java │ │ ├── ProgressMonitorInputStream.java │ │ ├── Version.java │ │ ├── DatumFilm.java │ │ ├── Datum.java │ │ ├── SingleInstance.java │ │ ├── DbgMsg.java │ │ ├── ReplaceList.java │ │ ├── MSInputStream.java │ │ ├── Hash.java │ │ ├── AbsoluteFromRelativeURI.java │ │ ├── Listener.java │ │ ├── Duration.java │ │ ├── MSStringBuilder.java │ │ ├── Functions.java │ │ ├── Log.java │ │ ├── FilenameUtils.java │ │ └── TimedTextMarkupLanguageParser.java │ │ ├── filmesuchen │ │ ├── ListenerFilmeLaden.java │ │ └── ListenerFilmeLadenEvent.java │ │ ├── Config.java │ │ ├── Const.java │ │ └── filmlisten │ │ ├── DatenFilmlisteUrl.java │ │ ├── WriteFilmlistJson.java │ │ ├── ListeFilmlistenUrls.java │ │ ├── FilmlistenSuchen.java │ │ └── FilmlisteLesen.java └── test │ └── java │ └── de │ └── mediathekview │ └── mlib │ └── daten │ └── ListeFilmeTest.java ├── .gitignore ├── .github └── workflows │ ├── maven.yml │ ├── release.yml │ └── nightly.yml ├── README.md ├── mvnw.cmd ├── MLib.iml ├── mvnw └── pom.xml /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MLib/HEAD/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.5.4/apache-maven-3.5.4-bin.zip -------------------------------------------------------------------------------- /src/main/resources/.gitignore: -------------------------------------------------------------------------------- 1 | # Keine Ressourcen vorhanden, aber gradle erzeugt hier die version.properties 2 | version.properties 3 | !.gitignore 4 | -------------------------------------------------------------------------------- /src/main/java/de/mediathekview/mlib/tool/InputStreamProgressMonitor.java: -------------------------------------------------------------------------------- 1 | package de.mediathekview.mlib.tool; 2 | 3 | /** 4 | * User: Christian F. 5 | * Date: 15.06.16 6 | * Time: 14:05 7 | */ 8 | public interface InputStreamProgressMonitor { 9 | void progress(long bytesRead, long size); 10 | } 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.gradle/ 2 | target 3 | /bin/ 4 | /build/ 5 | .classpath 6 | .settings 7 | .project 8 | *.class 9 | build/classes 10 | built-jar.properties 11 | dist/javadoc 12 | /nbproject/private/ 13 | .externalToolBuilders 14 | .idea 15 | /src/main/resources/version.properties 16 | /.nb-gradle/ 17 | RepoZugang.properties 18 | -------------------------------------------------------------------------------- /.github/workflows/maven.yml: -------------------------------------------------------------------------------- 1 | name: Build and test 2 | 3 | on: [push,pull_request] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v2 12 | - name: Set up JDK 17 13 | uses: actions/setup-java@v1 14 | with: 15 | java-version: 17 16 | - name: Build and test with Maven 17 | run: ./mvnw -B package 18 | - name: SonarCloud Scan 19 | run: ./mvnw -B org.jacoco:jacoco-maven-plugin:prepare-agent sonar:sonar -Dsonar.projectKey=mediathekview_MLib -Dsonar.organization=mediathekview -Dsonar.host.url=https://sonarcloud.io -Dsonar.login=$SONAR_TOKEN 20 | env: 21 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 22 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} 23 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | push: 4 | tags: 5 | - '*' 6 | 7 | jobs: 8 | build: 9 | strategy: 10 | fail-fast: false 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v2 15 | - name: Set up JDK 17 16 | uses: actions/setup-java@v1 17 | with: 18 | java-version: 17 19 | server-id: ossrh 20 | server-username: MAVEN_USERNAME 21 | server-password: MAVEN_PASSWORD 22 | - name: Build and test 23 | run: ./mvnw -B package 24 | - name: Publish to the Maven Central Repository 25 | uses: samuelmeuli/action-maven-publish@v1 26 | with: 27 | gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} 28 | gpg_passphrase: ${{ secrets.GPG_PASSPHRASE }} 29 | nexus_username: ${{ secrets.OSSRH_USERNAME }} 30 | nexus_password: ${{ secrets.OSSRH_TOKEN }} 31 | -------------------------------------------------------------------------------- /.github/workflows/nightly.yml: -------------------------------------------------------------------------------- 1 | name: Deploy develop nightly 2 | on: 3 | schedule: 4 | - cron: '0 0 * * *' 5 | 6 | jobs: 7 | nightly: 8 | name: Deploy nightly 9 | strategy: 10 | fail-fast: false 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v2 15 | with: 16 | ref: develop 17 | - name: Set up JDK 11 18 | uses: actions/setup-java@v1 19 | with: 20 | java-version: 11 21 | server-id: ossrh 22 | server-username: MAVEN_USERNAME 23 | server-password: MAVEN_PASSWORD 24 | - name: Build and test 25 | run: ./mvnw -B package 26 | - name: Publish to the Maven Central Repository 27 | uses: samuelmeuli/action-maven-publish@v1 28 | with: 29 | gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} 30 | gpg_passphrase: ${{ secrets.GPG_PASSPHRASE }} 31 | nexus_username: ${{ secrets.OSSRH_USERNAME }} 32 | nexus_password: ${{ secrets.OSSRH_TOKEN }} 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](http://www.gnu.org/licenses/gpl-3.0) 2 | [![Build Status](https://github.com/mediathekview/MLib/workflows/Build%20and%20test/badge.svg?branch=master)](https://github.com/mediathekview/MLib/actions?query=branch%3Amaster+workflow%3A%22Build+and+test%22) 3 | [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=mediathekview_MLib&metric=alert_status)](https://sonarcloud.io/dashboard?id=mediathekview_MLib) 4 | 5 | # MLib 6 | 7 | Bibliothek für das Programm **MediathekView** und den Crawler. 8 | 9 | # MediathekView 10 | 11 | - [Website](https://mediathekview.de) 12 | - [Download](https://mediathekview.de/download/) Installationspakete 13 | 14 | # Entwicklung 15 | 16 | ## Code auschecken 17 | 18 | ```bash 19 | git clone https://github.com/mediathekview/MLib.git 20 | ``` 21 | 22 | ## Bauen an der Kommandozeile 23 | 24 | ```bash 25 | cd MLib 26 | ./clean install 27 | ``` 28 | 29 | ## Entwicklung mit Netbeans 30 | 31 | * Verzeichniss `MLib` mit Netbeans öffnen 32 | 33 | ## Entwicklung mit Eclipse 34 | 35 | * Falls noch nicht vorhanden: [Plugin buildship](https://projects.eclipse.org/projects/tools.buildship) installieren 36 | * Projekt `MLib` als Gradle-Projekt importieren. 37 | -------------------------------------------------------------------------------- /src/main/java/de/mediathekview/mlib/tool/MVHttpClient.java: -------------------------------------------------------------------------------- 1 | package de.mediathekview.mlib.tool; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | import okhttp3.ConnectionPool; 6 | import okhttp3.OkHttpClient; 7 | 8 | public class MVHttpClient { 9 | private final static MVHttpClient ourInstance = new MVHttpClient(); 10 | private final OkHttpClient httpClient; 11 | private final OkHttpClient copyClient; 12 | 13 | private MVHttpClient() { 14 | httpClient = new OkHttpClient.Builder() 15 | .connectTimeout(30, TimeUnit.SECONDS) 16 | .writeTimeout(30, TimeUnit.SECONDS) 17 | .readTimeout(30, TimeUnit.SECONDS) 18 | .connectionPool(new ConnectionPool(100, 1, TimeUnit.SECONDS)) 19 | .build(); 20 | httpClient.dispatcher().setMaxRequests(100); 21 | 22 | copyClient = httpClient.newBuilder() 23 | .connectTimeout(5, TimeUnit.SECONDS) 24 | .readTimeout(5, TimeUnit.SECONDS) 25 | .writeTimeout(2, TimeUnit.SECONDS).build(); 26 | } 27 | 28 | public static MVHttpClient getInstance() { 29 | return ourInstance; 30 | } 31 | 32 | public OkHttpClient getHttpClient() { 33 | return httpClient; 34 | } 35 | 36 | public OkHttpClient getReducedTimeOutClient() { 37 | return copyClient; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/de/mediathekview/mlib/filmesuchen/ListenerFilmeLaden.java: -------------------------------------------------------------------------------- 1 | /* 2 | * MediathekView 3 | * Copyright (C) 2008 W. Xaver 4 | * W.Xaver[at]googlemail.com 5 | * http://zdfmediathk.sourceforge.net/ 6 | * 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 10 | * any later version. 11 | * 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. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | package de.mediathekview.mlib.filmesuchen; 21 | 22 | import java.util.EventListener; 23 | 24 | public class ListenerFilmeLaden implements EventListener { 25 | 26 | ListenerFilmeLadenEvent event; 27 | 28 | public void start(ListenerFilmeLadenEvent e) { 29 | } 30 | 31 | public void progress(ListenerFilmeLadenEvent e) { 32 | } 33 | 34 | public void fertig(ListenerFilmeLadenEvent e) { 35 | } 36 | 37 | public void fertigOnlyOne(ListenerFilmeLadenEvent e) { 38 | // dient dem Melden des ersten Mal Laden der Filmliste beim ProgStart 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/de/mediathekview/mlib/filmesuchen/ListenerFilmeLadenEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * MediathekView 3 | * Copyright (C) 2008 W. Xaver 4 | * W.Xaver[at]googlemail.com 5 | * http://zdfmediathk.sourceforge.net/ 6 | * 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 10 | * any later version. 11 | * 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. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | package de.mediathekview.mlib.filmesuchen; 21 | 22 | public class ListenerFilmeLadenEvent { 23 | 24 | public String senderUrl = ""; 25 | public String text = ""; 26 | public int max = 0; 27 | public int progress = 0; 28 | public boolean fehler = false; 29 | public int count = 0; 30 | 31 | public ListenerFilmeLadenEvent(String ssender, String ttext, int mmax, int pprogress, int ccount, boolean ffehler) { 32 | senderUrl = ssender; 33 | text = ttext; 34 | max = mmax; 35 | progress = pprogress; 36 | count = ccount; 37 | fehler = ffehler; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/de/mediathekview/mlib/tool/FileSize.java: -------------------------------------------------------------------------------- 1 | package de.mediathekview.mlib.tool; 2 | 3 | import okhttp3.Request; 4 | import okhttp3.Response; 5 | 6 | import java.io.IOException; 7 | 8 | public class FileSize { 9 | private FileSize() {} 10 | 11 | public static String laengeString(String url) { 12 | // liefert die Dateigröße einer URL in MB!! 13 | // Anzeige der Größe in MiB und deshalb: Faktor 1000 14 | String groesseStr = ""; 15 | 16 | long l = getFileSizeFromUrl(url); 17 | if (l > 1_000_000) { 18 | // größer als 1MiB sonst kann ich mirs sparen 19 | groesseStr = String.valueOf(l / 1_000_000); 20 | } else if (l > 0) { 21 | groesseStr = "1"; 22 | } 23 | return groesseStr; 24 | } 25 | 26 | /** 27 | * Return the size of a URL in bytes. 28 | * 29 | * @param url URL as String to query. 30 | * @return size in bytes or -1. 31 | */ 32 | private static long getFileSizeFromUrl(String url) { 33 | if (!url.toLowerCase().startsWith("http")) { 34 | return -1; 35 | } 36 | 37 | final Request request = new Request.Builder().url(url).head().build(); 38 | long respLength = -1; 39 | try (Response response 40 | = MVHttpClient.getInstance().getReducedTimeOutClient().newCall(request).execute()) { 41 | if (response.isSuccessful()) { 42 | respLength = Long.parseLong(response.header("Content-Length", "-1")); 43 | } 44 | } catch (IOException | NumberFormatException ignored) { 45 | respLength = -1; 46 | } 47 | 48 | if (respLength < 1_000_000) { 49 | // alles unter 1MB sind Playlisten, ORF: Trailer bei im Ausland gesperrten Filmen, ... 50 | // dann wars nix 51 | respLength = -1; 52 | } 53 | return respLength; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/de/mediathekview/mlib/tool/GermanStringSorter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * MediathekView 3 | * Copyright (C) 2008 W. Xaver 4 | * W.Xaver[at]googlemail.com 5 | * http://zdfmediathk.sourceforge.net/ 6 | * 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 10 | * any later version. 11 | * 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. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | package de.mediathekview.mlib.tool; 22 | 23 | import java.text.Collator; 24 | import java.util.Comparator; 25 | import java.util.Locale; 26 | 27 | public class GermanStringSorter implements Comparator { 28 | 29 | private static Collator collator; 30 | private static GermanStringSorter instance; 31 | 32 | private GermanStringSorter() { 33 | super(); 34 | } 35 | 36 | public static GermanStringSorter getInstance() { 37 | if (instance == null) { 38 | instance = new GermanStringSorter(); 39 | collator = Collator.getInstance(Locale.GERMANY); 40 | // ignore lower/upper case, but accept special characters in localised alphabetical order 41 | collator.setStrength(Collator.SECONDARY); 42 | } 43 | return instance; 44 | } 45 | 46 | @Override 47 | public int compare(String o1, String o2) { 48 | if (o1 != null && o2 != null) { 49 | if (collator != null) { 50 | return collator.compare(o1, o2); 51 | } 52 | return o1.compareTo(o2); 53 | } 54 | return 0; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/de/mediathekview/mlib/tool/MSLong.java: -------------------------------------------------------------------------------- 1 | /* 2 | * MediathekView 3 | * Copyright (C) 2013 W. Xaver 4 | * W.Xaver[at]googlemail.com 5 | * http://zdfmediathk.sourceforge.net/ 6 | * 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 10 | * any later version. 11 | * 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. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | package de.mediathekview.mlib.tool; 21 | 22 | import de.mediathekview.mlib.daten.DatenFilm; 23 | 24 | public class MSLong implements Comparable { 25 | 26 | public Long l = 0L; 27 | public String s = ""; 28 | 29 | public MSLong() { 30 | } 31 | 32 | public MSLong(long ll) { 33 | l = ll; 34 | s = l.toString(); 35 | } 36 | 37 | public MSLong(DatenFilm film) { 38 | if (film.arr[DatenFilm.FILM_GROESSE].equals("<1")) { 39 | film.arr[DatenFilm.FILM_GROESSE] = "1"; 40 | } 41 | try { 42 | if (!film.arr[DatenFilm.FILM_GROESSE].isEmpty()) { 43 | l = Long.valueOf(film.arr[DatenFilm.FILM_GROESSE]); 44 | s = film.arr[DatenFilm.FILM_GROESSE]; 45 | } 46 | } catch (Exception ex) { 47 | Log.errorLog(649891025, ex, "String: " + film.arr[DatenFilm.FILM_GROESSE]); 48 | l = 0L; 49 | s = ""; 50 | } 51 | } 52 | 53 | @Override 54 | public String toString() { 55 | return s; 56 | } 57 | 58 | @Override 59 | public int compareTo(MSLong ll) { 60 | return (l.compareTo(ll.l)); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/de/mediathekview/mlib/Config.java: -------------------------------------------------------------------------------- 1 | /* 2 | * MediathekView 3 | * Copyright (C) 2008 W. Xaver 4 | * W.Xaver[at]googlemail.com 5 | * http://zdfmediathk.sourceforge.net/ 6 | * 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 10 | * any later version. 11 | * 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. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | package de.mediathekview.mlib; 21 | 22 | import java.util.concurrent.atomic.AtomicBoolean; 23 | 24 | public class Config { 25 | 26 | public static int bandbreite = 0; // maxBandbreite in Byte 27 | private static String userAgent = null; 28 | public static boolean debug = false; // Debugmodus 29 | private static final AtomicBoolean stop = new AtomicBoolean(false); // damit kannn das Laden gestoppt werden 30 | 31 | public static void setUserAgent(String ua) { 32 | // Useragent den der Benutzer vorgegeben hat 33 | userAgent = ua; 34 | } 35 | 36 | public static String getUserAgent() { 37 | if (userAgent == null) { 38 | return Const.USER_AGENT_DEFAULT; 39 | } else { 40 | return userAgent; 41 | } 42 | } 43 | 44 | /** 45 | * Damit kann "stop" gesetzt/rückgesetzt werden. 46 | * 47 | * @param set Bei true wird die Suche abgebrochen. 48 | */ 49 | public static void setStop(boolean set) { 50 | stop.set(set); 51 | } 52 | 53 | /** 54 | * Abfrage, ob ein Abbruch erfogte 55 | * 56 | * @return true/false 57 | */ 58 | public static boolean getStop() { 59 | return stop.get(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/de/mediathekview/mlib/tool/ProgressMonitorInputStream.java: -------------------------------------------------------------------------------- 1 | package de.mediathekview.mlib.tool; 2 | 3 | import java.io.FilterInputStream; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | 7 | /** User: Christian F. Date: 15.06.16 Time: 14:03 */ 8 | public class ProgressMonitorInputStream extends FilterInputStream { 9 | private final InputStreamProgressMonitor monitor; 10 | /** The number of bytes that can be read from the InputStream. */ 11 | private final long size; 12 | /** The number of bytes that have been read from the InputStream. */ 13 | private long bytesRead = 0; 14 | 15 | /** 16 | * Creates a FilterInputStream by assigning the argument in to the field 17 | * this.in so as to remember it for later use. 18 | * 19 | * @param in the underlying input stream, or null if this instance is to be created 20 | * without an underlying stream. 21 | * @param maxSize The maximum stream size 22 | * @param mon The progress monitor which should be used 23 | * @throws IOException Will be thrown if the max size isn't greater then one 24 | */ 25 | public ProgressMonitorInputStream(InputStream in, long maxSize, InputStreamProgressMonitor mon) 26 | throws IOException { 27 | super(in); 28 | monitor = mon; 29 | this.size = maxSize; 30 | if (size == 0) { 31 | throw new IOException("Size must be greater than zero!"); 32 | } 33 | } 34 | 35 | @Override 36 | public int read() throws IOException { 37 | final int read = super.read(); 38 | if (read != -1) { 39 | bytesRead++; 40 | if (monitor != null) monitor.progress(bytesRead, size); 41 | } 42 | return read; 43 | } 44 | 45 | @Override 46 | public int read(byte[] b) throws IOException { 47 | final int read = super.read(b); 48 | if (read != -1) { 49 | bytesRead += read; 50 | if (monitor != null) monitor.progress(bytesRead, size); 51 | } 52 | return read; 53 | } 54 | 55 | @Override 56 | public int read(byte[] b, int off, int len) throws IOException { 57 | final int read = super.read(b, off, len); 58 | if (read != -1) { 59 | bytesRead += read; 60 | if (monitor != null) monitor.progress(bytesRead, size); 61 | } 62 | return read; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/de/mediathekview/mlib/tool/Version.java: -------------------------------------------------------------------------------- 1 | package de.mediathekview.mlib.tool; 2 | 3 | public class Version { 4 | 5 | private int major; 6 | private int minor; 7 | private int patch; 8 | 9 | public Version(int major, int minor, int patch) { 10 | this.major = major; 11 | this.minor = minor; 12 | this.patch = patch; 13 | } 14 | 15 | public Version(String versionsstring) { 16 | String[] versions = versionsstring.split("\\."); 17 | if(versions.length == 3) { 18 | try { 19 | major = Integer.parseInt(versions[0]); 20 | minor = Integer.parseInt(versions[1]); 21 | patch = Integer.parseInt(versions[2]); 22 | } catch(NumberFormatException ex) { 23 | Log.errorLog(12344564, ex, "Fehler beim Parsen der Version '" + versionsstring + "'."); 24 | major = 0; 25 | minor = 0; 26 | patch = 0; 27 | } 28 | } 29 | } 30 | 31 | public Version() { 32 | major = 0; 33 | minor = 0; 34 | patch = 0; 35 | } 36 | 37 | public int getMajor() { 38 | return major; 39 | } 40 | 41 | public void setMajor(int major) { 42 | this.major = major; 43 | } 44 | 45 | public int getMinor() { 46 | return minor; 47 | } 48 | 49 | public void setMinor(int minor) { 50 | this.minor = minor; 51 | } 52 | 53 | public int getPatch() { 54 | return patch; 55 | } 56 | 57 | public void setPatch(int patch) { 58 | this.patch = patch; 59 | } 60 | 61 | /** 62 | * Gibt die Version als gewichtete Zahl zurück. 63 | * @return gewichtete Zahl als Integer 64 | */ 65 | public int toNumber() { 66 | return major * 100 + minor * 10 + patch; 67 | } 68 | 69 | /** 70 | * Gibt die Version als String zurück 71 | * @return String mit der Version 72 | */ 73 | @Override 74 | public String toString() { 75 | return String.format("%d.%d.%d", major, minor, patch); 76 | } 77 | 78 | /** 79 | * Nimmt ein Objekt vom Typ Version an und vergleicht ihn mit sich selbst 80 | * @param versionzwei Versionsobjekt welches zum vergleich rangezogen werden soll 81 | * @return 1 Version a ist größer, 0 Versionen sind gleich oder -1 Version a ist kleiner 82 | */ 83 | public int compare(Version versionzwei) { 84 | if(this.toNumber() < versionzwei.toNumber()) { 85 | return 1; 86 | } else if(this.toNumber() == versionzwei.toNumber()) { 87 | return 0; 88 | } else { 89 | return -1; 90 | } 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/de/mediathekview/mlib/tool/DatumFilm.java: -------------------------------------------------------------------------------- 1 | /* 2 | * MediathekView 3 | * Copyright (C) 2008 W. Xaver 4 | * W.Xaver[at]googlemail.com 5 | * http://zdfmediathk.sourceforge.net/ 6 | * 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 10 | * any later version. 11 | * 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. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | package de.mediathekview.mlib.tool; 21 | 22 | import java.text.SimpleDateFormat; 23 | import java.util.Date; 24 | import java.util.TimeZone; 25 | 26 | @SuppressWarnings("serial") 27 | public class DatumFilm extends Datum { 28 | // die Filme werden immer in der Zeitzone "Europe/Berlin" gesucht 29 | 30 | private final static SDF dateFormatter1 = new SDF("dd.MM.yyyy"); 31 | private final static SDF dateFormatter2 = new SDF("yyyy.MM.dd"); 32 | 33 | public DatumFilm() { 34 | super(); 35 | } 36 | 37 | public DatumFilm(long l) { 38 | super(l); 39 | } 40 | 41 | @Override 42 | public String toString() { 43 | if (this.getTime() == 0) { 44 | return ""; 45 | } else { 46 | return dateFormatter1.format(this); 47 | } 48 | } 49 | 50 | @Override 51 | public String toStringR() { 52 | if (this.getTime() == 0) { 53 | return dateFormatter2.format(new Date()); 54 | } else { 55 | return dateFormatter2.format(this); 56 | } 57 | } 58 | 59 | private static class SDF extends SimpleDateFormat { 60 | private final static TimeZone tz = TimeZone.getTimeZone("Europe/Berlin"); 61 | 62 | public SDF() { 63 | super(); 64 | this.setTimeZone(tz); 65 | } 66 | 67 | public SDF(String str) { 68 | super(str); 69 | this.setTimeZone(tz); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/de/mediathekview/mlib/tool/Datum.java: -------------------------------------------------------------------------------- 1 | /* 2 | * MediathekView 3 | * Copyright (C) 2008 W. Xaver 4 | * W.Xaver[at]googlemail.com 5 | * http://zdfmediathk.sourceforge.net/ 6 | * 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 10 | * any later version. 11 | * 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. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | package de.mediathekview.mlib.tool; 21 | 22 | import java.text.SimpleDateFormat; 23 | import java.util.Date; 24 | 25 | @SuppressWarnings("serial") 26 | public class Datum extends Date { 27 | private final static SimpleDateFormat dateFormatter1 = new SimpleDateFormat("dd.MM.yyyy"); 28 | private final static SimpleDateFormat dateFormatter2 = new SimpleDateFormat("yyyy.MM.dd"); 29 | 30 | public Datum() { 31 | super(); 32 | } 33 | 34 | public Datum(long l) { 35 | super(l); 36 | } 37 | 38 | @Override 39 | public String toString() { 40 | if (this.getTime() == 0) { 41 | return ""; 42 | } else { 43 | return dateFormatter1.format(this); 44 | } 45 | } 46 | 47 | public String toStringR() { 48 | if (this.getTime() == 0) { 49 | return dateFormatter2.format(new Date()); 50 | } else { 51 | return dateFormatter2.format(this); 52 | } 53 | } 54 | 55 | /** 56 | * Liefert den Betrag der Zeitdifferenz zu jetzt. 57 | * 58 | * @return Differenz in Sekunden. 59 | */ 60 | public int diffInSekunden() { 61 | final int ret = new Long((this.getTime() - new Datum().getTime()) / (1000)).intValue(); 62 | return Math.abs(ret); 63 | } 64 | 65 | /** 66 | * Liefert den BETRAG! der Zeitdifferenz zu jetzt. 67 | * 68 | * @return Differenz in Minuten. 69 | */ 70 | public int diffInMinuten() { 71 | return (diffInSekunden() / 60); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/de/mediathekview/mlib/tool/SingleInstance.java: -------------------------------------------------------------------------------- 1 | /* 2 | * MVSingleInstance 3 | * Copyright (C) 2013 CrystalPalace 4 | * crystalpalace1977@googlemail.com 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | package de.mediathekview.mlib.tool; 20 | 21 | import java.io.File; 22 | import java.io.RandomAccessFile; 23 | import java.nio.channels.FileChannel; 24 | import java.nio.channels.FileLock; 25 | 26 | /** 27 | * Prevents startup of multiple instances 28 | */ 29 | final public class SingleInstance { 30 | 31 | private FileChannel channel; 32 | private FileLock lock; 33 | 34 | public boolean isAppAlreadyActive() { 35 | try { 36 | //store lock in temp directory, will not survive reboot 37 | final File file = new File(System.getProperty("java.io.tmpdir"), "MediathekView.lock"); 38 | channel = new RandomAccessFile(file, "rw").getChannel(); 39 | 40 | lock = channel.tryLock(); 41 | if (lock == null) { 42 | //we could not acquire the lock because another app already holds it...we are already active 43 | closeLock(); 44 | return true; 45 | } 46 | 47 | //delete the lockfile when VM gets shut down 48 | Runtime.getRuntime().addShutdownHook(new Thread() { 49 | @Override 50 | public void run() { 51 | closeLock(); 52 | final boolean deleted = file.delete(); 53 | } 54 | }); 55 | return false; 56 | } catch (Exception e) { 57 | //if there is any sort of error, pretend we are already running... 58 | closeLock(); 59 | return true; 60 | } 61 | } 62 | 63 | private void closeLock() { 64 | try { 65 | lock.release(); 66 | channel.close(); 67 | } catch (Exception ignored) { 68 | } 69 | } 70 | } -------------------------------------------------------------------------------- /src/main/java/de/mediathekview/mlib/tool/DbgMsg.java: -------------------------------------------------------------------------------- 1 | /* 2 | * MediathekView 3 | * Copyright (C) 2014 W. Xaver 4 | * W.Xaver[at]googlemail.com 5 | * http://zdfmediathk.sourceforge.net/ 6 | * 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 10 | * any later version. 11 | * 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. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | package de.mediathekview.mlib.tool; 21 | 22 | import de.mediathekview.mlib.Config; 23 | 24 | public class DbgMsg { 25 | 26 | public static synchronized void print(String text) { 27 | print_(new String[]{text}); 28 | } 29 | 30 | public static synchronized void print(String[] text) { 31 | print_(text); 32 | } 33 | 34 | public static synchronized void printCl(String text) { 35 | printCl(new String[]{text}); 36 | } 37 | 38 | public static synchronized void printCl(String[] text) { 39 | printCl_(text); 40 | } 41 | 42 | private static void printCl_(String[] texte) { 43 | final Throwable t = new Throwable(); 44 | final StackTraceElement methodCaller = t.getStackTrace()[2]; 45 | final String klasse = methodCaller.getClassName() + "." + methodCaller.getMethodName(); 46 | String kl; 47 | try { 48 | kl = klasse; 49 | while (kl.contains(".")) { 50 | if (Character.isUpperCase(kl.charAt(0))) { 51 | break; 52 | } else { 53 | kl = kl.substring(kl.indexOf(".") + 1); 54 | } 55 | } 56 | } catch (Exception ignored) { 57 | kl = klasse; 58 | } 59 | 60 | if (Config.debug) { 61 | final String z = "||"; 62 | System.out.println(z + " " + kl); 63 | for (String text : texte) { 64 | System.out.println(z + " " + text); 65 | } 66 | System.out.println(""); 67 | } 68 | } 69 | 70 | private static void print_(String[] texte) { 71 | if (Config.debug) { 72 | final String z = "||"; 73 | for (String text : texte) { 74 | System.out.println(z + " " + text); 75 | } 76 | } 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/de/mediathekview/mlib/tool/ReplaceList.java: -------------------------------------------------------------------------------- 1 | /* 2 | * MediathekView 3 | * Copyright (C) 2014 W. Xaver 4 | * W.Xaver[at]googlemail.com 5 | * http://zdfmediathk.sourceforge.net/ 6 | * 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 10 | * any later version. 11 | * 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. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | package de.mediathekview.mlib.tool; 21 | 22 | import java.io.File; 23 | import java.util.Iterator; 24 | import java.util.LinkedList; 25 | 26 | public final class ReplaceList { 27 | 28 | public final static String REPLACELIST = "Ersetzungstabelle"; 29 | public final static String VON = "von"; 30 | public final static int VON_NR = 0; 31 | public final static String NACH = "nach"; 32 | public final static int NACH_NR = 1; 33 | public final static String[] COLUMN_NAMES = {VON, NACH}; 34 | public static final int MAX_ELEM = 2; 35 | 36 | public static LinkedList list = new LinkedList<>(); 37 | 38 | public static void init() { 39 | list.clear(); 40 | list.add(new String[]{" ", "_"}); 41 | } 42 | 43 | public static String replace(String strCheck, boolean pfad) { 44 | Iterator it = list.iterator(); 45 | while (it.hasNext()) { 46 | String[] strReplace = it.next(); 47 | 48 | // hat der Nutzer als Suchbegriff "leer" eingegeben, dann weg damit 49 | if (strReplace[0].isEmpty()) { 50 | it.remove(); 51 | Listener.notify(Listener.EREIGNIS_REPLACELIST_CHANGED, ReplaceList.class.getSimpleName()); 52 | continue; 53 | } 54 | 55 | // bei Pfaden darf / oder \ natürlich nicht entfernt werden 56 | if (pfad && strReplace[0].equals(File.separator)) { 57 | continue; 58 | } 59 | 60 | strCheck = strCheck.replace(strReplace[0], strReplace[1]); 61 | } 62 | return strCheck; 63 | } 64 | 65 | public static boolean check() { 66 | for (int i = 0; i < list.size(); ++i) { 67 | String[] is = list.get(i); 68 | for (int k = i + 1; k < list.size(); ++k) { 69 | String[] ks = list.get(k); 70 | if (is[1].contains(ks[0])) { 71 | return true; 72 | } 73 | } 74 | } 75 | return false; 76 | } 77 | 78 | public static int up(int idx, boolean up) { 79 | String[] replace = list.remove(idx); 80 | int neu = idx; 81 | if (up) { 82 | if (neu > 0) { 83 | --neu; 84 | } 85 | } else if (neu < list.size()) { 86 | ++neu; 87 | } 88 | list.add(neu, replace); 89 | return neu; 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/test/java/de/mediathekview/mlib/daten/ListeFilmeTest.java: -------------------------------------------------------------------------------- 1 | package de.mediathekview.mlib.daten; 2 | 3 | import de.mediathekview.mlib.Const; 4 | import org.junit.Test; 5 | 6 | import static org.junit.Assert.assertEquals; 7 | 8 | public class ListeFilmeTest { 9 | 10 | @Test 11 | public void testUpdateListeIndex() { 12 | ListeFilme list = new ListeFilme(); 13 | list.add(createTestFilm(Const.ZDF, "ZDFinfo Doku", "Ermittler! Fatale Verbindungen (S2025/E05)", "https://nrodlzdf-a.akamaihd.net/none/zdf/25/03/250303_ermittler_fatale_verbindungen_inf/1/250303_ermittler_fatale_verbindungen_inf_3360k_p36v17.mp4")); 14 | ListeFilme listOld = new ListeFilme(); 15 | listOld.add(createTestFilm(Const.ZDF, "ZDFinfo Doku", "Ermittler! Fatale Verbindungen (S2025/E05)", "https://nrodlzdf-a.akamaihd.net/none/zdf/25/03/250303_ermittler_fatale_verbindungen_inf/1/250303_ermittler_fatale_verbindungen_inf_3360k_p36v17.mp4")); 16 | listOld.add(createTestFilm(Const.ZDF, "ZDFinfo Doku", "identische Url nicht hinzugefügt", "https://nrodlzdf-a.akamaihd.net/none/zdf/25/03/250303_ermittler_fatale_verbindungen_inf/1/250303_ermittler_fatale_verbindungen_inf_3360k_p36v17.mp4")); 17 | listOld.add(createTestFilm(Const.ZDF, "ZDFinfo Doku", "gleiche Url mit anderen Host nicht hinzugefügt", "https://rodlzdf-a.akamaihd.net/none/zdf/25/03/250303_ermittler_fatale_verbindungen_inf/1/250303_ermittler_fatale_verbindungen_inf_3360k_p36v17.mp4")); 18 | listOld.add(createTestFilm(Const.ZDF, "ZDFinfo Doku", "andere Url hinzugefügt", "https://nrodlzdf-a.akamaihd.net/none/zdf/25/02/250303_ermittler_fatale_verbindungen_inf/1/250303_ermittler_fatale_verbindungen_inf_3360k_p36v17.mp4")); 19 | 20 | list.updateListe(listOld, true, false); 21 | assertEquals(2, list.size()); 22 | } 23 | @Test 24 | public void testUpdateListeUrl() { 25 | ListeFilme list = new ListeFilme(); 26 | list.add(createTestFilm(Const.ZDF, "ZDFinfo Doku", "Ermittler! Fatale Verbindungen (S2025/E05)", "https://nrodlzdf-a.akamaihd.net/none/zdf/25/03/250303_ermittler_fatale_verbindungen_inf/1/250303_ermittler_fatale_verbindungen_inf_3360k_p36v17.mp4")); 27 | ListeFilme listOld = new ListeFilme(); 28 | listOld.add(createTestFilm(Const.ZDF, "ZDFinfo Doku", "Ermittler! Fatale Verbindungen (S2025/E05)", "https://nrodlzdf-a.akamaihd.net/none/zdf/25/03/250303_ermittler_fatale_verbindungen_inf/1/250303_ermittler_fatale_verbindungen_inf_3360k_p36v17.mp4")); 29 | listOld.add(createTestFilm(Const.ZDF, "ZDFinfo Doku", "Ermittler! Fatale Verbindungen (S2025/E05)", "https://nrodlzdf-a.akamaihd.net/none/zdf/25/03/250303_ermittler_fatale_verbindungen_inf/1/250303_ermittler_fatale_verbindungen_inf_3360k_p36v17.mp4")); 30 | listOld.add(createTestFilm(Const.ZDF, "ZDFinfo Doku", "Ermittler! Fatale Verbindungen (S2025/E05)", "https://nrodlzdf-a.akamaihd.net/none/zdf/25/03/250303_ermittler_fatale_verbindungen_inf/1/250303_ermittler_fatale_verbindungen_inf_3360k_p36v17.mp4")); 31 | listOld.add(createTestFilm(Const.ZDF, "ZDFinfo Doku", "andere Episode", "https://nrodlzdf-a.akamaihd.net/none/zdf/25/02/250303_ermittler_fatale_verbindungen_inf/1/250303_ermittler_fatale_verbindungen_inf_3360k_p36v17.mp4")); 32 | 33 | list.updateListe(listOld, false, false); 34 | assertEquals(2, list.size()); 35 | } 36 | 37 | private static DatenFilm createTestFilm(String sender, String topic, String title, 38 | String filmUrl) { 39 | DatenFilm film = new DatenFilm(sender, topic, "url", title, filmUrl, "", "", "", 12, 40 | ""); 41 | film.arr[DatenFilm.FILM_GROESSE] = "10"; 42 | 43 | return film; 44 | } 45 | 46 | } -------------------------------------------------------------------------------- /src/main/java/de/mediathekview/mlib/tool/MSInputStream.java: -------------------------------------------------------------------------------- 1 | /* 2 | * MediathekView 3 | * Copyright (C) 2013 W. Xaver 4 | * W.Xaver[at]googlemail.com 5 | * http://zdfmediathk.sourceforge.net/ 6 | * 7 | * org.apache.hadoop.tools.util.ThrottledInputStream 8 | * unter http://www.apache.org/licenses/LICENSE-2.0 9 | * diente als Vorlage 10 | * 11 | * This program is free software: you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation, either version 3 of the License, or 14 | * any later version. 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see . 23 | */ 24 | package de.mediathekview.mlib.tool; 25 | 26 | import java.io.IOException; 27 | import java.io.InputStream; 28 | 29 | import de.mediathekview.mlib.Config; 30 | 31 | public class MSInputStream extends InputStream { 32 | 33 | private final InputStream iStream; 34 | private long maxBytePerSec = 0; 35 | private final long startZeit = System.currentTimeMillis(); 36 | private long bytesGelesen = 0; 37 | private long gesamtVerpennt = 0; 38 | private static final long warten_ms = 50; 39 | 40 | public MSInputStream(InputStream in) { 41 | iStream = in; 42 | maxBytePerSec = Config.bandbreite; 43 | if (maxBytePerSec < 0) { 44 | maxBytePerSec = 0; 45 | } 46 | } 47 | 48 | @Override 49 | public int read() throws IOException { 50 | pause(); 51 | int einByte = iStream.read(); 52 | if (einByte != -1) { 53 | bytesGelesen++; 54 | } 55 | return einByte; 56 | } 57 | 58 | @Override 59 | public int read(byte[] b) throws IOException { 60 | pause(); 61 | int anzByte = iStream.read(b); 62 | if (anzByte != -1) { 63 | bytesGelesen += anzByte; 64 | } 65 | return anzByte; 66 | } 67 | 68 | private synchronized void pause() throws IOException { 69 | if (maxBytePerSec == 0) { 70 | return; 71 | } 72 | if (getBandbreite() > maxBytePerSec) { 73 | try { 74 | wait(warten_ms); 75 | gesamtVerpennt += warten_ms; 76 | } catch (InterruptedException ex) { 77 | Log.errorLog(591237096, ex); 78 | } 79 | } 80 | } 81 | 82 | public long getBandbreite() { 83 | long dauer = (System.currentTimeMillis() - startZeit) / 1000; 84 | if (dauer == 0) { 85 | return bytesGelesen; 86 | } else { 87 | return bytesGelesen / dauer; 88 | } 89 | } 90 | 91 | public long getTotalSleepTime() { 92 | return gesamtVerpennt; 93 | } 94 | 95 | @Override 96 | public String toString() { 97 | return "Download: " 98 | + "gelesen: " + (bytesGelesen > 0 ? bytesGelesen / 1000 : 0) + " kB, " 99 | + "Bandbreite: " + (getBandbreite() > 0 ? getBandbreite() / 1000 : 0) + " kB/s " 100 | + ", Wartezeit: " + (gesamtVerpennt > 0 ? gesamtVerpennt / 1000 : 0) + " s"; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/de/mediathekview/mlib/Const.java: -------------------------------------------------------------------------------- 1 | /* 2 | * MediathekView 3 | * Copyright (C) 2008 W. Xaver 4 | * W.Xaver[at]googlemail.com 5 | * http://zdfmediathk.sourceforge.net/ 6 | * 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 10 | * any later version. 11 | * 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. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | package de.mediathekview.mlib; 21 | 22 | import de.mediathekview.mlib.tool.Functions; 23 | 24 | public class Const { 25 | 26 | @Deprecated public static final String VERSION = "13"; 27 | public static final String VERSION_FILMLISTE = "3"; 28 | public static final String PROGRAMMNAME = "MSearch"; 29 | public static final String USER_AGENT_DEFAULT = Const.PROGRAMMNAME + Functions.getProgVersionString(); 30 | // MediathekView URLs 31 | public static final String ADRESSE_FILMLISTEN_SERVER_DIFF = "http://res.mediathekview.de/diff.xml"; 32 | public static final String ADRESSE_FILMLISTEN_SERVER_AKT = "http://res.mediathekview.de/akt.xml"; 33 | // Dateien/Verzeichnisse 34 | public static final int STRING_BUFFER_START_BUFFER = 8 * 1024 * 8; // 8 KiB 35 | public static final String FORMAT_ZIP = ".zip"; 36 | public static final String FORMAT_XZ = ".xz"; 37 | public static final String RTMP_PRTOKOLL = "rtmp"; 38 | public static final String RTMP_FLVSTREAMER = "-r "; 39 | public static final int ALTER_FILMLISTE_SEKUNDEN_FUER_AUTOUPDATE = 3 * 60 * 60; // beim Start des Programms wir die Liste geladen wenn sie älter ist als .. 40 | public static final String TIME_MAX_AGE_FOR_DIFF = "09"; // Uhrzeit ab der die Diffliste alle Änderungen abdeckt, die Filmliste darf also nicht vor xx erstellt worden sein 41 | public static final int MAX_BESCHREIBUNG = 400; // max länge der Beschreibung in Zeichen -> mehr gibts aber jetzt nicht mehr! 42 | 43 | public static final String DREISAT = "3Sat"; 44 | public static final String ARD = "ARD"; 45 | public static final String ARD_ALPHA = "ARD-alpha"; 46 | public static final String ARTE_DE = "ARTE.DE"; 47 | public static final String ARTE_FR = "ARTE.FR"; 48 | public static final String BR = "BR"; 49 | public static final String DW = "DW"; 50 | public static final String HR = "HR"; 51 | public static final String KIKA = "KiKA"; 52 | public static final String MDR = "MDR"; 53 | public static final String NDR = "NDR"; 54 | public static final String ORF = "ORF"; 55 | public static final String ONE = "ONE"; 56 | public static final String PHOENIX = "PHOENIX"; 57 | public static final String RBB = "RBB"; 58 | public static final String RBTV = "rbtv"; 59 | public static final String SR = "SR"; 60 | public static final String SRF = "SRF"; 61 | public static final String SRF_PODCAST = "SRF.Podcast"; 62 | public static final String SWR = "SWR"; 63 | public static final String TAGESSCHAU24 = "tagesschau24"; 64 | public static final String WDR = "WDR"; 65 | public static final String ZDF = "ZDF"; 66 | public static final String ZDF_INFO = "ZDFinfo"; 67 | public static final String ZDF_NEO = "ZDFneo"; 68 | public static final String ZDF_TIVI = "ZDF-tivi"; 69 | 70 | public static final String[] SENDER = {DREISAT, ARD, ARTE_DE, ARTE_FR, BR, DW, HR, KIKA, MDR, NDR, ORF, PHOENIX, RBB, SR, SRF, SRF_PODCAST, SWR, WDR, ZDF, ZDF_TIVI}; 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/de/mediathekview/mlib/tool/Hash.java: -------------------------------------------------------------------------------- 1 | package de.mediathekview.mlib.tool; 2 | 3 | import java.nio.ByteBuffer; 4 | import java.security.MessageDigest; 5 | import java.security.NoSuchAlgorithmException; 6 | import java.util.Arrays; 7 | 8 | public final class Hash { 9 | private final MessageDigest md; 10 | private byte[] bytes; 11 | 12 | public Hash() { 13 | try { 14 | md = MessageDigest.getInstance("MD5"); 15 | } catch (NoSuchAlgorithmException e) { 16 | throw new IllegalStateException("MD5 algorithm not found", e); 17 | } 18 | } 19 | 20 | public Hash(byte[] b) { 21 | this(); 22 | update(b); 23 | } 24 | 25 | public Hash(byte[] b, int off, int len) { 26 | this(); 27 | update(b, off, len); 28 | } 29 | 30 | public Hash(ByteBuffer bb) { 31 | this(); 32 | update(bb); 33 | } 34 | 35 | public Hash(String s) { 36 | this(); 37 | update(s); 38 | } 39 | 40 | public Hash(char c) { 41 | this(); 42 | update(c); 43 | } 44 | 45 | public Hash(short s) { 46 | this(); 47 | update(s); 48 | } 49 | 50 | public Hash(int i) { 51 | this(); 52 | update(i); 53 | } 54 | 55 | public Hash(long l) { 56 | this(); 57 | update(l); 58 | } 59 | 60 | public Hash(float f) { 61 | this(); 62 | update(f); 63 | } 64 | 65 | public Hash(double d) { 66 | this(); 67 | update(d); 68 | } 69 | 70 | public Hash update(byte b) { 71 | checkNotFinished(); 72 | md.update(b); 73 | return this; 74 | } 75 | 76 | public Hash update(byte[] b) { 77 | return update(b, 0, b.length); 78 | } 79 | 80 | public Hash update(byte[] b, int off, int len) { 81 | checkNotFinished(); 82 | md.update(b, off, len); 83 | return this; 84 | } 85 | 86 | public Hash update(ByteBuffer bb) { 87 | checkNotFinished(); 88 | md.update(bb); 89 | return this; 90 | } 91 | 92 | public Hash update(String s) { 93 | if (s != null) { 94 | for (int i = 0; i < s.length(); i++) { 95 | update(s.charAt(i)); 96 | } 97 | } 98 | return this; 99 | } 100 | 101 | public Hash update(short s) { 102 | return update((byte) (s >> 8)).update((byte) s); 103 | } 104 | 105 | public Hash update(char c) { 106 | return update((short) c); 107 | } 108 | 109 | public Hash update(int i) { 110 | return update((short) (i >> 16)).update((short) i); 111 | } 112 | 113 | public Hash update(long l) { 114 | return update((int) (l >> 32)).update((int) l); 115 | } 116 | 117 | public Hash update(float f) { 118 | return update(Float.floatToRawIntBits(f)); 119 | } 120 | 121 | public Hash update(double d) { 122 | return update(Double.doubleToRawLongBits(d)); 123 | } 124 | 125 | public Hash finish() { 126 | bytes = md.digest(); 127 | return this; 128 | } 129 | 130 | public void reset() { 131 | bytes = null; 132 | } 133 | 134 | public byte[] getBytes() { 135 | ensureFinished(); 136 | return bytes; 137 | } 138 | 139 | public String toHexString() { 140 | ensureFinished(); 141 | StringBuilder sb = new StringBuilder(bytes.length * 2); 142 | for (byte b : bytes) { 143 | sb.append(Character.forDigit((b >> 8) & 0xf, 16)); 144 | sb.append(Character.forDigit(b & 0xf, 16)); 145 | } 146 | return sb.toString(); 147 | } 148 | 149 | @Override 150 | public boolean equals(Object obj) { 151 | if (this == obj) 152 | return true; 153 | if (obj == null || !(obj instanceof Hash)) 154 | return false; 155 | 156 | Hash hash = (Hash) obj; 157 | return Arrays.equals(getBytes(), hash.getBytes()); 158 | } 159 | 160 | @Override 161 | public int hashCode() { 162 | byte[] b = getBytes(); 163 | return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]; 164 | } 165 | 166 | @Override 167 | public String toString() { 168 | return toHexString(); 169 | } 170 | 171 | private void checkNotFinished() { 172 | if (bytes != null) { 173 | throw new IllegalStateException("Hash must be reset before resuse"); 174 | } 175 | } 176 | 177 | private void ensureFinished() { 178 | if (bytes == null) 179 | finish(); 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | 20 | import java.net.*; 21 | import java.io.*; 22 | import java.nio.channels.*; 23 | import java.util.Properties; 24 | 25 | public class MavenWrapperDownloader { 26 | 27 | /** 28 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 29 | */ 30 | private static final String DEFAULT_DOWNLOAD_URL = 31 | "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; 32 | 33 | /** 34 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 35 | * use instead of the default one. 36 | */ 37 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 38 | ".mvn/wrapper/maven-wrapper.properties"; 39 | 40 | /** 41 | * Path where the maven-wrapper.jar will be saved to. 42 | */ 43 | private static final String MAVEN_WRAPPER_JAR_PATH = 44 | ".mvn/wrapper/maven-wrapper.jar"; 45 | 46 | /** 47 | * Name of the property which should be used to override the default download url for the wrapper. 48 | */ 49 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 50 | 51 | public static void main(String args[]) { 52 | System.out.println("- Downloader started"); 53 | File baseDirectory = new File(args[0]); 54 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 55 | 56 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 57 | // wrapperUrl parameter. 58 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 59 | String url = DEFAULT_DOWNLOAD_URL; 60 | if(mavenWrapperPropertyFile.exists()) { 61 | FileInputStream mavenWrapperPropertyFileInputStream = null; 62 | try { 63 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 64 | Properties mavenWrapperProperties = new Properties(); 65 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 66 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 67 | } catch (IOException e) { 68 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 69 | } finally { 70 | try { 71 | if(mavenWrapperPropertyFileInputStream != null) { 72 | mavenWrapperPropertyFileInputStream.close(); 73 | } 74 | } catch (IOException e) { 75 | // Ignore ... 76 | } 77 | } 78 | } 79 | System.out.println("- Downloading from: : " + url); 80 | 81 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 82 | if(!outputFile.getParentFile().exists()) { 83 | if(!outputFile.getParentFile().mkdirs()) { 84 | System.out.println( 85 | "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 86 | } 87 | } 88 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 89 | try { 90 | downloadFileFromURL(url, outputFile); 91 | System.out.println("Done"); 92 | System.exit(0); 93 | } catch (Throwable e) { 94 | System.out.println("- Error downloading"); 95 | e.printStackTrace(); 96 | System.exit(1); 97 | } 98 | } 99 | 100 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 101 | URL website = new URL(urlString); 102 | ReadableByteChannel rbc; 103 | rbc = Channels.newChannel(website.openStream()); 104 | FileOutputStream fos = new FileOutputStream(destination); 105 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 106 | fos.close(); 107 | rbc.close(); 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /src/main/java/de/mediathekview/mlib/tool/AbsoluteFromRelativeURI.java: -------------------------------------------------------------------------------- 1 | package de.mediathekview.mlib.tool; 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | /* 21 | * $Id: SystemIDResolver.java 468655 2006-10-28 07:12:06Z minchau $ 22 | */ 23 | 24 | import java.io.File; 25 | 26 | /** 27 | * This class is used to resolve relative URIs and SystemID 28 | * strings into absolute URIs. 29 | * 30 | *

31 | * This is a generic utility for resolving URIs, other than the 32 | * fact that it's declared to throw TransformerException. Please 33 | * see code comments for details on how resolution is performed.

34 | * 35 | */ 36 | public class AbsoluteFromRelativeURI { 37 | 38 | /** 39 | * Get an absolute URI from a given relative URI (local path). 40 | * 41 | *

42 | * The relative URI is a local filesystem path. The path can be 43 | * absolute or relative. If it is a relative path, it is resolved relative 44 | * to the system property "user.dir" if it is available; if not (i.e. in an 45 | * Applet perhaps which throws SecurityException) then we just return the 46 | * relative path. The space and backslash characters are also replaced to 47 | * generate a good absolute URI.

48 | * 49 | * @param localPath The relative URI to resolve 50 | * 51 | * @return Resolved absolute URI 52 | */ 53 | public static String getAbsoluteURIFromRelative(String localPath) { 54 | if (localPath == null || localPath.length() == 0) { 55 | return ""; 56 | } 57 | 58 | // If the local path is a relative path, then it is resolved against 59 | // the "user.dir" system property. 60 | String absolutePath = localPath; 61 | if (!isAbsolutePath(localPath)) { 62 | try { 63 | absolutePath = getAbsolutePathFromRelativePath(localPath); 64 | } // user.dir not accessible from applet 65 | catch (SecurityException se) { 66 | return "file:" + localPath; 67 | } 68 | } 69 | 70 | String urlString; 71 | if (null != absolutePath) { 72 | if (absolutePath.startsWith(File.separator)) { 73 | urlString = "file://" + absolutePath; 74 | } else { 75 | urlString = "file:///" + absolutePath; 76 | } 77 | } else { 78 | urlString = "file:" + localPath; 79 | } 80 | 81 | return replaceChars(urlString); 82 | } 83 | 84 | /** 85 | * Return an absolute path from a relative path. 86 | * 87 | * @param relativePath A relative path 88 | * @return The absolute path 89 | */ 90 | private static String getAbsolutePathFromRelativePath(String relativePath) { 91 | return new File(relativePath).getAbsolutePath(); 92 | } 93 | 94 | /** 95 | * Return true if the local path is an absolute path. 96 | * 97 | * @param systemId The path string 98 | * @return true if the path is absolute 99 | */ 100 | public static boolean isAbsolutePath(String systemId) { 101 | if (systemId == null) { 102 | return false; 103 | } 104 | final File file = new File(systemId); 105 | return file.isAbsolute(); 106 | 107 | } 108 | 109 | /** 110 | * Replace spaces with "%20" and backslashes with forward slashes in 111 | * the input string to generate a well-formed URI string. 112 | * 113 | * @param str The input string 114 | * @return The string after conversion 115 | */ 116 | private static String replaceChars(String str) { 117 | StringBuilder buf = new StringBuilder(str); 118 | int length = buf.length(); 119 | for (int i = 0; i < length; i++) { 120 | char currentChar = buf.charAt(i); 121 | // Replace space with "%20" 122 | if (currentChar == ' ') { 123 | buf.setCharAt(i, '%'); 124 | buf.insert(i + 1, "20"); 125 | length = length + 2; 126 | i = i + 2; 127 | } // Replace backslash with forward slash 128 | else if (currentChar == '\\') { 129 | buf.setCharAt(i, '/'); 130 | } 131 | } 132 | 133 | return buf.toString(); 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /src/main/java/de/mediathekview/mlib/tool/Listener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * MediathekView 3 | * Copyright (C) 2008 W. Xaver 4 | * W.Xaver[at]googlemail.com 5 | * http://zdfmediathk.sourceforge.net/ 6 | * 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 10 | * any later version. 11 | * 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. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | package de.mediathekview.mlib.tool; 21 | 22 | import java.util.EventListener; 23 | 24 | import javax.swing.SwingUtilities; 25 | import javax.swing.event.EventListenerList; 26 | 27 | public class Listener implements EventListener { 28 | 29 | public static final int EREIGNIS_LISTE_HISTORY_GEAENDERT = 1; 30 | public static final int EREIGNIS_LISTE_PSET = 2; 31 | 32 | public static final int EREIGNIS_ANZAHL_DOWNLOADS = 6; 33 | public static final int EREIGNIS_LISTE_URL_FILMLISTEN = 7; 34 | public static final int EREIGNIS_LISTE_FILMLISTEN_SERVER = 8; 35 | public static final int EREIGNIS_LISTE_DOWNLOADS = 9; 36 | public static final int EREIGNIS_LISTE_ABOS = 10; 37 | public static final int EREIGNIS_LISTE_ERLEDIGTE_ABOS = 11; 38 | public static final int EREIGNIS_ART_IMPORT_FILMLISTE = 12; 39 | public static final int EREIGNIS_ART_DOWNLOAD_PROZENT = 13; 40 | public static final int EREIGNIS_START_EVENT = 14; 41 | public static final int EREIGNIS_START_EVENT_BUTTON = 15; 42 | 43 | public static final int EREIGNIS_PROGRAMM_OEFFNEN = 16; 44 | public static final int EREIGNIS_MEDIATHEKGUI_ORG_TITEL = 17; 45 | public static final int EREIGNIS_MEDIATHEKGUI_PROGRAMM_AKTUELL = 18; 46 | public static final int EREIGNIS_MEDIATHEKGUI_UPDATE_VERFUEGBAR = 19; 47 | public static final int EREIGNIS_PANEL_FILTER_ANZEIGEN = 20; 48 | public static final int EREIGNIS_PANEL_DOWNLOAD_FILTER_ANZEIGEN = 21; 49 | public static final int EREIGNIS_PANEL_ABO_FILTER_ANZEIGEN = 22; 50 | public static final int EREIGNIS_FILM_BESCHREIBUNG_ANZEIGEN = 23; 51 | public static final int EREIGNIS_DOWNLOAD_BESCHREIBUNG_ANZEIGEN = 24; 52 | 53 | public static final int EREIGNIS_SUCHFELD_FOCUS_SETZEN = 26; 54 | public static final int EREIGNIS_BLACKLIST_AUCH_FUER_ABOS = 27; 55 | public static final int EREIGNIS_BANDBREITE = 28; 56 | public static final int EREIGNIS_REIHENFOLGE_DOWNLOAD = 29; 57 | public static final int EREIGNIS_TIMER = 30; 58 | public static final int EREIGNIS_GEO = 31; 59 | public static final int EREIGNIS_BESCHREIBUNG = 32; 60 | public static final int EREIGNIS_RESET_INTERRUPT = 33; 61 | public static final int EREIGNIS_FILTER_ANZAHL = 34; 62 | public static final int EREIGNIS_TRAYICON = 35; 63 | public static final int EREIGNIS_FONT = 36; 64 | public static final int EREIGNIS_DIALOG_MEDIA_DB = 37; 65 | public static final int EREIGNIS_REPLACELIST_CHANGED = 38; 66 | public static final int EREIGNIS_BLACKLIST_GEAENDERT = 39; 67 | public static final int EREIGNIS_BLACKLIST_START_GEAENDERT = 40; 68 | public static final int EREIGNIS_MEDIA_DB_START = 41; 69 | public static final int EREIGNIS_MEDIA_DB_STOP = 42; 70 | public static final int EREIGNIS_TABS_TOP = 43; 71 | public static final int EREIGNIS_TOOLBAR_VIS = 44; 72 | public static final int EREIGNIS_TOOLBAR_BUTTON_KLEIN = 45; 73 | public static final int EREIGNIS_BANDWIDTH_MONITOR = 46; 74 | 75 | public int[] mvEreignis = {-1}; 76 | public String klasse = ""; 77 | private static EventListenerList listeners = new EventListenerList(); 78 | 79 | public Listener(int eereignis, String kklasse) { 80 | mvEreignis = new int[]{eereignis}; 81 | klasse = kklasse; 82 | } 83 | 84 | public Listener(int[] eereignis, String kklasse) { 85 | mvEreignis = eereignis; 86 | klasse = kklasse; 87 | } 88 | 89 | public void ping() { 90 | } 91 | 92 | public static synchronized void addListener(Listener listener) { 93 | listeners.add(Listener.class, listener); 94 | } 95 | 96 | public static synchronized void notify(int ereignis, String klasse) { 97 | for (Listener l : listeners.getListeners(Listener.class)) { 98 | for (int er : l.mvEreignis) { 99 | if (er == ereignis) { 100 | if (!l.klasse.equals(klasse)) { 101 | // um einen Kreislauf zu verhindern 102 | try { 103 | l.pingen(); 104 | } catch (Exception ex) { 105 | DbgMsg.print("ListenerMediathekView.notifyMediathekListener: " + ex.getMessage()); 106 | } 107 | } 108 | } 109 | } 110 | } 111 | } 112 | 113 | private void pingen() { 114 | try { 115 | // if (SwingUtilities.isEventDispatchThread()) { 116 | // ping(); 117 | // } else { 118 | SwingUtilities.invokeLater(this::ping); 119 | // } 120 | } catch (Exception ex) { 121 | Log.errorLog(698989743, ex); 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 50 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" 124 | FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO ( 125 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 126 | ) 127 | 128 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 129 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 130 | if exist %WRAPPER_JAR% ( 131 | echo Found %WRAPPER_JAR% 132 | ) else ( 133 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 134 | echo Downloading from: %DOWNLOAD_URL% 135 | powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')" 136 | echo Finished downloading %WRAPPER_JAR% 137 | ) 138 | @REM End of extension 139 | 140 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 141 | if ERRORLEVEL 1 goto error 142 | goto end 143 | 144 | :error 145 | set ERROR_CODE=1 146 | 147 | :end 148 | @endlocal & set ERROR_CODE=%ERROR_CODE% 149 | 150 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 151 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 152 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 153 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 154 | :skipRcPost 155 | 156 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 157 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 158 | 159 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 160 | 161 | exit /B %ERROR_CODE% 162 | -------------------------------------------------------------------------------- /src/main/java/de/mediathekview/mlib/tool/Duration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * MediathekView 3 | * Copyright (C) 2008 W. Xaver 4 | * W.Xaver[at]googlemail.com 5 | * http://zdfmediathk.sourceforge.net/ 6 | * 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 10 | * any later version. 11 | * 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. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | package de.mediathekview.mlib.tool; 21 | 22 | import java.text.DecimalFormat; 23 | import java.util.ArrayList; 24 | import java.util.Date; 25 | 26 | 27 | public class Duration { 28 | 29 | private static Date stopZeitStatic = new Date(System.currentTimeMillis()); 30 | private static final DecimalFormat DF = new DecimalFormat("###,##0.00"); 31 | private static int sum = 0; 32 | private static final ArrayList COUNTER_LIST = new ArrayList<>(); 33 | 34 | private static class Counter { 35 | 36 | String text; 37 | int count; 38 | long time; 39 | Date start; 40 | 41 | public Counter(String nr, int count) { 42 | this.text = nr; 43 | this.count = count; 44 | start = new Date(); 45 | } 46 | } 47 | 48 | public static synchronized void counterStart(String text) { 49 | Counter cc = null; 50 | for (Counter c : COUNTER_LIST) { 51 | if (c.text.equals(text)) { 52 | cc = c; 53 | break; 54 | } 55 | } 56 | if (cc == null) { 57 | COUNTER_LIST.add(new Counter(text, 0)); 58 | } else { 59 | cc.start = new Date(); 60 | } 61 | } 62 | 63 | public static synchronized void counterStop(String text) { 64 | final Throwable t = new Throwable(); 65 | final StackTraceElement methodCaller = t.getStackTrace()[2]; 66 | final String klasse = methodCaller.getClassName() + "." + methodCaller.getMethodName(); 67 | String kl; 68 | try { 69 | kl = klasse; 70 | while (kl.contains(".")) { 71 | if (Character.isUpperCase(kl.charAt(0))) { 72 | break; 73 | } else { 74 | kl = kl.substring(kl.indexOf(".") + 1); 75 | } 76 | } 77 | } catch (Exception ignored) { 78 | kl = klasse; 79 | } 80 | 81 | String extra = ""; 82 | Counter cc = null; 83 | for (Counter c : COUNTER_LIST) { 84 | if (c.text.equals(text)) { 85 | cc = c; 86 | break; 87 | } 88 | } 89 | if (cc != null) { 90 | cc.count++; 91 | try { 92 | final long time = Math.round(new Date().getTime() - cc.start.getTime()); 93 | cc.time += time; 94 | extra = cc.text + " Anzahl: " + cc.count + " Dauer: " + roundDuration(time); 95 | } catch (Exception ex) { 96 | } 97 | } 98 | 99 | staticPing(kl, text, extra); 100 | } 101 | 102 | public static synchronized void printCounter() { 103 | int max = 0; 104 | for (Counter c : COUNTER_LIST) { 105 | if (c.text.length() > max) { 106 | max = c.text.length(); 107 | } 108 | } 109 | max++; 110 | for (Counter c : COUNTER_LIST) { 111 | while (c.text.length() < max) { 112 | c.text = c.text + " "; 113 | } 114 | } 115 | 116 | System.out.println(""); 117 | System.out.println(""); 118 | System.out.println("#################################################################"); 119 | for (Counter c : COUNTER_LIST) { 120 | System.out.println(c.text + " Anzahl: " + c.count + " Gesamtdauer: " + roundDuration(c.time)); 121 | } 122 | System.out.println("#################################################################"); 123 | System.out.println(""); 124 | } 125 | 126 | public synchronized static void staticPing(String text) { 127 | final Throwable t = new Throwable(); 128 | final StackTraceElement methodCaller = t.getStackTrace()[2]; 129 | final String klasse = methodCaller.getClassName() + "." + methodCaller.getMethodName(); 130 | String kl; 131 | try { 132 | kl = klasse; 133 | while (kl.contains(".")) { 134 | if (Character.isUpperCase(kl.charAt(0))) { 135 | break; 136 | } else { 137 | kl = kl.substring(kl.indexOf(".") + 1); 138 | } 139 | } 140 | } catch (Exception ignored) { 141 | kl = klasse; 142 | } 143 | staticPing(kl, text, ""); 144 | } 145 | 146 | private static void staticPing(String klasse, String text, String extra) { 147 | Date now = new Date(System.currentTimeMillis()); 148 | long sekunden; 149 | try { 150 | sekunden = Math.round(now.getTime() - stopZeitStatic.getTime()); 151 | } catch (Exception ex) { 152 | sekunden = -1; 153 | } 154 | System.out.println(""); 155 | System.out.println("========== ========== ========== ========== =========="); 156 | System.out.println("DURATION " + sum++ + ": " + text + " [" + roundDuration(sekunden) + "]"); 157 | System.out.println(" Klasse: " + klasse); 158 | if (!extra.isEmpty()) { 159 | System.out.println(" " + extra); 160 | } 161 | System.out.println("========== ========== ========== ========== =========="); 162 | System.out.println(""); 163 | 164 | stopZeitStatic = now; 165 | } 166 | 167 | public static String roundDuration(long s) { 168 | String ret; 169 | if (s > 1_000.0) { 170 | ret = DF.format(s / 1_000.0) + " s"; 171 | } else { 172 | ret = DF.format(s) + " ms"; 173 | } 174 | 175 | return ret; 176 | } 177 | 178 | } 179 | -------------------------------------------------------------------------------- /src/main/java/de/mediathekview/mlib/filmlisten/DatenFilmlisteUrl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * MediathekView 3 | * Copyright (C) 2008 W. Xaver 4 | * W.Xaver[at]googlemail.com 5 | * http://zdfmediathk.sourceforge.net/ 6 | * 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 10 | * any later version. 11 | * 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. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | package de.mediathekview.mlib.filmlisten; 21 | 22 | import java.text.ParseException; 23 | import java.text.SimpleDateFormat; 24 | import java.util.Calendar; 25 | import java.util.Date; 26 | import java.util.SimpleTimeZone; 27 | 28 | import de.mediathekview.mlib.tool.Log; 29 | 30 | public class DatenFilmlisteUrl implements Comparable { 31 | 32 | public static final String SERVER_ART_AKT = "akt"; 33 | public static final String SERVER_ART_OLD = "old"; 34 | public static final String SERVER_ART_DIFF = "diff"; 35 | 36 | public static final String FILM_UPDATE_SERVER_PRIO_1 = "1"; 37 | public static final String FILM_UPDATE_SERVER = "film-update-server"; 38 | public static final String FILM_UPDATE_SERVER_NR = "film-update-server-nr"; 39 | public static final int FILM_UPDATE_SERVER_NR_NR = 0; 40 | public static final String FILM_UPDATE_SERVER_URL = "film-update-server-url"; 41 | public static final int FILM_UPDATE_SERVER_URL_NR = 1; 42 | public static final String FILM_UPDATE_SERVER_DATUM = "film-update-server-datum"; // Datum in UTC 43 | public static final int FILM_UPDATE_SERVER_DATUM_NR = 2; 44 | public static final String FILM_UPDATE_SERVER_ZEIT = "film-update-server-zeit"; // Zeit in UTC 45 | public static final int FILM_UPDATE_SERVER_ZEIT_NR = 3; 46 | public static final String FILM_UPDATE_SERVER_PRIO = "film-update-server-prio"; 47 | public static final int FILM_UPDATE_SERVER_PRIO_NR = 4; 48 | public static final String FILM_UPDATE_SERVER_ART = "film-update-server-art"; 49 | public static final int FILM_UPDATE_SERVER_ART_NR = 5; 50 | public static final int FILM_UPDATE_SERVER_MAX_ELEM = 6; 51 | public static final String[] FILM_UPDATE_SERVER_COLUMN_NAMES = {FILM_UPDATE_SERVER_NR, FILM_UPDATE_SERVER_URL, 52 | FILM_UPDATE_SERVER_DATUM, FILM_UPDATE_SERVER_ZEIT, FILM_UPDATE_SERVER_PRIO, FILM_UPDATE_SERVER_ART}; 53 | 54 | public static final String[] FILM_UPDATE_SERVER_COLUMN_NAMES_ANZEIGE = {"Nr", "Update-Url", "Datum", "Zeit", "Prio", "Art"}; 55 | 56 | public String[] arr; 57 | private SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss"); 58 | 59 | public DatenFilmlisteUrl() { 60 | sdf.setTimeZone(new SimpleTimeZone(SimpleTimeZone.UTC_TIME, "UTC")); 61 | makeArr(); 62 | } 63 | 64 | public DatenFilmlisteUrl(String url, String prio, String art) { 65 | sdf.setTimeZone(new SimpleTimeZone(SimpleTimeZone.UTC_TIME, "UTC")); 66 | makeArr(); 67 | arr[FILM_UPDATE_SERVER_URL_NR] = url; 68 | arr[FILM_UPDATE_SERVER_PRIO_NR] = prio; 69 | arr[FILM_UPDATE_SERVER_DATUM_NR] = ""; 70 | arr[FILM_UPDATE_SERVER_ZEIT_NR] = ""; 71 | arr[FILM_UPDATE_SERVER_ART_NR] = art; 72 | } 73 | 74 | public DatenFilmlisteUrl(String url, String art) { 75 | sdf.setTimeZone(new SimpleTimeZone(SimpleTimeZone.UTC_TIME, "UTC")); 76 | makeArr(); 77 | arr[FILM_UPDATE_SERVER_URL_NR] = url; 78 | arr[FILM_UPDATE_SERVER_PRIO_NR] = DatenFilmlisteUrl.FILM_UPDATE_SERVER_PRIO_1; 79 | arr[FILM_UPDATE_SERVER_DATUM_NR] = ""; 80 | arr[FILM_UPDATE_SERVER_ZEIT_NR] = ""; 81 | arr[FILM_UPDATE_SERVER_ART_NR] = art; 82 | } 83 | 84 | public Date getDate() { 85 | String date = arr[FILM_UPDATE_SERVER_DATUM_NR] + " " + arr[FILM_UPDATE_SERVER_ZEIT_NR]; 86 | Date d; 87 | try { 88 | d = sdf.parse(date); 89 | } catch (Exception ex) { 90 | d = new Date(); 91 | } 92 | return d; 93 | } 94 | 95 | public String getDateStr() { 96 | SimpleDateFormat sdf_ = new SimpleDateFormat("dd.MM.yyyy"); 97 | sdf_.setTimeZone(SimpleTimeZone.getDefault()); 98 | String d; 99 | try { 100 | d = sdf_.format(getDate()); 101 | } catch (Exception ex) { 102 | d = sdf_.format(new Date()); 103 | } 104 | return d; 105 | } 106 | 107 | public String getTimeStr() { 108 | SimpleDateFormat sdf_ = new SimpleDateFormat("HH:mm:ss"); 109 | sdf_.setTimeZone(SimpleTimeZone.getDefault()); 110 | String d; 111 | try { 112 | d = sdf_.format(getDate()); 113 | } catch (Exception ex) { 114 | d = sdf_.format(new Date()); 115 | } 116 | return d; 117 | } 118 | 119 | @Override 120 | public int compareTo(DatenFilmlisteUrl arg0) { 121 | int ret = 0; 122 | try { 123 | //31.10.2010 16:54:17 124 | String ich = arr[FILM_UPDATE_SERVER_DATUM_NR] + " " + arr[FILM_UPDATE_SERVER_ZEIT_NR]; 125 | String du = arg0.arr[FILM_UPDATE_SERVER_DATUM_NR] + " " + arg0.arr[FILM_UPDATE_SERVER_ZEIT_NR]; 126 | if (ich.equals(du)) { 127 | return 0; 128 | } 129 | Date d_ich = sdf.parse(ich); 130 | Date d_du = sdf.parse(du); 131 | ret = d_du.compareTo(d_ich); 132 | } catch (ParseException ex) { 133 | Log.errorLog(936542876, ex); 134 | } 135 | return ret; 136 | } 137 | 138 | public boolean aelterAls(int tage) { 139 | boolean ret = false; 140 | try { 141 | //31.10.2010 16:54:17 142 | String ich = arr[FILM_UPDATE_SERVER_DATUM_NR] + " " + arr[FILM_UPDATE_SERVER_ZEIT_NR]; 143 | Date d_ich = sdf.parse(ich); 144 | Calendar cal = Calendar.getInstance(); 145 | // tage vom calendar abziehen 146 | cal.add(Calendar.DATE, -tage); 147 | ret = d_ich.before(cal.getTime()); 148 | } catch (ParseException ex) { 149 | Log.errorLog(915468973, ex); 150 | } 151 | return ret; 152 | } 153 | 154 | private void makeArr() { 155 | arr = new String[FILM_UPDATE_SERVER_MAX_ELEM]; 156 | for (int i = 0; i < arr.length; ++i) { 157 | arr[i] = ""; 158 | } 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /MLib.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /src/main/java/de/mediathekview/mlib/filmlisten/WriteFilmlistJson.java: -------------------------------------------------------------------------------- 1 | /* 2 | * MediathekView 3 | * Copyright (C) 2008 W. Xaver 4 | * W.Xaver[at]googlemail.com 5 | * http://zdfmediathk.sourceforge.net/ 6 | * 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 10 | * any later version. 11 | * 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. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | package de.mediathekview.mlib.filmlisten; 21 | 22 | import com.fasterxml.jackson.core.JsonEncoding; 23 | import com.fasterxml.jackson.core.JsonFactory; 24 | import com.fasterxml.jackson.core.JsonGenerator; 25 | import com.jidesoft.utils.SystemInfo; 26 | import de.mediathekview.mlib.Const; 27 | import de.mediathekview.mlib.daten.DatenFilm; 28 | import de.mediathekview.mlib.daten.ListeFilme; 29 | import de.mediathekview.mlib.tool.Log; 30 | import org.tukaani.xz.LZMA2Options; 31 | import org.tukaani.xz.XZOutputStream; 32 | 33 | import java.io.*; 34 | import java.nio.ByteBuffer; 35 | import java.nio.channels.Channels; 36 | import java.nio.channels.ReadableByteChannel; 37 | import java.nio.channels.WritableByteChannel; 38 | import java.nio.file.Files; 39 | import java.nio.file.Path; 40 | import java.nio.file.Paths; 41 | import java.nio.file.StandardCopyOption; 42 | 43 | public class WriteFilmlistJson { 44 | 45 | private void fastChannelCopy(final ReadableByteChannel src, final WritableByteChannel dest) throws IOException { 46 | final ByteBuffer buffer = ByteBuffer.allocateDirect(64 * 1024); 47 | while (src.read(buffer) != -1) { 48 | buffer.flip(); 49 | dest.write(buffer); 50 | buffer.compact(); 51 | } 52 | 53 | buffer.flip(); 54 | 55 | while (buffer.hasRemaining()) { 56 | dest.write(buffer); 57 | } 58 | } 59 | 60 | protected JsonGenerator getJsonGenerator(OutputStream os) throws IOException { 61 | JsonFactory jsonF = new JsonFactory(); 62 | JsonGenerator jg = jsonF.createGenerator(os, JsonEncoding.UTF8); 63 | //jg.useDefaultPrettyPrinter(); // enable indentation just to make debug/testing easier 64 | 65 | return jg; 66 | } 67 | 68 | /** 69 | * Write film data and compress with LZMA2. 70 | * 71 | * @param datei file path 72 | * @param listeFilme film data 73 | */ 74 | public void filmlisteSchreibenJsonCompressed(String datei, ListeFilme listeFilme) { 75 | final String tempFile = datei + "_temp"; 76 | filmlisteSchreibenJson(tempFile, listeFilme); 77 | 78 | try { 79 | Log.sysLog("Komprimiere Datei: " + datei); 80 | if (datei.endsWith(Const.FORMAT_XZ)) { 81 | final Path xz = testNativeXz(); 82 | if (xz != null) { 83 | Process p = new ProcessBuilder(xz.toString(), "-9", tempFile).start(); 84 | final int exitCode = p.waitFor(); 85 | if (exitCode == 0) { 86 | Files.move(Paths.get(tempFile + ".xz"), Paths.get(datei), StandardCopyOption.REPLACE_EXISTING); 87 | } 88 | } else 89 | compressFile(tempFile, datei); 90 | } 91 | 92 | Files.deleteIfExists(Paths.get(tempFile)); 93 | } catch (IOException | InterruptedException ex) { 94 | Log.sysLog("Komprimieren fehlgeschlagen"); 95 | } 96 | } 97 | 98 | public void filmlisteSchreibenJson(String datei, ListeFilme listeFilme) { 99 | try { 100 | Log.sysLog("Filme schreiben (" + listeFilme.size() + " Filme) :"); 101 | 102 | Log.sysLog(" --> Start Schreiben nach: " + datei); 103 | String sender = "", thema = ""; 104 | 105 | if (SystemInfo.isMacOSX()) { 106 | //Hotfix for OSX 10.12.4 update 107 | final Path f = Paths.get(datei); 108 | final Path parentDirectory = f.getParent(); 109 | if (!Files.exists(parentDirectory)) 110 | Files.createDirectory(parentDirectory); 111 | } 112 | 113 | try (FileOutputStream fos = new FileOutputStream(datei); 114 | JsonGenerator jg = getJsonGenerator(fos)) { 115 | 116 | jg.writeStartObject(); 117 | // Infos zur Filmliste 118 | jg.writeArrayFieldStart(ListeFilme.FILMLISTE); 119 | for (int i = 0; i < ListeFilme.MAX_ELEM; ++i) { 120 | jg.writeString(listeFilme.metaDaten[i]); 121 | } 122 | jg.writeEndArray(); 123 | // Infos der Felder in der Filmliste 124 | jg.writeArrayFieldStart(ListeFilme.FILMLISTE); 125 | for (int i = 0; i < DatenFilm.JSON_NAMES.length; ++i) { 126 | jg.writeString(DatenFilm.COLUMN_NAMES[DatenFilm.JSON_NAMES[i]]); 127 | } 128 | jg.writeEndArray(); 129 | //Filme schreiben 130 | for (DatenFilm datenFilm : listeFilme) { 131 | datenFilm.arr[DatenFilm.FILM_NEU] = Boolean.toString(datenFilm.isNew()); // damit wirs beim nächsten Programmstart noch wissen 132 | 133 | jg.writeArrayFieldStart(DatenFilm.TAG_JSON_LIST); 134 | for (int i = 0; i < DatenFilm.JSON_NAMES.length; ++i) { 135 | int m = DatenFilm.JSON_NAMES[i]; 136 | if (m == DatenFilm.FILM_SENDER) { 137 | if (datenFilm.arr[m].equals(sender)) { 138 | jg.writeString(""); 139 | } else { 140 | sender = datenFilm.arr[m]; 141 | jg.writeString(datenFilm.arr[m]); 142 | } 143 | } else if (m == DatenFilm.FILM_THEMA) { 144 | if (datenFilm.arr[m].equals(thema)) { 145 | jg.writeString(""); 146 | } else { 147 | thema = datenFilm.arr[m]; 148 | jg.writeString(datenFilm.arr[m]); 149 | } 150 | } else { 151 | jg.writeString(datenFilm.arr[m]); 152 | } 153 | } 154 | jg.writeEndArray(); 155 | } 156 | jg.writeEndObject(); 157 | Log.sysLog(" --> geschrieben!"); 158 | } 159 | } catch (Exception ex) { 160 | Log.errorLog(846930145, ex, "nach: " + datei); 161 | } 162 | } 163 | 164 | private Path testNativeXz() { 165 | final String[] paths = {"/usr/bin/xz", "/opt/local/bin/xz", "/usr/local/bin/xz"}; 166 | 167 | Path xz = null; 168 | 169 | for (String path : paths) { 170 | xz = Paths.get(path); 171 | if (Files.isExecutable(xz)) { 172 | break; 173 | } 174 | } 175 | 176 | return xz; 177 | } 178 | 179 | private void compressFile(String inputName, String outputName) throws IOException { 180 | try (InputStream input = new FileInputStream(inputName); 181 | FileOutputStream fos = new FileOutputStream(outputName); 182 | final OutputStream output = new XZOutputStream(fos, new LZMA2Options()); 183 | final ReadableByteChannel inputChannel = Channels.newChannel(input); 184 | final WritableByteChannel outputChannel = Channels.newChannel(output)) { 185 | 186 | fastChannelCopy(inputChannel, outputChannel); 187 | } catch (IOException ignored) { 188 | } 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /src/main/java/de/mediathekview/mlib/tool/MSStringBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * MediathekView 3 | * Copyright (C) 2008 W. Xaver 4 | * W.Xaver[at]googlemail.com 5 | * http://zdfmediathk.sourceforge.net/ 6 | * 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 10 | * any later version. 11 | * 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. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | package de.mediathekview.mlib.tool; 21 | 22 | import java.util.ArrayList; 23 | 24 | public class MSStringBuilder { 25 | 26 | private final StringBuilder cont; 27 | 28 | public MSStringBuilder() { 29 | cont = new StringBuilder(); 30 | } 31 | 32 | public MSStringBuilder(int capacity) { 33 | cont = new StringBuilder(capacity); 34 | } 35 | 36 | //===================================================== 37 | //StringBuilder Kram 38 | public String substring(int start) { 39 | return cont.substring(start); 40 | } 41 | 42 | public int lastIndexOf(String of) { 43 | return cont.lastIndexOf(of); 44 | } 45 | 46 | public int length() { 47 | return cont.length(); 48 | } 49 | 50 | public String substring(int start, int end) { 51 | return cont.substring(start, end); 52 | } 53 | 54 | public synchronized void append(char[] str) { 55 | cont.append(str); 56 | } 57 | 58 | public synchronized void append(char[] str, int offset, int len) { 59 | cont.append(str, offset, len); 60 | } 61 | 62 | public synchronized void setLength(int newLength) { 63 | cont.setLength(newLength); 64 | } 65 | 66 | public synchronized int indexOf(String str, int fromIndex) { 67 | return cont.indexOf(str, fromIndex); 68 | } 69 | 70 | public synchronized int indexOf(String str) { 71 | return cont.indexOf(str); 72 | } 73 | 74 | //===================================================== 75 | //===================================================== 76 | //===================================================== 77 | public String extract(String musterStart, String musterEnde) { 78 | return extract(musterStart, "", musterEnde, 0, 0, ""); 79 | } 80 | 81 | public String extract(String musterStart, String musterEnde, int abPos) { 82 | return extract(musterStart, "", musterEnde, abPos, 0, ""); 83 | } 84 | 85 | public String extract(String musterStart, String musterEnde, int abPos, int bisPos) { 86 | return extract(musterStart, "", musterEnde, abPos, bisPos, ""); 87 | } 88 | 89 | public String extract(String musterStart1, String musterStart2, String musterEnde) { 90 | return extract(musterStart1, musterStart2, musterEnde, 0, 0, ""); 91 | } 92 | 93 | public String extract(String musterStart1, String musterStart2, String musterEnde, String addUrl) { 94 | return extract(musterStart1, musterStart2, musterEnde, 0, 0, addUrl); 95 | } 96 | 97 | public String extract(String musterStart1, String musterStart2, String musterEnde, int abPos, int bisPos, String addUrl) { 98 | int pos1, pos2; 99 | if ((pos1 = cont.indexOf(musterStart1, abPos)) == -1) { 100 | return ""; 101 | } 102 | pos1 += musterStart1.length(); 103 | if (!musterStart2.isEmpty() && (pos1 = cont.indexOf(musterStart2, pos1)) == -1) { 104 | return ""; 105 | } 106 | pos1 += musterStart2.length(); 107 | if ((pos2 = cont.indexOf(musterEnde, pos1)) == -1) { 108 | return ""; 109 | } 110 | if (bisPos > 0 && pos2 > bisPos) { 111 | return ""; 112 | } 113 | String ret = cont.substring(pos1, pos2); 114 | if (!ret.isEmpty()) { 115 | // damit nicht nur! addUrl zurückkommt 116 | return addUrl + ret; 117 | } 118 | return ""; 119 | } 120 | 121 | public void extractList(String musterStart, String musterEnde, ArrayList result) { 122 | extractList("", "", musterStart, "", musterEnde, "", result); 123 | } 124 | 125 | public void extractList(String musterStart1, String musterStart2, String musterEnde, ArrayList result) { 126 | extractList("", "", musterStart1, musterStart2, musterEnde, "", result); 127 | } 128 | 129 | public void extractList(String abMuster, String bisMuster, String musterStart, String musterEnde, String addUrl, ArrayList result) { 130 | extractList(abMuster, bisMuster, musterStart, "", musterEnde, addUrl, result); 131 | } 132 | 133 | public void extractList(String abMuster, String bisMuster, String musterStart1, String musterStart2, String musterEnde, String addUrl, ArrayList result) { 134 | int pos1, pos2, stopPos, count = 0; 135 | String str; 136 | pos1 = abMuster.isEmpty() ? 0 : cont.indexOf(abMuster); 137 | if (pos1 == -1) { 138 | return; 139 | } 140 | 141 | stopPos = bisMuster.isEmpty() ? -1 : cont.indexOf(bisMuster, pos1); 142 | 143 | while ((pos1 = cont.indexOf(musterStart1, pos1)) != -1) { 144 | ++count; 145 | if (count > 10_000) { 146 | DbgMsg.print("Achtung"); 147 | break; 148 | } 149 | pos1 += musterStart1.length(); 150 | 151 | if (!musterStart2.isEmpty()) { 152 | if ((pos2 = cont.indexOf(musterStart2, pos1)) == -1) { 153 | continue; 154 | } 155 | pos1 = pos2 + musterStart2.length(); 156 | } 157 | 158 | if ((pos2 = cont.indexOf(musterEnde, pos1)) == -1) { 159 | continue; 160 | } 161 | if (stopPos > 0 && pos2 > stopPos) { 162 | continue; 163 | } 164 | 165 | if ((str = cont.substring(pos1, pos2)).isEmpty()) { 166 | continue; 167 | } 168 | 169 | str = addUrl + str; 170 | addStr(str, result); 171 | } 172 | } 173 | 174 | private void addStr(String str, ArrayList result) { 175 | if (!result.contains(str)) { 176 | result.add(str); 177 | if (result.size() > 1000) { 178 | DbgMsg.print("Achtung"); 179 | } 180 | } 181 | } 182 | 183 | public void extractList(int ab, int bis, String musterStart1, String musterStart2, String musterEnde, String addUrl, ArrayList result) { 184 | int pos1, pos2, stopPos, count = 0; 185 | String str; 186 | pos1 = ab; 187 | stopPos = bis; 188 | if (pos1 == -1) { 189 | return; 190 | } 191 | 192 | while ((pos1 = cont.indexOf(musterStart1, pos1)) != -1) { 193 | ++count; 194 | if (count > 10_000) { 195 | DbgMsg.print("Achtung"); 196 | break; 197 | } 198 | pos1 += musterStart1.length(); 199 | 200 | if (!musterStart2.isEmpty()) { 201 | if ((pos2 = cont.indexOf(musterStart2, pos1)) == -1) { 202 | continue; 203 | } 204 | pos1 = pos2 + musterStart2.length(); 205 | } 206 | 207 | if ((pos2 = cont.indexOf(musterEnde, pos1)) == -1) { 208 | continue; 209 | } 210 | if (stopPos > 0 && pos2 > stopPos) { 211 | continue; 212 | } 213 | 214 | if ((str = cont.substring(pos1, pos2)).isEmpty()) { 215 | continue; 216 | } 217 | 218 | str = addUrl + str; 219 | if (!result.contains(str)) { 220 | result.add(str); 221 | if (result.size() > 1000) { 222 | DbgMsg.print("Achtung"); 223 | } 224 | } 225 | 226 | } 227 | } 228 | 229 | } 230 | -------------------------------------------------------------------------------- /src/main/java/de/mediathekview/mlib/filmlisten/ListeFilmlistenUrls.java: -------------------------------------------------------------------------------- 1 | /* 2 | * MediathekView 3 | * Copyright (C) 2008 W. Xaver 4 | * W.Xaver[at]googlemail.com 5 | * http://zdfmediathk.sourceforge.net/ 6 | * 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 10 | * any later version. 11 | * 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. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | package de.mediathekview.mlib.filmlisten; 21 | 22 | import java.util.ArrayList; 23 | import java.util.Collections; 24 | import java.util.Iterator; 25 | import java.util.LinkedList; 26 | import java.util.Random; 27 | 28 | @SuppressWarnings("serial") 29 | public class ListeFilmlistenUrls extends LinkedList { 30 | // ist die Liste mit den URLs zum Download einer Filmliste 31 | public boolean addWithCheck(DatenFilmlisteUrl filmliste) { 32 | for (DatenFilmlisteUrl datenUrlFilmliste : this) { 33 | if (datenUrlFilmliste.arr[DatenFilmlisteUrl.FILM_UPDATE_SERVER_URL_NR].equals(filmliste.arr[DatenFilmlisteUrl.FILM_UPDATE_SERVER_URL_NR])) { 34 | return false; 35 | } 36 | } 37 | return add(filmliste); 38 | } 39 | 40 | public void sort() { 41 | int nr = 0; 42 | Collections.sort(this); 43 | for (DatenFilmlisteUrl datenUrlFilmliste : this) { 44 | String str = String.valueOf(nr++); 45 | while (str.length() < 3) { 46 | str = "0" + str; 47 | } 48 | datenUrlFilmliste.arr[DatenFilmlisteUrl.FILM_UPDATE_SERVER_NR_NR] = str; 49 | } 50 | } 51 | 52 | public String[][] getTableObjectData() { 53 | DatenFilmlisteUrl filmUpdate; 54 | String[][] object; 55 | Iterator iterator = this.iterator(); 56 | object = new String[this.size()][DatenFilmlisteUrl.FILM_UPDATE_SERVER_MAX_ELEM]; 57 | int i = 0; 58 | while (iterator.hasNext()) { 59 | filmUpdate = iterator.next(); 60 | System.arraycopy(filmUpdate.arr, 0, object[i], 0, DatenFilmlisteUrl.FILM_UPDATE_SERVER_MAX_ELEM); 61 | object[i][DatenFilmlisteUrl.FILM_UPDATE_SERVER_DATUM_NR] = filmUpdate.getDateStr(); // lokale Zeit anzeigen 62 | object[i][DatenFilmlisteUrl.FILM_UPDATE_SERVER_ZEIT_NR] = filmUpdate.getTimeStr(); // lokale Zeit anzeigen 63 | ++i; 64 | } 65 | return object; 66 | } 67 | 68 | public DatenFilmlisteUrl getDatenUrlFilmliste(String url) { 69 | DatenFilmlisteUrl update; 70 | for (DatenFilmlisteUrl datenUrlFilmliste : this) { 71 | update = datenUrlFilmliste; 72 | if (update.arr[DatenFilmlisteUrl.FILM_UPDATE_SERVER_URL_NR].equals(url)) { 73 | return update; 74 | } 75 | } 76 | return null; 77 | } 78 | 79 | public String getRand(ArrayList bereitsGebraucht) { 80 | // gibt nur noch akt.xml und diff.xml und da sind alle Listen 81 | // aktuell, Prio: momentan sind alle Listen gleich gewichtet 82 | if (this.isEmpty()) { 83 | return ""; 84 | } 85 | 86 | LinkedList listePrio = new LinkedList<>(); 87 | //nach prio gewichten 88 | for (DatenFilmlisteUrl datenFilmlisteUrl : this) { 89 | if (bereitsGebraucht != null) { 90 | if (bereitsGebraucht.contains(datenFilmlisteUrl.arr[DatenFilmlisteUrl.FILM_UPDATE_SERVER_URL_NR])) { 91 | // wurde schon versucht 92 | continue; 93 | } 94 | if (datenFilmlisteUrl.arr[DatenFilmlisteUrl.FILM_UPDATE_SERVER_PRIO_NR].equals(DatenFilmlisteUrl.FILM_UPDATE_SERVER_PRIO_1)) { 95 | listePrio.add(datenFilmlisteUrl); 96 | listePrio.add(datenFilmlisteUrl); 97 | } else { 98 | listePrio.add(datenFilmlisteUrl); 99 | listePrio.add(datenFilmlisteUrl); 100 | listePrio.add(datenFilmlisteUrl); 101 | } 102 | } 103 | } 104 | 105 | DatenFilmlisteUrl datenFilmlisteUrl; 106 | if (!listePrio.isEmpty()) { 107 | int nr = new Random().nextInt(listePrio.size()); 108 | datenFilmlisteUrl = listePrio.get(nr); 109 | } else { 110 | // dann wird irgendeine Versucht 111 | int nr = new Random().nextInt(this.size()); 112 | datenFilmlisteUrl = this.get(nr); 113 | } 114 | return datenFilmlisteUrl.arr[DatenFilmlisteUrl.FILM_UPDATE_SERVER_URL_NR]; 115 | } 116 | 117 | // public String getRand(ArrayList bereitsGebraucht, int errcount) { 118 | // final int MAXMINUTEN = 50; 119 | // int minCount = 3; 120 | // if (errcount > 0) { 121 | // minCount = 3 + 2 * errcount; 122 | // } 123 | // String ret = ""; 124 | // if (!this.isEmpty()) { 125 | // DatenFilmlisteUrl datenUrlFilmliste; 126 | // LinkedList listeZeit = new LinkedList<>(); 127 | // LinkedList listePrio = new LinkedList<>(); 128 | // //aktuellsten auswählen 129 | // Iterator it = this.iterator(); 130 | // Date today = new Date(System.currentTimeMillis()); 131 | // Date d; 132 | // int minuten = 200; 133 | // int count = 0; 134 | // while (it.hasNext()) { 135 | // datenUrlFilmliste = it.next(); 136 | // if (bereitsGebraucht != null) { 137 | // if (bereitsGebraucht.contains(datenUrlFilmliste.arr[DatenFilmlisteUrl.FILM_UPDATE_SERVER_URL_NR])) { 138 | // // wurde schon versucht 139 | // continue; 140 | // } 141 | // } 142 | // try { 143 | // d = datenUrlFilmliste.getDate(); 144 | // // debug 145 | // //SimpleDateFormat sdf_datum_zeit = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss"); 146 | // //String s = sdf_datum_zeit.format(d); 147 | // long m = today.getTime() - d.getTime(); 148 | // if (m < 0) { 149 | // m = 0; 150 | // } 151 | // minuten = Math.round(m / (1000 * 60)); 152 | // } catch (Exception ignored) { 153 | // } 154 | // if (minuten < MAXMINUTEN) { 155 | // listeZeit.add(datenUrlFilmliste); 156 | // ++count; 157 | // } else if (count < minCount) { 158 | // listeZeit.add(datenUrlFilmliste); 159 | // ++count; 160 | // } 161 | // } 162 | // //nach prio gewichten 163 | // it = listeZeit.iterator(); 164 | // while (it.hasNext()) { 165 | // datenUrlFilmliste = it.next(); 166 | // if (datenUrlFilmliste.arr[DatenFilmlisteUrl.FILM_UPDATE_SERVER_PRIO_NR].equals(DatenFilmlisteUrl.FILM_UPDATE_SERVER_PRIO_1)) { 167 | // listePrio.add(datenUrlFilmliste); 168 | // } else { 169 | // listePrio.add(datenUrlFilmliste); 170 | // listePrio.add(datenUrlFilmliste); 171 | // } 172 | // } 173 | // if (listePrio.size() > 0) { 174 | // int nr = new Random().nextInt(listePrio.size()); 175 | // datenUrlFilmliste = listePrio.get(nr); 176 | // } else { 177 | // // dann wird irgendeine Versucht 178 | // int nr = new Random().nextInt(this.size()); 179 | // datenUrlFilmliste = this.get(nr); 180 | // } 181 | // ret = datenUrlFilmliste.arr[DatenFilmlisteUrl.FILM_UPDATE_SERVER_URL_NR]; 182 | // } 183 | // return ret; 184 | // } 185 | } 186 | -------------------------------------------------------------------------------- /mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven2 Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 59 | if [ -z "$JAVA_HOME" ]; then 60 | if [ -x "/usr/libexec/java_home" ]; then 61 | export JAVA_HOME="`/usr/libexec/java_home`" 62 | else 63 | export JAVA_HOME="/Library/Java/Home" 64 | fi 65 | fi 66 | ;; 67 | esac 68 | 69 | if [ -z "$JAVA_HOME" ] ; then 70 | if [ -r /etc/gentoo-release ] ; then 71 | JAVA_HOME=`java-config --jre-home` 72 | fi 73 | fi 74 | 75 | if [ -z "$M2_HOME" ] ; then 76 | ## resolve links - $0 may be a link to maven's home 77 | PRG="$0" 78 | 79 | # need this for relative symlinks 80 | while [ -h "$PRG" ] ; do 81 | ls=`ls -ld "$PRG"` 82 | link=`expr "$ls" : '.*-> \(.*\)$'` 83 | if expr "$link" : '/.*' > /dev/null; then 84 | PRG="$link" 85 | else 86 | PRG="`dirname "$PRG"`/$link" 87 | fi 88 | done 89 | 90 | saveddir=`pwd` 91 | 92 | M2_HOME=`dirname "$PRG"`/.. 93 | 94 | # make it fully qualified 95 | M2_HOME=`cd "$M2_HOME" && pwd` 96 | 97 | cd "$saveddir" 98 | # echo Using m2 at $M2_HOME 99 | fi 100 | 101 | # For Cygwin, ensure paths are in UNIX format before anything is touched 102 | if $cygwin ; then 103 | [ -n "$M2_HOME" ] && 104 | M2_HOME=`cygpath --unix "$M2_HOME"` 105 | [ -n "$JAVA_HOME" ] && 106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 107 | [ -n "$CLASSPATH" ] && 108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 109 | fi 110 | 111 | # For Mingw, ensure paths are in UNIX format before anything is touched 112 | if $mingw ; then 113 | [ -n "$M2_HOME" ] && 114 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 115 | [ -n "$JAVA_HOME" ] && 116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 117 | # TODO classpath? 118 | fi 119 | 120 | if [ -z "$JAVA_HOME" ]; then 121 | javaExecutable="`which javac`" 122 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 123 | # readlink(1) is not available as standard on Solaris 10. 124 | readLink=`which readlink` 125 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 126 | if $darwin ; then 127 | javaHome="`dirname \"$javaExecutable\"`" 128 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 129 | else 130 | javaExecutable="`readlink -f \"$javaExecutable\"`" 131 | fi 132 | javaHome="`dirname \"$javaExecutable\"`" 133 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 134 | JAVA_HOME="$javaHome" 135 | export JAVA_HOME 136 | fi 137 | fi 138 | fi 139 | 140 | if [ -z "$JAVACMD" ] ; then 141 | if [ -n "$JAVA_HOME" ] ; then 142 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 143 | # IBM's JDK on AIX uses strange locations for the executables 144 | JAVACMD="$JAVA_HOME/jre/sh/java" 145 | else 146 | JAVACMD="$JAVA_HOME/bin/java" 147 | fi 148 | else 149 | JAVACMD="`which java`" 150 | fi 151 | fi 152 | 153 | if [ ! -x "$JAVACMD" ] ; then 154 | echo "Error: JAVA_HOME is not defined correctly." >&2 155 | echo " We cannot execute $JAVACMD" >&2 156 | exit 1 157 | fi 158 | 159 | if [ -z "$JAVA_HOME" ] ; then 160 | echo "Warning: JAVA_HOME environment variable is not set." 161 | fi 162 | 163 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 164 | 165 | # traverses directory structure from process work directory to filesystem root 166 | # first directory with .mvn subdirectory is considered project base directory 167 | find_maven_basedir() { 168 | 169 | if [ -z "$1" ] 170 | then 171 | echo "Path not specified to find_maven_basedir" 172 | return 1 173 | fi 174 | 175 | basedir="$1" 176 | wdir="$1" 177 | while [ "$wdir" != '/' ] ; do 178 | if [ -d "$wdir"/.mvn ] ; then 179 | basedir=$wdir 180 | break 181 | fi 182 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 183 | if [ -d "${wdir}" ]; then 184 | wdir=`cd "$wdir/.."; pwd` 185 | fi 186 | # end of workaround 187 | done 188 | echo "${basedir}" 189 | } 190 | 191 | # concatenates all lines of a file 192 | concat_lines() { 193 | if [ -f "$1" ]; then 194 | echo "$(tr -s '\n' ' ' < "$1")" 195 | fi 196 | } 197 | 198 | BASE_DIR=`find_maven_basedir "$(pwd)"` 199 | if [ -z "$BASE_DIR" ]; then 200 | exit 1; 201 | fi 202 | 203 | ########################################################################################## 204 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 205 | # This allows using the maven wrapper in projects that prohibit checking in binary data. 206 | ########################################################################################## 207 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then 208 | if [ "$MVNW_VERBOSE" = true ]; then 209 | echo "Found .mvn/wrapper/maven-wrapper.jar" 210 | fi 211 | else 212 | if [ "$MVNW_VERBOSE" = true ]; then 213 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." 214 | fi 215 | jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" 216 | while IFS="=" read key value; do 217 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;; 218 | esac 219 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" 220 | if [ "$MVNW_VERBOSE" = true ]; then 221 | echo "Downloading from: $jarUrl" 222 | fi 223 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" 224 | 225 | if command -v wget > /dev/null; then 226 | if [ "$MVNW_VERBOSE" = true ]; then 227 | echo "Found wget ... using wget" 228 | fi 229 | wget "$jarUrl" -O "$wrapperJarPath" 230 | elif command -v curl > /dev/null; then 231 | if [ "$MVNW_VERBOSE" = true ]; then 232 | echo "Found curl ... using curl" 233 | fi 234 | curl -o "$wrapperJarPath" "$jarUrl" 235 | else 236 | if [ "$MVNW_VERBOSE" = true ]; then 237 | echo "Falling back to using Java to download" 238 | fi 239 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" 240 | if [ -e "$javaClass" ]; then 241 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 242 | if [ "$MVNW_VERBOSE" = true ]; then 243 | echo " - Compiling MavenWrapperDownloader.java ..." 244 | fi 245 | # Compiling the Java class 246 | ("$JAVA_HOME/bin/javac" "$javaClass") 247 | fi 248 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 249 | # Running the downloader 250 | if [ "$MVNW_VERBOSE" = true ]; then 251 | echo " - Running MavenWrapperDownloader.java ..." 252 | fi 253 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") 254 | fi 255 | fi 256 | fi 257 | fi 258 | ########################################################################################## 259 | # End of extension 260 | ########################################################################################## 261 | 262 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 263 | if [ "$MVNW_VERBOSE" = true ]; then 264 | echo $MAVEN_PROJECTBASEDIR 265 | fi 266 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 267 | 268 | # For Cygwin, switch paths to Windows format before running java 269 | if $cygwin; then 270 | [ -n "$M2_HOME" ] && 271 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 272 | [ -n "$JAVA_HOME" ] && 273 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 274 | [ -n "$CLASSPATH" ] && 275 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 276 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 277 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 278 | fi 279 | 280 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 281 | 282 | exec "$JAVACMD" \ 283 | $MAVEN_OPTS \ 284 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 285 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 286 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 287 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 4.0.0 7 | 8 | de.mediathekview 9 | MLib 10 | 3.0.19 11 | jar 12 | 13 | ${project.groupId}:${project.artifactId} 14 | A central library with tools and utils for the MediathekView Client and the MediathekView Server 15 | 16 | https://www.mediathekview.de/ 17 | 18 | 19 | GNU General Public License (GPL) version 3.0 20 | https://www.gnu.org/licenses/gpl-3.0.txt 21 | 22 | 23 | 24 | 25 | 26 | Nicklas2751 27 | Nicklas Wiegandt 28 | nicklas@mediathekview.de 29 | nicklas.wiegandt.eu 30 | 31 | 32 | derreisende77 33 | Christian F. 34 | https://github.com/derreisende77 35 | 36 | 37 | pidoubleyou 38 | Peter W. 39 | https://github.com/pidoubleyou 40 | 41 | 42 | TheSasch 43 | Sascha Wiegandt 44 | https://github.com/thesasch 45 | 46 | 47 | alex1702 48 | Alexander Finkhäuser 49 | https://github.com/alex1702 50 | 51 | 52 | 53 | 54 | scm:git:git://github.com/mediathekview/MLib.git 55 | scm:git:ssh://github.com:mediathekview/MLib.git 56 | https://github.com/mediathekview/MLib/tree/master 57 | 58 | 59 | 60 | 61 | ossrh 62 | https://oss.sonatype.org/content/repositories/snapshots 63 | 64 | 65 | ossrh 66 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 67 | 68 | 69 | 70 | 71 | UTF-8 72 | 17 73 | 17 74 | 75 | 76 | 77 | 78 | com.jidesoft 79 | jide-oss 80 | 3.6.18 81 | 82 | 83 | 84 | 85 | org.apache.commons 86 | commons-text 87 | 1.10.0 88 | 89 | 90 | 91 | org.apache.commons 92 | commons-compress 93 | 1.24.0 94 | 95 | 96 | 97 | org.tukaani 98 | xz 99 | 1.9 100 | 101 | 102 | 103 | 104 | com.fasterxml.jackson.core 105 | jackson-core 106 | 2.14.2 107 | 108 | 109 | 110 | 111 | org.glassfish.jersey.core 112 | jersey-client 113 | 3.1.3 114 | 115 | 116 | javax.activation 117 | activation 118 | 1.1.1 119 | 120 | 121 | javax.xml.bind 122 | jaxb-api 123 | 2.4.0-b180830.0359 124 | 125 | 126 | com.sun.xml.bind 127 | jaxb-core 128 | 3.0.1 129 | 130 | 131 | com.sun.xml.bind 132 | jaxb-impl 133 | 3.0.2 134 | 135 | 136 | 137 | com.squareup.okhttp3 138 | okhttp 139 | 4.10.0 140 | 141 | 142 | 143 | org.jetbrains 144 | annotations 145 | 24.0.1 146 | 147 | 148 | 149 | com.github.fabriziocucci 150 | yacl4j-core 151 | 0.9.2 152 | 153 | 154 | 155 | 156 | org.apache.logging.log4j 157 | log4j-core 158 | 2.20.0 159 | 160 | 161 | 162 | 163 | junit 164 | junit 165 | 4.13.2 166 | test 167 | 168 | 169 | 170 | org.hamcrest 171 | hamcrest-junit 172 | 2.0.0.0 173 | test 174 | 175 | 176 | 177 | com.github.tomakehurst 178 | wiremock-jre8 179 | 2.35.1 180 | test 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | maven-clean-plugin 190 | 3.3.1 191 | 192 | 193 | 194 | 195 | maven-resources-plugin 196 | 3.3.1 197 | 198 | 199 | 200 | 201 | org.apache.maven.plugins 202 | maven-source-plugin 203 | 3.3.0 204 | 205 | 206 | attach-sources 207 | verify 208 | 209 | jar-no-fork 210 | 211 | 212 | 213 | 214 | 215 | 216 | org.apache.maven.plugins 217 | maven-javadoc-plugin 218 | 3.6.0 219 | 220 | 221 | attach-javadocs 222 | 223 | jar 224 | 225 | 226 | 227 | 228 | 229 | maven-compiler-plugin 230 | 3.11.0 231 | 232 | 233 | maven-surefire-plugin 234 | 2.22.2 235 | 236 | 237 | maven-jar-plugin 238 | 3.3.0 239 | 240 | 241 | maven-install-plugin 242 | 3.1.1 243 | 244 | 245 | maven-deploy-plugin 246 | 3.1.1 247 | 248 | 249 | 250 | 251 | 252 | 253 | src/main/resources 254 | true 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | deploy 263 | 264 | 265 | 266 | 267 | org.sonatype.plugins 268 | nexus-staging-maven-plugin 269 | 1.6.13 270 | true 271 | 272 | ossrh 273 | https://oss.sonatype.org/ 274 | true 275 | 276 | 277 | 278 | org.apache.maven.plugins 279 | maven-gpg-plugin 280 | 1.6 281 | 282 | 283 | sign-artifacts 284 | verify 285 | 286 | sign 287 | 288 | 289 | 290 | 291 | --pinentry-mode 292 | loopback 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | -------------------------------------------------------------------------------- /src/main/java/de/mediathekview/mlib/filmlisten/FilmlistenSuchen.java: -------------------------------------------------------------------------------- 1 | /* 2 | * MediathekView 3 | * Copyright (C) 2008 W. Xaver 4 | * W.Xaver[at]googlemail.com 5 | * http://zdfmediathk.sourceforge.net/ 6 | * 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 10 | * any later version. 11 | * 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. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | package de.mediathekview.mlib.filmlisten; 21 | 22 | import java.io.File; 23 | import java.io.FileInputStream; 24 | import java.io.InputStreamReader; 25 | import java.net.URL; 26 | import java.net.URLConnection; 27 | import java.nio.charset.StandardCharsets; 28 | import java.util.ArrayList; 29 | import java.util.Random; 30 | 31 | import javax.xml.stream.XMLInputFactory; 32 | import javax.xml.stream.XMLStreamConstants; 33 | import javax.xml.stream.XMLStreamException; 34 | import javax.xml.stream.XMLStreamReader; 35 | 36 | import de.mediathekview.mlib.Config; 37 | import de.mediathekview.mlib.Const; 38 | import de.mediathekview.mlib.tool.Functions; 39 | import de.mediathekview.mlib.tool.Log; 40 | 41 | public class FilmlistenSuchen { 42 | 43 | // damit werden die DownloadURLs zum Laden einer Filmliste gesucht 44 | // Liste mit den URLs zum Download der Filmliste 45 | public ListeFilmlistenUrls listeFilmlistenUrls_akt = new ListeFilmlistenUrls(); 46 | public ListeFilmlistenUrls listeFilmlistenUrls_diff = new ListeFilmlistenUrls(); 47 | private static boolean firstSearchAkt = true; 48 | private static boolean firstSearchDiff = true; 49 | private final int UPDATE_LISTE_MAX = 10; // die Downloadliste für die Filmlisten nur jeden 10. Programmstart aktualisieren 50 | 51 | public String suchenAkt(ArrayList bereitsVersucht) { 52 | // passende URL zum Laden der Filmliste suchen 53 | String retUrl; 54 | if (listeFilmlistenUrls_akt.isEmpty()) { 55 | // bei leerer Liste immer aktualisieren 56 | updateURLsFilmlisten(true); 57 | } else if (firstSearchAkt) { 58 | // nach dem Programmstart wird die Liste einmal aktualisiert aber 59 | // da sich die Listen nicht ändern, nur jeden xx Start 60 | int nr = new Random().nextInt(UPDATE_LISTE_MAX); 61 | if (nr == 0) { 62 | updateURLsFilmlisten(true); 63 | } 64 | } 65 | firstSearchAkt = false; 66 | retUrl = (listeFilmlistenUrls_akt.getRand(bereitsVersucht)); //eine Zufällige Adresse wählen 67 | if (bereitsVersucht != null) { 68 | bereitsVersucht.add(retUrl); 69 | } 70 | return retUrl; 71 | } 72 | 73 | public String suchenDiff(ArrayList bereitsVersucht) { 74 | // passende URL zum Laden der Filmliste suchen 75 | String retUrl; 76 | if (listeFilmlistenUrls_diff.isEmpty()) { 77 | // bei leerer Liste immer aktualisieren 78 | updateURLsFilmlisten(false); 79 | } else if (firstSearchDiff) { 80 | // nach dem Programmstart wird die Liste einmal aktualisiert aber 81 | // da sich die Listen nicht ändern, nur jeden xx Start 82 | int nr = new Random().nextInt(UPDATE_LISTE_MAX); 83 | if (nr == 0) { 84 | updateURLsFilmlisten(false); 85 | } 86 | } 87 | firstSearchDiff = false; 88 | retUrl = (listeFilmlistenUrls_diff.getRand(bereitsVersucht)); //eine Zufällige Adresse wählen 89 | if (bereitsVersucht != null) { 90 | bereitsVersucht.add(retUrl); 91 | } 92 | return retUrl; 93 | } 94 | 95 | /** 96 | * Add our default full list servers. 97 | */ 98 | private void insertDefaultActiveServers() 99 | { 100 | listeFilmlistenUrls_akt.add(new DatenFilmlisteUrl("http://m.picn.de/f/Filmliste-akt.xz", DatenFilmlisteUrl.SERVER_ART_AKT)); 101 | listeFilmlistenUrls_akt.add(new DatenFilmlisteUrl("http://m1.picn.de/f/Filmliste-akt.xz", DatenFilmlisteUrl.SERVER_ART_AKT)); 102 | listeFilmlistenUrls_akt.add(new DatenFilmlisteUrl("http://m2.picn.de/f/Filmliste-akt.xz", DatenFilmlisteUrl.SERVER_ART_AKT)); 103 | listeFilmlistenUrls_akt.add(new DatenFilmlisteUrl("http://download10.onlinetvrecorder.com/mediathekview/Filmliste-akt.xz", DatenFilmlisteUrl.SERVER_ART_AKT)); 104 | listeFilmlistenUrls_akt.add(new DatenFilmlisteUrl("http://mediathekview.jankal.me/Filmliste-akt.xz", DatenFilmlisteUrl.SERVER_ART_AKT)); 105 | listeFilmlistenUrls_akt.add(new DatenFilmlisteUrl("http://verteiler1.mediathekview.de/Filmliste-akt.xz", DatenFilmlisteUrl.SERVER_ART_AKT)); 106 | listeFilmlistenUrls_akt.add(new DatenFilmlisteUrl("http://verteiler2.mediathekview.de/Filmliste-akt.xz", DatenFilmlisteUrl.SERVER_ART_AKT)); 107 | listeFilmlistenUrls_akt.add(new DatenFilmlisteUrl("http://verteiler3.mediathekview.de/Filmliste-akt.xz", DatenFilmlisteUrl.SERVER_ART_AKT)); 108 | } 109 | 110 | /** 111 | * Add our default diff list servers. 112 | */ 113 | private void insertDefaultDifferentialListServers() 114 | { 115 | listeFilmlistenUrls_diff.add(new DatenFilmlisteUrl("http://m.picn.de/f/Filmliste-diff.xz", DatenFilmlisteUrl.SERVER_ART_DIFF)); 116 | listeFilmlistenUrls_diff.add(new DatenFilmlisteUrl("http://m1.picn.de/f/Filmliste-diff.xz", DatenFilmlisteUrl.SERVER_ART_DIFF)); 117 | listeFilmlistenUrls_diff.add(new DatenFilmlisteUrl("http://m2.picn.de/f/Filmliste-diff.xz", DatenFilmlisteUrl.SERVER_ART_DIFF)); 118 | listeFilmlistenUrls_diff.add(new DatenFilmlisteUrl("http://download10.onlinetvrecorder.com/mediathekview/Filmliste-diff.xz", DatenFilmlisteUrl.SERVER_ART_DIFF)); 119 | listeFilmlistenUrls_diff.add(new DatenFilmlisteUrl("http://mediathekview.jankal.me/Filmliste-diff.xz", DatenFilmlisteUrl.SERVER_ART_DIFF)); 120 | listeFilmlistenUrls_diff.add(new DatenFilmlisteUrl("http://verteiler1.mediathekview.de/Filmliste-diff.xz", DatenFilmlisteUrl.SERVER_ART_DIFF)); 121 | listeFilmlistenUrls_diff.add(new DatenFilmlisteUrl("http://verteiler2.mediathekview.de/Filmliste-diff.xz", DatenFilmlisteUrl.SERVER_ART_DIFF)); 122 | listeFilmlistenUrls_diff.add(new DatenFilmlisteUrl("http://verteiler3.mediathekview.de/Filmliste-diff.xz", DatenFilmlisteUrl.SERVER_ART_DIFF)); 123 | } 124 | 125 | /** 126 | * Update the download server URLs. 127 | * @param updateFullList if true, update full list server, otherwise diff servers. 128 | **/ 129 | public void updateURLsFilmlisten(final boolean updateFullList) { 130 | ListeFilmlistenUrls tmp = new ListeFilmlistenUrls(); 131 | if (updateFullList) { 132 | getDownloadUrlsFilmlisten(Const.ADRESSE_FILMLISTEN_SERVER_AKT, tmp, Config.getUserAgent(), DatenFilmlisteUrl.SERVER_ART_AKT); 133 | if (!tmp.isEmpty()) { 134 | listeFilmlistenUrls_akt = tmp; 135 | } else if (listeFilmlistenUrls_akt.isEmpty()) { 136 | insertDefaultActiveServers(); 137 | } 138 | listeFilmlistenUrls_akt.sort(); 139 | } else { 140 | getDownloadUrlsFilmlisten(Const.ADRESSE_FILMLISTEN_SERVER_DIFF, tmp, Config.getUserAgent(), DatenFilmlisteUrl.SERVER_ART_DIFF); 141 | if (!tmp.isEmpty()) { 142 | listeFilmlistenUrls_diff = tmp; 143 | } else if (listeFilmlistenUrls_diff.isEmpty()) { 144 | insertDefaultDifferentialListServers(); 145 | } 146 | listeFilmlistenUrls_diff.sort(); 147 | } 148 | if (tmp.isEmpty()) { 149 | Log.errorLog(491203216, new String[]{"Es ist ein Fehler aufgetreten!", 150 | "Es konnten keine Updateserver zum aktualisieren der Filme", 151 | "gefunden werden."}); 152 | } 153 | } 154 | 155 | public void getDownloadUrlsFilmlisten(String dateiUrl, ListeFilmlistenUrls listeFilmlistenUrls, String userAgent, String art) { 156 | //String[] ret = new String[]{""/* version */, ""/* release */, ""/* updateUrl */}; 157 | try { 158 | int event; 159 | XMLInputFactory inFactory = XMLInputFactory.newInstance(); 160 | inFactory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.FALSE); 161 | XMLStreamReader parser; 162 | InputStreamReader inReader; 163 | if (Functions.istUrl(dateiUrl)) { 164 | // eine URL verarbeiten 165 | int timeout = 20000; //ms 166 | URLConnection conn; 167 | conn = new URL(dateiUrl).openConnection(); 168 | conn.setRequestProperty("User-Agent", userAgent); 169 | conn.setReadTimeout(timeout); 170 | conn.setConnectTimeout(timeout); 171 | inReader = new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8); 172 | } else { 173 | // eine Datei verarbeiten 174 | File f = new File(dateiUrl); 175 | if (!f.exists()) { 176 | return; 177 | } 178 | inReader = new InputStreamReader(new FileInputStream(f), StandardCharsets.UTF_8); 179 | } 180 | parser = inFactory.createXMLStreamReader(inReader); 181 | while (parser.hasNext()) { 182 | event = parser.next(); 183 | if (event == XMLStreamConstants.START_ELEMENT) { 184 | String parsername = parser.getLocalName(); 185 | if (parsername.equals("Server")) { 186 | //wieder ein neuer Server, toll 187 | parseServerEntry(parser, listeFilmlistenUrls, art); 188 | } 189 | } 190 | } 191 | } catch (Exception ex) { 192 | Log.errorLog(821069874, ex, "Die URL-Filmlisten konnte nicht geladen werden: " + dateiUrl); 193 | } 194 | } 195 | 196 | /** 197 | * Parse the server XML file. 198 | * @param parser 199 | * @param listeFilmlistenUrls 200 | * @param art 201 | */ 202 | private void parseServerEntry(XMLStreamReader parser, ListeFilmlistenUrls listeFilmlistenUrls, String art) { 203 | String serverUrl = ""; 204 | String prio = ""; 205 | int event; 206 | try { 207 | while (parser.hasNext()) { 208 | event = parser.next(); 209 | if (event == XMLStreamConstants.START_ELEMENT) { 210 | //parsername = parser.getLocalName(); 211 | switch (parser.getLocalName()) { 212 | case "URL": 213 | serverUrl = parser.getElementText(); 214 | break; 215 | case "Prio": 216 | prio = parser.getElementText(); 217 | break; 218 | } 219 | } 220 | if (event == XMLStreamConstants.END_ELEMENT) { 221 | //parsername = parser.getLocalName(); 222 | if (parser.getLocalName().equals("Server")) { 223 | if (!serverUrl.equals("")) { 224 | //public DatenFilmUpdate(String url, String prio, String zeit, String datum, String anzahl) { 225 | if (prio.equals("")) { 226 | prio = DatenFilmlisteUrl.FILM_UPDATE_SERVER_PRIO_1; 227 | } 228 | listeFilmlistenUrls.addWithCheck(new DatenFilmlisteUrl(serverUrl, prio, art)); 229 | } 230 | break; 231 | } 232 | } 233 | } 234 | } catch (XMLStreamException ignored) { 235 | } 236 | 237 | } 238 | 239 | } 240 | -------------------------------------------------------------------------------- /src/main/java/de/mediathekview/mlib/tool/Functions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * MediathekView 3 | * Copyright (C) 2008 W. Xaver 4 | * W.Xaver[at]googlemail.com 5 | * http://zdfmediathk.sourceforge.net/ 6 | * 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 10 | * any later version. 11 | * 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. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | package de.mediathekview.mlib.tool; 21 | 22 | import java.io.File; 23 | import java.security.CodeSource; 24 | import java.util.ResourceBundle; 25 | 26 | import org.apache.commons.text.StringEscapeUtils; 27 | 28 | import com.jidesoft.utils.SystemInfo; 29 | 30 | import de.mediathekview.mlib.Const; 31 | import de.mediathekview.mlib.daten.DatenFilm; 32 | 33 | public class Functions { 34 | 35 | private static final String RBVERSION = "version"; 36 | 37 | public static String textLaenge(int max, String text, boolean mitte, boolean addVorne) { 38 | if (text.length() > max) { 39 | if (mitte) { 40 | text = text.substring(0, 25) + " .... " + text.substring(text.length() - (max - 31)); 41 | } else { 42 | text = text.substring(0, max - 1); 43 | } 44 | } 45 | while (text.length() < max) { 46 | if (addVorne) { 47 | text = ' ' + text; 48 | } else { 49 | text = text + ' '; 50 | } 51 | } 52 | return text; 53 | } 54 | 55 | public static String minTextLaenge(int max, String text) { 56 | while (text.length() < max) { 57 | text = text + ' '; 58 | } 59 | return text; 60 | } 61 | 62 | public enum OperatingSystemType { 63 | 64 | UNKNOWN(""), WIN32("Windows"), WIN64("Windows"), LINUX("Linux"), MAC("Mac"); 65 | private final String name; 66 | 67 | OperatingSystemType(String name) { 68 | this.name = name; 69 | } 70 | 71 | @Override 72 | public String toString() { 73 | return name; 74 | } 75 | } 76 | 77 | /** 78 | * Detect and return the currently used operating system. 79 | * 80 | * @return The enum for supported Operating Systems. 81 | */ 82 | public static OperatingSystemType getOs() { 83 | OperatingSystemType os = OperatingSystemType.UNKNOWN; 84 | 85 | if (System.getProperty("os.name").toLowerCase().contains("windows")) { 86 | if (System.getenv("ProgramFiles(x86)") != null) { 87 | // win 64Bit 88 | os = OperatingSystemType.WIN64; 89 | } else if (System.getenv("ProgramFiles") != null) { 90 | // win 32Bit 91 | os = OperatingSystemType.WIN32; 92 | } 93 | 94 | } else if (SystemInfo.isLinux()) { 95 | os = OperatingSystemType.LINUX; 96 | } else if (System.getProperty("os.name").toLowerCase().contains("freebsd")) { 97 | os = OperatingSystemType.LINUX; 98 | 99 | } else if (SystemInfo.isMacOSX()) { 100 | os = OperatingSystemType.MAC; 101 | } 102 | return os; 103 | } 104 | 105 | public static String getOsString() { 106 | return getOs().toString(); 107 | } 108 | 109 | public static String getPathJar() { 110 | // liefert den Pfad der Programmdatei mit File.separator am Schluss 111 | String pFilePath = "version.properties"; 112 | File propFile = new File(pFilePath); 113 | if (!propFile.exists()) { 114 | try { 115 | CodeSource cS = Const.class.getProtectionDomain().getCodeSource(); 116 | File jarFile = new File(cS.getLocation().toURI().getPath()); 117 | String jarDir = jarFile.getParentFile().getPath(); 118 | propFile = new File(jarDir + File.separator + pFilePath); 119 | } catch (Exception ignored) { 120 | } 121 | } else { 122 | DbgMsg.print("getPath"); 123 | } 124 | String s = propFile.getAbsolutePath().replace(pFilePath, ""); 125 | if (!s.endsWith(File.separator)) { 126 | s = s + File.separator; 127 | } 128 | if (s.endsWith("/lib/")) { 129 | // dann sind wir in der msearch-lib 130 | s = s.replace("/lib/", ""); 131 | } 132 | return s; 133 | } 134 | 135 | public static String getProgVersionString() { 136 | return " [Vers.: " + getProgVersion().toString() + ']'; 137 | } 138 | 139 | public static String[] getJavaVersion() { 140 | String[] ret = new String[4]; 141 | int i = 0; 142 | ret[i++] = "Vendor: " + System.getProperty("java.vendor"); 143 | ret[i++] = "VMname: " + System.getProperty("java.vm.name"); 144 | ret[i++] = "Version: " + System.getProperty("java.version"); 145 | ret[i++] = "Runtimeversion: " + System.getProperty("java.runtime.version"); 146 | return ret; 147 | } 148 | 149 | public static String getCompileDate() { 150 | String propToken = "DATE"; 151 | String msg = ""; 152 | try { 153 | ResourceBundle.clearCache(); 154 | ResourceBundle rb = ResourceBundle.getBundle(RBVERSION); 155 | if (rb.containsKey(propToken)) { 156 | msg = rb.getString(propToken); 157 | } 158 | } catch (Exception e) { 159 | Log.errorLog(807293847, e); 160 | } 161 | return msg; 162 | } 163 | 164 | public static Version getProgVersion() { 165 | String TOKEN_VERSION = "VERSION"; 166 | try { 167 | ResourceBundle.clearCache(); 168 | ResourceBundle rb = ResourceBundle.getBundle(RBVERSION); 169 | if (rb.containsKey(TOKEN_VERSION)) { 170 | return new Version(rb.getString(TOKEN_VERSION)); 171 | } 172 | } catch (Exception e) { 173 | Log.errorLog(134679898, e); 174 | } 175 | return new Version(""); 176 | } 177 | 178 | @Deprecated 179 | public static String getBuildNr() { 180 | String TOKEN_VERSION = "VERSION"; 181 | try { 182 | ResourceBundle.clearCache(); 183 | ResourceBundle rb = ResourceBundle.getBundle(RBVERSION); 184 | if (rb.containsKey(TOKEN_VERSION)) { 185 | return new Version(rb.getString(TOKEN_VERSION)).toString(); 186 | } 187 | } catch (Exception e) { 188 | Log.errorLog(134679898, e); 189 | } 190 | return new Version("").toString(); 191 | } 192 | 193 | private static void unescapeThema(DatenFilm film) { 194 | // Thema 195 | film.arr[DatenFilm.FILM_THEMA] = StringEscapeUtils.unescapeXml(film.arr[DatenFilm.FILM_THEMA]); 196 | film.arr[DatenFilm.FILM_THEMA] = StringEscapeUtils.unescapeHtml4(film.arr[DatenFilm.FILM_THEMA]); 197 | film.arr[DatenFilm.FILM_THEMA] = StringEscapeUtils.unescapeJava(film.arr[DatenFilm.FILM_THEMA]); 198 | } 199 | 200 | private static void unescapeTitel(DatenFilm film) { 201 | // Titel 202 | film.arr[DatenFilm.FILM_TITEL] = StringEscapeUtils.unescapeXml(film.arr[DatenFilm.FILM_TITEL]); 203 | film.arr[DatenFilm.FILM_TITEL] = StringEscapeUtils.unescapeHtml4(film.arr[DatenFilm.FILM_TITEL]); 204 | film.arr[DatenFilm.FILM_TITEL] = StringEscapeUtils.unescapeJava(film.arr[DatenFilm.FILM_TITEL]); 205 | } 206 | 207 | private static void unescapeDescription(DatenFilm film) { 208 | // Beschreibung 209 | film.arr[DatenFilm.FILM_BESCHREIBUNG] = StringEscapeUtils.unescapeXml(film.arr[DatenFilm.FILM_BESCHREIBUNG]); 210 | film.arr[DatenFilm.FILM_BESCHREIBUNG] = StringEscapeUtils.unescapeHtml4(film.arr[DatenFilm.FILM_BESCHREIBUNG]); 211 | film.arr[DatenFilm.FILM_BESCHREIBUNG] = StringEscapeUtils.unescapeJava(film.arr[DatenFilm.FILM_BESCHREIBUNG]); 212 | film.arr[DatenFilm.FILM_BESCHREIBUNG] = removeHtml(film.arr[DatenFilm.FILM_BESCHREIBUNG]); 213 | } 214 | 215 | private static void replaceText(DatenFilm film) { 216 | film.arr[DatenFilm.FILM_THEMA] = film.arr[DatenFilm.FILM_THEMA].replace("\\", "/").trim(); 217 | film.arr[DatenFilm.FILM_TITEL] = film.arr[DatenFilm.FILM_TITEL].replace("\\", "/").trim(); 218 | film.arr[DatenFilm.FILM_BESCHREIBUNG] = film.arr[DatenFilm.FILM_BESCHREIBUNG].replace("\\", "/").trim(); 219 | } 220 | 221 | public static void unescape(DatenFilm film) { 222 | unescapeThema(film); 223 | unescapeTitel(film); 224 | unescapeDescription(film); 225 | 226 | replaceText(film); 227 | } 228 | 229 | // public static String utf8(String ret) { 230 | // ret = ret.replace("\\u0026", "&"); 231 | // ret = ret.replace("\\u003C", "<"); 232 | // ret = ret.replace("\\u003c", "<"); 233 | // ret = ret.replace("\\u003E", ">"); 234 | // ret = ret.replace("\\u003e", ">"); 235 | // ret = ret.replace("\\u00E4", "ä"); 236 | // ret = ret.replace("\\u00e4", "ä"); 237 | // ret = ret.replace("\\u00C4", "Ä"); 238 | // ret = ret.replace("\\u00c4", "Ä"); 239 | // ret = ret.replace("\\u00F6", "ö"); 240 | // ret = ret.replace("\\u00f6", "ö"); 241 | // ret = ret.replace("\\u00D6", "Ö"); 242 | // ret = ret.replace("\\u00d6", "Ö"); 243 | // ret = ret.replace("\\u00FC", "ü"); 244 | // ret = ret.replace("\\u00fc", "ü"); 245 | // ret = ret.replace("\\u00DC", "Ü"); 246 | // ret = ret.replace("\\u00dc", "Ü"); 247 | // ret = ret.replace("\\u00DF", "ß"); 248 | // ret = ret.replace("\\u00df", "ß"); 249 | // ret = ret.replace("\\u20AC", "€"); 250 | // ret = ret.replace("\\u20ac", "€"); 251 | // ret = ret.replace("\\u0024", "$"); 252 | // ret = ret.replace("\\u00A3", "£"); 253 | // ret = ret.replace("\\u00a3", "£"); 254 | // ret = ret.replace("\\u00F3", "\u00f3"); 255 | // ret = ret.replace("\\u00f3", "\u00f3"); 256 | // return ret; 257 | // } 258 | public static String addsPfad(String pfad1, String pfad2) { 259 | String ret = ""; 260 | if (pfad1 != null && pfad2 != null) { 261 | if (pfad1.isEmpty()) { 262 | ret = pfad2; 263 | } else if (pfad2.isEmpty()) { 264 | ret = pfad1; 265 | } else if (!pfad1.isEmpty() && !pfad2.isEmpty()) { 266 | if (pfad1.endsWith(File.separator)) { 267 | ret = pfad1.substring(0, pfad1.length() - 1); 268 | } else { 269 | ret = pfad1; 270 | } 271 | if (pfad2.charAt(0) == File.separatorChar) { 272 | ret += pfad2; 273 | } else { 274 | ret += File.separator + pfad2; 275 | } 276 | } 277 | } 278 | if (ret.isEmpty()) { 279 | Log.errorLog(283946015, pfad1 + " - " + pfad2); 280 | } 281 | return ret; 282 | } 283 | 284 | public static String addUrl(String u1, String u2) { 285 | if (u1.endsWith("/")) { 286 | return u1 + u2; 287 | } else { 288 | return u1 + '/' + u2; 289 | } 290 | } 291 | 292 | public static boolean istUrl(String dateiUrl) { 293 | //return dateiUrl.startsWith("http") ? true : false || dateiUrl.startsWith("www") ? true : false; 294 | return dateiUrl.startsWith("http") || dateiUrl.startsWith("www"); 295 | } 296 | 297 | public static String getDateiName(String pfad) { 298 | //Dateinamen einer URL extrahieren 299 | String ret = ""; 300 | if (pfad != null) { 301 | if (!pfad.isEmpty()) { 302 | ret = pfad.substring(pfad.lastIndexOf('/') + 1); 303 | } 304 | } 305 | if (ret.contains("?")) { 306 | ret = ret.substring(0, ret.indexOf('?')); 307 | } 308 | if (ret.contains("&")) { 309 | ret = ret.substring(0, ret.indexOf('&')); 310 | } 311 | if (ret.isEmpty()) { 312 | Log.errorLog(395019631, pfad); 313 | } 314 | return ret; 315 | } 316 | 317 | public static String removeHtml(String in) { 318 | return in.replaceAll("\\<.*?>", ""); 319 | } 320 | } 321 | -------------------------------------------------------------------------------- /src/main/java/de/mediathekview/mlib/filmlisten/FilmlisteLesen.java: -------------------------------------------------------------------------------- 1 | /* 2 | * MediathekView 3 | * Copyright (C) 2008 W. Xaver 4 | * W.Xaver[at]googlemail.com 5 | * http://zdfmediathk.sourceforge.net/ 6 | * 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 10 | * any later version. 11 | * 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. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | package de.mediathekview.mlib.filmlisten; 21 | 22 | import java.io.FileInputStream; 23 | import java.io.FileNotFoundException; 24 | import java.io.IOException; 25 | import java.io.InputStream; 26 | import java.net.MalformedURLException; 27 | import java.net.URL; 28 | import java.util.Date; 29 | import java.util.concurrent.TimeUnit; 30 | import java.util.zip.ZipInputStream; 31 | 32 | import javax.swing.event.EventListenerList; 33 | 34 | import org.apache.commons.lang3.time.FastDateFormat; 35 | import org.tukaani.xz.XZInputStream; 36 | 37 | import com.fasterxml.jackson.core.JsonFactory; 38 | import com.fasterxml.jackson.core.JsonParser; 39 | import com.fasterxml.jackson.core.JsonToken; 40 | 41 | import de.mediathekview.mlib.Config; 42 | import de.mediathekview.mlib.Const; 43 | import de.mediathekview.mlib.daten.DatenFilm; 44 | import de.mediathekview.mlib.daten.ListeFilme; 45 | import de.mediathekview.mlib.filmesuchen.ListenerFilmeLaden; 46 | import de.mediathekview.mlib.filmesuchen.ListenerFilmeLadenEvent; 47 | import de.mediathekview.mlib.tool.InputStreamProgressMonitor; 48 | import de.mediathekview.mlib.tool.Log; 49 | import de.mediathekview.mlib.tool.MVHttpClient; 50 | import de.mediathekview.mlib.tool.ProgressMonitorInputStream; 51 | import okhttp3.Request; 52 | import okhttp3.Response; 53 | import okhttp3.ResponseBody; 54 | 55 | public class FilmlisteLesen { 56 | private static final int PROGRESS_MAX = 100; 57 | private static WorkMode workMode = WorkMode.NORMAL; // die Klasse wird an verschiedenen Stellen benutzt, klappt sonst nicht immer, zB. FilmListe zu alt und neu laden 58 | private final EventListenerList listeners = new EventListenerList(); 59 | private int max = 0; 60 | private int progress = 0; 61 | private long milliseconds = 0; 62 | 63 | /** 64 | * Set the specific work mode for reading film list. 65 | * In FASTAUTO mode, no film descriptions will be read into memory. 66 | * 67 | * @param mode The mode in which to operate when reading film list. 68 | */ 69 | public static void setWorkMode(WorkMode mode) { 70 | workMode = mode; 71 | } 72 | 73 | public void addAdListener(ListenerFilmeLaden listener) { 74 | listeners.add(ListenerFilmeLaden.class, listener); 75 | } 76 | 77 | private InputStream selectDecompressor(String source, InputStream in) throws Exception { 78 | if (source.endsWith(Const.FORMAT_XZ)) { 79 | in = new XZInputStream(in); 80 | } else if (source.endsWith(Const.FORMAT_ZIP)) { 81 | ZipInputStream zipInputStream = new ZipInputStream(in); 82 | zipInputStream.getNextEntry(); 83 | in = zipInputStream; 84 | } 85 | return in; 86 | } 87 | 88 | private void readData(JsonParser jp, ListeFilme listeFilme) throws IOException { 89 | JsonToken jsonToken; 90 | String sender = "", thema = ""; 91 | 92 | if (jp.nextToken() != JsonToken.START_OBJECT) { 93 | throw new IllegalStateException("Expected data to start with an Object"); 94 | } 95 | 96 | while ((jsonToken = jp.nextToken()) != null) { 97 | if (jsonToken == JsonToken.END_OBJECT) { 98 | break; 99 | } 100 | if (jp.isExpectedStartArrayToken()) { 101 | for (int k = 0; k < ListeFilme.MAX_ELEM; ++k) { 102 | listeFilme.metaDaten[k] = jp.nextTextValue(); 103 | } 104 | break; 105 | } 106 | } 107 | while ((jsonToken = jp.nextToken()) != null) { 108 | if (jsonToken == JsonToken.END_OBJECT) { 109 | break; 110 | } 111 | if (jp.isExpectedStartArrayToken()) { 112 | // sind nur die Feldbeschreibungen, brauch mer nicht 113 | jp.nextToken(); 114 | break; 115 | } 116 | } 117 | while (!Config.getStop() && (jsonToken = jp.nextToken()) != null) { 118 | if (jsonToken == JsonToken.END_OBJECT) { 119 | break; 120 | } 121 | if (jp.isExpectedStartArrayToken()) { 122 | DatenFilm datenFilm = new DatenFilm(); 123 | for (int i = 0; i < DatenFilm.JSON_NAMES.length; ++i) { 124 | //if we are in FASTAUTO mode, we don´t need film descriptions. 125 | //this should speed up loading on low end devices... 126 | if (workMode == WorkMode.FASTAUTO) { 127 | if (DatenFilm.JSON_NAMES[i] == DatenFilm.FILM_BESCHREIBUNG 128 | || DatenFilm.JSON_NAMES[i] == DatenFilm.FILM_WEBSEITE 129 | || DatenFilm.JSON_NAMES[i] == DatenFilm.FILM_GEO) { 130 | jp.nextToken(); 131 | continue; 132 | } 133 | } 134 | if (DatenFilm.JSON_NAMES[i] == DatenFilm.FILM_NEU) { 135 | final String value = jp.nextTextValue(); 136 | //This value is unused... 137 | //datenFilm.arr[DatenFilm.FILM_NEU_NR] = value; 138 | datenFilm.setNew(Boolean.parseBoolean(value)); 139 | } else { 140 | datenFilm.arr[DatenFilm.JSON_NAMES[i]] = jp.nextTextValue(); 141 | } 142 | 143 | /// für die Entwicklungszeit 144 | if (datenFilm.arr[DatenFilm.JSON_NAMES[i]] == null) { 145 | datenFilm.arr[DatenFilm.JSON_NAMES[i]] = ""; 146 | } 147 | } 148 | if (datenFilm.arr[DatenFilm.FILM_SENDER].isEmpty()) { 149 | datenFilm.arr[DatenFilm.FILM_SENDER] = sender; 150 | } else { 151 | sender = datenFilm.arr[DatenFilm.FILM_SENDER]; 152 | } 153 | if (datenFilm.arr[DatenFilm.FILM_THEMA].isEmpty()) { 154 | datenFilm.arr[DatenFilm.FILM_THEMA] = thema; 155 | } else { 156 | thema = datenFilm.arr[DatenFilm.FILM_THEMA]; 157 | } 158 | 159 | listeFilme.importFilmliste(datenFilm); 160 | if (milliseconds > 0) { 161 | // muss "rückwärts" laufen, da das Datum sonst 2x gebaut werden muss 162 | // wenns drin bleibt, kann mans noch ändern 163 | if (!checkDate(datenFilm)) { 164 | listeFilme.remove(datenFilm); 165 | } 166 | } 167 | } 168 | } 169 | } 170 | 171 | /** 172 | * Read a locally available filmlist. 173 | * 174 | * @param source file path as string 175 | * @param listeFilme the list to read to 176 | */ 177 | private void processFromFile(String source, ListeFilme listeFilme) { 178 | notifyProgress(source, PROGRESS_MAX); 179 | try (InputStream in = selectDecompressor(source, new FileInputStream(source)); 180 | JsonParser jp = new JsonFactory().createParser(in)) { 181 | readData(jp, listeFilme); 182 | } catch (FileNotFoundException ex) { 183 | Log.errorLog(894512369, "FilmListe existiert nicht: " + source); 184 | listeFilme.clear(); 185 | } catch (Exception ex) { 186 | Log.errorLog(945123641, ex, "FilmListe: " + source); 187 | listeFilme.clear(); 188 | } 189 | } 190 | 191 | private void checkDays(long days) { 192 | if (days > 0) { 193 | milliseconds = System.currentTimeMillis() - TimeUnit.MILLISECONDS.convert(days, TimeUnit.DAYS); 194 | } else { 195 | milliseconds = 0; 196 | } 197 | } 198 | 199 | public void readFilmListe(String source, final ListeFilme listeFilme, int days) { 200 | try { 201 | Log.sysLog("Liste Filme lesen von: " + source); 202 | listeFilme.clear(); 203 | this.notifyStart(source, PROGRESS_MAX); // für die Progressanzeige 204 | 205 | checkDays(days); 206 | 207 | if (!source.startsWith("http")) { 208 | processFromFile(source, listeFilme); 209 | } else { 210 | processFromWeb(new URL(source), listeFilme); 211 | } 212 | 213 | if (Config.getStop()) { 214 | Log.sysLog("--> Abbruch"); 215 | listeFilme.clear(); 216 | } 217 | } catch (MalformedURLException ex) { 218 | ex.printStackTrace(); 219 | } 220 | 221 | notifyFertig(source, listeFilme); 222 | } 223 | 224 | /** 225 | * Download a process a filmliste from the web. 226 | * 227 | * @param source source url as string 228 | * @param listeFilme the list to read to 229 | */ 230 | private void processFromWeb(URL source, ListeFilme listeFilme) { 231 | Request.Builder builder = new Request.Builder().url(source); 232 | builder.addHeader("User-Agent", Config.getUserAgent()); 233 | 234 | //our progress monitor callback 235 | InputStreamProgressMonitor monitor = new InputStreamProgressMonitor() { 236 | private int oldProgress = 0; 237 | 238 | @Override 239 | public void progress(long bytesRead, long size) { 240 | final int iProgress = (int) (bytesRead * 100 / size); 241 | if (iProgress != oldProgress) { 242 | oldProgress = iProgress; 243 | notifyProgress(source.toString(), iProgress); 244 | } 245 | } 246 | }; 247 | 248 | try (Response response = MVHttpClient.getInstance().getHttpClient().newCall(builder.build()).execute(); 249 | ResponseBody body = response.body()) { 250 | if (response.isSuccessful()) { 251 | try (InputStream input = new ProgressMonitorInputStream(body.byteStream(), body.contentLength(), monitor)) { 252 | try (InputStream is = selectDecompressor(source.toString(), input); 253 | JsonParser jp = new JsonFactory().createParser(is)) { 254 | readData(jp, listeFilme); 255 | } 256 | } 257 | } 258 | } catch (Exception ex) { 259 | Log.errorLog(945123641, ex, "FilmListe: " + source); 260 | listeFilme.clear(); 261 | } 262 | } 263 | 264 | private boolean checkDate(DatenFilm film) { 265 | // true wenn der Film angezeigt werden kann! 266 | try { 267 | if (film.datumFilm.getTime() != 0) { 268 | if (film.datumFilm.getTime() < milliseconds) { 269 | return false; 270 | } 271 | } 272 | } catch (Exception ex) { 273 | Log.errorLog(495623014, ex); 274 | } 275 | return true; 276 | } 277 | 278 | private void notifyStart(String url, int mmax) { 279 | max = mmax; 280 | progress = 0; 281 | for (ListenerFilmeLaden l : listeners.getListeners(ListenerFilmeLaden.class)) { 282 | l.start(new ListenerFilmeLadenEvent(url, "", max, 0, 0, false)); 283 | } 284 | } 285 | 286 | private void notifyProgress(String url, int iProgress) { 287 | progress = iProgress; 288 | if (progress > max) { 289 | progress = max; 290 | } 291 | for (ListenerFilmeLaden l : listeners.getListeners(ListenerFilmeLaden.class)) { 292 | l.progress(new ListenerFilmeLadenEvent(url, "Download", max, progress, 0, false)); 293 | } 294 | } 295 | 296 | private void notifyFertig(String url, ListeFilme liste) { 297 | Log.sysLog("Liste Filme gelesen am: " + FastDateFormat.getInstance("dd.MM.yyyy, HH:mm").format(new Date())); 298 | Log.sysLog(" erstellt am: " + liste.genDate()); 299 | Log.sysLog(" Anzahl Filme: " + liste.size()); 300 | for (ListenerFilmeLaden l : listeners.getListeners(ListenerFilmeLaden.class)) { 301 | l.fertig(new ListenerFilmeLadenEvent(url, "", max, progress, 0, false)); 302 | } 303 | } 304 | 305 | public enum WorkMode { 306 | 307 | NORMAL, FASTAUTO 308 | } 309 | } 310 | -------------------------------------------------------------------------------- /src/main/java/de/mediathekview/mlib/tool/Log.java: -------------------------------------------------------------------------------- 1 | /* 2 | * MediathekView 3 | * Copyright (C) 2008 W. Xaver 4 | * W.Xaver[at]googlemail.com 5 | * http://zdfmediathk.sourceforge.net/ 6 | * 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 10 | * any later version. 11 | * 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. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | package de.mediathekview.mlib.tool; 21 | 22 | import java.io.File; 23 | import java.io.FileOutputStream; 24 | import java.io.OutputStreamWriter; 25 | import java.io.PrintWriter; 26 | import java.io.StringWriter; 27 | import java.nio.charset.StandardCharsets; 28 | import java.text.SimpleDateFormat; 29 | import java.util.ArrayList; 30 | import java.util.Date; 31 | import java.util.LinkedList; 32 | 33 | import com.jidesoft.utils.SystemInfo; 34 | 35 | import de.mediathekview.mlib.Config; 36 | import de.mediathekview.mlib.Const; 37 | 38 | public class Log { 39 | 40 | private final static String FEHLER = "Fehler(" + Const.PROGRAMMNAME + "): "; 41 | public final static String LILNE = "################################################################################"; 42 | 43 | // private 44 | private static class Error { 45 | 46 | String cl = ""; 47 | int nr = 0; 48 | int count = 0; 49 | boolean ex = false; 50 | 51 | public Error(int nr, String cl, boolean ex) { 52 | this.nr = nr; 53 | this.cl = cl; 54 | this.ex = ex; 55 | this.count = 1; 56 | } 57 | } 58 | private static final LinkedList fehlerListe = new LinkedList<>(); 59 | private static boolean progress = false; 60 | public static final Date startZeit = new Date(System.currentTimeMillis()); 61 | private static File logFile = null; 62 | private static final ArrayList logList = new ArrayList<>(); 63 | 64 | public static synchronized void setLogfile(String logFileString) { 65 | logFile = new File(logFileString); 66 | File dir = new File(logFile.getParent()); 67 | if (!dir.exists()) { 68 | if (!dir.mkdirs()) { 69 | logFile = null; 70 | Log.errorLog(632012165, "Kann den Pfad nicht anlegen: " + dir.toString()); 71 | } 72 | } 73 | 74 | } 75 | 76 | private static final SimpleDateFormat dateFormatter = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss"); 77 | 78 | private static final long TO_MEGABYTE = 1000L * 1000L; 79 | 80 | public static void versionMsg(String progName) { 81 | if (!SystemInfo.isMacOSX()) { 82 | sysLog(""); 83 | sysLog(""); 84 | sysLog(""); 85 | sysLog(""); 86 | sysLog(""); 87 | sysLog("___ ___ _ _ _ _ _ _ _ _ "); 88 | sysLog("| \\/ | | (_) | | | | | | | | | (_) "); 89 | sysLog("| . . | ___ __| |_ __ _| |_| |__ ___| | _| | | |_ _____ __"); 90 | sysLog("| |\\/| |/ _ \\/ _` | |/ _` | __| '_ \\ / _ \\ |/ / | | | |/ _ \\ \\ /\\ / /"); 91 | sysLog("| | | | __/ (_| | | (_| | |_| | | | __/ <\\ \\_/ / | __/\\ V V / "); 92 | sysLog("\\_| |_/\\___|\\__,_|_|\\__,_|\\__|_| |_|\\___|_|\\_\\\\___/|_|\\___| \\_/\\_/ "); 93 | sysLog(""); 94 | sysLog(""); 95 | } 96 | sysLog(LILNE); 97 | sysLog("Programmstart: " + dateFormatter.format(Log.startZeit)); 98 | sysLog(LILNE); 99 | sysLog(""); 100 | final long totalMem = Runtime.getRuntime().totalMemory(); 101 | sysLog("totalMemory: " + totalMem / TO_MEGABYTE + " MB"); 102 | final long maxMem = Runtime.getRuntime().maxMemory(); 103 | sysLog("maxMemory: " + maxMem / TO_MEGABYTE + " MB"); 104 | final long freeMem = Runtime.getRuntime().freeMemory(); 105 | sysLog("freeMemory: " + freeMem / TO_MEGABYTE + " MB"); 106 | sysLog(""); 107 | sysLog(LILNE); 108 | sysLog(""); 109 | //Version 110 | sysLog(progName + Functions.getProgVersionString()); 111 | String compile = Functions.getCompileDate(); 112 | if (!compile.isEmpty()) { 113 | sysLog("Compiled: " + compile); 114 | } 115 | sysLog(""); 116 | sysLog(LILNE); 117 | sysLog(""); 118 | sysLog("Java"); 119 | final String[] java = Functions.getJavaVersion(); 120 | for (String ja : java) { 121 | sysLog(ja); 122 | } 123 | sysLog(""); 124 | } 125 | 126 | public static void endMsg() { 127 | sysLog(""); 128 | sysLog(""); 129 | sysLog(""); 130 | sysLog(""); 131 | 132 | printErrorMsg().forEach(Log::sysLog); 133 | 134 | // Laufzeit ausgeben 135 | Date stopZeit = new Date(System.currentTimeMillis()); 136 | int minuten; 137 | try { 138 | minuten = Math.round((stopZeit.getTime() - Log.startZeit.getTime()) / (1000 * 60)); 139 | } catch (Exception ex) { 140 | minuten = -1; 141 | } 142 | sysLog(""); 143 | sysLog(""); 144 | sysLog(LILNE); 145 | sysLog(" --> Beginn: " + dateFormatter.format(Log.startZeit)); 146 | sysLog(" --> Fertig: " + dateFormatter.format(stopZeit)); 147 | sysLog(" --> Dauer[Min]: " + (minuten == 0 ? "<1" : minuten)); 148 | sysLog(LILNE); 149 | sysLog(""); 150 | sysLog(" und Tschuess"); 151 | sysLog(""); 152 | sysLog(""); 153 | sysLog(LILNE); 154 | } 155 | 156 | public static synchronized ArrayList printErrorMsg() { 157 | int max = 0; 158 | ArrayList retList = new ArrayList<>(); 159 | retList.add(""); 160 | retList.add(LILNE); 161 | if (fehlerListe.isEmpty()) { 162 | retList.add(" Keine Fehler :)"); 163 | } else { 164 | // Fehler ausgeben 165 | int i_1; 166 | int i_2; 167 | for (Error e : fehlerListe) { 168 | if (e.cl.length() > max) { 169 | max = e.cl.length(); 170 | } 171 | } 172 | max++; 173 | for (Error e : fehlerListe) { 174 | while (e.cl.length() < max) { 175 | e.cl = e.cl + ' '; 176 | } 177 | } 178 | for (int i = 1; i < fehlerListe.size(); ++i) { 179 | for (int k = i; k > 0; --k) { 180 | i_1 = fehlerListe.get(k - 1).nr; 181 | i_2 = fehlerListe.get(k).nr; 182 | // if (str1.compareToIgnoreCase(str2) > 0) { 183 | if (i_1 < i_2) { 184 | fehlerListe.add(k - 1, fehlerListe.remove(k)); 185 | } else { 186 | break; 187 | } 188 | } 189 | } 190 | for (Error e : fehlerListe) { 191 | String strEx; 192 | if (e.ex) { 193 | strEx = "Ex! "; 194 | } else { 195 | strEx = " "; 196 | } 197 | retList.add(strEx + e.cl + " Fehlernummer: " + e.nr + " Anzahl: " + e.count); 198 | } 199 | } 200 | retList.add(LILNE); 201 | return retList; 202 | } 203 | 204 | // Fehlermeldung mit Exceptions 205 | public static synchronized void errorLog(int fehlerNummer, Exception ex) { 206 | fehlermeldung_(fehlerNummer, ex, new String[]{}); 207 | } 208 | 209 | public static synchronized void errorLog(int fehlerNummer, Exception ex, String text) { 210 | fehlermeldung_(fehlerNummer, ex, new String[]{text}); 211 | } 212 | 213 | public static synchronized void errorLog(int fehlerNummer, Exception ex, String text[]) { 214 | fehlermeldung_(fehlerNummer, ex, text); 215 | } 216 | 217 | // Fehlermeldungen 218 | public static synchronized void errorLog(int fehlerNummer, String text) { 219 | fehlermeldung_(fehlerNummer, null, new String[]{text}); 220 | } 221 | 222 | public static synchronized void errorLog(int fehlerNummer, String[] text) { 223 | fehlermeldung_(fehlerNummer, null, text); 224 | } 225 | 226 | // public static synchronized void systemMeldung(String[] text) { 227 | // systemmeldung_(text); 228 | // } 229 | public static synchronized void sysLog(String text) { 230 | systemmeldung_(new String[]{text}); 231 | } 232 | 233 | public static synchronized void progress(String texte) { 234 | progress = true; 235 | if (!texte.isEmpty()) { 236 | System.out.print(texte + '\r'); 237 | } 238 | } 239 | 240 | private static void resetProgress() { 241 | // Leerzeile um die Progresszeile zu löschen 242 | if (progress) { 243 | System.out.print(" \r"); 244 | progress = false; 245 | } 246 | } 247 | 248 | private static void addFehlerNummer(int nr, String classs, boolean exception) { 249 | for (Error e : fehlerListe) { 250 | if (e.nr == nr) { 251 | ++e.count; 252 | return; 253 | } 254 | } 255 | // dann gibts die Nummer noch nicht 256 | fehlerListe.add(new Error(nr, classs, exception)); 257 | } 258 | 259 | private static void fehlermeldung_(int fehlerNummer, Exception ex, String[] texte) { 260 | final Throwable t = new Throwable(); 261 | final StackTraceElement methodCaller = t.getStackTrace()[2]; 262 | final String klasse = methodCaller.getClassName() + '.' + methodCaller.getMethodName(); 263 | String kl; 264 | try { 265 | kl = klasse; 266 | while (kl.contains(".")) { 267 | if (Character.isUpperCase(kl.charAt(0))) { 268 | break; 269 | } else { 270 | kl = kl.substring(kl.indexOf('.') + 1); 271 | } 272 | } 273 | } catch (Exception ignored) { 274 | kl = klasse; 275 | } 276 | addFehlerNummer(fehlerNummer, kl, ex != null); 277 | if (ex != null || Config.debug) { 278 | // Exceptions immer ausgeben 279 | resetProgress(); 280 | String x, z; 281 | if (ex != null) { 282 | x = "!"; 283 | } else { 284 | x = "="; 285 | } 286 | z = "*"; 287 | logList.add(x + x + x + x + x + x + x + x + x + x 288 | + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x); 289 | 290 | try { 291 | // Stacktrace 292 | try (StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw)) { 293 | if (ex != null) { 294 | ex.printStackTrace(pw); 295 | } 296 | pw.flush(); 297 | sw.flush(); 298 | logList.add(sw.toString()); 299 | } 300 | } catch (Exception ignored) { 301 | } 302 | 303 | logList.add(z + " Fehlernr: " + fehlerNummer); 304 | if (ex != null) { 305 | logList.add(z + " Exception: " + ex.getMessage()); 306 | } 307 | logList.add(z + ' ' + FEHLER + kl); 308 | for (String aTexte : texte) { 309 | logList.add(z + " " + aTexte); 310 | } 311 | logList.add(""); 312 | printLog(); 313 | } 314 | } 315 | 316 | private static void systemmeldung_(String[] texte) { 317 | resetProgress(); 318 | final String z = ". "; 319 | if (texte.length <= 1) { 320 | logList.add(z + ' ' + texte[0]); 321 | } else { 322 | String zeile = "---------------------------------------"; 323 | String txt; 324 | logList.add(z + zeile); 325 | for (String aTexte : texte) { 326 | txt = "| " + aTexte; 327 | logList.add(z + txt); 328 | } 329 | logList.add(z + zeile); 330 | } 331 | printLog(); 332 | } 333 | 334 | private static void printLog() { 335 | logList.forEach(System.out::println); 336 | 337 | if (logFile != null) { 338 | try (OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(logFile, true), StandardCharsets.UTF_8)) { 339 | for (String s : logList) { 340 | out.write(s); 341 | out.write("\n"); 342 | } 343 | } catch (Exception ex) { 344 | System.out.println(ex.getMessage()); 345 | } 346 | } 347 | logList.clear(); 348 | } 349 | } 350 | -------------------------------------------------------------------------------- /src/main/java/de/mediathekview/mlib/tool/FilenameUtils.java: -------------------------------------------------------------------------------- 1 | package de.mediathekview.mlib.tool; 2 | 3 | import java.io.File; 4 | import java.nio.ByteBuffer; 5 | import java.nio.CharBuffer; 6 | import java.nio.charset.CharacterCodingException; 7 | import java.nio.charset.Charset; 8 | import java.nio.charset.CharsetEncoder; 9 | import java.nio.charset.CodingErrorAction; 10 | 11 | import com.jidesoft.utils.SystemInfo; 12 | 13 | /** 14 | * User: crystalpalace1977 15 | * Date: 28.12.14 16 | * Time: 16:02 17 | */ 18 | public class FilenameUtils { 19 | 20 | /** 21 | * Valid characters for Windows in file names: 22 | * Based on http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx 23 | */ 24 | public static final String REGEXP_ILLEGAL_CHARACTERS_WINDOWS = "[:\\\\/*?|<>\"]"; 25 | public static final String REGEXP_ILLEGAL_CHARACTERS_WINDOWS_PATH = "[:/*?|<>\"]"; 26 | 27 | /** 28 | * Valid characters for all UNIX-like OS. 29 | */ 30 | public static final String REGEXP_ILLEGAL_CHARACTERS_OTHERS = "[:\\\\/*|<>]"; 31 | public static final String REGEXP_ILLEGAL_CHARACTERS_OTHERS_PATH = "[:\\\\*|<>]"; 32 | 33 | public static String checkDateiname(final String name, final boolean isPath) { 34 | // dient nur zur Anzeige für Probleme (Textfeld wird rot) 35 | String ret = name; 36 | boolean isWindowsPath = false; 37 | final String splitChar; 38 | 39 | if (SystemInfo.isWindows()) { 40 | splitChar = "\\\\"; 41 | } else { 42 | splitChar = "/"; 43 | } 44 | 45 | if (SystemInfo.isWindows()) { 46 | ret = removeWindowsTrailingDots(ret); 47 | if (isPath) { 48 | if (ret.length() > 1 && ret.charAt(1) == ':') { 49 | // damit auch "d:" und nicht nur "d:\" als Pfad geht 50 | isWindowsPath = true; 51 | ret = ret.replaceFirst(":", ""); // muss zum Schluss wieder rein, kann aber so nicht ersetzt werden 52 | } 53 | } 54 | } else { 55 | ret = removeStartingDots(ret); 56 | } 57 | 58 | if (isPath && ret.contains(File.separator)) { 59 | String str = ""; 60 | final String[] sa = ret.split(splitChar); // Regex 61 | for (String s : sa) { 62 | if (!s.isEmpty()) { 63 | str += File.separator + convertToNativeEncoding(s, false); //sind ja nur noch die Ordnernamen 64 | } 65 | } 66 | if (!ret.startsWith(File.separator)) { 67 | str = str.replaceFirst(splitChar, ""); // wieder Regex 68 | } 69 | if (ret.endsWith(File.separator)) { 70 | str = str + File.separator; 71 | } 72 | ret = str; 73 | } else { 74 | ret = convertToNativeEncoding(ret, false); 75 | } 76 | 77 | if (isWindowsPath) { 78 | // c: wieder herstellen 79 | if (ret.length() == 1) { 80 | ret = ret + ":"; 81 | } else if (ret.length() > 1) { 82 | ret = ret.charAt(0) + ":" + ret.substring(1); 83 | } 84 | } 85 | 86 | return ret; 87 | } 88 | 89 | /** 90 | * Remove stray trailing dots from string when we are on Windows OS. 91 | * 92 | * @param fileName A filename string that might include trailing dots. 93 | * @return Cleanup string with no dots anymore. 94 | */ 95 | private static String removeWindowsTrailingDots(String fileName) { 96 | // machte unter Win noch Probleme, zB. bei dem Titel: "betrifft: ..." 97 | // "." und " " am Ende machen Probleme 98 | while (!fileName.isEmpty() && (fileName.endsWith(".") || fileName.endsWith(" "))) { 99 | fileName = fileName.substring(0, fileName.length() - 1); 100 | } 101 | return fileName; 102 | } 103 | 104 | /** 105 | * Remove dots from string when we are on Linux/OS X 106 | * 107 | * @param fileName A filename string that might start with dots. 108 | * @return Cleanup string with no dots anymore. 109 | */ 110 | private static String removeStartingDots(String fileName) { 111 | // machte unter OS X/Linux Probleme, zB. bei dem Titel: "....Paula" 112 | while (!fileName.isEmpty() && (fileName.startsWith("."))) { 113 | fileName = fileName.substring(1, fileName.length()); 114 | } 115 | return fileName; 116 | } 117 | 118 | /** 119 | * Convert a filename from Java´s native UTF-16 to OS native character encoding. 120 | * 121 | * @param fileName The UTF-16 filename string. 122 | * @return Natively encoded string for the OS. 123 | */ 124 | private static String convertToNativeEncoding(String fileName, boolean isPath) { 125 | String ret = fileName; 126 | 127 | ret = removeIllegalCharacters(ret, isPath); 128 | 129 | //convert our filename to OS encoding... 130 | try { 131 | final CharsetEncoder charsetEncoder = Charset.defaultCharset().newEncoder(); 132 | charsetEncoder.onMalformedInput(CodingErrorAction.REPLACE); // otherwise breaks on first unconvertable char 133 | charsetEncoder.onUnmappableCharacter(CodingErrorAction.REPLACE); 134 | charsetEncoder.replaceWith(new byte[]{'_'}); 135 | 136 | final ByteBuffer buf = charsetEncoder.encode(CharBuffer.wrap(ret)); 137 | if (buf.hasArray()) { 138 | ret = new String(buf.array()); 139 | } 140 | 141 | //remove NUL character from conversion... 142 | ret = ret.replaceAll("\\u0000", ""); 143 | } catch (CharacterCodingException e) { 144 | e.printStackTrace(); 145 | } 146 | 147 | return ret; 148 | } 149 | 150 | /** 151 | * Convert a filename from Java´s native UTF-16 to US-ASCII character encoding. 152 | * 153 | * @param fileName The UTF-16 filename string. 154 | * @return US-ASCII encoded string for the OS. 155 | */ 156 | private static String convertToASCIIEncoding(String fileName, boolean isPath) { 157 | String ret = fileName; 158 | 159 | ret = ret.replace("ä", "ae"); 160 | ret = ret.replace("ö", "oe"); 161 | ret = ret.replace("ü", "ue"); 162 | ret = ret.replace("Ä", "Ae"); 163 | ret = ret.replace("Ö", "Oe"); 164 | ret = ret.replace("Ü", "Ue"); 165 | ret = ret.replace("ß", "ss"); 166 | 167 | // ein Versuch zu vereinfachen 168 | ret = cleanUnicode(ret); 169 | 170 | ret = removeIllegalCharacters(ret, isPath); 171 | 172 | //convert our filename to OS encoding... 173 | try { 174 | final CharsetEncoder charsetEncoder = Charset.forName("US-ASCII").newEncoder(); 175 | charsetEncoder.onMalformedInput(CodingErrorAction.REPLACE); // otherwise breaks on first unconvertable char 176 | charsetEncoder.onUnmappableCharacter(CodingErrorAction.REPLACE); 177 | charsetEncoder.replaceWith(new byte[]{'_'}); 178 | 179 | final ByteBuffer buf = charsetEncoder.encode(CharBuffer.wrap(ret)); 180 | if (buf.hasArray()) { 181 | ret = new String(buf.array()); 182 | } 183 | 184 | //remove NUL character from conversion... 185 | ret = ret.replaceAll("\\u0000", ""); 186 | } catch (CharacterCodingException e) { 187 | e.printStackTrace(); 188 | } 189 | 190 | return ret; 191 | } 192 | 193 | private static String cleanUnicode(String ret) { 194 | String r = ""; 195 | char c; 196 | for (int i = 0; i < ret.length(); ++i) { 197 | c = ret.charAt(i); 198 | //char hex = ret.charAt(i); 199 | if (Character.UnicodeBlock.of(c) == Character.UnicodeBlock.BASIC_LATIN) { 200 | r += c; 201 | } else if (c == 'ß') { 202 | r += "ß"; 203 | } else // Buchstaben 204 | { 205 | if (c == 'Â' || c == 'À' || c == 'Å' || c == 'Á') { 206 | r += "A"; 207 | } else if (c == 'å' || c == 'á' || c == 'à' || c == 'â') { 208 | r += "a"; 209 | } else if (c == 'Č') { 210 | r += "C"; 211 | } else if (c == 'ć' || c == 'č' || c == 'ç') { 212 | r += "c"; 213 | } else if (c == 'Đ') { 214 | r += "D"; 215 | } else if (c == 'É' || c == 'È') { 216 | r += "E"; 217 | } else if (c == 'é' || c == 'è' || c == 'ê' || c == 'ě' || c == 'ë') { 218 | r += "e"; 219 | } else if (c == 'í') { 220 | r += "i"; 221 | } else if (c == 'ñ') { 222 | r += "n"; 223 | } else if (c == 'ó' || c == 'ô' || c == 'ø') { 224 | r += "o"; 225 | } else if (c == 'Š') { 226 | r += "S"; 227 | } else if (c == 'ś' || c == 'š' || c == 'ş') { 228 | r += "s"; 229 | } else if (c == 'ł' || c == 'Ł') { 230 | r += "t"; 231 | } else if (c == 'û' || c == 'ù') { 232 | r += "u"; 233 | } else if (c == 'ý') { 234 | r += "y"; 235 | } else if (c == 'Ž' || c == 'Ź') { 236 | r += "Z"; 237 | } else if (c == 'ž' || c == 'ź') { 238 | r += "z"; 239 | } else if (c == 'æ') { 240 | r += "ae"; 241 | } else if (c == '–') { 242 | r += "-"; 243 | } else if (c == '„') { 244 | r += "\""; 245 | } else if (c == '”' || c == '“' || c == '«' || c == '»') { 246 | r += "\""; 247 | } else if (c == '?') { 248 | r += "?"; 249 | } else if (c == '°' || c == '™') { 250 | } else if (c == '…') { 251 | r += "..."; 252 | } else if (c == '€') { 253 | r += "€"; 254 | } else if (c == '´' || c == '’' || c == '‘' || c == '¿') { 255 | r += "'"; 256 | } else if (c == '\u003F') { 257 | r += "?"; 258 | } else if (c == '\u0096') { 259 | r += "-"; 260 | } else if (c == '\u0085') { 261 | } else if (c == '\u0080') { 262 | } else if (c == '\u0084') { 263 | } else if (c == '\u0092') { 264 | } else if (c == '\u0093') { 265 | } else if (c == '\u0091') { 266 | r += "-"; 267 | } else if (c == '\n') { 268 | } else { 269 | r += "_"; 270 | } 271 | } 272 | } 273 | return r; 274 | } 275 | 276 | /** 277 | * Remove illegal characters from String based on current OS. 278 | * 279 | * @param input The input string 280 | * @param isPath Flag to switch replacing of illegal path characters on and off 281 | * @return Cleaned-up string. 282 | */ 283 | public static String removeIllegalCharacters(final String input, boolean isPath) { 284 | String ret = input; 285 | 286 | switch (Functions.getOs()) { 287 | case MAC: 288 | case LINUX: 289 | //On OSX the VFS take care of writing correct filenames to FAT filesystems... 290 | //Just remove the default illegal characters 291 | ret = removeStartingDots(ret); 292 | ret = ret.replaceAll(isPath ? REGEXP_ILLEGAL_CHARACTERS_OTHERS_PATH : REGEXP_ILLEGAL_CHARACTERS_OTHERS, "_"); 293 | break; 294 | 295 | case WIN64: 296 | case WIN32: 297 | //we need to be more careful on Windows when using e.g. FAT32 298 | //Therefore be more conservative by default and replace more characters. 299 | ret = removeWindowsTrailingDots(ret); 300 | ret = ret.replaceAll(isPath ? REGEXP_ILLEGAL_CHARACTERS_WINDOWS_PATH : REGEXP_ILLEGAL_CHARACTERS_WINDOWS, "_"); 301 | break; 302 | 303 | default: 304 | //we need to be more careful on Linux when using e.g. FAT32 305 | //Therefore be more conservative by default and replace more characters. 306 | ret = removeStartingDots(ret); 307 | ret = ret.replaceAll(isPath ? REGEXP_ILLEGAL_CHARACTERS_WINDOWS_PATH : REGEXP_ILLEGAL_CHARACTERS_WINDOWS, "_"); 308 | break; 309 | } 310 | 311 | return ret; 312 | } 313 | 314 | /** 315 | * Remove illegal file name characters 316 | * 317 | * @param name The file name 318 | * @param isPath Flag to switch replacing of illegal path characters on and off 319 | * @param userReplace Flag to switch the user replacing table on and off 320 | * @param onlyAscii Flag to switch if only ASCII characters should be allowed 321 | * @return Bereinigte Fassung 322 | */ 323 | public static String replaceLeerDateiname(String name, boolean isPath, boolean userReplace, boolean onlyAscii) { 324 | String ret = name; 325 | boolean isWindowsPath = false; 326 | if (SystemInfo.isWindows() && isPath && ret.length() > 1 && ret.charAt(1) == ':') { 327 | // damit auch "d:" und nicht nur "d:\" als Pfad geht 328 | isWindowsPath = true; 329 | ret = ret.replaceFirst(":", ""); // muss zum Schluss wieder rein, kann aber so nicht ersetzt werden 330 | } 331 | 332 | // zuerst die Ersetzungstabelle mit den Wünschen des Users 333 | if (userReplace) { 334 | ret = ReplaceList.replace(ret, isPath); 335 | } 336 | 337 | // und wenn gewünscht: "NUR Ascii-Zeichen" 338 | if (onlyAscii) { 339 | ret = convertToASCIIEncoding(ret, isPath); 340 | } else { 341 | ret = convertToNativeEncoding(ret, isPath); 342 | } 343 | 344 | if (isWindowsPath) { 345 | // c: wieder herstellen 346 | if (ret.length() == 1) { 347 | ret = ret + ":"; 348 | } else if (ret.length() > 1) { 349 | ret = ret.charAt(0) + ":" + ret.substring(1); 350 | } 351 | } 352 | return ret; 353 | } 354 | 355 | } 356 | -------------------------------------------------------------------------------- /src/main/java/de/mediathekview/mlib/tool/TimedTextMarkupLanguageParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * TimedTextMarkupLanguageParser 3 | * Copyright (C) 2016 CrystalPalace 4 | * crystalpalace1977@googlemail.com 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | package de.mediathekview.mlib.tool; 20 | 21 | import java.io.FileOutputStream; 22 | import java.io.OutputStreamWriter; 23 | import java.io.PrintWriter; 24 | import java.nio.charset.Charset; 25 | import java.nio.file.Path; 26 | import java.text.ParseException; 27 | import java.text.SimpleDateFormat; 28 | import java.util.ArrayList; 29 | import java.util.Date; 30 | import java.util.Hashtable; 31 | import java.util.List; 32 | import java.util.Map; 33 | 34 | import javax.xml.parsers.DocumentBuilder; 35 | import javax.xml.parsers.DocumentBuilderFactory; 36 | 37 | import org.w3c.dom.Document; 38 | import org.w3c.dom.NamedNodeMap; 39 | import org.w3c.dom.Node; 40 | import org.w3c.dom.NodeList; 41 | 42 | /** 43 | * Converter for TTML XML subtitle files into SubRip Text format. 44 | * Tested with MediathekView downloaded subtitles and TTML format version 1.0. 45 | */ 46 | public class TimedTextMarkupLanguageParser { 47 | 48 | private final SimpleDateFormat ttmlFormat = new SimpleDateFormat("HH:mm:ss.SS"); 49 | private final SimpleDateFormat srtFormat = new SimpleDateFormat("HH:mm:ss,SS"); 50 | private final SimpleDateFormat sdfFlash = new SimpleDateFormat("s.S"); 51 | 52 | private final Map colorMap = new Hashtable<>(); 53 | private final List subtitleList = new ArrayList<>(); 54 | private String color = "#FFFFFF"; 55 | private Document doc = null; 56 | 57 | public TimedTextMarkupLanguageParser() { 58 | } 59 | 60 | /** 61 | * Build a map of used colors within the TTML file. 62 | */ 63 | private void buildColorMap() { 64 | final NodeList styleData = doc.getElementsByTagName("tt:style"); 65 | for (int i = 0; i < styleData.getLength(); i++) { 66 | final Node subnode = styleData.item(i); 67 | if (subnode.hasAttributes()) { 68 | final NamedNodeMap attrMap = subnode.getAttributes(); 69 | final Node idNode = attrMap.getNamedItem("xml:id"); 70 | final Node colorNode = attrMap.getNamedItem("tts:color"); 71 | if (idNode != null && colorNode != null) { 72 | colorMap.put(idNode.getNodeValue(), colorNode.getNodeValue()); 73 | } 74 | } 75 | } 76 | } 77 | 78 | /** 79 | * Build the Subtitle objects from TTML content. 80 | */ 81 | @SuppressWarnings("deprecation") 82 | private void buildFilmList() throws Exception { 83 | final NodeList subtitleData = doc.getElementsByTagName("tt:p"); 84 | 85 | for (int i = 0; i < subtitleData.getLength(); i++) { 86 | final Subtitle subtitle = new Subtitle(); 87 | 88 | final Node subnode = subtitleData.item(i); 89 | if (subnode.hasAttributes()) { 90 | // retrieve the begin and end attributes... 91 | final NamedNodeMap attrMap = subnode.getAttributes(); 92 | final Node beginNode = attrMap.getNamedItem("begin"); 93 | final Node endNode = attrMap.getNamedItem("end"); 94 | if (beginNode != null && endNode != null) { 95 | subtitle.begin = ttmlFormat.parse(beginNode.getNodeValue()); 96 | //HACK:: Don´t know why this is set like this... 97 | //but we have to subract 10 hours from the XML 98 | if (subtitle.begin.getHours() >= 10) { 99 | subtitle.begin.setHours(subtitle.begin.getHours() - 10); 100 | } 101 | subtitle.end = ttmlFormat.parse(endNode.getNodeValue()); 102 | if (subtitle.end.getHours() >= 10) { 103 | subtitle.end.setHours(subtitle.end.getHours() - 10); 104 | } 105 | 106 | } 107 | } 108 | 109 | final NodeList childNodes = subnode.getChildNodes(); 110 | for (int j = 0; j < childNodes.getLength(); j++) { 111 | final Node node = childNodes.item(j); 112 | if (node.getNodeName().equalsIgnoreCase("tt:span")) { 113 | //retrieve the text and color information... 114 | final NamedNodeMap attrMap = node.getAttributes(); 115 | final Node styleNode = attrMap.getNamedItem("style"); 116 | final StyledString textContent = new StyledString(); 117 | 118 | textContent.setText(node.getTextContent()); 119 | final String col = colorMap.get(styleNode.getNodeValue()); 120 | if (col == null) { 121 | textContent.setColor(color); // gabs beim BR 122 | } else { 123 | textContent.setColor(colorMap.get(styleNode.getNodeValue())); 124 | } 125 | subtitle.listOfStrings.add(textContent); 126 | } 127 | } 128 | subtitleList.add(subtitle); 129 | } 130 | } 131 | 132 | private Date parseFlash(String tStamp) throws ParseException { 133 | Date da; 134 | if (tStamp.contains(":")) { 135 | da = ttmlFormat.parse(tStamp); 136 | } else { 137 | da = sdfFlash.parse(tStamp + "00"); 138 | } 139 | return da; 140 | } 141 | 142 | /** 143 | * Build the Subtitle objects from TTML content. 144 | */ 145 | private void buildFilmListFlash() throws Exception { 146 | final NodeList subtitleData = doc.getElementsByTagName("p"); 147 | 148 | for (int i = 0; i < subtitleData.getLength(); i++) { 149 | final Subtitle subtitle = new Subtitle(); 150 | 151 | final Node subnode = subtitleData.item(i); 152 | if (subnode.hasAttributes()) { 153 | // retrieve the begin and end attributes... 154 | final NamedNodeMap attrMap = subnode.getAttributes(); 155 | final Node beginNode = attrMap.getNamedItem("begin"); 156 | final Node endNode = attrMap.getNamedItem("end"); 157 | if (beginNode != null && endNode != null) { 158 | subtitle.begin = parseFlash(beginNode.getNodeValue()); 159 | subtitle.end = parseFlash(endNode.getNodeValue()); 160 | final StyledString textContent = new StyledString(); 161 | textContent.setColor(color); // sicher ist sicher 162 | textContent.setText(subnode.getTextContent()); 163 | 164 | final Node col = attrMap.getNamedItem("tts:color"); 165 | if (col != null) { 166 | textContent.setColor(col.getNodeValue()); 167 | } else { 168 | final NodeList childNodes = subnode.getChildNodes(); 169 | for (int j = 0; j < childNodes.getLength(); j++) { 170 | final Node node = childNodes.item(j); 171 | if (node.getNodeName().equalsIgnoreCase("span")) { 172 | //retrieve the text and color information... 173 | final NamedNodeMap attr = node.getAttributes(); 174 | final Node co = attr.getNamedItem("tts:color"); 175 | textContent.setColor(co.getNodeValue()); 176 | } 177 | } 178 | } 179 | subtitle.listOfStrings.add(textContent); 180 | 181 | } 182 | } 183 | subtitleList.add(subtitle); 184 | } 185 | } 186 | 187 | /** 188 | * Parse the TTML file into internal representation. 189 | * 190 | * @param ttmlFilePath the TTML file to parse 191 | * @return true if the parsing was successful 192 | */ 193 | public boolean parse(Path ttmlFilePath) { 194 | boolean ret; 195 | try { 196 | final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 197 | dbf.setNamespaceAware(true); 198 | 199 | final DocumentBuilder db = dbf.newDocumentBuilder(); 200 | doc = db.parse(ttmlFilePath.toFile()); 201 | 202 | //Check that we have TTML v1.0 file as we have tested only them... 203 | final NodeList metaData = doc.getElementsByTagName("ebuttm:documentEbuttVersion"); 204 | if (metaData != null) { 205 | final Node versionNode = metaData.item(0); 206 | if (versionNode == null || !versionNode.getTextContent().equalsIgnoreCase("v1.0")) { 207 | throw new Exception("Unknown TTML file version"); 208 | } 209 | } else { 210 | throw new Exception("Unknown File Format"); 211 | } 212 | 213 | buildColorMap(); 214 | buildFilmList(); 215 | ret = true; 216 | } catch (Exception ex) { 217 | Log.errorLog(912036478, new String[]{ex.getLocalizedMessage(), "File: " + ttmlFilePath}); 218 | ret = false; 219 | } 220 | return ret; 221 | } 222 | 223 | /** 224 | * Parse the XML Subtitle File for Flash Player into internal representation. 225 | * 226 | * @param ttmlFilePath the TTML file to parse 227 | * @return true if the parsing was successful 228 | */ 229 | public boolean parseXmlFlash(Path ttmlFilePath) { 230 | boolean ret; 231 | try { 232 | final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 233 | dbf.setNamespaceAware(true); 234 | 235 | final DocumentBuilder db = dbf.newDocumentBuilder(); 236 | doc = db.parse(ttmlFilePath.toFile()); 237 | 238 | //Check that we have TTML v1.0 file as we have tested only them... 239 | final NodeList metaData = doc.getElementsByTagName("tt"); 240 | final NodeList colorNote = doc.getElementsByTagName("style"); 241 | if (metaData != null) { 242 | final Node node = metaData.item(0); 243 | 244 | if (node.hasAttributes()) { 245 | // retrieve the begin and end attributes... 246 | final NamedNodeMap attrMap = node.getAttributes(); 247 | final Node xmlns = attrMap.getNamedItem("xmlns"); 248 | if (xmlns != null) { 249 | final String s = xmlns.getNodeValue(); 250 | if (!s.equals("http://www.w3.org/2006/04/ttaf1") 251 | && !s.equals("http://www.w3.org/ns/ttml")) { 252 | throw new Exception("Unknown TTML file version"); 253 | } 254 | } 255 | } else { 256 | throw new Exception("Unknown File Format"); 257 | } 258 | } else { 259 | throw new Exception("Unknown File Format"); 260 | } 261 | if (colorNote != null) { 262 | if (colorNote.getLength() == 0) { 263 | this.color = "#FFFFFF"; 264 | } else { 265 | final Node node = colorNote.item(0); 266 | 267 | if (node.hasAttributes()) { 268 | // retrieve the begin and end attributes... 269 | final NamedNodeMap attrMap = node.getAttributes(); 270 | final Node col = attrMap.getNamedItem("tts:color"); 271 | if (col != null) { 272 | if (!col.getNodeValue().isEmpty()) { 273 | this.color = col.getNodeValue(); 274 | } 275 | } 276 | } else { 277 | throw new Exception("Unknown File Format"); 278 | } 279 | } 280 | } else { 281 | throw new Exception("Unknown File Format"); 282 | } 283 | buildFilmListFlash(); 284 | ret = true; 285 | } catch (Exception ex) { 286 | //Log.errorLog(46231470, ex, "File: " + ttmlFilePath); 287 | Log.errorLog(46231470, new String[]{ex.getLocalizedMessage(), "File: " + ttmlFilePath}); 288 | ret = false; 289 | } 290 | return ret; 291 | } 292 | 293 | /** 294 | * Convert internal representation into SubRip Text Format and save to file. 295 | * @param srtFile The path to the srt file to convert 296 | */ 297 | public void toSrt(Path srtFile) { 298 | try (FileOutputStream fos = new FileOutputStream(srtFile.toFile()); 299 | OutputStreamWriter osw = new OutputStreamWriter(fos, Charset.forName("UTF-8")); 300 | PrintWriter writer = new PrintWriter(osw)) { 301 | long counter = 1; 302 | for (Subtitle title : subtitleList) { 303 | writer.println(counter); 304 | writer.println(srtFormat.format(title.begin) + " --> " + srtFormat.format(title.end)); 305 | for (StyledString entry : title.listOfStrings) { 306 | if (!entry.color.isEmpty()) { 307 | writer.print(""); 308 | } 309 | writer.print(entry.text); 310 | if (!entry.color.isEmpty()) { 311 | writer.print(""); 312 | } 313 | writer.println(); 314 | } 315 | writer.println(""); 316 | counter++; 317 | } 318 | } catch (Exception ex) { 319 | Log.errorLog(201036470, ex, "File: " + srtFile); 320 | } 321 | } 322 | 323 | public void cleanup() { 324 | colorMap.clear(); 325 | subtitleList.clear(); 326 | } 327 | 328 | private class StyledString { 329 | 330 | public String getText() { 331 | return text; 332 | } 333 | 334 | public void setText(String text) { 335 | this.text = text; 336 | } 337 | 338 | public String getColor() { 339 | return color; 340 | } 341 | 342 | public void setColor(String color) { 343 | this.color = color; 344 | } 345 | 346 | private String text = ""; 347 | private String color = ""; 348 | } 349 | 350 | private class Subtitle { 351 | 352 | public Date begin; 353 | public Date end; 354 | public List listOfStrings = new ArrayList<>(); 355 | } 356 | } 357 | --------------------------------------------------------------------------------