### Build and Run MServer from Command Line Source: https://github.com/mediathekview/mserver/blob/master/README.md Navigate to the MServer directory and use Gradle to build and start the server. ```bash cd MServer ./gradlew start ``` -------------------------------- ### Clone Repository and Start MServer Source: https://context7.com/mediathekview/mserver/llms.txt Clone the MServer and MLib repositories, then build and start MServer using Gradle. Alternatively, run the compiled JAR with arguments for debug mode, a custom config path, version output, GUI, or to disable XZ compression. Docker is also supported. ```bash # Repository klonen (MLib als Subprojekt erforderlich) mkdir mediathekview && cd mediathekview git clone https://github.com/mediathekview/MServer.git git clone https://github.com/mediathekview/MLib.git cd MServer # Bauen und starten ./gradlew start # Mit Argumenten: Debug-Modus, optionaler Arbeitspfad java -jar MServer.jar /pfad/zum/konfigordner -d # Nur Version ausgeben java -jar MServer.jar -v # Grafische Oberfläche (JavaFX) java -jar MServer.jar -gui # XZ-Komprimierung deaktivieren export NOCOMPRESS=y java -jar MServer.jar # Docker docker run mediathekview/mserver:latest ``` -------------------------------- ### MServer Main Entry Point and Start Modes Source: https://context7.com/mediathekview/mserver/llms.txt The `mServer.Main` class parses command-line arguments to select the operating mode: server, version output, or GUI. In server mode, `MServer.starten()` runs in a loop, sleeping until the next midnight after each crawl cycle. Debug logging can be enabled with the '-d' argument. ```java // Startmodi: // (kein Argument) -> SERVER: läuft dauerhaft, täglicher Neustart // -d -> Debug-Logging aktivieren // -v -> Version ausgeben und beenden // -gui -> JavaFX-GUI starten public static void main(String[] args) { // Performance-Monitoring initialisieren BasicEtmConfigurator.configure(); EtmManager.getEtmMonitor().start(); // Argument "-d" setzt MserverDaten.debug = true // Argument "-gui" startet Application.launch(MSG.class, args) // Standard: runServer(args) // Im Servermodus: Schleife bis MServer.starten() false zurückgibt // Nach jedem Lauf: Thread.sleep(SekundenBisMitternacht + 120 Sekunden) } // Beispielaufruf: täglicher Dauerbetrieb // while (new MServer(args).starten()) { // long sleep = (MserverDatumZeit.getSecondsUntilNextDay() + 120) * 1000; // Thread.sleep(sleep); // schläft bis 00:02 Uhr // } ``` -------------------------------- ### Configure Global Crawler Settings with CrawlerConfig Source: https://context7.com/mediathekview/mserver/llms.txt Set global parameters for all crawlers, such as loading modes, proxy settings, and directory paths. This class should be configured before starting the crawlers. ```java // Lademodus: LOAD_SHORT (nur Update), LOAD_LONG, LOAD_MAX (alles) CrawlerConfig.senderLoadHow = CrawlerConfig.LOAD_LONG; // Filmliste aktualisieren statt neu erstellen CrawlerConfig.updateFilmliste = true; // Proxy konfigurieren CrawlerConfig.proxyUrl = "proxy.example.com"; CrawlerConfig.proxyPort = 8080; // Nur bestimmte Sender laden CrawlerConfig.nurSenderLaden = new String[]{"ARD", "ZDF"}; // Verzeichnis der Filmlisten CrawlerConfig.dirFilme = "/var/data/filmlisten/"; // Alte Liste importieren und mergen CrawlerConfig.importOld = "/pfad/zur/alte-liste.json"; // Aktuelle Liste eines anderen Crawlers importieren CrawlerConfig.importAkt = "https://res.mediathekview.de/akt.xml"; // Crawler-Auswahl einschränken (Komma-getrennt in Systemkonfiguration): // "ARD,ZDF,ARTE,DW,KIKA,3SAT,SR,SRF,SRFPOD,ORF,PHONIX" ``` -------------------------------- ### Initialize ArteCrawler Instances Source: https://context7.com/mediathekview/mserver/llms.txt Registers ArteCrawler instances for different languages with specified priorities. Priority 0 starts immediately, while priority 1 starts with a delay. ```java // Crawler für alle Sprachen werden in FilmeSuchen registriert: // new ArteCrawler(this, 0) -> ARTE.DE (Prio 0, startet sofort) // new ArteCrawler_FR(this, 1) -> ARTE.FR (Prio 1) // new ArteCrawler_EN(this, 1) -> ARTE.EN (Prio 1) // new ArteCrawler_ES(this, 1) -> ARTE.ES (Prio 1) // new ArteCrawler_PL(this, 1) -> ARTE.PL (Prio 1) // new ArteCrawler_IT(this, 1) -> ARTE.IT (Prio 1) // API-Endpunkt (paginiert): // ArteConstants.VIDEOS_URL = https://api.arte.tv/api/player/v2/config/{lang}/videos?page={page} // Authorization: ArteConstants.API_TOKEN // Maximale Seiten: 5 (Short-Modus) oder 10 (Long/Max-Modus) // Tatsächliche Seitenanzahl wird dynamisch aus meta.videos.pages gelesen // Ablauf: ArteVideoInfoTask -> ArteVideoLinkTask -> ArteDtoVideo2FilmTask // 1. Video-Übersicht laden (paginiert) // 2. Stream-Links pro Video auflösen // 3. DatenFilm-Objekte erzeugen ``` -------------------------------- ### Build and Run MServer from Command Line Source: https://github.com/mediathekview/mserver/wiki/Entwicklung Execute the Gradle wrapper to build and run the MServer application. Ensure you are in the MServer directory. ```bash cd MServer ./gradlew run ``` -------------------------------- ### MServer Main Cycle Coordination Source: https://context7.com/mediathekview/mserver/llms.txt The `MServer.starten()` method reads the configuration file, initiates a timer thread (`MserverTimer`), and orchestrates the search and upload cycle. It returns `true` if a restart is requested, indicating that the server should continue running. ```java MServer server = new MServer(new String[]{"/etc/mserver/"}); // starten() liest Konfiguration, startet Suche und Upload boolean neustart = server.starten(); // -> false: kein Neustart, Programm endet // -> true: Neustart gewünscht (MserverDaten.restart == true) // Intern: MServer.laufen() wird vom Timer aufgerufen // Ablauf pro Zyklus: // 1. aktSearchTask aus MserverDaten.listeSuchen holen // 2. mvsSearch.filmeSuchen(aktSearchTask) aufrufen // 3. Bei Erfolg: MserverUpload.upload(aktSearchTask) ``` -------------------------------- ### Clone MServer and Mlib Repositories Source: https://github.com/mediathekview/mserver/blob/master/README.md Clone the MServer and Mlib repositories into a new directory to set up the project structure. ```bash mkdir mediathekview cd mediathekview git clone https://github.com/mediathekview/MServer.git git clone https://github.com/mediathekview/Mlib.git ``` -------------------------------- ### Clone MServer and MLib Repositories Source: https://github.com/mediathekview/mserver/wiki/Entwicklung Clone the necessary MServer and MLib repositories into a new directory. Navigate into the MServer directory to prepare for building. ```bash mkdir mediathekview cd mediathekview git clone https://github.com/mediathekview/MServer.git git clone https://github.com/mediathekview/MLib.git cd MServer ``` -------------------------------- ### Run SonarCloud Analysis Source: https://context7.com/mediathekview/mserver/llms.txt Execute a SonarCloud analysis for the MServer project using Gradle. Ensure the SONAR_TOKEN environment variable is set. ```bash ./gradlew sonarqube \ -Dsonar.projectKey=mediathekview_MServer \ -Dsonar.organization=mediathekview \ -Dsonar.host.url=https://sonarcloud.io \ -Dsonar.login=$SONAR_TOKEN ``` -------------------------------- ### Manage Film Lists with ListeFilme Source: https://context7.com/mediathekview/mserver/llms.txt Shows how to initialize and manage a list of films using ListeFilme. Includes adding films, importing from saved lists, merging lists, calculating differences, sorting, writing metadata, and searching for films by URL. Use for managing collections of film data. ```java ListeFilme liste = new ListeFilme(); // Film hinzufügen (beim Crawlen vom Sender) boolean neu = liste.addFilmVomSender(film); // -> false wenn URL bereits bekannt (Duplikat) // Film aus gespeicherter Filmliste importieren liste.importFilmliste(film); // setzt Laufnummer, kein Duplikatcheck // Alte Liste mergen (neue Filme ergänzen, vorhandene behalten) ListeFilme neueListe = new ListeFilme(); // ... neueListe befüllen ... lis te.updateListe( neueListe, true, // index-basierter Vergleich (Sender+Thema+URL) false // ersetzen=false: nur neue hinzufügen ); // Diff berechnen (welche Filme sind im Vergleich zur orgListe neu?) ListeFilme orgListe = new ListeFilme(); // Basis ListeFilme diff = liste.neueFilme(orgListe); System.out.println("Neue Filme: " + diff.size()); // Filmliste nach Sender/Thema sortieren lis te.sort(); // Metadaten schreiben (Datum, Version, ID) lis te.writeMetaData(); System.out.println("ID: " + liste.getId()); System.out.println("Datum: " + liste.genDate()); System.out.println("Alter (s): " + liste.getAge()); System.out.println("Zu alt für Auto-Update: " + liste.isTooOld()); System.out.println("Zu alt für Diff: " + liste.isTooOldForDiff()); // Film per URL suchen DatenFilm gefunden = liste.getFilmByUrl("https://cdn.ard.de/tatort.mp4"); // Film per URL (inkl. Klein/HD-Varianten) suchen DatenFilm gefunden2 = liste.getFilmByUrl_klein_hoch_hd("https://cdn.ard.de/tatort-hd.mp4"); // Alle Filme eines Senders löschen lis te.deleteAllFilms("ARD"); // Neue Filme zählen long anzNeu = liste.countNewFilms(); // Themen laden (für Filter-UI) lis te.themenLaden(); String[] alleSender = liste.sender; // ["", "ARD", "ZDF", ...] String[] themenARD = liste.themenPerSender[1]; // Themen für sender[1] ``` -------------------------------- ### Execute MServer Tests Source: https://context7.com/mediathekview/mserver/llms.txt MServer utilizes three distinct test directories. Run these commands from the project root to execute unit, integration, or performance tests. ```bash # Unit-Tests (ohne Mediathek-Zugriffe, verwendet Mocks) ./gradlew developTest # Integrationstests (mit echten Mediathek-API-Zugriffen) ./gradlew integrationTest # Performance-Tests ./gradlew performanceTest # Alle Tests + Build ./gradlew check developTest build ``` -------------------------------- ### Create and Manipulate DatenFilm Object Source: https://context7.com/mediathekview/mserver/llms.txt Demonstrates how to create a new DatenFilm object, add various URLs (HD, small, subtitle), set geo-restrictions, access fields directly, and clean descriptions. Use this for representing individual film entries. ```java DatenFilm film = new DatenFilm( "ARD", // Sender "Tatort", // Thema "https://www.ardmediathek.de/video/abc123", // Website "Tatort: Der letzte Fall", // Titel "https://cdn.ard.de/tatort.mp4", // URL (Normal) "", // RTMP-URL (leer lassen) "15.05.2024", // Datum (dd.MM.yyyy) "20:15:00", // Uhrzeit (HH:mm:ss) 5400L, // Dauer in Sekunden (90 min) "Spannender Krimi aus München." // Beschreibung ); // HD- und Klein-URL setzen (komprimiertes Diff-Format) CrawlerTool.addUrlHd(film, "https://cdn.ard.de/tatort-hd.mp4"); CrawlerTool.addUrlKlein(film, "https://cdn.ard.de/tatort-klein.mp4"); CrawlerTool.addUrlSubtitle(film, "https://cdn.ard.de/tatort.ttml"); // Geo-Beschränkung setzen film.arr[DatenFilm.FILM_GEO] = DatenFilm.GEO_DE; // nur DE // Felder direkt auslesen String sender = film.arr[DatenFilm.FILM_SENDER]; // "ARD" String titel = film.arr[DatenFilm.FILM_TITEL]; // "Tatort: Der letzte Fall" String url = film.arr[DatenFilm.FILM_URL]; // "https://cdn.ard.de/tatort.mp4" String datum = film.arr[DatenFilm.FILM_DATUM]; // "15.05.2024" String dauer = film.arr[DatenFilm.FILM_DAUER]; // "01:30:00" String geo = film.arr[DatenFilm.FILM_GEO]; // "DE" boolean hatHD = film.isHD(); // true boolean hatUT = film.hasUT(); // true // URL je nach gewünschter Auflösung String urlHD = film.getUrlFuerAufloesung(DatenFilm.AUFLOESUNG_HD); String urlKlein = film.getUrlFuerAufloesung(DatenFilm.AUFLOESUNG_KLEIN); // Eindeutiger Index (für Duplikatprüfung) String index = film.getIndex(); // Sender+Thema+URL String idxOld = film.getIndexAddOld(); // Sender+Thema+Titel (für Merge) // Beschreibung bereinigen (HTML entfernen, Rechtswarnungen löschen, max. 400 Zeichen) String sauber = DatenFilm.cleanDescription("
Text mit HTML...
"); ``` -------------------------------- ### Run MServer with Compression Disabled Source: https://github.com/mediathekview/mserver/blob/master/README.md To disable xz compression when running MServer, set the NOCOMPRESS environment variable to 'y' before executing the jar file. ```bash export NOCOMPRESS=y java -jar MServer.jar ``` -------------------------------- ### Implement Custom Senders with MediathekCrawler Source: https://context7.com/mediathekview/mserver/llms.txt Extend the abstract MediathekCrawler class to create custom crawlers for specific media sources. This involves defining how to fetch topic URLs and process individual films. ```java // Eigenen Crawler implementieren: public class MeinSenderCrawler extends MediathekCrawler { public MeinSenderCrawler(FilmeSuchen suchen, int prio) { super(suchen, "MeinSender", /* maxThreads */ 4, /* warteMs */ 500, /* startPrio */ 0); } @Override protected RecursiveTask