├── .gitattributes ├── .github ├── FUNDING.yml └── workflows │ └── build.yml ├── res ├── MediathekView.ico └── MediathekView_256x256.png ├── src ├── main │ ├── resources │ │ ├── splash.png │ │ ├── splash@2x.png │ │ ├── mediathek │ │ │ ├── res │ │ │ │ ├── sender │ │ │ │ │ ├── ard.png │ │ │ │ │ ├── br.png │ │ │ │ │ ├── dw.png │ │ │ │ │ ├── hr.png │ │ │ │ │ ├── mdr.png │ │ │ │ │ ├── ndr.png │ │ │ │ │ ├── orf.png │ │ │ │ │ ├── rbb.png │ │ │ │ │ ├── sr.png │ │ │ │ │ ├── srf.png │ │ │ │ │ ├── swr.png │ │ │ │ │ ├── wdr.png │ │ │ │ │ ├── zdf.png │ │ │ │ │ ├── 3sat.png │ │ │ │ │ ├── kika.png │ │ │ │ │ ├── rbtv.jpg │ │ │ │ │ ├── arte-de.png │ │ │ │ │ ├── arte-en.png │ │ │ │ │ ├── arte-es.png │ │ │ │ │ ├── arte-fr.png │ │ │ │ │ ├── arte-it.png │ │ │ │ │ ├── arte-pl.png │ │ │ │ │ ├── funk_net.png │ │ │ │ │ ├── phoenix.png │ │ │ │ │ ├── zdf-tivi.png │ │ │ │ │ └── srf-podcast.png │ │ │ │ ├── MediathekView.png │ │ │ │ ├── programm │ │ │ │ │ ├── tray.png │ │ │ │ │ ├── achtung.png │ │ │ │ │ ├── tab-film.png │ │ │ │ │ ├── button-add.png │ │ │ │ │ ├── button-del.png │ │ │ │ │ ├── menue-help.png │ │ │ │ │ ├── tabelle-aus.png │ │ │ │ │ ├── tabelle-ein.png │ │ │ │ │ ├── tray-fehler.png │ │ │ │ │ ├── button-move-up.png │ │ │ │ │ ├── button-remove.png │ │ │ │ │ ├── dialog-ein-sw.png │ │ │ │ │ ├── tab-download.png │ │ │ │ │ ├── tray-download.png │ │ │ │ │ ├── button-move-down.png │ │ │ │ │ └── menue-blacklist.png │ │ │ │ ├── MediathekView_k.png │ │ │ │ └── muster │ │ │ │ │ ├── button-add.png │ │ │ │ │ ├── button-del.png │ │ │ │ │ ├── button-help.png │ │ │ │ │ ├── button-clear.png │ │ │ │ │ ├── button-remove.png │ │ │ │ │ ├── button-file-open.png │ │ │ │ │ ├── button-move-down.png │ │ │ │ │ ├── button-move-up.png │ │ │ │ │ ├── button-aktualisieren.png │ │ │ │ │ └── button-blacklist-aus.png │ │ │ └── file │ │ │ │ ├── hilfetext_beenden.txt │ │ │ │ ├── hilfetext_geo.txt │ │ │ │ ├── hilfetext_reset.txt │ │ │ │ ├── hilfetext_editDownloadProg.txt │ │ │ │ ├── hilfetext_standardPset.txt │ │ │ │ ├── hilfetext_reset_set.txt │ │ │ │ └── hilfetext_blacklist.txt │ │ ├── icons │ │ │ ├── countries │ │ │ │ ├── 003-austria.png │ │ │ │ ├── 162-germany.png │ │ │ │ ├── 195-france.png │ │ │ │ ├── 205-switzerland.png │ │ │ │ └── 259-european-union.png │ │ │ ├── fontawesome │ │ │ │ ├── minus.svg │ │ │ │ ├── circle-half-stroke.svg │ │ │ │ ├── caret-down.svg │ │ │ │ ├── ellipsis-vertical.svg │ │ │ │ ├── plus.svg │ │ │ │ ├── check.svg │ │ │ │ ├── arrow-down.svg │ │ │ │ ├── arrow-up.svg │ │ │ │ ├── triangle-exclamation.svg │ │ │ │ ├── xmark.svg │ │ │ │ ├── folder-open.svg │ │ │ │ ├── circle-question.svg │ │ │ │ ├── envelope-open-text.svg │ │ │ │ └── pen-to-square.svg │ │ │ └── sender │ │ │ │ └── ard.svg │ │ ├── raven │ │ │ └── toast │ │ │ │ └── svg │ │ │ │ ├── info.svg │ │ │ │ ├── success.svg │ │ │ │ ├── warning.svg │ │ │ │ ├── close.svg │ │ │ │ └── error.svg │ │ └── log4j2.xml │ ├── java │ │ ├── mediathek │ │ │ ├── gui │ │ │ │ ├── messages │ │ │ │ │ ├── BaseEvent.java │ │ │ │ │ ├── ShowSettingsDialogEvent.kt │ │ │ │ │ ├── TimerEvent.java │ │ │ │ │ ├── StartEvent.java │ │ │ │ │ ├── TrayIconEvent.java │ │ │ │ │ ├── ButtonStartEvent.java │ │ │ │ │ ├── DarkModeChangeEvent.java │ │ │ │ │ ├── DownloadStartEvent.java │ │ │ │ │ ├── FontSizeChangedEvent.java │ │ │ │ │ ├── GeoStateChangedEvent.java │ │ │ │ │ ├── RestartDownloadEvent.java │ │ │ │ │ ├── FilmListReadStartEvent.java │ │ │ │ │ ├── FilmListReadStopEvent.java │ │ │ │ │ ├── FilmListWriteStartEvent.java │ │ │ │ │ ├── FilmListWriteStopEvent.java │ │ │ │ │ ├── ProgramSetChangedEvent.java │ │ │ │ │ ├── ReplaceListChangedEvent.java │ │ │ │ │ ├── AboListChangedEvent.java │ │ │ │ │ ├── DownloadFinishedEvent.java │ │ │ │ │ ├── DownloadListChangedEvent.java │ │ │ │ │ ├── BlacklistChangedEvent.java │ │ │ │ │ ├── DownloadProgressChangedEvent.java │ │ │ │ │ ├── ProgramLocationChangedEvent.java │ │ │ │ │ ├── SenderIconStyleChangedEvent.java │ │ │ │ │ ├── ToolBarIconSizeChangedEvent.java │ │ │ │ │ ├── DownloadQueueRankChangedEvent.java │ │ │ │ │ ├── FilmListImportTypeChangedEvent.java │ │ │ │ │ ├── NotificationCenterChangeEvent.java │ │ │ │ │ ├── TabVisualSettingsChangedEvent.java │ │ │ │ │ ├── UpdateStatusBarLeftDisplayEvent.java │ │ │ │ │ ├── DownloadInfoUpdateAvailableEvent.java │ │ │ │ │ ├── ParallelDownloadNumberChangedEvent.java │ │ │ │ │ ├── history │ │ │ │ │ │ ├── AboHistoryChangedEvent.java │ │ │ │ │ │ ├── DownloadHistoryChangedEvent.java │ │ │ │ │ │ └── HistoryChangedEvent.java │ │ │ │ │ ├── TableModelChangeEvent.kt │ │ │ │ │ ├── InstallTabSwitchListenerEvent.java │ │ │ │ │ ├── DownloadRateLimitChangedEvent.java │ │ │ │ │ ├── UpdateStateChangedEvent.java │ │ │ │ │ └── ReloadTableDataEvent.java │ │ │ │ ├── duplicates │ │ │ │ │ ├── FilmStatistics.java │ │ │ │ │ ├── BigSenderPenaltyComparator.java │ │ │ │ │ └── CommonStatsEvaluationTask.java │ │ │ │ ├── dialog │ │ │ │ │ ├── ButtonFlowPanel.kt │ │ │ │ │ ├── ButtonPanel.kt │ │ │ │ │ ├── reset │ │ │ │ │ │ └── ResetSettingsDialog.java │ │ │ │ │ └── StandardCloseDialog.java │ │ │ │ ├── filmInformation │ │ │ │ │ ├── DisabledCheckBox.java │ │ │ │ │ └── HtmlMultilineLabel.java │ │ │ │ ├── PanelVorlage.java │ │ │ │ ├── history │ │ │ │ │ ├── AboHistoryDialog.java │ │ │ │ │ ├── ResetAboHistoryAction.kt │ │ │ │ │ ├── ResetDownloadHistoryAction.kt │ │ │ │ │ └── MVUsedUrlTableFormat.java │ │ │ │ ├── actions │ │ │ │ │ ├── ShowProgramInfosAction.java │ │ │ │ │ ├── SearchProgramUpdateAction.java │ │ │ │ │ ├── StopDownloadsAction.java │ │ │ │ │ ├── StopAllDownloadsAction.java │ │ │ │ │ ├── StopAllWaitingDownloadsAction.java │ │ │ │ │ ├── StartAllDownloadsTimedAction.java │ │ │ │ │ ├── DisposeDialogAction.java │ │ │ │ │ ├── ShowAboHistoryAction.java │ │ │ │ │ ├── QuitAction.java │ │ │ │ │ ├── EditDownloadAction.java │ │ │ │ │ ├── ShowDuplicateStatisticsAction.java │ │ │ │ │ ├── AdvanceDownloadsAction.java │ │ │ │ │ ├── DeleteDownloadAction.java │ │ │ │ │ ├── OpenTargetFolderAction.java │ │ │ │ │ ├── StartDownloadsAction.java │ │ │ │ │ ├── CleanupDownloadListAction.java │ │ │ │ │ ├── DeferDownloadsAction.java │ │ │ │ │ ├── ManageBookmarkAction.java │ │ │ │ │ ├── ResetSettingsAction.java │ │ │ │ │ ├── StartAllDownloadsAction.java │ │ │ │ │ ├── DeleteDownloadsAction.java │ │ │ │ │ ├── PlayDownloadAction.java │ │ │ │ │ ├── LoadFilmListAction.java │ │ │ │ │ ├── MemoryMonitorAction.java │ │ │ │ │ ├── SettingsAction.java │ │ │ │ │ ├── RefreshDownloadListAction.java │ │ │ │ │ ├── ShowFilmInformationAction.java │ │ │ │ │ └── DeleteLocalFilmlistAction.java │ │ │ │ ├── tabs │ │ │ │ │ ├── tab_film │ │ │ │ │ │ ├── searchfilters │ │ │ │ │ │ │ ├── FinalStagePatternFilter.java │ │ │ │ │ │ │ ├── FinalStageFilterNoPattern.java │ │ │ │ │ │ │ ├── FinalStagePatternFilterWithDescription.java │ │ │ │ │ │ │ └── FinalStageFilterNoPatternWithDescription.java │ │ │ │ │ │ ├── OnlineSearchProviders.kt │ │ │ │ │ │ ├── SearchFieldData.kt │ │ │ │ │ │ └── SearchControlFieldMode.kt │ │ │ │ │ ├── tab_downloads │ │ │ │ │ │ ├── AboLabel.java │ │ │ │ │ │ ├── FailedDownloadsInfoLabel.java │ │ │ │ │ │ ├── ManualDownloadsInfoLabel.java │ │ │ │ │ │ ├── ActiveDownloadsInfoLabel.java │ │ │ │ │ │ ├── FinishedDownloadsInfoLabel.java │ │ │ │ │ │ ├── WaitingDownloadsInfoLabel.java │ │ │ │ │ │ └── TotalDownloadsLabel.java │ │ │ │ │ └── tab_livestreams │ │ │ │ │ │ ├── services │ │ │ │ │ │ ├── StreamInfo.kt │ │ │ │ │ │ ├── StreamService.kt │ │ │ │ │ │ ├── ShowService.kt │ │ │ │ │ │ ├── ShowsResponse.kt │ │ │ │ │ │ └── ShowInfo.kt │ │ │ │ │ │ ├── LivestreamEntry.kt │ │ │ │ │ │ └── SenderUtils.kt │ │ │ │ ├── tasks │ │ │ │ │ ├── BlacklistFilterWorker.java │ │ │ │ │ └── RefreshAboWorker.java │ │ │ │ ├── dialogEinstellungen │ │ │ │ │ ├── allgemein │ │ │ │ │ │ ├── TextFieldConfigWriter.java │ │ │ │ │ │ └── TimedDocumentListener.java │ │ │ │ │ ├── PanelNotifications.jfd │ │ │ │ │ └── PanelPset.jfd │ │ │ │ ├── expiration │ │ │ │ │ └── ExpiryInfo.kt │ │ │ │ ├── bandwidth │ │ │ │ │ └── WriteConfigComponentListener.kt │ │ │ │ └── bookmark │ │ │ │ │ └── BookmarkAddedAtComparator.java │ │ │ ├── tool │ │ │ │ ├── TABS.java │ │ │ │ ├── FilmListUpdateType.java │ │ │ │ ├── notification │ │ │ │ │ ├── MessageType.java │ │ │ │ │ ├── NotificationMessage.kt │ │ │ │ │ ├── INotificationCenter.kt │ │ │ │ │ ├── NullNotificationCenter.kt │ │ │ │ │ ├── MacNotificationCenter.kt │ │ │ │ │ └── GenericNotificationCenter.kt │ │ │ │ ├── InputStreamProgressMonitor.java │ │ │ │ ├── sender_icon_cache │ │ │ │ │ └── SenderIconSize.kt │ │ │ │ ├── cellrenderer │ │ │ │ │ ├── SenderCacheKey.java │ │ │ │ │ ├── SelfEvictingSenderIconCache.java │ │ │ │ │ └── CellRendererColor.java │ │ │ │ ├── FilterDTO.java │ │ │ │ ├── DarkModeFactory.kt │ │ │ │ ├── SenderListComboBoxModel.java │ │ │ │ ├── LightModeFactory.kt │ │ │ │ ├── datum │ │ │ │ │ ├── Datum.java │ │ │ │ │ └── DatumFilm.java │ │ │ │ ├── CopyToClipboardAction.kt │ │ │ │ ├── NoSelectionErrorDialog.java │ │ │ │ ├── SVGIconUtilities.java │ │ │ │ ├── models │ │ │ │ │ ├── NonEditableTableModel.java │ │ │ │ │ └── TModelColor.java │ │ │ │ ├── table │ │ │ │ │ ├── MVProgTable.java │ │ │ │ │ └── MVPsetTable.java │ │ │ │ ├── TrailerTeaserChecker.kt │ │ │ │ ├── CustomConversionHandler.java │ │ │ │ ├── MVC.java │ │ │ │ ├── episodes │ │ │ │ │ └── SeasonEpisode.java │ │ │ │ ├── affinity │ │ │ │ │ ├── IAffinity.kt │ │ │ │ │ ├── Affinity.kt │ │ │ │ │ └── NullAffinity.kt │ │ │ │ ├── GermanStringSorter.java │ │ │ │ ├── Ipify.kt │ │ │ │ ├── ttml │ │ │ │ │ ├── ITtmlParser.java │ │ │ │ │ └── ITtmlExporter.java │ │ │ │ ├── EventListWithEmptyFirstEntry.java │ │ │ │ ├── UIProgressState.java │ │ │ │ ├── MessageBus.kt │ │ │ │ └── FilmSize.java │ │ │ ├── daten │ │ │ │ ├── Country.java │ │ │ │ ├── abo │ │ │ │ │ ├── FilmLengthState.kt │ │ │ │ │ └── AboTags.kt │ │ │ │ ├── blacklist │ │ │ │ │ └── BlacklistTags.kt │ │ │ │ ├── DatenFilmFlags.java │ │ │ │ ├── DownloadStartInfo.java │ │ │ │ ├── FilmResolution.java │ │ │ │ └── IndexedFilmList.java │ │ │ ├── filmlisten │ │ │ │ ├── IAction.java │ │ │ │ ├── FilmListDownloadType.java │ │ │ │ ├── reader │ │ │ │ │ ├── IDateFilter.kt │ │ │ │ │ ├── NoOpDateFilter.kt │ │ │ │ │ └── DateFilter.kt │ │ │ │ └── IDownloadAction.java │ │ │ ├── update │ │ │ │ └── ServerProgramInformation.kt │ │ │ ├── filmeSuchen │ │ │ │ ├── ListenerFilmeLaden.java │ │ │ │ └── ListenerFilmeLadenEvent.java │ │ │ ├── controller │ │ │ │ ├── history │ │ │ │ │ └── SeenHistoryShutdownHook.kt │ │ │ │ └── starter │ │ │ │ │ └── HttpDownloadState.java │ │ │ ├── mainwindow │ │ │ │ ├── SelectedListItemsLabel.java │ │ │ │ ├── ListSelectedItemsProperty.java │ │ │ │ ├── PositionSavingTabbedPane.java │ │ │ │ └── FixedRedrawStatusBar.java │ │ │ ├── res │ │ │ │ └── GetIcon.java │ │ │ ├── config │ │ │ │ └── ApplicationType.kt │ │ │ └── swing │ │ │ │ ├── NoIconMenuItem.java │ │ │ │ └── JIkonliSafeButton.kt │ │ └── raven │ │ │ └── toast │ │ │ ├── ToastClientProperties.java │ │ │ └── util │ │ │ └── UIUtils.java │ └── kotlin │ │ ├── mediathek │ │ ├── mainwindow │ │ │ └── Log4jShutdownHookThread.kt │ │ ├── gui │ │ │ └── actions │ │ │ │ ├── ResetFilterDialogPosition.kt │ │ │ │ ├── CreateNewAboAction.kt │ │ │ │ ├── ShowAboutAction.kt │ │ │ │ ├── ShowBandwidthUsageAction.kt │ │ │ │ ├── ManageAboAction.kt │ │ │ │ └── export │ │ │ │ └── DiskSpaceUtil.kt │ │ ├── tool │ │ │ └── dns │ │ │ │ └── IPvPreferenceMode.kt │ │ └── windows │ │ │ ├── WinFlags.kt │ │ │ └── MediathekGuiWindows.kt │ │ └── feed │ │ ├── FeedMessage.kt │ │ └── Feed.kt └── test │ ├── kotlin │ ├── mediathek │ │ ├── tool │ │ │ ├── dns │ │ │ │ └── IPvPreferenceModeTest.kt │ │ │ ├── FileUtilsTest.kt │ │ │ ├── VersionTest.kt │ │ │ └── TrailerTeaserCheckerTest.kt │ │ └── daten │ │ │ ├── blacklist │ │ │ └── BlacklistTagsTest.kt │ │ │ └── abo │ │ │ └── AboTagsTest.kt │ └── feed │ │ └── RSSFeedParserTest.kt │ ├── resources │ └── log4j2.xml │ └── java │ └── mediathek │ ├── tool │ ├── LanguageCodeTest.java │ ├── ttml │ │ └── TimedTextMarkupLanguageParserTest.java │ ├── SingleInstanceTest.java │ └── table │ │ └── MVTableTest.java │ ├── config │ └── MVConfigTest.java │ └── controller │ └── history │ └── MVUsedUrlTest.java ├── .install4j ├── MediathekView@x16.png ├── MediathekView@x32.png ├── MediathekView@x48.png └── MediathekView@x128.png ├── installers └── mac │ └── MediathekView.icns ├── maven-repository ├── airsquared │ └── JMacNotification │ │ ├── 1.1 │ │ ├── JMacNotification-1.1.jar │ │ ├── _remote.repositories │ │ └── JMacNotification-1.1.pom │ │ └── maven-metadata-local.xml └── com │ └── formdev │ └── jformdesigner-annotations │ ├── 1.0 │ ├── jformdesigner-annotations-1.0.jar │ ├── _remote.repositories │ └── jformdesigner-annotations-1.0.pom │ └── maven-metadata-local.xml ├── .mvn └── wrapper │ └── maven-wrapper.properties └── .gitignore /.gitattributes: -------------------------------------------------------------------------------- 1 | *.exe filter=lfs diff=lfs merge=lfs -text 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | custom: ['https://www.paypal.me/MediathekView', 'https://mediathekview.de/spenden/'] 2 | -------------------------------------------------------------------------------- /res/MediathekView.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/res/MediathekView.ico -------------------------------------------------------------------------------- /res/MediathekView_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/res/MediathekView_256x256.png -------------------------------------------------------------------------------- /src/main/resources/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/splash.png -------------------------------------------------------------------------------- /.install4j/MediathekView@x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/.install4j/MediathekView@x16.png -------------------------------------------------------------------------------- /.install4j/MediathekView@x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/.install4j/MediathekView@x32.png -------------------------------------------------------------------------------- /.install4j/MediathekView@x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/.install4j/MediathekView@x48.png -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/BaseEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages; 2 | 3 | public class BaseEvent { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/resources/splash@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/splash@2x.png -------------------------------------------------------------------------------- /.install4j/MediathekView@x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/.install4j/MediathekView@x128.png -------------------------------------------------------------------------------- /installers/mac/MediathekView.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/installers/mac/MediathekView.icns -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/TABS.java: -------------------------------------------------------------------------------- 1 | package mediathek.tool; 2 | 3 | public enum TABS { 4 | TAB_FILME, TAB_DOWNLOADS 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/mediathek/daten/Country.java: -------------------------------------------------------------------------------- 1 | package mediathek.daten; 2 | 3 | public enum Country { 4 | DE, AT, CH, EU, FR, OTHER 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/FilmListUpdateType.java: -------------------------------------------------------------------------------- 1 | package mediathek.tool; 2 | 3 | public enum FilmListUpdateType {MANUAL, AUTOMATIC} 4 | -------------------------------------------------------------------------------- /src/main/java/mediathek/daten/abo/FilmLengthState.kt: -------------------------------------------------------------------------------- 1 | package mediathek.daten.abo 2 | 3 | enum class FilmLengthState { 4 | MINIMUM, MAXIMUM 5 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/ShowSettingsDialogEvent.kt: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages 2 | 3 | class ShowSettingsDialogEvent : BaseEvent() -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/TimerEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages; 2 | 3 | public class TimerEvent extends BaseEvent { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/mediathek/filmlisten/IAction.java: -------------------------------------------------------------------------------- 1 | package mediathek.filmlisten; 2 | 3 | interface IAction { 4 | void onFinished(boolean ok); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/StartEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages; 2 | 3 | 4 | public class StartEvent extends BaseEvent { 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/TrayIconEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages; 2 | 3 | public class TrayIconEvent extends BaseEvent { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/mediathek/filmlisten/FilmListDownloadType.java: -------------------------------------------------------------------------------- 1 | package mediathek.filmlisten; 2 | 3 | public enum FilmListDownloadType {FULL, DIFF_ONLY} 4 | -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/sender/ard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/sender/ard.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/sender/br.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/sender/br.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/sender/dw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/sender/dw.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/sender/hr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/sender/hr.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/sender/mdr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/sender/mdr.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/sender/ndr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/sender/ndr.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/sender/orf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/sender/orf.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/sender/rbb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/sender/rbb.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/sender/sr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/sender/sr.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/sender/srf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/sender/srf.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/sender/swr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/sender/swr.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/sender/wdr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/sender/wdr.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/sender/zdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/sender/zdf.png -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/ButtonStartEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages; 2 | 3 | public class ButtonStartEvent extends BaseEvent { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/resources/icons/countries/003-austria.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/icons/countries/003-austria.png -------------------------------------------------------------------------------- /src/main/resources/icons/countries/162-germany.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/icons/countries/162-germany.png -------------------------------------------------------------------------------- /src/main/resources/icons/countries/195-france.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/icons/countries/195-france.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/MediathekView.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/MediathekView.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/programm/tray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/programm/tray.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/sender/3sat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/sender/3sat.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/sender/kika.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/sender/kika.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/sender/rbtv.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/sender/rbtv.jpg -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/DarkModeChangeEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages; 2 | 3 | public class DarkModeChangeEvent extends BaseEvent { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/DownloadStartEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages; 2 | 3 | public class DownloadStartEvent extends BaseEvent { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/FontSizeChangedEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages; 2 | 3 | public class FontSizeChangedEvent extends BaseEvent { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/GeoStateChangedEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages; 2 | 3 | public class GeoStateChangedEvent extends BaseEvent { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/RestartDownloadEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages; 2 | 3 | public class RestartDownloadEvent extends BaseEvent { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/notification/MessageType.java: -------------------------------------------------------------------------------- 1 | package mediathek.tool.notification; 2 | 3 | public enum MessageType { 4 | INFO, 5 | ERROR 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/MediathekView_k.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/MediathekView_k.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/sender/arte-de.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/sender/arte-de.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/sender/arte-en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/sender/arte-en.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/sender/arte-es.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/sender/arte-es.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/sender/arte-fr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/sender/arte-fr.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/sender/arte-it.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/sender/arte-it.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/sender/arte-pl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/sender/arte-pl.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/sender/funk_net.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/sender/funk_net.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/sender/phoenix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/sender/phoenix.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/sender/zdf-tivi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/sender/zdf-tivi.png -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/duplicates/FilmStatistics.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.duplicates; 2 | 3 | public record FilmStatistics(String sender, long count) { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/FilmListReadStartEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages; 2 | 3 | public class FilmListReadStartEvent extends BaseEvent { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/FilmListReadStopEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages; 2 | 3 | public class FilmListReadStopEvent extends BaseEvent { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/FilmListWriteStartEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages; 2 | 3 | public class FilmListWriteStartEvent extends BaseEvent { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/FilmListWriteStopEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages; 2 | 3 | public class FilmListWriteStopEvent extends BaseEvent { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/ProgramSetChangedEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages; 2 | 3 | public class ProgramSetChangedEvent extends BaseEvent { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/ReplaceListChangedEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages; 2 | 3 | public class ReplaceListChangedEvent extends BaseEvent { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/resources/icons/countries/205-switzerland.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/icons/countries/205-switzerland.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/muster/button-add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/muster/button-add.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/muster/button-del.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/muster/button-del.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/muster/button-help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/muster/button-help.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/programm/achtung.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/programm/achtung.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/programm/tab-film.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/programm/tab-film.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/sender/srf-podcast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/sender/srf-podcast.png -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/AboListChangedEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages; 2 | 3 | public class AboListChangedEvent extends ReloadTableDataEvent { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/DownloadFinishedEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages; 2 | 3 | public class DownloadFinishedEvent extends BaseEvent { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/DownloadListChangedEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages; 2 | 3 | public class DownloadListChangedEvent extends BaseEvent { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/resources/icons/countries/259-european-union.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/icons/countries/259-european-union.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/muster/button-clear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/muster/button-clear.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/muster/button-remove.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/muster/button-remove.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/programm/button-add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/programm/button-add.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/programm/button-del.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/programm/button-del.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/programm/menue-help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/programm/menue-help.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/programm/tabelle-aus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/programm/tabelle-aus.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/programm/tabelle-ein.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/programm/tabelle-ein.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/programm/tray-fehler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/programm/tray-fehler.png -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/BlacklistChangedEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages; 2 | 3 | public class BlacklistChangedEvent extends ReloadTableDataEvent { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/DownloadProgressChangedEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages; 2 | 3 | public class DownloadProgressChangedEvent extends BaseEvent { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/ProgramLocationChangedEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages; 2 | 3 | public class ProgramLocationChangedEvent extends BaseEvent { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/SenderIconStyleChangedEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages; 2 | 3 | public class SenderIconStyleChangedEvent extends BaseEvent { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/ToolBarIconSizeChangedEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages; 2 | 3 | public class ToolBarIconSizeChangedEvent extends BaseEvent { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/muster/button-file-open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/muster/button-file-open.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/muster/button-move-down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/muster/button-move-down.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/muster/button-move-up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/muster/button-move-up.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/programm/button-move-up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/programm/button-move-up.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/programm/button-remove.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/programm/button-remove.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/programm/dialog-ein-sw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/programm/dialog-ein-sw.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/programm/tab-download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/programm/tab-download.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/programm/tray-download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/programm/tray-download.png -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/DownloadQueueRankChangedEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages; 2 | 3 | public class DownloadQueueRankChangedEvent extends BaseEvent { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/FilmListImportTypeChangedEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages; 2 | 3 | public class FilmListImportTypeChangedEvent extends BaseEvent { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/NotificationCenterChangeEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages; 2 | 3 | public class NotificationCenterChangeEvent extends BaseEvent { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/TabVisualSettingsChangedEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages; 2 | 3 | public class TabVisualSettingsChangedEvent extends BaseEvent { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/programm/button-move-down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/programm/button-move-down.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/programm/menue-blacklist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/programm/menue-blacklist.png -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/UpdateStatusBarLeftDisplayEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages; 2 | 3 | public class UpdateStatusBarLeftDisplayEvent extends BaseEvent { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/muster/button-aktualisieren.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/muster/button-aktualisieren.png -------------------------------------------------------------------------------- /src/main/resources/mediathek/res/muster/button-blacklist-aus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/src/main/resources/mediathek/res/muster/button-blacklist-aus.png -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/DownloadInfoUpdateAvailableEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages; 2 | 3 | public class DownloadInfoUpdateAvailableEvent extends BaseEvent { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/ParallelDownloadNumberChangedEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages; 2 | 3 | public class ParallelDownloadNumberChangedEvent extends BaseEvent { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/history/AboHistoryChangedEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages.history; 2 | 3 | public class AboHistoryChangedEvent extends HistoryChangedEvent { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/InputStreamProgressMonitor.java: -------------------------------------------------------------------------------- 1 | package mediathek.tool; 2 | 3 | public interface InputStreamProgressMonitor { 4 | void progress(long bytesRead, long size); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/sender_icon_cache/SenderIconSize.kt: -------------------------------------------------------------------------------- 1 | package mediathek.tool.sender_icon_cache 2 | 3 | internal enum class SenderIconSize(val height: Int) { 4 | SMALL(16), LARGE(32); 5 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/history/DownloadHistoryChangedEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages.history; 2 | 3 | public class DownloadHistoryChangedEvent extends HistoryChangedEvent { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/resources/mediathek/file/hilfetext_beenden.txt: -------------------------------------------------------------------------------- 1 | 2 | Damit unter Linux das Herunterfahren des Rechners 3 | funktioniert, muss der User diesen Aufruf 4 | ausführen dürfen: 5 | 6 | shutdown -h now 7 | -------------------------------------------------------------------------------- /maven-repository/airsquared/JMacNotification/1.1/JMacNotification-1.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/maven-repository/airsquared/JMacNotification/1.1/JMacNotification-1.1.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | wrapperVersion=3.3.4 2 | distributionType=only-script 3 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.11/apache-maven-3.9.11-bin.zip 4 | -------------------------------------------------------------------------------- /src/main/java/mediathek/filmlisten/reader/IDateFilter.kt: -------------------------------------------------------------------------------- 1 | package mediathek.filmlisten.reader 2 | 3 | import mediathek.daten.DatenFilm 4 | 5 | internal interface IDateFilter { 6 | fun filter(film: DatenFilm) 7 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/cellrenderer/SenderCacheKey.java: -------------------------------------------------------------------------------- 1 | package mediathek.tool.cellrenderer; 2 | 3 | import java.awt.*; 4 | 5 | record SenderCacheKey(String sender, Dimension cellDimension) { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/TableModelChangeEvent.kt: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages 2 | 3 | data class TableModelChangeEvent(@JvmField val active: Boolean, @JvmField val fromSearchField: Boolean) : BaseEvent() 4 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/history/HistoryChangedEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages.history; 2 | 3 | import mediathek.gui.messages.BaseEvent; 4 | 5 | public class HistoryChangedEvent extends BaseEvent { 6 | } 7 | -------------------------------------------------------------------------------- /maven-repository/com/formdev/jformdesigner-annotations/1.0/jformdesigner-annotations-1.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mediathekview/MediathekView/HEAD/maven-repository/com/formdev/jformdesigner-annotations/1.0/jformdesigner-annotations-1.0.jar -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/notification/NotificationMessage.kt: -------------------------------------------------------------------------------- 1 | package mediathek.tool.notification 2 | 3 | open class NotificationMessage { 4 | lateinit var title: String 5 | lateinit var type: MessageType 6 | lateinit var message: String 7 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/filmlisten/IDownloadAction.java: -------------------------------------------------------------------------------- 1 | package mediathek.filmlisten; 2 | 3 | import mediathek.daten.ListeFilme; 4 | 5 | interface IDownloadAction { 6 | boolean performDownload(String dateiUrl, ListeFilme listeFilme, int days); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/dialog/ButtonFlowPanel.kt: -------------------------------------------------------------------------------- 1 | package mediathek.gui.dialog 2 | 3 | import java.awt.FlowLayout 4 | import javax.swing.JPanel 5 | 6 | class ButtonFlowPanel : JPanel() { 7 | init { 8 | layout = FlowLayout() 9 | } 10 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/FilterDTO.java: -------------------------------------------------------------------------------- 1 | package mediathek.tool; 2 | 3 | import java.util.UUID; 4 | 5 | public record FilterDTO(UUID id, String name) { 6 | @Override 7 | public String toString() { 8 | return name; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/InstallTabSwitchListenerEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages; 2 | 3 | public class InstallTabSwitchListenerEvent extends BaseEvent { 4 | public enum INSTALL_TYPE {INSTALL, REMOVE} 5 | 6 | public INSTALL_TYPE event; 7 | } 8 | -------------------------------------------------------------------------------- /maven-repository/airsquared/JMacNotification/1.1/_remote.repositories: -------------------------------------------------------------------------------- 1 | #NOTE: This is a Maven Resolver internal implementation file, its format can be changed without prior notice. 2 | #Fri Dec 03 16:02:37 CET 2021 3 | JMacNotification-1.1.pom>= 4 | JMacNotification-1.1.jar>= 5 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/filmInformation/DisabledCheckBox.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.filmInformation; 2 | 3 | import javax.swing.*; 4 | 5 | public class DisabledCheckBox extends JCheckBox { 6 | public DisabledCheckBox() { 7 | setEnabled(false); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /maven-repository/com/formdev/jformdesigner-annotations/1.0/_remote.repositories: -------------------------------------------------------------------------------- 1 | #NOTE: This is a Maven Resolver internal implementation file, its format can be changed without prior notice. 2 | #Tue Apr 08 14:58:20 CEST 2025 3 | jformdesigner-annotations-1.0.jar>= 4 | jformdesigner-annotations-1.0.pom>= 5 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/DownloadRateLimitChangedEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages; 2 | 3 | public class DownloadRateLimitChangedEvent extends BaseEvent { 4 | /** 5 | * new limit in KBytes 6 | */ 7 | public int newLimit; 8 | public boolean active; 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/notification/INotificationCenter.kt: -------------------------------------------------------------------------------- 1 | package mediathek.tool.notification 2 | 3 | import java.io.Closeable 4 | 5 | /** 6 | * Interface for the platform specific notification implementation 7 | */ 8 | interface INotificationCenter : Closeable { 9 | fun displayNotification(msg: NotificationMessage) 10 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/notification/NullNotificationCenter.kt: -------------------------------------------------------------------------------- 1 | package mediathek.tool.notification 2 | 3 | /** 4 | * A notification center which does nothing. Used when notifications are deactivated. 5 | */ 6 | class NullNotificationCenter : INotificationCenter { 7 | override fun displayNotification(msg: NotificationMessage) {} 8 | override fun close() {} 9 | } -------------------------------------------------------------------------------- /src/main/resources/raven/toast/svg/info.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/test/kotlin/mediathek/tool/dns/IPvPreferenceModeTest.kt: -------------------------------------------------------------------------------- 1 | package mediathek.tool.dns 2 | 3 | import org.junit.jupiter.api.Assertions.assertEquals 4 | import org.junit.jupiter.api.Test 5 | 6 | class IPvPreferenceModeTest { 7 | 8 | @Test 9 | fun fromString() { 10 | val r = IPvPreferenceMode.fromString("ip_v6_only") 11 | assertEquals(IPvPreferenceMode.IPV6_ONLY, r) 12 | } 13 | } -------------------------------------------------------------------------------- /src/main/resources/raven/toast/svg/success.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /maven-repository/airsquared/JMacNotification/maven-metadata-local.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | airsquared 4 | JMacNotification 5 | 6 | 1.1 7 | 8 | 1.1 9 | 10 | 20211203150237 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/main/java/mediathek/update/ServerProgramInformation.kt: -------------------------------------------------------------------------------- 1 | package mediathek.update 2 | 3 | import mediathek.tool.Version 4 | 5 | data class ServerProgramInformation(val version: Version) { 6 | class ParserTags { 7 | companion object { 8 | const val INFO = "Info" 9 | const val VERSION = "Program_Version" 10 | const val INFO_NO = "number" 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /maven-repository/com/formdev/jformdesigner-annotations/maven-metadata-local.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.formdev 4 | jformdesigner-annotations 5 | 6 | 1.0 7 | 8 | 1.0 9 | 10 | 20250408125820 11 | 12 | 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | dist/javadoc 3 | /.gradle/ 4 | /bin/ 5 | /.checkstyle 6 | .classpath 7 | .project 8 | .settings/ 9 | *.build 10 | MediathekView.exe 11 | res/Icons/Sender 12 | /.idea/ 13 | /.nb-gradle/ 14 | /src/main/resources/version.properties 15 | deploy.key 16 | RepoZugang.properties 17 | /target/ 18 | /dependency-reduced-pom.xml 19 | *.iml 20 | /install4j*/ 21 | /res/macOS/bin 22 | `/.vs/ 23 | /javafx_sdk/mac/aarch64/javafx-sdk/ 24 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/UpdateStateChangedEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.messages; 2 | 3 | /** 4 | * 5 | * @author Klaus 6 | */ 7 | public class UpdateStateChangedEvent extends BaseEvent { 8 | private final boolean new_state; 9 | 10 | public UpdateStateChangedEvent(boolean new_state) { 11 | this.new_state = new_state; 12 | } 13 | 14 | public boolean isActive() { 15 | return new_state; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/kotlin/mediathek/mainwindow/Log4jShutdownHookThread.kt: -------------------------------------------------------------------------------- 1 | package mediathek.mainwindow 2 | 3 | import mediathek.tool.Log4jShutdownCallbackRegistry.Companion.execute 4 | 5 | /** 6 | * Gracefully shutdown config and log. 7 | * This may be necessary in case the app is not properly quit. 8 | */ 9 | class Log4jShutdownHookThread : Thread() { 10 | override fun run() { 11 | //shut down log4j 12 | execute() 13 | } 14 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/dialog/ButtonPanel.kt: -------------------------------------------------------------------------------- 1 | package mediathek.gui.dialog 2 | 3 | import java.awt.BorderLayout 4 | import javax.swing.JPanel 5 | import javax.swing.border.EmptyBorder 6 | 7 | /** 8 | * Placeholder {@link JPanel} with an empty border. 9 | * Used for button panels in a dialog. 10 | */ 11 | class ButtonPanel : JPanel() { 12 | init { 13 | layout = BorderLayout() 14 | border = EmptyBorder(0, 10, 10, 10) 15 | } 16 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/DarkModeFactory.kt: -------------------------------------------------------------------------------- 1 | package mediathek.tool 2 | 3 | import com.formdev.flatlaf.FlatDarkLaf 4 | import com.formdev.flatlaf.themes.FlatMacDarkLaf 5 | import org.apache.commons.lang3.SystemUtils 6 | import javax.swing.LookAndFeel 7 | 8 | object DarkModeFactory { 9 | @JvmStatic 10 | val lookAndFeel: LookAndFeel 11 | get() { 12 | return if (SystemUtils.IS_OS_MAC_OSX) FlatMacDarkLaf() else FlatDarkLaf() 13 | } 14 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/SenderListComboBoxModel.java: -------------------------------------------------------------------------------- 1 | package mediathek.tool; 2 | 3 | import ca.odell.glazedlists.swing.DefaultEventComboBoxModel; 4 | import mediathek.config.Daten; 5 | 6 | public class SenderListComboBoxModel extends DefaultEventComboBoxModel { 7 | 8 | public SenderListComboBoxModel() { 9 | super(new EventListWithEmptyFirstEntry(Daten.getInstance().getAllSendersList())); 10 | setSelectedItem(""); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/LightModeFactory.kt: -------------------------------------------------------------------------------- 1 | package mediathek.tool 2 | 3 | import com.formdev.flatlaf.FlatLightLaf 4 | import com.formdev.flatlaf.themes.FlatMacLightLaf 5 | import org.apache.commons.lang3.SystemUtils 6 | import javax.swing.LookAndFeel 7 | 8 | object LightModeFactory { 9 | @JvmStatic 10 | val lookAndFeel: LookAndFeel 11 | get() { 12 | return if (SystemUtils.IS_OS_MAC_OSX) FlatMacLightLaf() else FlatLightLaf() 13 | } 14 | } -------------------------------------------------------------------------------- /src/main/kotlin/feed/FeedMessage.kt: -------------------------------------------------------------------------------- 1 | package feed 2 | 3 | /* 4 | * A RSS message 5 | */ 6 | data class FeedMessage( 7 | val title: String, val description: String, val link: String, val author: String, 8 | val guid: String 9 | ) { 10 | override fun toString(): String { 11 | return ("FeedMessage [title=" + title + ", description=" + description 12 | + ", link=" + link + ", author=" + author + ", guid=" + guid 13 | + "]") 14 | } 15 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/PanelVorlage.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui; 2 | 3 | import mediathek.config.Daten; 4 | 5 | import javax.swing.*; 6 | 7 | public abstract class PanelVorlage extends JPanel { 8 | protected final Daten daten; 9 | protected boolean stopBeob; 10 | protected final JFrame parentComponent; 11 | 12 | public PanelVorlage(Daten daten, JFrame pparentComponent) { 13 | this.daten = daten; 14 | parentComponent = pparentComponent; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/test/kotlin/mediathek/daten/blacklist/BlacklistTagsTest.kt: -------------------------------------------------------------------------------- 1 | package mediathek.daten.blacklist 2 | 3 | import org.junit.jupiter.api.Assertions.assertEquals 4 | import org.junit.jupiter.api.Assertions.assertTrue 5 | import org.junit.jupiter.api.Test 6 | 7 | class BlacklistTagsTest { 8 | 9 | @Test 10 | fun fromXmlTag() { 11 | val r = BlacklistTags.fromXmlTag("black-sender") 12 | assertTrue(r.isPresent) 13 | assertEquals(r.get(), BlacklistTags.SENDER) 14 | } 15 | } -------------------------------------------------------------------------------- /src/main/resources/raven/toast/svg/warning.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/history/AboHistoryDialog.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.history; 2 | 3 | import mediathek.gui.dialog.StandardCloseDialog; 4 | 5 | import javax.swing.*; 6 | import java.awt.*; 7 | 8 | public class AboHistoryDialog extends StandardCloseDialog { 9 | public AboHistoryDialog(Frame owner) { 10 | super(owner, "Abo-Historie", true); 11 | } 12 | 13 | @Override 14 | public JComponent createContentPanel() { 15 | return new PanelErledigteUrls(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/test/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/datum/Datum.java: -------------------------------------------------------------------------------- 1 | package mediathek.tool.datum; 2 | 3 | import java.util.Date; 4 | 5 | public class Datum extends Date { 6 | public Datum() { 7 | super(); 8 | } 9 | 10 | public Datum(long l) { 11 | super(l); 12 | } 13 | 14 | @Override 15 | public String toString() { 16 | if (getTime() == 0) { 17 | return ""; 18 | } else { 19 | return DateUtil.FORMATTER.format(DateUtil.convertToLocalDate(this)); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/raven/toast/svg/close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/CopyToClipboardAction.kt: -------------------------------------------------------------------------------- 1 | package mediathek.tool 2 | 3 | import java.awt.event.ActionEvent 4 | import javax.swing.AbstractAction 5 | 6 | class CopyToClipboardAction(private val webSiteUrl: String) : AbstractAction() { 7 | init { 8 | putValue(NAME, "In Zwischenablage kopieren") 9 | } 10 | 11 | override fun actionPerformed(e: ActionEvent) { 12 | try { 13 | GuiFunktionen.copyToClipboard(webSiteUrl) 14 | } catch (ignored: Exception) { 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/main/kotlin/feed/Feed.kt: -------------------------------------------------------------------------------- 1 | package feed 2 | 3 | class Feed( 4 | val title: String, val link: String, val description: String, val language: String, 5 | val copyright: String, val pubDate: String 6 | ) { 7 | val messages: ArrayList = ArrayList() 8 | override fun toString(): String { 9 | return ("Feed [copyright=" + copyright + ", description=" + description 10 | + ", language=" + language + ", link=" + link + ", pubDate=" 11 | + pubDate + ", title=" + title + "]") 12 | } 13 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/filmlisten/reader/NoOpDateFilter.kt: -------------------------------------------------------------------------------- 1 | package mediathek.filmlisten.reader 2 | 3 | import mediathek.daten.DatenFilm 4 | import mediathek.daten.ListeFilme 5 | 6 | internal class NoOpDateFilter(listeFilme: ListeFilme) : IDateFilter { 7 | private val listeFilme: ListeFilme 8 | 9 | override fun filter(film: DatenFilm) { 10 | // just add the film objet to the list as we are not supposed to do any filtering 11 | listeFilme.add(film) 12 | } 13 | 14 | init { 15 | this.listeFilme = listeFilme 16 | } 17 | } -------------------------------------------------------------------------------- /src/main/kotlin/mediathek/gui/actions/ResetFilterDialogPosition.kt: -------------------------------------------------------------------------------- 1 | package mediathek.gui.actions 2 | 3 | import mediathek.mainwindow.MediathekGui 4 | import java.awt.event.ActionEvent 5 | import javax.swing.AbstractAction 6 | 7 | class ResetFilterDialogPosition(private val mediathekGui: MediathekGui) : AbstractAction() { 8 | init { 9 | putValue(NAME, "Filterdialog-Position zurücksetzen") 10 | } 11 | 12 | override fun actionPerformed(e: ActionEvent) { 13 | mediathekGui.tabFilme?.swingFilterDialog?.setLocation(100, 100) 14 | } 15 | } -------------------------------------------------------------------------------- /maven-repository/airsquared/JMacNotification/1.1/JMacNotification-1.1.pom: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | airsquared 6 | JMacNotification 7 | 1.1 8 | POM was created from install:install-file 9 | 10 | -------------------------------------------------------------------------------- /src/main/java/mediathek/filmeSuchen/ListenerFilmeLaden.java: -------------------------------------------------------------------------------- 1 | package mediathek.filmeSuchen; 2 | 3 | import java.util.EventListener; 4 | 5 | public class ListenerFilmeLaden implements EventListener { 6 | public void start(ListenerFilmeLadenEvent e) { 7 | } 8 | 9 | public void progress(ListenerFilmeLadenEvent e) { 10 | } 11 | 12 | public void fertig(ListenerFilmeLadenEvent e) { 13 | } 14 | 15 | public void fertigOnlyOne(ListenerFilmeLadenEvent e) { 16 | // dient dem Melden des ersten Mal Laden der Filmliste beim ProgStart 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/actions/ShowProgramInfosAction.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.actions; 2 | 3 | import mediathek.update.ProgrammUpdateSuchen; 4 | 5 | import javax.swing.*; 6 | import java.awt.event.ActionEvent; 7 | 8 | public class ShowProgramInfosAction extends AbstractAction { 9 | public ShowProgramInfosAction() { 10 | putValue(Action.NAME,"Programminfos anzeigen..."); 11 | } 12 | 13 | @Override 14 | public void actionPerformed(ActionEvent e) { 15 | new ProgrammUpdateSuchen().checkVersion(false, true, false, false); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/mediathek/controller/history/SeenHistoryShutdownHook.kt: -------------------------------------------------------------------------------- 1 | package mediathek.controller.history 2 | 3 | import java.sql.Connection 4 | 5 | /** 6 | * Shutdown hook implementation to close a SQL connection if it is still open at program end. 7 | */ 8 | class SeenHistoryShutdownHook(private val connection: Connection?) : Thread() { 9 | override fun run() { 10 | if (connection == null) 11 | return 12 | else { 13 | if (!connection.isClosed) { 14 | connection.close() 15 | } 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/filmeSuchen/ListenerFilmeLadenEvent.java: -------------------------------------------------------------------------------- 1 | package mediathek.filmeSuchen; 2 | 3 | public class ListenerFilmeLadenEvent { 4 | 5 | public String senderUrl; 6 | public String text; 7 | public int max; 8 | public int progress; 9 | public final boolean fehler; 10 | 11 | public ListenerFilmeLadenEvent(String ssender, String ttext, int mmax, int pprogress, boolean ffehler) { 12 | senderUrl = ssender; 13 | text = ttext; 14 | max = mmax; 15 | progress = pprogress; 16 | fehler = ffehler; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/actions/SearchProgramUpdateAction.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.actions; 2 | 3 | import mediathek.update.ProgrammUpdateSuchen; 4 | 5 | import javax.swing.*; 6 | import java.awt.event.ActionEvent; 7 | 8 | public class SearchProgramUpdateAction extends AbstractAction { 9 | public SearchProgramUpdateAction() { 10 | putValue(Action.NAME, "Nach Update suchen..."); 11 | } 12 | 13 | @Override 14 | public void actionPerformed(ActionEvent e) { 15 | new ProgrammUpdateSuchen().checkVersion(true, false, false, false); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /maven-repository/com/formdev/jformdesigner-annotations/1.0/jformdesigner-annotations-1.0.pom: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | com.formdev 6 | jformdesigner-annotations 7 | 1.0 8 | POM was created from install:install-file 9 | 10 | -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/NoSelectionErrorDialog.java: -------------------------------------------------------------------------------- 1 | package mediathek.tool; 2 | 3 | import mediathek.config.Konstanten; 4 | import org.jetbrains.annotations.Nullable; 5 | 6 | import javax.swing.*; 7 | import java.awt.*; 8 | 9 | public class NoSelectionErrorDialog { 10 | 11 | public static void show(@Nullable Component parent) { 12 | JOptionPane.showMessageDialog(parent, "Der Befehl kann nicht ausgeführt werden.\n" + 13 | "Sie haben keinen Tabelleneintrag ausgewählt.", 14 | Konstanten.PROGRAMMNAME, JOptionPane.ERROR_MESSAGE); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/mediathek/daten/blacklist/BlacklistTags.kt: -------------------------------------------------------------------------------- 1 | package mediathek.daten.blacklist 2 | 3 | import java.util.* 4 | 5 | enum class BlacklistTags(val index: Int, val xmlName: String) { 6 | SENDER(0, "black-sender"), 7 | THEMA(1, "black-thema"), 8 | TITEL(2, "black-titel"), 9 | THEMA_TITEL(3, "black-thema-titel"); 10 | 11 | companion object { 12 | @JvmStatic 13 | fun fromXmlTag(tag: String): Optional { 14 | return Arrays.stream(entries.toTypedArray()).filter { e: BlacklistTags -> e.xmlName == tag }.findAny() 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /src/test/java/mediathek/tool/LanguageCodeTest.java: -------------------------------------------------------------------------------- 1 | package mediathek.tool; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.util.EnumSet; 6 | 7 | import static org.junit.jupiter.api.Assertions.assertFalse; 8 | 9 | class LanguageCodeTest { 10 | /** 11 | * Test if all codes can be converted to 3 letter code and there is no exception. 12 | */ 13 | @Test 14 | void testConversion() { 15 | for (var code : EnumSet.allOf(LanguageCode.class)) { 16 | var out = code.getISO3Language(); 17 | assertFalse(out.isEmpty()); 18 | } 19 | 20 | } 21 | } -------------------------------------------------------------------------------- /src/main/java/raven/toast/ToastClientProperties.java: -------------------------------------------------------------------------------- 1 | package raven.toast; 2 | 3 | public interface ToastClientProperties { 4 | String TOAST_ICON = "Toast.icon"; 5 | String TOAST_COMPONENT = "Toast.component"; 6 | String TOAST_SHOW_CLOSE_BUTTON = "Toast.showCloseButton"; 7 | String TOAST_CLOSE_CALLBACK = "Toast.closeCallback"; 8 | String TOAST_CLOSE_ICON = "Toast.closeIcon"; 9 | String TOAST_SUCCESS_ICON = "Toast.success.icon"; 10 | String TOAST_INFO_ICON = "Toast.info.icon"; 11 | String TOAST_WARNING_ICON = "Toast.warning.icon"; 12 | String TOAST_ERROR_ICON = "Toast.error.icon"; 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/dialog/reset/ResetSettingsDialog.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.dialog.reset; 2 | 3 | import mediathek.config.Daten; 4 | import mediathek.gui.dialog.StandardCloseDialog; 5 | 6 | import javax.swing.*; 7 | import java.awt.*; 8 | 9 | public class ResetSettingsDialog extends StandardCloseDialog { 10 | public ResetSettingsDialog(Frame owner, Daten daten) { 11 | super(owner, "Programm zurücksetzen", true); 12 | setResizable(false); 13 | } 14 | 15 | @Override 16 | public JComponent createContentPanel() { 17 | return new ResetSettingsPanel(null); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/tabs/tab_film/searchfilters/FinalStagePatternFilter.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.tabs.tab_film.searchfilters; 2 | 3 | import mediathek.daten.DatenFilm; 4 | import mediathek.tool.Filter; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | import java.util.function.Predicate; 8 | 9 | public record FinalStagePatternFilter(@NotNull String[] searchStr) implements Predicate { 10 | @Override 11 | public boolean test(@NotNull DatenFilm film) { 12 | return Filter.pruefen(searchStr, film.getThema()) 13 | || Filter.pruefen(searchStr, film.getTitle()); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/SVGIconUtilities.java: -------------------------------------------------------------------------------- 1 | package mediathek.tool; 2 | 3 | import com.formdev.flatlaf.extras.FlatSVGIcon; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | public class SVGIconUtilities { 7 | public static FlatSVGIcon createSVGIcon(@NotNull String resource) { 8 | return createSVGIcon(resource, 16f); 9 | } 10 | 11 | public static FlatSVGIcon createSVGIcon(@NotNull String resource, float height) { 12 | FlatSVGIcon icon = new FlatSVGIcon(resource); 13 | float scaleFactor = (1f / icon.getIconHeight()) * height; 14 | return icon.derive(scaleFactor); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/resources/raven/toast/svg/error.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/test/java/mediathek/config/MVConfigTest.java: -------------------------------------------------------------------------------- 1 | package mediathek.config; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertFalse; 6 | import static org.junit.jupiter.api.Assertions.assertTrue; 7 | 8 | class MVConfigTest { 9 | 10 | @Test 11 | void enum_find_invalid() { 12 | var res = MVConfig.Configs.find("blaXblubb"); 13 | assertFalse(res); 14 | } 15 | 16 | @Test 17 | void enum_find_valid() { 18 | var res = MVConfig.Configs.find(MVConfig.Configs.SYSTEM_BLACKLIST_ZUKUNFT_NICHT_ANZEIGEN.cValue); 19 | assertTrue(res); 20 | } 21 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/models/NonEditableTableModel.java: -------------------------------------------------------------------------------- 1 | package mediathek.tool.models; 2 | 3 | import javax.swing.table.DefaultTableModel; 4 | 5 | /** 6 | * Simple extension of DefaultTableModel which prevents cell from being editable 7 | */ 8 | public class NonEditableTableModel extends DefaultTableModel { 9 | public NonEditableTableModel() { 10 | super(); 11 | } 12 | 13 | public NonEditableTableModel(Object[][] data, Object[] columnNames) { 14 | super(data, columnNames); 15 | } 16 | 17 | @Override 18 | public boolean isCellEditable(int i, int j) { 19 | return false; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/notification/MacNotificationCenter.kt: -------------------------------------------------------------------------------- 1 | package mediathek.tool.notification 2 | 3 | import airsquared.JMacNotification.NSUserNotification 4 | import java.io.IOException 5 | 6 | class MacNotificationCenter : INotificationCenter { 7 | override fun displayNotification(msg: NotificationMessage) { 8 | val notification = NSUserNotification() 9 | notification.title = msg.title 10 | notification.informativeText = msg.message 11 | notification.hasReplyButton = false 12 | notification.show() 13 | } 14 | 15 | @Throws(IOException::class) 16 | override fun close() { 17 | } 18 | } -------------------------------------------------------------------------------- /src/test/kotlin/mediathek/daten/abo/AboTagsTest.kt: -------------------------------------------------------------------------------- 1 | package mediathek.daten.abo 2 | 3 | import org.junit.jupiter.api.Assertions.assertEquals 4 | import org.junit.jupiter.api.Assertions.assertTrue 5 | import org.junit.jupiter.api.Test 6 | 7 | class AboTagsTest { 8 | 9 | @Test 10 | fun fromXmlTag() { 11 | val r = AboTags.fromXmlTag("Sender") 12 | assertTrue(r.isPresent) 13 | assertEquals(r.get(), AboTags.SENDER) 14 | } 15 | 16 | @Test 17 | fun fromIndex() { 18 | val r = AboTags.fromIndex(DatenAbo.ABO_NR) 19 | assertTrue(r.isPresent) 20 | assertEquals(r.get(), AboTags.NR) 21 | } 22 | } -------------------------------------------------------------------------------- /src/test/java/mediathek/tool/ttml/TimedTextMarkupLanguageParserTest.java: -------------------------------------------------------------------------------- 1 | package mediathek.tool.ttml; 2 | 3 | import mediathek.tool.ttml.parsers.EbuTimedTextMarkupLanguageParser; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import static org.junit.jupiter.api.Assertions.assertThrows; 7 | 8 | class TimedTextMarkupLanguageParserTest { 9 | @Test 10 | void getSubtitleList() { 11 | try (TimedTextMarkupLanguageParser parser = new EbuTimedTextMarkupLanguageParser()) { 12 | var list = parser.getSubtitleList(); 13 | assertThrows(UnsupportedOperationException.class, () -> list.add(new Subtitle())); 14 | }} 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/cellrenderer/SelfEvictingSenderIconCache.java: -------------------------------------------------------------------------------- 1 | package mediathek.tool.cellrenderer; 2 | 3 | import mediathek.tool.timer.TimerPool; 4 | 5 | import javax.swing.*; 6 | import java.util.concurrent.ConcurrentHashMap; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | /** 10 | * A cache for sender icons at a specific cell dimension. 11 | * Will get cleared periodically. 12 | */ 13 | public class SelfEvictingSenderIconCache extends ConcurrentHashMap { 14 | public SelfEvictingSenderIconCache() { 15 | TimerPool.getTimerPool().scheduleAtFixedRate(this::clear, 5, 5, TimeUnit.MINUTES); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/models/TModelColor.java: -------------------------------------------------------------------------------- 1 | package mediathek.tool.models; 2 | 3 | import mediathek.config.MVColor; 4 | import mediathek.tool.MVC; 5 | 6 | public class TModelColor extends NonEditableTableModel { 7 | public TModelColor(Object[][] data) { 8 | super(data, new String[]{"Beschreibung", "Farbe"}); 9 | } 10 | 11 | @Override 12 | public Class getColumnClass(int columnIndex) { 13 | Class result; 14 | if (columnIndex == MVColor.MVC_COLOR) { 15 | result = MVC.class; 16 | } else { 17 | result = String.class; 18 | } 19 | return result; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/actions/StopDownloadsAction.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.actions; 2 | 3 | import mediathek.gui.tabs.tab_downloads.GuiDownloads; 4 | 5 | import javax.swing.*; 6 | import java.awt.event.ActionEvent; 7 | 8 | public class StopDownloadsAction extends AbstractAction { 9 | private final GuiDownloads guiDownloads; 10 | 11 | public StopDownloadsAction(GuiDownloads guiDownloads) { 12 | this.guiDownloads = guiDownloads; 13 | putValue(Action.NAME, "Ausgewählte Downloads stoppen"); 14 | } 15 | 16 | @Override 17 | public void actionPerformed(ActionEvent e) { 18 | guiDownloads.stoppen(false); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/resources/mediathek/file/hilfetext_geo.txt: -------------------------------------------------------------------------------- 1 | 2 | Nicht alle Filme lassen sich im Ausland abrufen. 3 | Wenn geblockte Filme markiert werden sollen, 4 | kann man hier seinen Standort angeben. 5 | 6 | Der Download geogeblockter Sendungen 7 | bricht im Ausland sofort ab (Download 8 | "fehlerhaft"). MediathekView kennt nicht alle 9 | Muster für geogeblockte Sendungen. Ob ein 10 | fehlerhafter Download auf Geoblocking 11 | zurückzuführen ist, zeigt sich beim Klick auf 12 | den Link zur Sendung ("zur Website") ganz 13 | unten im Tab "Filme". Wenn die Sendung 14 | auch auf der Website des Senders nicht 15 | abgespielt werden kann, liegt fast immer 16 | Geoblocking vor. 17 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/actions/StopAllDownloadsAction.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.actions; 2 | 3 | import mediathek.gui.tabs.tab_downloads.GuiDownloads; 4 | 5 | import javax.swing.*; 6 | import java.awt.event.ActionEvent; 7 | 8 | public class StopAllDownloadsAction extends AbstractAction { 9 | 10 | private final GuiDownloads guiDownloads; 11 | 12 | public StopAllDownloadsAction(GuiDownloads guiDownloads) { 13 | this.guiDownloads = guiDownloads; 14 | putValue(Action.NAME, "Alle Downloads stoppen"); 15 | } 16 | 17 | @Override 18 | public void actionPerformed(ActionEvent e) { 19 | guiDownloads.stoppen(true); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/kotlin/mediathek/gui/actions/CreateNewAboAction.kt: -------------------------------------------------------------------------------- 1 | package mediathek.gui.actions 2 | 3 | import mediathek.daten.ListeAbo 4 | import mediathek.tool.SVGIconUtilities 5 | import java.awt.event.ActionEvent 6 | import javax.swing.AbstractAction 7 | 8 | class CreateNewAboAction(private val listeAbo: ListeAbo) : AbstractAction() { 9 | override fun actionPerformed(e: ActionEvent?) { 10 | listeAbo.addAbo("Neu", "", "", "") 11 | } 12 | 13 | init { 14 | putValue(NAME, "Abo anlegen...") 15 | putValue(SHORT_DESCRIPTION, "Abo anlegen") 16 | putValue(SMALL_ICON, SVGIconUtilities.createSVGIcon("icons/fontawesome/plus.svg")) 17 | } 18 | } -------------------------------------------------------------------------------- /src/main/kotlin/mediathek/gui/actions/ShowAboutAction.kt: -------------------------------------------------------------------------------- 1 | package mediathek.gui.actions 2 | 3 | import mediathek.gui.dialog.AboutDialog 4 | import mediathek.mainwindow.MediathekGui 5 | import mediathek.tool.GuiFunktionen 6 | import java.awt.event.ActionEvent 7 | import javax.swing.AbstractAction 8 | 9 | class ShowAboutAction : AbstractAction() { 10 | override fun actionPerformed(e: ActionEvent?) { 11 | val dialog = AboutDialog(MediathekGui.ui()) 12 | GuiFunktionen.centerOnScreen(dialog, false) 13 | dialog.isVisible = true 14 | dialog.dispose() 15 | } 16 | 17 | init { 18 | putValue(NAME, "Über dieses Programm...") 19 | } 20 | } -------------------------------------------------------------------------------- /src/main/kotlin/mediathek/tool/dns/IPvPreferenceMode.kt: -------------------------------------------------------------------------------- 1 | package mediathek.tool.dns 2 | 3 | /** 4 | * Specifies, which IP addresses shall be used in DNS resolution. 5 | */ 6 | enum class IPvPreferenceMode(val code: String) { 7 | SYSTEM("system"), 8 | IPV6_FIRST("ip_v6"), 9 | IPV4_FIRST("ip_v4"), 10 | IPV6_ONLY("ip_v6_only"), 11 | IPV4_ONLY("ip_v4_only"); 12 | 13 | override fun toString(): String { 14 | return code 15 | } 16 | 17 | companion object { 18 | @JvmStatic 19 | fun fromString(ipMode: String): IPvPreferenceMode = 20 | entries.find { it.code == ipMode } ?: throw IllegalArgumentException("Unknown value $ipMode") 21 | } 22 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/actions/StopAllWaitingDownloadsAction.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.actions; 2 | 3 | import mediathek.gui.tabs.tab_downloads.GuiDownloads; 4 | 5 | import javax.swing.*; 6 | import java.awt.event.ActionEvent; 7 | 8 | public class StopAllWaitingDownloadsAction extends AbstractAction { 9 | private final GuiDownloads guiDownloads; 10 | 11 | public StopAllWaitingDownloadsAction(GuiDownloads guiDownloads) { 12 | this.guiDownloads = guiDownloads; 13 | putValue(Action.NAME, "Wartende Downloads stoppen"); 14 | } 15 | 16 | @Override 17 | public void actionPerformed(ActionEvent e) { 18 | guiDownloads.stopAllWaitingDownloads(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/kotlin/mediathek/gui/actions/ShowBandwidthUsageAction.kt: -------------------------------------------------------------------------------- 1 | package mediathek.gui.actions 2 | 3 | import mediathek.gui.bandwidth.BandwidthDialog 4 | import mediathek.mainwindow.MediathekGui 5 | import java.awt.event.ActionEvent 6 | import java.util.* 7 | import javax.swing.AbstractAction 8 | 9 | class ShowBandwidthUsageAction(private val mediathekGui: MediathekGui) : AbstractAction() { 10 | var dialogOptional = Optional.empty() 11 | 12 | init { 13 | putValue(NAME, "Bandbreitennutzung") 14 | } 15 | 16 | override fun actionPerformed(e: ActionEvent?) { 17 | val dialog = BandwidthDialog(mediathekGui, this) 18 | dialog.isVisible = true 19 | } 20 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/filmInformation/HtmlMultilineLabel.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.filmInformation; 2 | 3 | import javax.swing.*; 4 | 5 | public class HtmlMultilineLabel extends JLabel { 6 | @Override 7 | public void setText(String text) { 8 | super.setText(prepareString(text)); 9 | } 10 | 11 | private String prepareString(String text) { 12 | var newText = ""; 13 | if (!text.startsWith("")) { 14 | newText += text; 15 | newText += ""; 16 | } 17 | else 18 | newText = text; 19 | 20 | return newText; 21 | } 22 | 23 | public HtmlMultilineLabel() { 24 | super(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/actions/StartAllDownloadsTimedAction.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.actions; 2 | 3 | import mediathek.gui.tabs.tab_downloads.GuiDownloads; 4 | 5 | import javax.swing.*; 6 | import java.awt.event.ActionEvent; 7 | 8 | public class StartAllDownloadsTimedAction extends AbstractAction { 9 | private final GuiDownloads guiDownloads; 10 | 11 | public StartAllDownloadsTimedAction(GuiDownloads guiDownloads) { 12 | this.guiDownloads = guiDownloads; 13 | putValue(Action.NAME, "Alle Downloads zeitverzögert starten..."); 14 | } 15 | 16 | @Override 17 | public void actionPerformed(ActionEvent e) { 18 | guiDownloads.startAllDownloadsAtSpecificTime(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/resources/icons/fontawesome/minus.svg: -------------------------------------------------------------------------------- 1 | 2 | 8 | 10 | 11 | 15 | 16 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/actions/DisposeDialogAction.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.actions; 2 | 3 | import javax.swing.*; 4 | import java.awt.event.ActionEvent; 5 | 6 | /** 7 | * Generic action for disposing dialogs. 8 | */ 9 | @SuppressWarnings("serial") 10 | public class DisposeDialogAction extends AbstractAction { 11 | 12 | private final JDialog dlg; 13 | 14 | public DisposeDialogAction(JDialog dlg, String description, String shortDescription) { 15 | super(); 16 | putValue(NAME, description); 17 | putValue(SHORT_DESCRIPTION, shortDescription); 18 | this.dlg = dlg; 19 | } 20 | 21 | public void actionPerformed(ActionEvent e) { 22 | dlg.dispose(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/actions/ShowAboHistoryAction.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.actions; 2 | 3 | import mediathek.gui.history.AboHistoryDialog; 4 | 5 | import javax.swing.*; 6 | import java.awt.*; 7 | import java.awt.event.ActionEvent; 8 | 9 | public class ShowAboHistoryAction extends AbstractAction { 10 | private final Frame owner; 11 | 12 | public ShowAboHistoryAction(Frame owner) { 13 | this.owner = owner; 14 | 15 | putValue(Action.NAME, "Abo-Historie anzeigen..."); 16 | } 17 | 18 | @Override 19 | public void actionPerformed(ActionEvent e) { 20 | AboHistoryDialog dialog = new AboHistoryDialog(owner); 21 | dialog.pack(); 22 | dialog.setVisible(true); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/tasks/BlacklistFilterWorker.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.tasks; 2 | 3 | import mediathek.config.Daten; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import javax.swing.*; 7 | 8 | public class BlacklistFilterWorker extends SwingWorker { 9 | 10 | public BlacklistFilterWorker(@NotNull JLabel progLabel, @NotNull JProgressBar progressBar) { 11 | SwingUtilities.invokeLater(() -> { 12 | progLabel.setText("Blacklist anwenden"); 13 | progressBar.setIndeterminate(true); 14 | }); 15 | } 16 | 17 | @Override 18 | protected Void doInBackground() { 19 | Daten.getInstance().getListeBlacklist().filterListe(); 20 | 21 | return null; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/actions/QuitAction.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.actions; 2 | 3 | import mediathek.mainwindow.MediathekGui; 4 | 5 | import javax.swing.*; 6 | import java.awt.event.ActionEvent; 7 | import java.awt.event.KeyEvent; 8 | 9 | public class QuitAction extends AbstractAction { 10 | private final MediathekGui mediathekGui; 11 | 12 | public QuitAction(MediathekGui mediathekGui) { 13 | this.mediathekGui = mediathekGui; 14 | putValue(Action.NAME, "Beenden"); 15 | putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_Q, KeyEvent.CTRL_DOWN_MASK)); 16 | } 17 | 18 | @Override 19 | public void actionPerformed(ActionEvent e) { 20 | mediathekGui.quitApplication(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/tabs/tab_downloads/AboLabel.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.tabs.tab_downloads; 2 | 3 | import mediathek.daten.DownloadStartInfo; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import javax.swing.*; 7 | 8 | public class AboLabel extends JLabel { 9 | public AboLabel(@NotNull DownloadStartInfoProperty startInfoProperty) { 10 | setToolTipText("Anzahl der Abos in der Liste"); 11 | startInfoProperty.addStartInfoChangeListener(evt -> SwingUtilities.invokeLater(() -> process((DownloadStartInfo) evt.getNewValue()))); 12 | 13 | } 14 | private void process(@NotNull DownloadStartInfo info) { 15 | String abo = (info.num_abos == 1) ? "1 Abo" : info.num_abos + " Abos"; 16 | setText(abo); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/resources/icons/fontawesome/circle-half-stroke.svg: -------------------------------------------------------------------------------- 1 | 2 | 8 | 10 | 11 | 15 | 16 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/tasks/RefreshAboWorker.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.tasks; 2 | 3 | import mediathek.config.Daten; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import javax.swing.*; 7 | 8 | public class RefreshAboWorker extends SwingWorker { 9 | 10 | public RefreshAboWorker(@NotNull JLabel progLabel, @NotNull JProgressBar progressBar) { 11 | SwingUtilities.invokeLater(() -> { 12 | progLabel.setText("Abos eintragen"); 13 | progressBar.setIndeterminate(true); 14 | }); 15 | } 16 | 17 | @Override 18 | protected Void doInBackground() { 19 | var daten = Daten.getInstance(); 20 | daten.getListeAbo().setAboFuerFilm(daten.getListeFilme(), false); 21 | 22 | return null; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/test/java/mediathek/tool/SingleInstanceTest.java: -------------------------------------------------------------------------------- 1 | package mediathek.tool; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertFalse; 6 | import static org.junit.jupiter.api.Assertions.assertTrue; 7 | 8 | class SingleInstanceTest { 9 | @Test 10 | void instance1_not_active() { 11 | try (var instance1 = new SingleInstance()) { 12 | assertFalse(instance1.isAppAlreadyActive()); 13 | } 14 | } 15 | 16 | @Test 17 | void instance2_activity_test() { 18 | try (var instance1 = new SingleInstance(); 19 | var instance2 = new SingleInstance()) { 20 | assertFalse(instance1.isAppAlreadyActive()); 21 | assertTrue(instance2.isAppAlreadyActive()); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/actions/EditDownloadAction.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.actions; 2 | 3 | import mediathek.gui.tabs.tab_downloads.GuiDownloads; 4 | import mediathek.tool.SVGIconUtilities; 5 | 6 | import javax.swing.*; 7 | import java.awt.event.ActionEvent; 8 | 9 | public class EditDownloadAction extends AbstractAction { 10 | private final GuiDownloads guiDownloads; 11 | 12 | public EditDownloadAction(GuiDownloads guiDownloads) { 13 | this.guiDownloads = guiDownloads; 14 | putValue(Action.NAME, "Download ändern"); 15 | putValue(Action.SMALL_ICON, SVGIconUtilities.createSVGIcon("icons/fontawesome/pen-to-square.svg")); 16 | } 17 | 18 | @Override 19 | public void actionPerformed(ActionEvent e) { 20 | guiDownloads.editDownload(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/actions/ShowDuplicateStatisticsAction.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.actions; 2 | 3 | import mediathek.gui.duplicates.statistics.DuplicateStatisticsDialog; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import javax.swing.*; 7 | import java.awt.*; 8 | import java.awt.event.ActionEvent; 9 | 10 | public class ShowDuplicateStatisticsAction extends AbstractAction { 11 | private final Frame owner; 12 | 13 | public ShowDuplicateStatisticsAction(@NotNull Frame owner) { 14 | this.owner = owner; 15 | putValue(Action.NAME, "Film-Statistik anzeigen"); 16 | } 17 | 18 | @Override 19 | public void actionPerformed(ActionEvent e) { 20 | var dlg = new DuplicateStatisticsDialog(owner, this); 21 | dlg.setVisible(true); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/dialogEinstellungen/allgemein/TextFieldConfigWriter.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.dialogEinstellungen.allgemein; 2 | 3 | import mediathek.tool.ApplicationConfiguration; 4 | 5 | import javax.swing.*; 6 | import java.awt.event.ActionEvent; 7 | import java.awt.event.ActionListener; 8 | 9 | /** 10 | * Generic config writer for textfields. 11 | * Action will be performed on Swing EDT. 12 | */ 13 | record TextFieldConfigWriter(JTextField control, 14 | String configPropertyKey) implements ActionListener { 15 | 16 | @Override 17 | public void actionPerformed(ActionEvent e) { 18 | final String controlText = control.getText(); 19 | ApplicationConfiguration.getConfiguration().setProperty(configPropertyKey, controlText); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/table/MVProgTable.java: -------------------------------------------------------------------------------- 1 | package mediathek.tool.table; 2 | 3 | import mediathek.daten.DatenProg; 4 | import mediathek.tool.models.NonEditableTableModel; 5 | 6 | import java.util.Optional; 7 | 8 | public class MVProgTable extends MVTable { 9 | public MVProgTable() { 10 | super(DatenProg.MAX_ELEM, new boolean[DatenProg.MAX_ELEM], 11 | Optional.empty(), 12 | Optional.empty(), 13 | Optional.empty()); 14 | 15 | setModel(new NonEditableTableModel(new Object[][]{}, DatenProg.COLUMN_NAMES)); 16 | } 17 | 18 | @Override 19 | protected void spaltenAusschalten() { 20 | //do nothing 21 | } 22 | 23 | @Override 24 | public void calculateRowHeight() { 25 | // do nothing 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/resources/icons/fontawesome/caret-down.svg: -------------------------------------------------------------------------------- 1 | 2 | 8 | 10 | 11 | 15 | 16 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/actions/AdvanceDownloadsAction.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.actions; 2 | 3 | import mediathek.gui.tabs.tab_downloads.GuiDownloads; 4 | import mediathek.tool.SVGIconUtilities; 5 | 6 | import javax.swing.*; 7 | import java.awt.event.ActionEvent; 8 | 9 | public class AdvanceDownloadsAction extends AbstractAction { 10 | private final GuiDownloads guiDownloads; 11 | 12 | public AdvanceDownloadsAction(GuiDownloads guiDownloads) { 13 | this.guiDownloads = guiDownloads; 14 | putValue(Action.NAME, "Downloads vorziehen"); 15 | putValue(Action.SMALL_ICON, SVGIconUtilities.createSVGIcon("icons/fontawesome/arrow-up.svg")); 16 | } 17 | 18 | @Override 19 | public void actionPerformed(ActionEvent e) { 20 | guiDownloads.downloadsVorziehen(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/actions/DeleteDownloadAction.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.actions; 2 | 3 | import mediathek.gui.tabs.tab_downloads.GuiDownloads; 4 | import mediathek.tool.SVGIconUtilities; 5 | 6 | import javax.swing.*; 7 | import java.awt.event.ActionEvent; 8 | 9 | public class DeleteDownloadAction extends AbstractAction { 10 | private final GuiDownloads guiDownloads; 11 | 12 | public DeleteDownloadAction(GuiDownloads guiDownloads) { 13 | this.guiDownloads = guiDownloads; 14 | putValue(Action.SMALL_ICON, SVGIconUtilities.createSVGIcon("icons/fontawesome/xmark.svg")); 15 | putValue(Action.NAME, "gespeicherten Film (Datei) löschen"); 16 | } 17 | 18 | @Override 19 | public void actionPerformed(ActionEvent e) { 20 | guiDownloads.filmLoeschen_(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/actions/OpenTargetFolderAction.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.actions; 2 | 3 | import mediathek.gui.tabs.tab_downloads.GuiDownloads; 4 | import mediathek.tool.SVGIconUtilities; 5 | 6 | import javax.swing.*; 7 | import java.awt.event.ActionEvent; 8 | 9 | public class OpenTargetFolderAction extends AbstractAction { 10 | private final GuiDownloads guiDownloads; 11 | 12 | public OpenTargetFolderAction(GuiDownloads guiDownloads) { 13 | this.guiDownloads = guiDownloads; 14 | putValue(Action.NAME, "Zielordner öffnen"); 15 | putValue(Action.SMALL_ICON, SVGIconUtilities.createSVGIcon("icons/fontawesome/folder-open.svg")); 16 | } 17 | 18 | @Override 19 | public void actionPerformed(ActionEvent e) { 20 | guiDownloads.zielordnerOeffnen(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/actions/StartDownloadsAction.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.actions; 2 | 3 | import mediathek.gui.tabs.tab_downloads.GuiDownloads; 4 | import mediathek.tool.SVGIconUtilities; 5 | 6 | import javax.swing.*; 7 | import java.awt.event.ActionEvent; 8 | 9 | public class StartDownloadsAction extends AbstractAction { 10 | private final GuiDownloads guiDownloads; 11 | 12 | public StartDownloadsAction(GuiDownloads guiDownloads) { 13 | this.guiDownloads = guiDownloads; 14 | putValue(Action.NAME, "Ausgewählte Downloads starten"); 15 | putValue(Action.SMALL_ICON, SVGIconUtilities.createSVGIcon("icons/fontawesome/caret-down.svg")); 16 | } 17 | 18 | @Override 19 | public void actionPerformed(ActionEvent e) { 20 | guiDownloads.starten(false); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/tabs/tab_film/OnlineSearchProviders.kt: -------------------------------------------------------------------------------- 1 | package mediathek.gui.tabs.tab_film 2 | 3 | enum class OnlineSearchProviders(private val displayName: String, val queryUrl: String) { 4 | BING("Bing", "https://www.bing.com/search?q="), 5 | DUCKDUCKGO("DuckDuckGo", "https://duckduckgo.com/?q="), 6 | GOOGLE("Google", "https://www.google.de/search?q="), 7 | IMDB("IMDB","https://www.imdb.com/find?q="), 8 | STARTPAGE("Startpage", "https://www.startpage.com/do/search?q="), 9 | MOVIEDB("The Movie Database", "https://www.themoviedb.org/search?language=de-DE&query="), 10 | TVDB("TheTVDB", "https://thetvdb.com/search?query="), 11 | YOUTUBE("YouTube", "https://www.youtube.com/results?search_query="); 12 | 13 | override fun toString(): String { 14 | return displayName 15 | } 16 | } -------------------------------------------------------------------------------- /src/main/resources/icons/fontawesome/ellipsis-vertical.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/tabs/tab_film/searchfilters/FinalStageFilterNoPattern.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.tabs.tab_film.searchfilters; 2 | 3 | import mediathek.daten.DatenFilm; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.util.function.Predicate; 7 | 8 | public class FinalStageFilterNoPattern implements Predicate { 9 | private final String searchText; 10 | 11 | public FinalStageFilterNoPattern(@NotNull String[] searchStr) { 12 | this.searchText = searchStr[0]; 13 | } 14 | 15 | @Override 16 | public boolean test(DatenFilm datenFilm) { 17 | // searchText cannot be empty as it is checked before 18 | return datenFilm.getThema().toLowerCase().contains(searchText) 19 | || datenFilm.getTitle().toLowerCase().contains(searchText); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/resources/mediathek/file/hilfetext_reset.txt: -------------------------------------------------------------------------------- 1 | "Einstellungen zum Abspielen/Aufzeichnen zurücksetzen" 2 | 3 | Damit werden alle Sets (auch eigene), die zum Abspielen 4 | und Aufzeichnen der Filme gebraucht werden, gelöscht. 5 | Anschließend werden die aktuellen Standardsets 6 | eingerichtet. Es kann dann direkt damit 7 | weitergearbeitet werden. 8 | Abos und Blacklist bleiben erhalten. 9 | 10 | Das sollte vor dem kompletten Zurücksetzen 11 | des Programms versucht werden. 12 | 13 | 14 | oder ============================== 15 | 16 | "Alle Einstellungen zurücksetzen" 17 | 18 | Damit wird das Programm in den 19 | Ursprungszustand zurückgesetzt. 20 | 21 | Es gehen ALLE Einstellungen verloren. 22 | 23 | Das Programm beendet sich und muss neu 24 | gestartet werden. Der neue Start beginnt 25 | mit dem Einrichtungsdialog. 26 | 27 | -------------------------------------------------------------------------------- /src/main/java/mediathek/mainwindow/SelectedListItemsLabel.java: -------------------------------------------------------------------------------- 1 | package mediathek.mainwindow; 2 | 3 | import javax.swing.*; 4 | import java.beans.PropertyChangeEvent; 5 | import java.beans.PropertyChangeListener; 6 | 7 | public class SelectedListItemsLabel extends JLabel implements PropertyChangeListener { 8 | public SelectedListItemsLabel(MediathekGui mediathekGui) { 9 | setText("0"); 10 | setToolTipText("Ausgewählte Einträge der aktiven Tabelle"); 11 | mediathekGui.selectedListItemsProperty.addSelectedItemsChangeListener(this); 12 | } 13 | 14 | @Override 15 | public void propertyChange(PropertyChangeEvent evt) { 16 | SwingUtilities.invokeLater(() -> { 17 | long items = (long) evt.getNewValue(); 18 | setText(Long.toString(items)); 19 | }); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/resources/mediathek/file/hilfetext_editDownloadProg.txt: -------------------------------------------------------------------------------- 1 | 2 | Der Programmaufruf wird von MediathekView in die einzelnen 3 | Teile (Programmschalter) zerlegt. Die einzelnen Programmschalter 4 | werden durch "<>" getrennt angegeben. Dadurch ist es 5 | möglich, auch Pfade mit Leerzeichen zu verwenden. 6 | 7 | Bei ÄNDERUNGEN des Programmaufrufs in diesem Dialog, muss diese Form 8 | verwendet werden. 9 | 10 | der Aufruf: 11 | PFAD/ffmpeg -i URL -c copy -bsf:a aac_adtstoasc ZIELPFAD/DATEI.mp4 12 | 13 | wird so angegeben: 14 | Pfad/ffmpeg<>-i<>URL<>-c<>copy<>-bsf:a<>aac_adtstoasc<>ZIELPFAD/DATEI.mp4 15 | 16 | Der Programmaufruf kann auch so (ohne <>) angegben werden: 17 | PFAD/ffmpeg -i URL -c copy -bsf:a aac_adtstoasc ZIELPFAD/DATEI.mp4 18 | 19 | Das funktioniert, kann dann aber bei Leerzeichen im Pfad zu Problemen 20 | führen. 21 | 22 | -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/TrailerTeaserChecker.kt: -------------------------------------------------------------------------------- 1 | package mediathek.tool 2 | 3 | /** 4 | * This class check if titel contains specific keywords. 5 | */ 6 | class TrailerTeaserChecker { 7 | /** 8 | * Check if a string might belong to a trailer, teaser, etc. 9 | */ 10 | fun check(content: String): Boolean { 11 | val lTitel = content.lowercase() 12 | return containsTrailer(lTitel) || containsTeaser(lTitel) || containsVorschau(lTitel) 13 | } 14 | 15 | private fun containsTrailer(titel: String): Boolean { 16 | return titel.contains("trailer") 17 | } 18 | 19 | private fun containsTeaser(titel: String): Boolean { 20 | return titel.contains("teaser") 21 | } 22 | 23 | private fun containsVorschau(titel: String): Boolean { 24 | return titel.contains("vorschau") 25 | } 26 | } -------------------------------------------------------------------------------- /src/main/resources/icons/fontawesome/plus.svg: -------------------------------------------------------------------------------- 1 | 2 | 8 | 10 | 11 | 15 | 16 | -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/CustomConversionHandler.java: -------------------------------------------------------------------------------- 1 | package mediathek.tool; 2 | 3 | import org.apache.commons.configuration2.convert.DefaultConversionHandler; 4 | import org.apache.commons.configuration2.interpol.ConfigurationInterpolator; 5 | 6 | import java.util.UUID; 7 | 8 | public class CustomConversionHandler extends DefaultConversionHandler { 9 | 10 | 11 | 12 | @Override 13 | @SuppressWarnings("unchecked") 14 | protected T convertValue(Object src, Class targetCls, ConfigurationInterpolator ci) { 15 | if (src == null) { 16 | return null; 17 | } else if (UUID.class.equals(targetCls)) { 18 | String uuidAsString = super.convertValue(src, String.class, ci); 19 | return (T) UUID.fromString(uuidAsString); 20 | } else { 21 | return super.convertValue(src, targetCls, ci); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/resources/icons/fontawesome/check.svg: -------------------------------------------------------------------------------- 1 | 2 | 8 | 10 | 11 | 15 | 16 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/tabs/tab_downloads/FailedDownloadsInfoLabel.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.tabs.tab_downloads; 2 | 3 | import mediathek.daten.DownloadStartInfo; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import javax.swing.*; 7 | 8 | public class FailedDownloadsInfoLabel extends JLabel { 9 | public FailedDownloadsInfoLabel(@NotNull DownloadStartInfoProperty startInfoProperty) { 10 | setToolTipText("Anzahl der fehlerhaften Downloads"); 11 | startInfoProperty.addStartInfoChangeListener(evt -> SwingUtilities.invokeLater(() -> process((DownloadStartInfo) evt.getNewValue()))); 12 | } 13 | 14 | private void process(@NotNull DownloadStartInfo info) { 15 | if (info.hasValues()) { 16 | setText(info.error + " fehlerhaft"); 17 | } else 18 | setText("0 fehlerhaft"); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/duplicates/BigSenderPenaltyComparator.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.duplicates; 2 | 3 | import mediathek.daten.DatenFilm; 4 | 5 | import java.util.Comparator; 6 | 7 | public class BigSenderPenaltyComparator implements Comparator { 8 | @Override 9 | public int compare(DatenFilm s1, DatenFilm s2) { 10 | // "ARD" und "ZDF" immer am Ende um die kleineren Mediatheken nicht zu benachteiligen 11 | final var s1_sender = s1.getSender(); 12 | final var s2_sender = s2.getSender(); 13 | if (s1_sender.equals("ARD") || s1_sender.equals("ZDF")) { 14 | return 1; 15 | } 16 | if (s2_sender.equals("ARD") || s2_sender.equals("ZDF")) { 17 | return -1; 18 | } 19 | // Alphabetisch sortieren für alle anderen 20 | return s1.compareTo(s2); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/mediathek/filmlisten/reader/DateFilter.kt: -------------------------------------------------------------------------------- 1 | package mediathek.filmlisten.reader 2 | 3 | import mediathek.daten.DatenFilm 4 | import mediathek.daten.ListeFilme 5 | import mediathek.tool.datum.DateUtil 6 | import java.time.LocalDate 7 | 8 | internal class DateFilter(private val listeFilme: ListeFilme, days: Long) : IDateFilter { 9 | private val cutoffDate: LocalDate = LocalDate.now().minusDays(days) 10 | 11 | private fun isBeforeOrEqual(date: LocalDate, compareToDate: LocalDate): Boolean { 12 | return !compareToDate.isAfter(date) 13 | } 14 | 15 | override fun filter(film: DatenFilm) { 16 | // do not filter livestreams 17 | val localDate = DateUtil.convertToLocalDate(film.datumFilm) 18 | if (film.isLivestream || isBeforeOrEqual(localDate, cutoffDate)) { 19 | listeFilme.add(film) 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/tabs/tab_downloads/ManualDownloadsInfoLabel.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.tabs.tab_downloads; 2 | 3 | import mediathek.daten.DownloadStartInfo; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import javax.swing.*; 7 | 8 | public class ManualDownloadsInfoLabel extends JLabel { 9 | public ManualDownloadsInfoLabel(@NotNull DownloadStartInfoProperty startInfoProperty) { 10 | setToolTipText("Anzahl der manuellen Downloads in der Downloadliste"); 11 | startInfoProperty.addStartInfoChangeListener(evt -> SwingUtilities.invokeLater(() -> process((DownloadStartInfo) evt.getNewValue()))); 12 | } 13 | 14 | private void process(@NotNull DownloadStartInfo info) { 15 | String numDownloads = (info.num_downloads == 1) ? "1 Download" : info.num_downloads + " Downloads"; 16 | setText(numDownloads); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/MVC.java: -------------------------------------------------------------------------------- 1 | package mediathek.tool; 2 | 3 | import mediathek.config.MVConfig; 4 | 5 | import java.awt.*; 6 | 7 | public class MVC { 8 | 9 | private final String text; 10 | private final MVConfig.Configs config; 11 | public Color color = new Color(0); 12 | private Color colorReset = new Color(0); 13 | public MVC(MVConfig.Configs configs, Color color, String ttext) { 14 | this.config = configs; 15 | text = ttext; 16 | this.color = color; 17 | colorReset = color; 18 | } 19 | 20 | public MVConfig.Configs getConfig() { 21 | return config; 22 | } 23 | 24 | public String getText() { 25 | return text; 26 | } 27 | 28 | public void set(Color c) { 29 | color = c; 30 | } 31 | 32 | public void reset() { 33 | color = colorReset; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/resources/icons/fontawesome/arrow-down.svg: -------------------------------------------------------------------------------- 1 | 2 | 8 | 10 | 11 | 15 | 16 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build and test 2 | on: [ push,pull_request ] 3 | 4 | jobs: 5 | build: 6 | 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - uses: actions/checkout@v4 11 | - name: Set up JDK 25 12 | uses: actions/setup-java@v4 13 | with: 14 | distribution: 'liberica' 15 | java-version: '25' 16 | java-package: jdk 17 | cache: 'maven' 18 | - name: Build and test with Maven 19 | run: mvn -B package 20 | - name: SonarCloud Scan 21 | run: mvn -B org.jacoco:jacoco-maven-plugin:prepare-agent sonar:sonar -Dsonar.projectKey=mediathekview_MediathekView -Dsonar.organization=mediathekview -Dsonar.host.url=https://sonarcloud.io -Dsonar.login=$SONAR_TOKEN 22 | env: 23 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 24 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} 25 | -------------------------------------------------------------------------------- /src/main/resources/icons/fontawesome/arrow-up.svg: -------------------------------------------------------------------------------- 1 | 2 | 8 | 10 | 11 | 15 | 16 | -------------------------------------------------------------------------------- /src/main/java/mediathek/mainwindow/ListSelectedItemsProperty.java: -------------------------------------------------------------------------------- 1 | package mediathek.mainwindow; 2 | 3 | import java.beans.PropertyChangeListener; 4 | import java.beans.PropertyChangeSupport; 5 | 6 | public class ListSelectedItemsProperty { 7 | private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); 8 | private long selectedItems; 9 | 10 | public ListSelectedItemsProperty(long selectedItems) { 11 | this.selectedItems = selectedItems; 12 | } 13 | 14 | public void addSelectedItemsChangeListener(PropertyChangeListener listener) { 15 | this.pcs.addPropertyChangeListener(listener); 16 | } 17 | 18 | public void setSelectedItems(long selectedItems) { 19 | long oldValue = this.selectedItems; 20 | this.selectedItems = selectedItems; 21 | this.pcs.firePropertyChange("sel_items", oldValue, selectedItems); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/history/ResetAboHistoryAction.kt: -------------------------------------------------------------------------------- 1 | package mediathek.gui.history 2 | 3 | import mediathek.config.Daten 4 | import java.awt.event.ActionEvent 5 | import javax.swing.AbstractAction 6 | import javax.swing.JFrame 7 | import javax.swing.JOptionPane 8 | 9 | class ResetAboHistoryAction(private val owner: JFrame) : AbstractAction() { 10 | override fun actionPerformed(e: ActionEvent) { 11 | val ret = JOptionPane.showConfirmDialog(owner, """ 12 | Sind Sie sicher dass Sie alle Einträge der Abo-Historie löschen wollen? 13 | Dies kann nicht rückgängig gemacht werden. 14 | """.trimIndent(), "Abo-Historie löschen", JOptionPane.YES_NO_OPTION) 15 | if (ret == JOptionPane.OK_OPTION) { 16 | Daten.getInstance().aboHistoryController.removeAll() 17 | } 18 | } 19 | 20 | init { 21 | putValue(NAME, "Abo-Historie zurücksetzen...") 22 | } 23 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/tabs/tab_film/SearchFieldData.kt: -------------------------------------------------------------------------------- 1 | package mediathek.gui.tabs.tab_film 2 | 3 | import mediathek.tool.Filter 4 | import java.util.regex.Pattern 5 | 6 | @JvmRecord 7 | data class SearchFieldData(val searchFieldText: String, val searchMode: SearchControlFieldMode) { 8 | fun searchThroughDescriptions(): Boolean { 9 | return searchMode == SearchControlFieldMode.IRGENDWO 10 | } 11 | 12 | fun isEmpty(): Boolean { 13 | return searchFieldText.isEmpty() 14 | } 15 | 16 | fun evaluateThemaTitel(): Array { 17 | return if (Filter.isPattern(searchFieldText)) { 18 | arrayOf(searchFieldText) 19 | } else { 20 | Pattern.compile(",") 21 | .splitAsStream(searchFieldText).map { s: String -> s.lowercase() } 22 | .toArray { size -> arrayOfNulls(size) } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/actions/CleanupDownloadListAction.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.actions; 2 | 3 | import mediathek.gui.tabs.tab_downloads.GuiDownloads; 4 | import mediathek.swing.IconUtils; 5 | import org.kordamp.ikonli.fontawesome6.FontAwesomeSolid; 6 | 7 | import javax.swing.*; 8 | import java.awt.event.ActionEvent; 9 | 10 | public class CleanupDownloadListAction extends AbstractAction { 11 | private final GuiDownloads guiDownloads; 12 | 13 | public CleanupDownloadListAction(GuiDownloads guiDownloads) { 14 | this.guiDownloads = guiDownloads; 15 | putValue(Action.NAME, "Liste säubern"); 16 | putValue(Action.SHORT_DESCRIPTION, "Liste säubern"); 17 | putValue(Action.SMALL_ICON, IconUtils.toolbarIcon(FontAwesomeSolid.ERASER)); 18 | } 19 | 20 | @Override 21 | public void actionPerformed(ActionEvent e) { 22 | guiDownloads.cleanupDownloads(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/table/MVPsetTable.java: -------------------------------------------------------------------------------- 1 | package mediathek.tool.table; 2 | 3 | import mediathek.daten.DatenPset; 4 | import mediathek.tool.models.NonEditableTableModel; 5 | 6 | import java.util.Optional; 7 | 8 | public class MVPsetTable extends MVTable { 9 | public MVPsetTable() { 10 | super(DatenPset.MAX_ELEM, new boolean[DatenPset.MAX_ELEM], 11 | Optional.empty(), 12 | Optional.empty(), 13 | Optional.empty()); 14 | 15 | setModel(new NonEditableTableModel(new Object[][]{}, DatenPset.COLUMN_NAMES)); 16 | setRowSorter(null); 17 | setAutoCreateRowSorter(false); // Reihenfolge ist die Anzeige der Button! 18 | } 19 | 20 | @Override 21 | protected void spaltenAusschalten() { 22 | //do nothing 23 | } 24 | 25 | @Override 26 | public void calculateRowHeight() { 27 | // do nothing 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/resources/mediathek/file/hilfetext_standardPset.txt: -------------------------------------------------------------------------------- 1 | 2 | Hiermit können die Standardprogramme zum "Ansehen" und "Aufzeichnen" 3 | der Filme eingetragen werden. Werden die Pfade nicht automatisch erkannt, 4 | kann man sie auch per Hand auswählen. 5 | 6 | Der Zielpfad gibt an, wo Filme gespeichert werden sollen. 7 | 8 | 9 | Um alle Filme ansehen und aufzeichnen zu können, müssen mindestens 10 | diese Programme installiert sein: 11 | 12 | VLC 13 | Dieses Programm dient zum Ansehen und teilweise auch zum Aufzeichnen der Filme. 14 | 15 | ffmpeg 16 | Zum Aufzeichnen von Playlisten (URL endet mit "m3u8") 17 | 18 | 19 | Linux: 20 | Die Programme können über die Paketverwaltung eingespielt werden. 21 | 22 | 23 | Windows, OS X: 24 | Das Programm "ffmpeg" ist bereits in MediathekView integriert. 25 | Es muss bloss noch "VLC" aus dem Internet geladen werden: 26 | 27 | 28 | http://www.videolan.org 29 | http://ffmpeg.org 30 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/tabs/tab_downloads/ActiveDownloadsInfoLabel.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.tabs.tab_downloads; 2 | 3 | import mediathek.daten.DownloadStartInfo; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import javax.swing.*; 7 | 8 | public class ActiveDownloadsInfoLabel extends JLabel { 9 | public ActiveDownloadsInfoLabel(@NotNull DownloadStartInfoProperty startInfoProperty) { 10 | setToolTipText("Anzahl der aktiven Downloads"); 11 | startInfoProperty.addStartInfoChangeListener(evt -> SwingUtilities.invokeLater(() -> process((DownloadStartInfo) evt.getNewValue()))); 12 | } 13 | 14 | private void process(@NotNull DownloadStartInfo info) { 15 | if (info.hasValues()) { 16 | var numDownloads = (info.running == 1) ? "1 läuft" : info.running + " laufen"; 17 | setText(numDownloads); 18 | } else 19 | setText("0 laufen"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/tabs/tab_downloads/FinishedDownloadsInfoLabel.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.tabs.tab_downloads; 2 | 3 | import mediathek.daten.DownloadStartInfo; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import javax.swing.*; 7 | 8 | public class FinishedDownloadsInfoLabel extends JLabel { 9 | public FinishedDownloadsInfoLabel(@NotNull DownloadStartInfoProperty startInfoProperty) { 10 | setToolTipText("Anzahl der abgeschlossenen Downloads"); 11 | startInfoProperty.addStartInfoChangeListener(evt -> SwingUtilities.invokeLater(() -> process((DownloadStartInfo) evt.getNewValue()))); 12 | } 13 | 14 | private void process(@NotNull DownloadStartInfo info) { 15 | if (info.hasValues()) { 16 | String fin = (info.finished == 1) ? "1 fertig" : info.finished + " fertig"; 17 | setText(fin); 18 | } else 19 | setText("0 fertig"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/tabs/tab_downloads/WaitingDownloadsInfoLabel.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.tabs.tab_downloads; 2 | 3 | import mediathek.daten.DownloadStartInfo; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import javax.swing.*; 7 | 8 | public class WaitingDownloadsInfoLabel extends JLabel { 9 | public WaitingDownloadsInfoLabel(@NotNull DownloadStartInfoProperty startInfoProperty) { 10 | setToolTipText("Anzahl der wartenden Downloads"); 11 | startInfoProperty.addStartInfoChangeListener(evt -> SwingUtilities.invokeLater(() -> process((DownloadStartInfo) evt.getNewValue()))); 12 | } 13 | 14 | private void process(@NotNull DownloadStartInfo info) { 15 | if (info.hasValues()) { 16 | String waiting = (info.initialized == 1) ? "1 wartet" : info.initialized + " warten"; 17 | setText(waiting); 18 | } else 19 | setText(""); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/resources/mediathek/file/hilfetext_reset_set.txt: -------------------------------------------------------------------------------- 1 | ENTWEDER 2 | ========================================= 3 | "Neue Sets hinzufügen" 4 | 5 | Die aktuellen Einstellungen werden damit nicht 6 | verändert. Die neuen Sets werden an die Liste der 7 | bestehenden Sets angehängt und sind danach noch 8 | nicht aktiv. Das muss dann noch geschehen: 9 | 10 | "Datei->Einstellungen->Set bearbeiten" 11 | 12 | Zum Aktivieren: Haken bei Speichern und Abspielen 13 | bei den neuen Sets setzen und bei den alten entfernen 14 | und die neuen Sets ganz nach oben Verschieben. 15 | 16 | 17 | ODER 18 | ========================================= 19 | "Bestehende Sets durch die neuen ersetzen" 20 | 21 | Damit werden alle Sets (auch eigene), die zum Abspielen 22 | und Aufzeichnen der Filme gebraucht werden, gelöscht. 23 | Anschließend werden die aktuellen Standardsets 24 | eingerichtet. Es kann dann direkt damit 25 | weitergearbeitet werden. 26 | 27 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/actions/DeferDownloadsAction.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.actions; 2 | 3 | import mediathek.gui.tabs.tab_downloads.GuiDownloads; 4 | import mediathek.swing.IconUtils; 5 | import org.kordamp.ikonli.fontawesome6.FontAwesomeRegular; 6 | 7 | import javax.swing.*; 8 | import java.awt.event.ActionEvent; 9 | 10 | public class DeferDownloadsAction extends AbstractAction { 11 | private final GuiDownloads guiDownloads; 12 | 13 | public DeferDownloadsAction(GuiDownloads guiDownloads) { 14 | this.guiDownloads = guiDownloads; 15 | putValue(Action.NAME, "Downloads zurückstellen"); 16 | putValue(Action.SHORT_DESCRIPTION, "Downloads zurückstellen"); 17 | putValue(Action.SMALL_ICON, IconUtils.toolbarIcon(FontAwesomeRegular.CLOCK)); 18 | } 19 | 20 | @Override 21 | public void actionPerformed(ActionEvent e) { 22 | guiDownloads.downloadLoeschen(false); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/actions/ManageBookmarkAction.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.actions; 2 | 3 | import mediathek.mainwindow.MediathekGui; 4 | import mediathek.swing.IconUtils; 5 | import org.kordamp.ikonli.materialdesign2.MaterialDesignF; 6 | 7 | import javax.swing.*; 8 | import java.awt.event.ActionEvent; 9 | 10 | public class ManageBookmarkAction extends AbstractAction { 11 | private final MediathekGui mediathekGui; 12 | 13 | public ManageBookmarkAction(MediathekGui mediathekGui) { 14 | this.mediathekGui = mediathekGui; 15 | putValue(Action.NAME, "Merkliste verwalten..."); 16 | putValue(Action.SMALL_ICON, IconUtils.toolbarIcon(MaterialDesignF.FILE_DOCUMENT)); 17 | putValue(Action.SHORT_DESCRIPTION, "Merkliste verwalten"); 18 | } 19 | 20 | @Override 21 | public void actionPerformed(ActionEvent e) { 22 | mediathekGui.tabFilme.showManageBookmarkWindow(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/actions/ResetSettingsAction.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.actions; 2 | 3 | import mediathek.config.Daten; 4 | import mediathek.gui.dialog.reset.ResetSettingsDialog; 5 | import mediathek.tool.GuiFunktionen; 6 | 7 | import javax.swing.*; 8 | import java.awt.event.ActionEvent; 9 | 10 | public class ResetSettingsAction extends AbstractAction { 11 | private final JFrame owner; 12 | private final Daten daten; 13 | 14 | public ResetSettingsAction(JFrame parent, Daten daten) { 15 | super(); 16 | owner = parent; 17 | this.daten = daten; 18 | 19 | putValue(NAME, "Einstellungen zurücksetzen..."); 20 | } 21 | 22 | @Override 23 | public void actionPerformed(ActionEvent e) { 24 | ResetSettingsDialog dialog = new ResetSettingsDialog(owner, daten); 25 | GuiFunktionen.centerOnScreen(dialog, false); 26 | dialog.setVisible(true); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/actions/StartAllDownloadsAction.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.actions; 2 | 3 | import mediathek.gui.tabs.tab_downloads.GuiDownloads; 4 | import mediathek.swing.IconUtils; 5 | import org.kordamp.ikonli.fontawesome6.FontAwesomeSolid; 6 | 7 | import javax.swing.*; 8 | import java.awt.event.ActionEvent; 9 | 10 | public class StartAllDownloadsAction extends AbstractAction { 11 | private final GuiDownloads guiDownloads; 12 | 13 | public StartAllDownloadsAction(GuiDownloads guiDownloads) { 14 | this.guiDownloads = guiDownloads; 15 | putValue(Action.SMALL_ICON, IconUtils.toolbarIcon(FontAwesomeSolid.ANGLE_DOUBLE_DOWN)); 16 | putValue(Action.SHORT_DESCRIPTION, "Alle Downloads starten"); 17 | putValue(Action.NAME, "Alle Downloads starten"); 18 | } 19 | 20 | @Override 21 | public void actionPerformed(ActionEvent e) { 22 | guiDownloads.starten(true); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/mediathek/mainwindow/PositionSavingTabbedPane.java: -------------------------------------------------------------------------------- 1 | package mediathek.mainwindow; 2 | 3 | import mediathek.tool.ApplicationConfiguration; 4 | 5 | import javax.swing.*; 6 | 7 | public class PositionSavingTabbedPane extends JTabbedPane { 8 | 9 | public PositionSavingTabbedPane() { 10 | } 11 | 12 | public void installChangeListener() { 13 | addChangeListener(l -> saveTabPosition()); 14 | } 15 | 16 | public void restoreSavedTabPosition() { 17 | var idx = ApplicationConfiguration.getConfiguration().getInt(Config.TAB_POSITION, -1); 18 | setSelectedIndex(Math.max(idx, 0)); 19 | } 20 | 21 | private void saveTabPosition() { 22 | ApplicationConfiguration.getConfiguration().setProperty(Config.TAB_POSITION, getSelectedIndex()); 23 | } 24 | 25 | private static class Config { 26 | public static final String TAB_POSITION = "app.ui.tab_position"; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/actions/DeleteDownloadsAction.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.actions; 2 | 3 | import mediathek.gui.tabs.tab_downloads.GuiDownloads; 4 | import mediathek.swing.IconUtils; 5 | import org.kordamp.ikonli.fontawesome6.FontAwesomeRegular; 6 | 7 | import javax.swing.*; 8 | import java.awt.event.ActionEvent; 9 | 10 | public class DeleteDownloadsAction extends AbstractAction { 11 | private final GuiDownloads guiDownloads; 12 | 13 | public DeleteDownloadsAction(GuiDownloads guiDownloads) { 14 | this.guiDownloads = guiDownloads; 15 | putValue(Action.NAME, "Downloads aus Liste entfernen"); 16 | putValue(Action.SHORT_DESCRIPTION, "Downloads entfernen"); 17 | putValue(Action.SMALL_ICON, IconUtils.toolbarIcon(FontAwesomeRegular.TRASH_ALT)); 18 | } 19 | 20 | @Override 21 | public void actionPerformed(ActionEvent e) { 22 | guiDownloads.downloadLoeschen(true); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/kotlin/mediathek/gui/actions/ManageAboAction.kt: -------------------------------------------------------------------------------- 1 | package mediathek.gui.actions 2 | 3 | import mediathek.gui.abo.ManageAboDialog 4 | import mediathek.mainwindow.MediathekGui 5 | import mediathek.swing.IconUtils 6 | import org.kordamp.ikonli.materialdesign2.MaterialDesignD 7 | import java.awt.event.ActionEvent 8 | import javax.swing.AbstractAction 9 | 10 | class ManageAboAction : AbstractAction() { 11 | private var dialog: ManageAboDialog? = null 12 | 13 | fun closeDialog() { 14 | dialog?.dispose() 15 | } 16 | 17 | override fun actionPerformed(e: ActionEvent?) { 18 | dialog = ManageAboDialog(MediathekGui.ui()) 19 | dialog!!.isVisible = true 20 | dialog = null 21 | } 22 | 23 | init { 24 | putValue(NAME, "Abos verwalten...") 25 | putValue(SMALL_ICON, IconUtils.windowBarSpecificToolbarIcon(MaterialDesignD.DATABASE)) 26 | putValue(SHORT_DESCRIPTION, "Abos verwalten") 27 | } 28 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/actions/PlayDownloadAction.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.actions; 2 | 3 | import mediathek.gui.tabs.tab_downloads.GuiDownloads; 4 | import mediathek.swing.IconUtils; 5 | import org.kordamp.ikonli.fontawesome6.FontAwesomeSolid; 6 | 7 | import javax.swing.*; 8 | import java.awt.event.ActionEvent; 9 | 10 | public class PlayDownloadAction extends AbstractAction { 11 | private static final String ACTION_TEXT = "Gespeicherten Film abspielen"; 12 | private final GuiDownloads guiDownloads; 13 | 14 | public PlayDownloadAction(GuiDownloads guiDownloads) { 15 | this.guiDownloads = guiDownloads; 16 | putValue(Action.NAME, ACTION_TEXT); 17 | putValue(Action.SHORT_DESCRIPTION, ACTION_TEXT); 18 | putValue(Action.SMALL_ICON, IconUtils.toolbarIcon(FontAwesomeSolid.PLAY)); 19 | } 20 | 21 | @Override 22 | public void actionPerformed(ActionEvent e) { 23 | guiDownloads.filmAbspielen(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/resources/icons/fontawesome/triangle-exclamation.svg: -------------------------------------------------------------------------------- 1 | 2 | 8 | 10 | 11 | 15 | 16 | -------------------------------------------------------------------------------- /src/main/resources/icons/fontawesome/xmark.svg: -------------------------------------------------------------------------------- 1 | 2 | 8 | 10 | 11 | 15 | 16 | -------------------------------------------------------------------------------- /src/main/resources/icons/fontawesome/folder-open.svg: -------------------------------------------------------------------------------- 1 | 2 | 8 | 10 | 11 | 15 | 16 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/dialogEinstellungen/PanelNotifications.jfd: -------------------------------------------------------------------------------- 1 | JFDML JFormDesigner: "7.0.3.0.337" Java: "11.0.9.1" encoding: "UTF-8" 2 | 3 | new FormModel { 4 | contentType: "form/swing" 5 | root: new FormRoot { 6 | add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { 7 | "$layoutConstraints": "hidemode 3" 8 | "$columnConstraints": "[fill][fill]" 9 | "$rowConstraints": "[]" 10 | } ) { 11 | name: "this" 12 | add( new FormComponent( "javax.swing.JCheckBox" ) { 13 | name: "cbShowNotifications" 14 | "text": "Benachrichtigungen anzeigen" 15 | "toolTipText": "Zeige Programminformationen als Benachrichtigungen in einem Popup-Fenster an." 16 | }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { 17 | "value": "cell 0 0" 18 | } ) 19 | }, new FormLayoutConstraints( null ) { 20 | "location": new java.awt.Point( 0, 0 ) 21 | "size": new java.awt.Dimension( 400, 300 ) 22 | } ) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/tabs/tab_downloads/TotalDownloadsLabel.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.tabs.tab_downloads; 2 | 3 | import mediathek.daten.DownloadStartInfo; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import javax.swing.*; 7 | 8 | public class TotalDownloadsLabel extends JLabel { 9 | public TotalDownloadsLabel(@NotNull DownloadStartInfoProperty startInfoProperty) { 10 | setToolTipText("Gesamtzahl aller Downloads"); 11 | startInfoProperty.addStartInfoChangeListener(evt -> SwingUtilities.invokeLater(() -> process((DownloadStartInfo) evt.getNewValue()))); 12 | } 13 | 14 | private void process(@NotNull DownloadStartInfo info) { 15 | final int anz = info.total_num_download_list_entries; 16 | final int diff = anz - info.total_starts; 17 | String download = "Gesamtdownloads: " + anz; 18 | if (diff >= 1) { 19 | download += " (" + diff + " zurückgestellt)"; 20 | } 21 | setText(download); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/episodes/SeasonEpisode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 derreisende77. 3 | * This code was developed as part of the MediathekView project https://github.com/mediathekview/MediathekView 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package mediathek.tool.episodes; 20 | 21 | public record SeasonEpisode(int season, int episode) {} -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/messages/ReloadTableDataEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 derreisende77. 3 | * This code was developed as part of the MediathekView project https://github.com/mediathekview/MediathekView 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package mediathek.gui.messages; 20 | 21 | public class ReloadTableDataEvent extends BaseEvent { 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/affinity/IAffinity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 derreisende77. 3 | * This code was developed as part of the MediathekView project https://github.com/mediathekview/MediathekView 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package mediathek.tool.affinity 20 | 21 | interface IAffinity { 22 | fun setDesiredCpuAffinity(numCpus: Int) 23 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/tabs/tab_film/searchfilters/FinalStagePatternFilterWithDescription.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.tabs.tab_film.searchfilters; 2 | 3 | import mediathek.daten.DatenFilm; 4 | import mediathek.tool.Filter; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | import java.util.function.Predicate; 8 | 9 | public record FinalStagePatternFilterWithDescription(@NotNull String[] searchStr) implements Predicate { 10 | @Override 11 | public boolean test(@NotNull DatenFilm film) { 12 | var result = searchDefault(film); 13 | 14 | // search description if available 15 | var description = film.getDescription(); 16 | if (!description.isEmpty()) 17 | result = Filter.pruefen(searchStr, description) || result; 18 | 19 | return result; 20 | } 21 | 22 | private boolean searchDefault(@NotNull DatenFilm film) { 23 | return Filter.pruefen(searchStr, film.getThema()) 24 | || Filter.pruefen(searchStr, film.getTitle()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/mediathek/res/GetIcon.java: -------------------------------------------------------------------------------- 1 | package mediathek.res; 2 | 3 | import javax.swing.*; 4 | import java.awt.*; 5 | 6 | public class GetIcon { 7 | 8 | private final static String PFAD_PROGRAMM = "/mediathek/res/programm/"; 9 | 10 | public static ImageIcon getProgramIcon(String strIcon, int w, int h) { 11 | return getIcon(strIcon, PFAD_PROGRAMM, w, h); 12 | } 13 | 14 | public static ImageIcon getIcon(String strIcon, String path, int w, int h) { 15 | ImageIcon icon = getStandard(strIcon, path); 16 | 17 | if (w > 0 && h > 0) { 18 | if (icon.getIconWidth() != w || icon.getIconHeight() != h) { 19 | // nur dann macht es Sinn 20 | icon.setImage(icon.getImage().getScaledInstance(w, h, Image.SCALE_AREA_AVERAGING)); 21 | } 22 | } 23 | return icon; 24 | } 25 | 26 | private static ImageIcon getStandard(String strIcon, String path) { 27 | return new ImageIcon(GetIcon.class.getResource(path + strIcon)); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/GermanStringSorter.java: -------------------------------------------------------------------------------- 1 | package mediathek.tool; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.text.Collator; 6 | import java.util.Comparator; 7 | import java.util.Locale; 8 | 9 | public class GermanStringSorter implements Comparator { 10 | 11 | private static final Collator collator = Collator.getInstance(Locale.GERMANY); 12 | private static GermanStringSorter instance; 13 | 14 | private GermanStringSorter() { 15 | super(); 16 | } 17 | 18 | public static GermanStringSorter getInstance() { 19 | if (instance == null) { 20 | instance = new GermanStringSorter(); 21 | // ignore lower/upper case, but accept special characters in localised alphabetical order 22 | collator.setStrength(Collator.SECONDARY); 23 | } 24 | return instance; 25 | } 26 | 27 | @Override 28 | public int compare(@NotNull String o1, @NotNull String o2) { 29 | return collator.compare(o1, o2); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/history/ResetDownloadHistoryAction.kt: -------------------------------------------------------------------------------- 1 | package mediathek.gui.history 2 | 3 | import mediathek.controller.history.SeenHistoryController 4 | import java.awt.event.ActionEvent 5 | import javax.swing.AbstractAction 6 | import javax.swing.JFrame 7 | import javax.swing.JOptionPane 8 | 9 | class ResetDownloadHistoryAction(private val owner: JFrame) : AbstractAction() { 10 | override fun actionPerformed(e: ActionEvent) { 11 | val ret = JOptionPane.showConfirmDialog(owner, """ 12 | Sind Sie sicher dass Sie alle Einträge der Download-Historie löschen wollen? 13 | Dies kann nicht rückgängig gemacht werden. 14 | """.trimIndent(), "Download-Historie löschen", JOptionPane.YES_NO_OPTION) 15 | if (ret == JOptionPane.OK_OPTION) { 16 | val controller = SeenHistoryController() 17 | controller.use { 18 | controller.removeAll() 19 | } 20 | } 21 | } 22 | 23 | init { 24 | putValue(NAME, "Download-Historie zurücksetzen...") 25 | } 26 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/config/ApplicationType.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 derreisende77. 3 | * This code was developed as part of the MediathekView project https://github.com/mediathekview/MediathekView 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package mediathek.config 20 | 21 | @Suppress("unused") 22 | enum class ApplicationType { 23 | NIGHTLY, 24 | PRODUCTION 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/mediathek/controller/starter/HttpDownloadState.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 derreisende77. 3 | * This code was developed as part of the MediathekView project https://github.com/mediathekview/MediathekView 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package mediathek.controller.starter; 20 | 21 | public enum HttpDownloadState { 22 | 23 | CANCEL, ERROR, DOWNLOAD 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/mediathek/daten/DatenFilmFlags.java: -------------------------------------------------------------------------------- 1 | package mediathek.daten; 2 | 3 | public enum DatenFilmFlags { 4 | /** 5 | * Is this film an audio version? (aka Hörfassung) 6 | */ 7 | AUDIO_VERSION, 8 | /** 9 | * Flag indicating a trailer, teaser or german Vorschau. 10 | */ 11 | TRAILER_TEASER, 12 | /** 13 | * Flag that this entry is in sign language (aka Gebärdensprache). 14 | */ 15 | SIGN_LANGUAGE, 16 | /** 17 | * Indicates that entry is a livestream, not a regular movie. 18 | */ 19 | LIVESTREAM, 20 | /** 21 | * Indicates that the film is "new" and has not been in the local filmlist before. 22 | */ 23 | NEW_ENTRY, 24 | /** 25 | * Indicates that a film has "burned in" subtitles. 26 | */ 27 | BURNED_IN_SUBTITLES, 28 | /** 29 | * Indicates that film contains a .m3u8 URL. 30 | */ 31 | PLAYLIST, 32 | /** 33 | * Indicate that this film's URL is already existing hence this entry is a duplicate. 34 | */ 35 | DUPLICATE 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/expiration/ExpiryInfo.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 derreisende77. 3 | * This code was developed as part of the MediathekView project https://github.com/mediathekview/MediathekView 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package mediathek.gui.expiration 19 | 20 | import java.time.LocalDate 21 | 22 | @JvmRecord 23 | data class ExpiryInfo(val expiryDate: LocalDate?) -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/tabs/tab_film/SearchControlFieldMode.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 derreisende77. 3 | * This code was developed as part of the MediathekView project https://github.com/mediathekview/MediathekView 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package mediathek.gui.tabs.tab_film 20 | 21 | enum class SearchControlFieldMode { 22 | THEMA_TITEL, IRGENDWO, LUCENE 23 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/Ipify.kt: -------------------------------------------------------------------------------- 1 | package mediathek.tool 2 | 3 | import java.io.IOException 4 | import java.net.URI 5 | import java.net.http.HttpClient 6 | import java.net.http.HttpRequest 7 | import java.net.http.HttpResponse 8 | 9 | 10 | object Ipify { 11 | /** 12 | * Get the public ip address through ipify's api. 13 | * @return The public ip address. 14 | * @throws IOException If there is an IO error. 15 | */ 16 | @JvmStatic 17 | @get:Throws(IOException::class) 18 | val publicIp: String 19 | get() { 20 | val client: HttpClient = HttpClient.newBuilder() 21 | .version(HttpClient.Version.HTTP_2) 22 | .followRedirects(HttpClient.Redirect.ALWAYS) 23 | .build() 24 | 25 | val request = HttpRequest.newBuilder() 26 | .uri(URI.create("https://api64.ipify.org")) 27 | .build() 28 | 29 | val response = client.send(request, HttpResponse.BodyHandlers.ofString()) 30 | return response.body() 31 | } 32 | } -------------------------------------------------------------------------------- /src/main/kotlin/mediathek/windows/WinFlags.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 derreisende77. 3 | * This code was developed as part of the MediathekView project https://github.com/mediathekview/MediathekView 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package mediathek.windows 20 | 21 | object WinFlags { 22 | const val ES_CONTINUOUS: Int = Int.MIN_VALUE 23 | const val ES_SYSTEM_REQUIRED: Int = 1 24 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/actions/LoadFilmListAction.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.actions; 2 | 3 | import mediathek.mainwindow.MediathekGui; 4 | import mediathek.swing.IconUtils; 5 | import org.kordamp.ikonli.fontawesome6.FontAwesomeSolid; 6 | 7 | import javax.swing.*; 8 | import java.awt.event.ActionEvent; 9 | import java.awt.event.KeyEvent; 10 | 11 | public class LoadFilmListAction extends AbstractAction { 12 | private final MediathekGui mediathekGui; 13 | 14 | public LoadFilmListAction(MediathekGui mediathekGui) { 15 | this.mediathekGui = mediathekGui; 16 | putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_F5, 0)); 17 | putValue(Action.SMALL_ICON, IconUtils.windowBarSpecificToolbarIcon(FontAwesomeSolid.CLOUD_DOWNLOAD_ALT)); 18 | putValue(Action.NAME, "Neue Filmliste laden..."); 19 | putValue(Action.SHORT_DESCRIPTION, "Neue Filmliste laden"); 20 | } 21 | @Override 22 | public void actionPerformed(ActionEvent e) { 23 | mediathekGui.performFilmListLoadOperation(false); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/ttml/ITtmlParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 derreisende77. 3 | * This code was developed as part of the MediathekView project https://github.com/mediathekview/MediathekView 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package mediathek.tool.ttml; 20 | 21 | import java.nio.file.Path; 22 | 23 | public interface ITtmlParser { 24 | boolean parse(Path ttmlFilePath); 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/actions/MemoryMonitorAction.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.actions; 2 | 3 | import mediathek.gui.dialog.MemoryMonitorDialog; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import javax.swing.*; 7 | import java.awt.event.ActionEvent; 8 | 9 | public class MemoryMonitorAction extends AbstractAction { 10 | private MemoryMonitorDialog dialog; 11 | private final JFrame parent; 12 | 13 | public MemoryMonitorAction(@NotNull JFrame parent) { 14 | this.parent = parent; 15 | putValue(Action.NAME, "Speicherverbrauch anzeigen"); 16 | } 17 | 18 | public void closeMemoryMonitor() { 19 | if (dialog != null) { 20 | dialog.dispose(); 21 | dialog = null; 22 | } 23 | } 24 | 25 | public void showMemoryMonitor() { 26 | if (dialog == null) 27 | dialog = new MemoryMonitorDialog(parent); 28 | dialog.setVisible(true); 29 | } 30 | 31 | @Override 32 | public void actionPerformed(ActionEvent e) { 33 | showMemoryMonitor(); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/actions/SettingsAction.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.actions; 2 | 3 | import mediathek.gui.messages.ShowSettingsDialogEvent; 4 | import mediathek.swing.IconUtils; 5 | import mediathek.tool.MessageBus; 6 | import org.apache.commons.lang3.SystemUtils; 7 | import org.kordamp.ikonli.fontawesome6.FontAwesomeSolid; 8 | 9 | import javax.swing.*; 10 | import java.awt.event.ActionEvent; 11 | import java.awt.event.KeyEvent; 12 | 13 | public class SettingsAction extends AbstractAction { 14 | public SettingsAction() { 15 | putValue(Action.NAME, "Einstellungen..."); 16 | if (!SystemUtils.IS_OS_MAC_OSX) 17 | putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_F4, 0)); 18 | putValue(Action.SMALL_ICON, IconUtils.windowBarSpecificToolbarIcon(FontAwesomeSolid.COGS)); 19 | putValue(Action.SHORT_DESCRIPTION, "Einstellungen öffnen"); 20 | } 21 | @Override 22 | public void actionPerformed(ActionEvent e) { 23 | MessageBus.getMessageBus().publishAsync(new ShowSettingsDialogEvent()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/test/kotlin/mediathek/tool/FileUtilsTest.kt: -------------------------------------------------------------------------------- 1 | package mediathek.tool 2 | 3 | import org.junit.jupiter.api.Assertions.assertEquals 4 | import org.junit.jupiter.api.Test 5 | 6 | internal class FileUtilsTest { 7 | 8 | @Test 9 | fun removeExtension() { 10 | val testStr = "file.jpeg" 11 | val result = FileUtils.removeExtension(testStr) 12 | assertEquals("file", result) 13 | } 14 | 15 | @Test 16 | fun humanReadableByteCountBinary_megabytes() { 17 | val bytes:Long = 25165824 18 | val result = FileUtils.humanReadableByteCountBinary(bytes) 19 | 20 | val expected = String.format("%.1f MiB", (bytes / FileUtils.ONE_MB.toDouble())); 21 | assertEquals(expected, result) 22 | } 23 | 24 | @Test 25 | fun humanReadableByteCountBinary_kilobytes() { 26 | val bytes:Long = 24*1024 27 | val result = FileUtils.humanReadableByteCountBinary(bytes) 28 | 29 | val expected = String.format("%.1f KiB", (bytes / FileUtils.ONE_KB.toDouble())); 30 | assertEquals(expected, result) 31 | } 32 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/tabs/tab_livestreams/services/StreamInfo.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 derreisende77. 3 | * This code was developed as part of the MediathekView project https://github.com/mediathekview/MediathekView 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package mediathek.gui.tabs.tab_livestreams.services 20 | 21 | data class StreamInfo( 22 | val streamUrl: String = "", 23 | val name: String = "" 24 | ) -------------------------------------------------------------------------------- /src/main/java/mediathek/daten/DownloadStartInfo.java: -------------------------------------------------------------------------------- 1 | package mediathek.daten; 2 | 3 | public class DownloadStartInfo { 4 | /** 5 | * Size of the download list. 6 | */ 7 | public int total_num_download_list_entries = 0; 8 | public int total_starts = 0; 9 | public int num_abos = 0; 10 | public int num_downloads = 0; 11 | /** 12 | * not yet started but initialized. 13 | */ 14 | public int initialized = 0; 15 | public int running = 0; 16 | /** 17 | * finished without error. 18 | */ 19 | public int finished = 0; 20 | /** 21 | * finished with error. 22 | */ 23 | public int error = 0; 24 | 25 | /** 26 | * determine if it has non standard values. 27 | * @return true if data was changed 28 | */ 29 | public boolean hasValues() { 30 | boolean result = false; 31 | if (total_starts > 0 || num_abos > 0 || num_downloads > 0 || initialized > 0 || 32 | running > 0 || finished > 0 || error > 0) 33 | result = true; 34 | 35 | return result; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/actions/RefreshDownloadListAction.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.actions; 2 | 3 | import mediathek.gui.tabs.tab_downloads.GuiDownloads; 4 | import mediathek.swing.IconUtils; 5 | import org.kordamp.ikonli.fontawesome6.FontAwesomeSolid; 6 | 7 | import javax.swing.*; 8 | import java.awt.event.ActionEvent; 9 | import java.awt.event.KeyEvent; 10 | 11 | public class RefreshDownloadListAction extends AbstractAction { 12 | private final GuiDownloads guiDownloads; 13 | 14 | public RefreshDownloadListAction(GuiDownloads guiDownloads) { 15 | this.guiDownloads = guiDownloads; 16 | putValue(Action.NAME, "Liste der Downloads aktualisieren"); 17 | putValue(Action.SHORT_DESCRIPTION, "Downloadliste aktualisieren"); 18 | putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_W, KeyEvent.CTRL_DOWN_MASK)); 19 | putValue(Action.SMALL_ICON, IconUtils.toolbarIcon(FontAwesomeSolid.REDO_ALT)); 20 | } 21 | 22 | @Override 23 | public void actionPerformed(ActionEvent e) { 24 | guiDownloads.updateDownloads(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/ttml/ITtmlExporter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 derreisende77. 3 | * This code was developed as part of the MediathekView project https://github.com/mediathekview/MediathekView 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package mediathek.tool.ttml; 20 | 21 | import java.nio.file.Path; 22 | 23 | public interface ITtmlExporter { 24 | void write(TimedTextMarkupLanguageParser parser, Path destinationPath); 25 | } 26 | -------------------------------------------------------------------------------- /src/main/resources/icons/fontawesome/circle-question.svg: -------------------------------------------------------------------------------- 1 | 2 | 8 | 10 | 11 | 15 | 16 | -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/EventListWithEmptyFirstEntry.java: -------------------------------------------------------------------------------- 1 | package mediathek.tool; 2 | 3 | import ca.odell.glazedlists.EventList; 4 | import ca.odell.glazedlists.TransformedList; 5 | import ca.odell.glazedlists.event.ListEvent; 6 | 7 | /** 8 | * Read-only event list which also containing an " " for a "select all" selection. 9 | */ 10 | public class EventListWithEmptyFirstEntry extends TransformedList { 11 | 12 | public EventListWithEmptyFirstEntry(EventList sourceList) { 13 | super(sourceList); 14 | source.addListEventListener(this); 15 | } 16 | 17 | @Override 18 | protected boolean isWritable() { 19 | return false; 20 | } 21 | 22 | @Override 23 | public void listChanged(ListEvent listChanges) { 24 | updates.forwardEvent(listChanges); 25 | } 26 | 27 | @Override 28 | public String get(int index) { 29 | if (index == 0) 30 | return ""; 31 | else 32 | return source.get(index - 1); 33 | } 34 | 35 | public int size() { 36 | return source.size() + 1; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/UIProgressState.java: -------------------------------------------------------------------------------- 1 | package mediathek.tool; 2 | 3 | public enum UIProgressState { 4 | INIT_FX("UI Toolkit initialisieren..."), 5 | FILE_CLEANUP("Dateien bereinigen..."), 6 | START_UI("Anwendungsklassen laden..."), 7 | LOAD_MAINWINDOW("Hauptfenster initialisieren..."), 8 | WAIT_FOR_HISTORY_DATA("Warte auf Abschluss des Ladens der History..."), 9 | CREATE_STATUS_BAR("Statusbar initialisieren..."), 10 | SETUP_FILM_LISTENERS("Listener initialisieren..."), 11 | LOAD_TABS("Tabs laden..."), 12 | LOAD_FILM_TAB("Filme-Tab laden"), 13 | LOAD_DOWNLOAD_TAB("Download-Tab laden"), 14 | ADD_TABS_TO_UI("Tabs zum UI hinzufügen"), 15 | CONFIGURE_TABS("Tabs konfigurieren"), 16 | INIT_MENUS("Menüs initialisieren..."), 17 | LOAD_MEMORY_MONITOR("Speichermonitor initialisieren..."), 18 | FINISHED("Anwendungsfenster wird geöffnet..."); 19 | 20 | private final String title; 21 | 22 | UIProgressState(String title) { 23 | this.title = title; 24 | } 25 | 26 | @Override 27 | public String toString() { 28 | return title; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/actions/ShowFilmInformationAction.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.actions; 2 | 3 | import mediathek.mainwindow.MediathekGui; 4 | import mediathek.swing.IconUtils; 5 | import mediathek.tool.GuiFunktionen; 6 | import org.kordamp.ikonli.fontawesome6.FontAwesomeSolid; 7 | 8 | import javax.swing.*; 9 | import java.awt.event.ActionEvent; 10 | import java.awt.event.KeyEvent; 11 | 12 | public class ShowFilmInformationAction extends AbstractAction { 13 | 14 | public ShowFilmInformationAction() { 15 | putValue(Action.NAME, "Filminformation anzeigen"); 16 | putValue(Action.SHORT_DESCRIPTION, "Filminformation anzeigen"); 17 | putValue(Action.SMALL_ICON, IconUtils.windowBarSpecificToolbarIcon(FontAwesomeSolid.INFO_CIRCLE)); 18 | putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_I, GuiFunktionen.getPlatformControlKey())); 19 | } 20 | 21 | @Override 22 | public void actionPerformed(ActionEvent e) { 23 | if (!MediathekGui.ui().getFilmInfoDialog().isVisible()) { 24 | MediathekGui.ui().getFilmInfoDialog().showInfo(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/kotlin/mediathek/tool/VersionTest.kt: -------------------------------------------------------------------------------- 1 | package mediathek.tool 2 | 3 | import org.junit.jupiter.api.Assertions.assertFalse 4 | import org.junit.jupiter.api.Assertions.assertTrue 5 | import org.junit.jupiter.api.Test 6 | 7 | internal class VersionTest { 8 | 9 | @Test 10 | fun isOlderThan() { 11 | val v1 = Version(13,6,0) 12 | val v2 = Version(13,7,0) 13 | 14 | assertTrue { v1.isOlderThan(v2) } 15 | assertFalse { v2.isOlderThan(v1) } 16 | } 17 | 18 | @Test 19 | fun isInvalid() { 20 | val invVersion = Version.INVALID_VERSION 21 | assertTrue {invVersion.isInvalid() } 22 | 23 | val manInv = Version(0,0,0) 24 | assertTrue { manInv.isInvalid() } 25 | 26 | val t3 = Version(13,6,0) 27 | assertFalse { t3.isInvalid() } 28 | } 29 | 30 | @Test 31 | fun fromString() { 32 | val str = "13.7.0" 33 | val v = Version.fromString(str) 34 | assertTrue { v == Version(13,7,0) } 35 | 36 | val t2 = "13.6.0-SNAPSHOT" 37 | val v2 = Version.fromString(t2) 38 | assertTrue { v2 == Version(13,6,0) } 39 | } 40 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/daten/FilmResolution.java: -------------------------------------------------------------------------------- 1 | package mediathek.daten; 2 | 3 | //FIXME convert indices to int!! 4 | public class FilmResolution { 5 | public enum Enum { 6 | LOW, 7 | NORMAL, 8 | HIGH_QUALITY; 9 | 10 | @Override 11 | public String toString() { 12 | return switch (super.toString()) { 13 | case "LOW" -> FilmResolution.LOW; 14 | case "NORMAL" -> FilmResolution.NORMAL; 15 | case "HIGH_QUALITY" -> FilmResolution.HIGH_QUALITY; 16 | default -> throw new IndexOutOfBoundsException("Illegal enum to string!"); 17 | }; 18 | } 19 | 20 | public static Enum fromLegacyString(String in) { 21 | return switch (in) { 22 | case FilmResolution.LOW -> LOW; 23 | case FilmResolution.HIGH_QUALITY -> HIGH_QUALITY; 24 | default -> NORMAL; 25 | }; 26 | } 27 | } 28 | 29 | public static final String NORMAL = "normal"; 30 | public static final String HIGH_QUALITY = "hd"; 31 | public static final String LOW = "klein"; 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/notification/GenericNotificationCenter.kt: -------------------------------------------------------------------------------- 1 | package mediathek.tool.notification 2 | 3 | import raven.toast.Notifications 4 | import javax.swing.SwingUtilities 5 | 6 | /** 7 | * Implements notification based on controlsfx JavaFX implemention. 8 | */ 9 | class GenericNotificationCenter : INotificationCenter { 10 | override fun displayNotification(msg: NotificationMessage) { 11 | SwingUtilities.invokeLater { 12 | try { 13 | val ravenNotificationType: Notifications.Type = when (msg.type) { 14 | MessageType.INFO -> Notifications.Type.INFO 15 | MessageType.ERROR -> Notifications.Type.ERROR 16 | } 17 | 18 | val message = msg.title + "\n\n" + msg.message 19 | Notifications.getInstance() 20 | .show(ravenNotificationType, Notifications.Location.TOP_RIGHT, message) 21 | } catch (_: NullPointerException) { 22 | //the generic version might fail to display a notification with NPE 23 | } 24 | } 25 | } 26 | 27 | override fun close() {} 28 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/swing/NoIconMenuItem.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 derreisende77. 3 | * This code was developed as part of the MediathekView project https://github.com/mediathekview/MediathekView 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package mediathek.swing; 20 | 21 | import javax.swing.*; 22 | 23 | public class NoIconMenuItem extends JMenuItem { 24 | public NoIconMenuItem(Action action) { 25 | super(action); 26 | setIcon(null); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/mediathek/daten/IndexedFilmList.java: -------------------------------------------------------------------------------- 1 | package mediathek.daten; 2 | 3 | import mediathek.config.StandardLocations; 4 | import org.apache.logging.log4j.LogManager; 5 | import org.apache.logging.log4j.Logger; 6 | import org.apache.lucene.index.DirectoryReader; 7 | import org.apache.lucene.store.Directory; 8 | import org.apache.lucene.store.MMapDirectory; 9 | 10 | public class IndexedFilmList extends ListeFilme { 11 | private static final Logger logger = LogManager.getLogger(); 12 | private Directory luceneDirectory; 13 | private DirectoryReader reader; 14 | 15 | public IndexedFilmList() { 16 | try { 17 | luceneDirectory = new MMapDirectory(StandardLocations.getFilmIndexPath()); 18 | 19 | } catch (Exception ex) { 20 | logger.error("Creation of Lucene index directory failed!", ex); 21 | } 22 | } 23 | 24 | public DirectoryReader getReader() { 25 | return reader; 26 | } 27 | 28 | public void setReader(DirectoryReader reader) { 29 | this.reader = reader; 30 | } 31 | 32 | public Directory getLuceneDirectory() { 33 | return luceneDirectory; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/dialogEinstellungen/PanelPset.jfd: -------------------------------------------------------------------------------- 1 | JFDML JFormDesigner: "8.2.4.0.393" Java: "21.0.3" encoding: "UTF-8" 2 | 3 | new FormModel { 4 | contentType: "form/swing" 5 | root: new FormRoot { 6 | add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { 7 | "$layoutConstraints": "insets 5,hidemode 3,gap 5 5" 8 | "$columnConstraints": "[grow,fill]" 9 | "$rowConstraints": "[fill][grow,fill]" 10 | } ) { 11 | name: "this" 12 | add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.BorderLayout ) ) { 13 | name: "jPanelPset" 14 | }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { 15 | "value": "cell 0 1" 16 | } ) 17 | add( new FormComponent( "javax.swing.JCheckBox" ) { 18 | name: "jCheckBoxAlleEinstellungen" 19 | "text": "alle Einstellungen anzeigen" 20 | }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { 21 | "value": "cell 0 0" 22 | } ) 23 | }, new FormLayoutConstraints( null ) { 24 | "size": new java.awt.Dimension( 400, 300 ) 25 | "location": new java.awt.Point( 0, 0 ) 26 | } ) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/tabs/tab_livestreams/services/StreamService.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 derreisende77. 3 | * This code was developed as part of the MediathekView project https://github.com/mediathekview/MediathekView 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package mediathek.gui.tabs.tab_livestreams.services 20 | 21 | import retrofit2.http.GET 22 | 23 | interface StreamService { 24 | @GET("/v1/channelinfolist") // Anpassen! 25 | suspend fun getStreams(): Map 26 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/tabs/tab_livestreams/services/ShowService.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 derreisende77. 3 | * This code was developed as part of the MediathekView project https://github.com/mediathekview/MediathekView 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package mediathek.gui.tabs.tab_livestreams.services 20 | 21 | import retrofit2.http.GET 22 | import retrofit2.http.Path 23 | 24 | 25 | interface ShowService { 26 | @GET("/v1/shows/{key}") 27 | suspend fun getShow(@Path("key") key: String): ShowsResponse 28 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/actions/DeleteLocalFilmlistAction.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.actions; 2 | 3 | import mediathek.config.Konstanten; 4 | import mediathek.config.StandardLocations; 5 | import mediathek.mainwindow.MediathekGui; 6 | import mediathek.tool.FileUtils; 7 | 8 | import javax.swing.*; 9 | import java.awt.event.ActionEvent; 10 | import java.nio.file.Paths; 11 | 12 | public class DeleteLocalFilmlistAction extends AbstractAction { 13 | private final JFrame owner; 14 | 15 | public DeleteLocalFilmlistAction(MediathekGui parent) { 16 | super(); 17 | owner = parent; 18 | 19 | putValue(NAME, "Lokale Filmliste löschen"); 20 | } 21 | 22 | @Override 23 | public void actionPerformed(ActionEvent e) { 24 | var filmlistPathStr = StandardLocations.getFilmlistFilePathString(); 25 | var fimlistPath = Paths.get(filmlistPathStr); 26 | FileUtils.moveToTrash(fimlistPath); 27 | JOptionPane.showMessageDialog(owner, 28 | "Filmliste wurde gelöscht.\nDas Programm wird nun beendet.", 29 | Konstanten.PROGRAMMNAME, JOptionPane.INFORMATION_MESSAGE); 30 | MediathekGui.ui().quitApplication(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/tabs/tab_livestreams/LivestreamEntry.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 derreisende77. 3 | * This code was developed as part of the MediathekView project https://github.com/mediathekview/MediathekView 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package mediathek.gui.tabs.tab_livestreams 20 | 21 | import mediathek.gui.tabs.tab_livestreams.services.ShowInfo 22 | 23 | data class LivestreamEntry( 24 | val key: String, 25 | val streamName: String, 26 | val streamUrl: String, 27 | var show: ShowInfo? = null 28 | ) -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/tabs/tab_film/searchfilters/FinalStageFilterNoPatternWithDescription.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.tabs.tab_film.searchfilters; 2 | 3 | import mediathek.daten.DatenFilm; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.util.function.Predicate; 7 | 8 | public class FinalStageFilterNoPatternWithDescription implements Predicate { 9 | private final String searchText; 10 | 11 | public FinalStageFilterNoPatternWithDescription(@NotNull String[] searchStr) { 12 | this.searchText = searchStr[0]; 13 | } 14 | 15 | @Override 16 | public boolean test(DatenFilm datenFilm) { 17 | var result = searchDefault(datenFilm); 18 | 19 | // search description if available 20 | var description = datenFilm.getDescription(); 21 | if (!description.isEmpty()) { 22 | result = description.toLowerCase().contains(searchText) || result; 23 | } 24 | 25 | return result; 26 | } 27 | 28 | private boolean searchDefault(@NotNull DatenFilm film) { 29 | return film.getThema().toLowerCase().contains(searchText) 30 | || film.getTitle().toLowerCase().contains(searchText); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/tabs/tab_livestreams/services/ShowsResponse.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 derreisende77. 3 | * This code was developed as part of the MediathekView project https://github.com/mediathekview/MediathekView 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package mediathek.gui.tabs.tab_livestreams.services 20 | 21 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties 22 | 23 | @JsonIgnoreProperties(ignoreUnknown = true) 24 | data class ShowsResponse( 25 | val shows: List = emptyList(), 26 | val error: String? = null 27 | ) -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/MessageBus.kt: -------------------------------------------------------------------------------- 1 | package mediathek.tool 2 | 3 | import mediathek.gui.messages.BaseEvent 4 | import net.engio.mbassy.bus.MBassador 5 | import net.engio.mbassy.bus.config.BusConfiguration 6 | import net.engio.mbassy.bus.config.Feature 7 | import net.engio.mbassy.bus.config.IBusConfiguration 8 | import net.engio.mbassy.bus.error.PublicationError 9 | import org.apache.logging.log4j.LogManager 10 | 11 | /** 12 | * The central message bus to dispatch notifications throughout the program 13 | */ 14 | object MessageBus { 15 | @JvmStatic 16 | val messageBus: MBassador 17 | private val logger = LogManager.getLogger() 18 | 19 | init { 20 | logger.trace("Initializing message bus") 21 | messageBus = MBassador(BusConfiguration() 22 | .addFeature(Feature.SyncPubSub.Default()) 23 | .addFeature(Feature.AsynchronousHandlerInvocation.Default()) 24 | .addFeature(Feature.AsynchronousMessageDispatch.Default()) 25 | .addPublicationErrorHandler { error: PublicationError -> 26 | logger.error(error.message, error.cause) 27 | } 28 | .setProperty(IBusConfiguration.Properties.BusId, "global bus")) 29 | } 30 | } -------------------------------------------------------------------------------- /src/main/kotlin/mediathek/gui/actions/export/DiskSpaceUtil.kt: -------------------------------------------------------------------------------- 1 | package mediathek.gui.actions.export 2 | 3 | import org.apache.logging.log4j.LogManager 4 | import java.io.File 5 | import java.nio.file.Files 6 | 7 | internal object DiskSpaceUtil { 8 | private val logger = LogManager.getLogger() 9 | 10 | /** 11 | * Check if there is more than 1 GB of free disk space available. 12 | */ 13 | fun enoughDiskSpace(selectedFile: File): Boolean { 14 | try { 15 | var tempFileCreated = false 16 | 17 | if (!selectedFile.exists()) { 18 | selectedFile.createNewFile() 19 | tempFileCreated = true 20 | } 21 | val store = Files.getFileStore(selectedFile.toPath()) 22 | val availFreeSpace = store.usableSpace / (1024 * 1024) //Megabyte 23 | 24 | if (tempFileCreated) 25 | selectedFile.delete() 26 | 27 | return availFreeSpace >= 1024 28 | } 29 | catch (e: Exception) { 30 | // in case of error pretend there is space available as it may fail on network drives 31 | logger.error("enoughDiskSpace failed!", e) 32 | return true 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/main/resources/mediathek/file/hilfetext_blacklist.txt: -------------------------------------------------------------------------------- 1 | Bei der Funktion "Blacklist" werden Filme, die den 2 | Angaben in einer Zeile in der Tabelle entsprechen, 3 | nicht angezeigt. 4 | 5 | Die Funktion "Whitelist" zeigt nur die Filme an, die 6 | den Angaben in einer Zeile in der Tabelle entsprechen. 7 | 8 | Beim Umschalten "Blacklist - Whitelist" werden genau 9 | die vorher nicht angezeigten Filme jetzt angezeigt. 10 | 11 | "Sender" "Thema" werden exakt verglichen. 12 | Der Titelfilter muss im Titel enthalten sein. 13 | Das Filterfeld "Thema/Titel" muss entweder im Filmthema 14 | oder im Filmtitel enthalten sein. 15 | 16 | Groß- und Kleinschreibung wird beim Filtern nicht beachtet. 17 | 18 | Im Feld "Titel" (dann wird im Titel gesucht) und "Thema/Titel" 19 | (dann wird in den Feldern Thema und Titel gesucht) 20 | kann auch mit regulären Ausdrücken gesucht 21 | werden. Diese müssen mit "#:" eingeleitet werden. 22 | Auch bei den regulären Ausdrücken wird nicht zwischen 23 | Groß- und Kleinschreibung unterschieden. 24 | 25 | #:Abend.* 26 | Das bedeutet z.B.: Es werden alle Filme gefiltert, die 27 | im jeweiligen Feld mit "Abend" (oder auch: "abend") beginnen. 28 | 29 | https://de.wikipedia.org/wiki/Regul%C3%A4rer_Ausdruck 30 | 31 | -------------------------------------------------------------------------------- /src/main/java/mediathek/mainwindow/FixedRedrawStatusBar.java: -------------------------------------------------------------------------------- 1 | package mediathek.mainwindow; 2 | 3 | import org.jdesktop.swingx.JXStatusBar; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import javax.swing.*; 7 | import java.awt.*; 8 | 9 | /** 10 | * This class tries to fix some redraw issues with JXStatusBar on removal. 11 | */ 12 | public class FixedRedrawStatusBar extends JXStatusBar { 13 | public FixedRedrawStatusBar(@NotNull MediathekGui mediathekGui) { 14 | add(new SelectedListItemsLabel(mediathekGui)); 15 | add(new FilmSizeInfoLabel(mediathekGui)); 16 | add(new DownloadInformationLabel()); 17 | 18 | add(new JPanel(), new Constraint(Constraint.ResizeBehavior.FILL)); 19 | add(new FilmListCreationDateLabel()); 20 | add(new FilmAgeLabel()); 21 | } 22 | 23 | @Override 24 | public void remove(int index) { 25 | super.remove(index); 26 | this.revalidate(); 27 | } 28 | 29 | @Override 30 | public void remove(Component comp) { 31 | super.remove(comp); 32 | this.revalidate(); 33 | } 34 | 35 | @Override 36 | public void removeAll() { 37 | super.removeAll(); 38 | this.revalidate(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/dialogEinstellungen/allgemein/TimedDocumentListener.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.dialogEinstellungen.allgemein; 2 | 3 | import javax.swing.*; 4 | import javax.swing.event.DocumentEvent; 5 | import javax.swing.event.DocumentListener; 6 | import java.awt.event.ActionListener; 7 | 8 | /** 9 | * Listens to changes in a Document and finally fires the assigned Action. 10 | * All operations will be performed on Swing EDT. 11 | */ 12 | public final class TimedDocumentListener implements DocumentListener { 13 | private final Timer timer; 14 | 15 | public TimedDocumentListener(ActionListener taskPerformer) { 16 | timer = new Timer(1_000, taskPerformer); 17 | timer.setRepeats(false); 18 | } 19 | 20 | private void fireTimer() { 21 | if (timer.isRunning()) 22 | timer.restart(); 23 | else 24 | timer.start(); 25 | } 26 | 27 | @Override 28 | public void insertUpdate(DocumentEvent e) { 29 | fireTimer(); 30 | } 31 | 32 | @Override 33 | public void removeUpdate(DocumentEvent e) { 34 | fireTimer(); 35 | } 36 | 37 | @Override 38 | public void changedUpdate(DocumentEvent e) { 39 | fireTimer(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/affinity/Affinity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 derreisende77. 3 | * This code was developed as part of the MediathekView project https://github.com/mediathekview/MediathekView 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package mediathek.tool.affinity 20 | 21 | import org.apache.commons.lang3.SystemUtils 22 | 23 | /** 24 | * Utility class to set OS-specific CPU affinity. 25 | */ 26 | object Affinity { 27 | @JvmStatic 28 | var affinityImpl: IAffinity = if (SystemUtils.IS_OS_WINDOWS) 29 | WindowsAffinity() 30 | else 31 | NullAffinity() 32 | 33 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/datum/DatumFilm.java: -------------------------------------------------------------------------------- 1 | package mediathek.tool.datum; 2 | 3 | import java.time.ZonedDateTime; 4 | import java.util.Date; 5 | 6 | public class DatumFilm extends Date { 7 | /** 8 | * When no date is specified in the film list, set to undefined for proper sorting. 9 | * Fictious date is 1.1.1900 10 | */ 11 | public static final DatumFilm UNDEFINED_FILM_DATE = new DatumFilm(0, 0, 1); 12 | private ZonedDateTime zonedDateTime; 13 | 14 | public DatumFilm(long date) { 15 | super(date); 16 | convertToZonedDateTime(); 17 | } 18 | 19 | public DatumFilm(int year, int month, int date) { 20 | super(year, month, date); 21 | convertToZonedDateTime(); 22 | } 23 | 24 | @Override 25 | public String toString() { 26 | if (this.equals(UNDEFINED_FILM_DATE)) { 27 | return ""; 28 | } 29 | else { 30 | return DateUtil.FORMATTER.format(DateUtil.convertToLocalDate(this)); 31 | } 32 | } 33 | 34 | public ZonedDateTime getZonedDateTime() { 35 | return zonedDateTime; 36 | } 37 | 38 | private void convertToZonedDateTime() { 39 | zonedDateTime = this.toInstant().atZone(DateUtil.MV_DEFAULT_TIMEZONE); 40 | } 41 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/cellrenderer/CellRendererColor.java: -------------------------------------------------------------------------------- 1 | package mediathek.tool.cellrenderer; 2 | 3 | import mediathek.config.Daten; 4 | import mediathek.tool.MVC; 5 | import org.apache.logging.log4j.LogManager; 6 | import org.apache.logging.log4j.Logger; 7 | 8 | import javax.swing.*; 9 | import javax.swing.table.DefaultTableCellRenderer; 10 | import java.awt.*; 11 | 12 | public class CellRendererColor extends DefaultTableCellRenderer { 13 | private static final Logger logger = LogManager.getLogger(); 14 | 15 | @Override 16 | public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, 17 | boolean hasFocus, int row, int column) { 18 | super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); 19 | final int r = table.convertRowIndexToModel(row); 20 | 21 | try { 22 | MVC color = Daten.mVColor.liste.get(r); 23 | setHorizontalAlignment(SwingConstants.CENTER); 24 | setBackground(color.color); 25 | setText(""); 26 | } catch (IndexOutOfBoundsException ex) { 27 | logger.error("unable to get color", ex); 28 | } 29 | return this; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/test/kotlin/mediathek/tool/TrailerTeaserCheckerTest.kt: -------------------------------------------------------------------------------- 1 | package mediathek.tool 2 | 3 | import org.junit.jupiter.api.Assertions.assertFalse 4 | import org.junit.jupiter.api.Assertions.assertTrue 5 | import org.junit.jupiter.api.Test 6 | 7 | internal class TrailerTeaserCheckerTest { 8 | 9 | @Test 10 | fun successTest1() { 11 | val checker = TrailerTeaserChecker() 12 | 13 | val testStr = "TrAiLeR" 14 | assertTrue {checker.check(testStr)} 15 | } 16 | 17 | @Test 18 | fun successTest2() { 19 | val checker = TrailerTeaserChecker() 20 | 21 | val testStr = "TeAsEr" 22 | assertTrue {checker.check(testStr)} 23 | } 24 | 25 | @Test 26 | fun successTest3() { 27 | val checker = TrailerTeaserChecker() 28 | 29 | val testStr = "VoRsChAu" 30 | assertTrue {checker.check(testStr)} 31 | 32 | } 33 | 34 | @Test 35 | fun failTest1() { 36 | val checker = TrailerTeaserChecker() 37 | 38 | val testStr = "bla" 39 | assertFalse {checker.check(testStr)} 40 | } 41 | 42 | @Test 43 | fun failTest2() { 44 | val checker = TrailerTeaserChecker() 45 | 46 | val testStr = "BlA" 47 | assertFalse {checker.check(testStr)} 48 | } 49 | 50 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/daten/abo/AboTags.kt: -------------------------------------------------------------------------------- 1 | package mediathek.daten.abo 2 | 3 | import java.util.* 4 | 5 | enum class AboTags(val index: Int, val xmlName: String) { 6 | NR(DatenAbo.ABO_NR, "Nr"), 7 | EINGESCHALTET(DatenAbo.ABO_EINGESCHALTET, "aktiv"), 8 | NAME(DatenAbo.ABO_NAME, "Name"), 9 | SENDER(DatenAbo.ABO_SENDER, "Sender"), 10 | THEMA(DatenAbo.ABO_THEMA, "Thema"), 11 | TITEL(DatenAbo.ABO_TITEL, "Titel"), 12 | THEMA_TITEL(DatenAbo.ABO_THEMA_TITEL, "Thema-Titel"), 13 | IRGENDWO(DatenAbo.ABO_IRGENDWO, "Irgendwo"), 14 | MINDESTDAUER(DatenAbo.ABO_MINDESTDAUER, "Mindestdauer"), 15 | MIN(DatenAbo.ABO_MIN, "min_max"), 16 | ZIELPFAD(DatenAbo.ABO_ZIELPFAD, "Zielpfad"), 17 | DOWN_DATUM(DatenAbo.ABO_DOWN_DATUM, "letztes_Abo"), 18 | PSET(DatenAbo.ABO_PSET, "Programmset"); 19 | 20 | companion object { 21 | @JvmStatic 22 | fun fromXmlTag(tag: String): Optional { 23 | return Arrays.stream(entries.toTypedArray()).filter { e: AboTags -> e.xmlName == tag }.findAny() 24 | } 25 | 26 | @JvmStatic 27 | fun fromIndex(index: Int): Optional { 28 | return Arrays.stream(entries.toTypedArray()).filter { e: AboTags -> e.index == index }.findAny() 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/swing/JIkonliSafeButton.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 derreisende77. 3 | * This code was developed as part of the MediathekView project https://github.com/mediathekview/MediathekView 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package mediathek.swing 20 | 21 | import javax.swing.Icon 22 | import javax.swing.JButton 23 | 24 | /** 25 | * Generates disabled icons automatically 26 | */ 27 | class JIkonliSafeButton : JButton() { 28 | override fun setIcon(defaultIcon: Icon?) { 29 | super.setIcon(defaultIcon) 30 | disabledIcon = IconUtils.generateDisabledIcon(this.icon) 31 | } 32 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/affinity/NullAffinity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 derreisende77. 3 | * This code was developed as part of the MediathekView project https://github.com/mediathekview/MediathekView 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package mediathek.tool.affinity 20 | 21 | import org.apache.logging.log4j.LogManager 22 | 23 | class NullAffinity : IAffinity { 24 | override fun setDesiredCpuAffinity(numCpus: Int) { 25 | logger.warn("This OS is not supported for setting cpu affinity") 26 | } 27 | 28 | companion object { 29 | private val logger = LogManager.getLogger() 30 | } 31 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/tabs/tab_livestreams/SenderUtils.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 derreisende77. 3 | * This code was developed as part of the MediathekView project https://github.com/mediathekview/MediathekView 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package mediathek.gui.tabs.tab_livestreams 20 | 21 | class SenderUtils { 22 | companion object { 23 | /** 24 | * Remove soft hyphens and control characters from string. 25 | */ 26 | @JvmStatic 27 | fun sanitizeName(name: String): String { 28 | return name.replace(Regex("[\\u00AD\\p{Cf}]"), "") 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/tool/FilmSize.java: -------------------------------------------------------------------------------- 1 | package mediathek.tool; 2 | 3 | import org.apache.logging.log4j.LogManager; 4 | import org.apache.logging.log4j.Logger; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * Store film size in Megabytes. 9 | */ 10 | public class FilmSize implements Comparable { 11 | private int size; 12 | private static final Logger logger = LogManager.getLogger(); 13 | 14 | public FilmSize() { 15 | this.size = 0; 16 | } 17 | 18 | public void setSize(String strSize) { 19 | if (strSize.equalsIgnoreCase("<1")) { 20 | size = 1; 21 | } 22 | 23 | try { 24 | if (!strSize.isEmpty()) { 25 | size = Integer.parseInt(strSize); 26 | } 27 | } catch (NumberFormatException ex) { 28 | logger.error("String: {}", strSize,ex); 29 | size = 0; 30 | } 31 | } 32 | 33 | public Integer toInteger() { 34 | return (size == 0) ? 0 : size; 35 | } 36 | 37 | @Override 38 | public String toString() { 39 | return (size == 0) ? "" : Integer.toString(size); 40 | } 41 | 42 | @Override 43 | public int compareTo(@NotNull FilmSize other) { 44 | return (Integer.compare(size, other.size)); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/duplicates/CommonStatsEvaluationTask.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.duplicates; 2 | 3 | import ca.odell.glazedlists.TransactionList; 4 | import mediathek.config.Daten; 5 | import mediathek.daten.DatenFilm; 6 | 7 | import java.util.Map; 8 | import java.util.stream.Collectors; 9 | 10 | public class CommonStatsEvaluationTask implements Runnable { 11 | @Override 12 | public void run() { 13 | final var films = Daten.getInstance().getListeFilme().parallelStream() 14 | .filter(f -> !f.isLivestream()) 15 | .toList(); 16 | 17 | var statisticsList = Daten.getInstance().getCommonStatistics(); 18 | 19 | Map statisticsMap = films.parallelStream() 20 | .collect(Collectors.groupingBy(DatenFilm::getSender, Collectors.counting())); 21 | TransactionList tList = new TransactionList<>(statisticsList); 22 | statisticsList.getReadWriteLock().writeLock().lock(); 23 | tList.beginEvent(true); 24 | tList.clear(); 25 | for (var sender : statisticsMap.keySet()) { 26 | tList.add(new FilmStatistics(sender, statisticsMap.get(sender))); 27 | } 28 | tList.commitEvent(); 29 | statisticsList.getReadWriteLock().writeLock().unlock(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/bandwidth/WriteConfigComponentListener.kt: -------------------------------------------------------------------------------- 1 | package mediathek.gui.bandwidth 2 | 3 | import org.apache.commons.configuration2.Configuration 4 | import org.apache.commons.configuration2.sync.LockMode 5 | import java.awt.event.ComponentAdapter 6 | import java.awt.event.ComponentEvent 7 | import javax.swing.JDialog 8 | 9 | internal class WriteConfigComponentListener(private val config: Configuration, private val dialog: JDialog) : 10 | ComponentAdapter() { 11 | override fun componentResized(e: ComponentEvent) { 12 | try { 13 | config.lock(LockMode.WRITE) 14 | val size = dialog.size 15 | config.setProperty(BandwidthDialog.CONFIG_WIDTH, size.width) 16 | config.setProperty(BandwidthDialog.CONFIG_HEIGHT, size.height) 17 | } 18 | finally { 19 | config.unlock(LockMode.WRITE) 20 | } 21 | } 22 | 23 | override fun componentMoved(e: ComponentEvent) { 24 | try { 25 | config.lock(LockMode.WRITE) 26 | val location = dialog.location 27 | config.setProperty(BandwidthDialog.CONFIG_X, location.x) 28 | config.setProperty(BandwidthDialog.CONFIG_Y, location.y) 29 | } 30 | finally { 31 | config.unlock(LockMode.WRITE) 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /src/main/resources/icons/sender/ard.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/test/java/mediathek/controller/history/MVUsedUrlTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 derreisende77. 3 | * This code was developed as part of the MediathekView project https://github.com/mediathekview/MediathekView 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package mediathek.controller.history; 20 | 21 | import org.junit.jupiter.api.Test; 22 | 23 | import static org.junit.jupiter.api.Assertions.assertEquals; 24 | 25 | class MVUsedUrlTest { 26 | 27 | @Test 28 | void putzen() { 29 | var testStr = "g|a |###| b"; 30 | var expected = "ga ### b"; 31 | var result = MVUsedUrl.putzen(testStr); 32 | assertEquals(expected, result); 33 | } 34 | } -------------------------------------------------------------------------------- /src/test/java/mediathek/tool/table/MVTableTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 derreisende77. 3 | * This code was developed as part of the MediathekView project https://github.com/mediathekview/MediathekView 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package mediathek.tool.table; 20 | 21 | import org.junit.jupiter.api.Test; 22 | 23 | import static org.junit.jupiter.api.Assertions.assertEquals; 24 | 25 | class MVTableTest { 26 | 27 | @Test 28 | void countNumberOfColumns() { 29 | var count = MVTable.countNumberOfColumns("a,b,c,d"); 30 | assertEquals(4, count); 31 | 32 | count = MVTable.countNumberOfColumns("a,b,c,d,e"); 33 | assertEquals(5, count); 34 | } 35 | } -------------------------------------------------------------------------------- /src/main/kotlin/mediathek/windows/MediathekGuiWindows.kt: -------------------------------------------------------------------------------- 1 | package mediathek.windows 2 | 3 | import mediathek.mainwindow.MediathekGui 4 | import mediathek.tool.notification.INotificationCenter 5 | import mediathek.tool.notification.WinNotificationCenter 6 | import mediathek.tool.threads.IndicatorThread 7 | import org.apache.logging.log4j.LogManager 8 | import java.io.IOException 9 | 10 | class MediathekGuiWindows : MediathekGui() { 11 | private val logger = LogManager.getLogger() 12 | 13 | override fun createDarkModeToggleButton() { 14 | //not used on Windows 10+, we are creating a menu bar action here 15 | } 16 | 17 | override fun createMenuBar() { 18 | super.createMenuBar() 19 | createDarkModeMenuAction() 20 | } 21 | override fun shutdownComputer() { 22 | val strShutdownCommand = arrayOf("shutdown.exe", "-s", "-t", "0") 23 | try { 24 | logger.info("Windows shutdown binary called.") 25 | Runtime.getRuntime().exec(strShutdownCommand) 26 | } catch (ex: IOException) { 27 | logger.error(ex) 28 | } 29 | } 30 | 31 | override fun createProgressIndicatorThread(): IndicatorThread { 32 | return TaskbarIndicatorThread(this) 33 | } 34 | 35 | override fun getNotificationCenter(): INotificationCenter { 36 | return WinNotificationCenter() 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/resources/icons/fontawesome/envelope-open-text.svg: -------------------------------------------------------------------------------- 1 | 2 | 8 | 10 | 11 | 15 | 16 | -------------------------------------------------------------------------------- /src/test/kotlin/feed/RSSFeedParserTest.kt: -------------------------------------------------------------------------------- 1 | package feed 2 | 3 | import org.junit.jupiter.api.Assertions 4 | import org.junit.jupiter.api.Test 5 | import java.io.File 6 | 7 | internal class RSSFeedParserTest { 8 | @Test 9 | fun mvwTest() { 10 | try { 11 | File("src/test/resources/rss/mediathekviewweb.xml").inputStream().use { 12 | val parser = RSSFeedParser() 13 | val feed = parser.readFeed(it) 14 | Assertions.assertNotNull(feed) 15 | //println(feed); 16 | Assertions.assertNotNull(feed!!.messages) 17 | Assertions.assertFalse(feed.messages.isEmpty()) 18 | for (message in feed.messages) { 19 | //println(message); 20 | Assertions.assertNotNull(message) 21 | Assertions.assertTrue(message.author.isBlank()) 22 | Assertions.assertFalse(message.guid.isBlank()) 23 | Assertions.assertFalse(message.link.isBlank()) 24 | Assertions.assertFalse(message.description.isBlank()) 25 | Assertions.assertFalse(message.title.isBlank()) 26 | Assertions.assertTrue(message.guid.endsWith('=')) 27 | } 28 | } 29 | } catch (e: Exception) { 30 | Assertions.fail(e) 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/tabs/tab_livestreams/services/ShowInfo.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 derreisende77. 3 | * This code was developed as part of the MediathekView project https://github.com/mediathekview/MediathekView 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package mediathek.gui.tabs.tab_livestreams.services 20 | 21 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties 22 | import java.time.Instant 23 | 24 | @JsonIgnoreProperties(ignoreUnknown = true) 25 | data class ShowInfo( 26 | val title: String = "", 27 | val subtitle: String? = "", 28 | val description: String = "", 29 | val channel: String = "", 30 | val startTime: Instant = Instant.EPOCH, 31 | val endTime: Instant = Instant.EPOCH 32 | ) -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/bookmark/BookmarkAddedAtComparator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2025 derreisende77. 3 | * This code was developed as part of the MediathekView project https://github.com/mediathekview/MediathekView 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package mediathek.gui.bookmark; 20 | 21 | import java.util.Comparator; 22 | 23 | public class BookmarkAddedAtComparator implements Comparator { 24 | 25 | @Override 26 | public int compare(BookmarkData o1, BookmarkData o2) { 27 | var o1ba = o1.getBookmarkAdded(); 28 | var o2ba = o2.getBookmarkAdded(); 29 | if (o1ba == null || o2ba == null) { 30 | return 0; 31 | } 32 | return o1ba.compareTo(o2ba); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/dialog/StandardCloseDialog.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.dialog; 2 | 3 | import mediathek.gui.actions.DisposeDialogAction; 4 | import mediathek.tool.EscapeKeyHandler; 5 | 6 | import javax.swing.*; 7 | import java.awt.*; 8 | 9 | /** 10 | * A standard swing dialog template with a close button. 11 | */ 12 | public abstract class StandardCloseDialog extends JDialog { 13 | public StandardCloseDialog(Frame owner, String title, boolean modal) { 14 | super(owner, title, modal); 15 | setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); 16 | EscapeKeyHandler.installHandler(this, this::dispose); 17 | 18 | var contentPane = getContentPane(); 19 | contentPane.setLayout(new BorderLayout()); 20 | contentPane.add(createContentPanel(), BorderLayout.CENTER); 21 | var buttonPanel = new ButtonPanel(); 22 | buttonPanel.add(createButtonPanel(),BorderLayout.EAST); 23 | contentPane.add(buttonPanel, BorderLayout.SOUTH); 24 | pack(); 25 | } 26 | 27 | public abstract JComponent createContentPanel(); 28 | 29 | public final ButtonFlowPanel createButtonPanel() { 30 | ButtonFlowPanel pnl = new ButtonFlowPanel(); 31 | JButton btn = new JButton(new DisposeDialogAction(this, "Schließen", "Dialog schließen")); 32 | getRootPane().setDefaultButton(btn); 33 | pnl.add(btn); 34 | return pnl; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/mediathek/gui/history/MVUsedUrlTableFormat.java: -------------------------------------------------------------------------------- 1 | package mediathek.gui.history; 2 | 3 | import ca.odell.glazedlists.gui.TableFormat; 4 | import mediathek.controller.history.MVUsedUrl; 5 | 6 | public class MVUsedUrlTableFormat implements TableFormat { 7 | private static final int USED_URL_DATUM = 0; 8 | private static final int USED_URL_THEMA = 1; 9 | private static final int USED_URL_TITEL = 2; 10 | private static final int USED_URL_URL = 3; 11 | 12 | @Override 13 | public int getColumnCount() { 14 | return 4; 15 | } 16 | 17 | @Override 18 | public String getColumnName(int column) { 19 | return switch (column) { 20 | case USED_URL_DATUM -> "Datum"; 21 | case USED_URL_THEMA -> "Thema"; 22 | case USED_URL_TITEL -> "Titel"; 23 | case USED_URL_URL -> "URL"; 24 | default -> throw new IllegalStateException(); 25 | }; 26 | } 27 | 28 | @Override 29 | public Object getColumnValue(MVUsedUrl baseObject, int column) { 30 | return switch (column) { 31 | case USED_URL_DATUM -> baseObject.getDatum(); 32 | case USED_URL_THEMA -> baseObject.getThema(); 33 | case USED_URL_TITEL -> baseObject.getTitel(); 34 | case USED_URL_URL -> baseObject.getUrl(); 35 | default -> throw new IllegalStateException(); 36 | }; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/raven/toast/util/UIUtils.java: -------------------------------------------------------------------------------- 1 | package raven.toast.util; 2 | 3 | import com.formdev.flatlaf.extras.FlatSVGIcon; 4 | 5 | import javax.swing.*; 6 | import java.awt.*; 7 | 8 | /** 9 | * @author Raven 10 | */ 11 | public class UIUtils { 12 | 13 | public static Icon getIcon(String key, Icon defaultValue) { 14 | Icon icon = UIManager.getIcon(key); 15 | if (icon == null) { 16 | return defaultValue; 17 | } 18 | return icon; 19 | } 20 | 21 | public static Insets getInsets(String key, Insets defaultValue) { 22 | Insets insets = UIManager.getInsets(key); 23 | if (insets == null) { 24 | return defaultValue; 25 | } 26 | return insets; 27 | } 28 | 29 | public static String getString(String key, String defaultValue) { 30 | String string = UIManager.getString(key); 31 | if (string == null) { 32 | return defaultValue; 33 | } 34 | return string; 35 | } 36 | 37 | public static Icon createIcon(String path, Color color, float scale) { 38 | FlatSVGIcon icon = new FlatSVGIcon(path, scale); 39 | if (color != null) { 40 | FlatSVGIcon.ColorFilter colorFilter = new FlatSVGIcon.ColorFilter(); 41 | colorFilter.add(new Color(150, 150, 150), color); 42 | icon.setColorFilter(colorFilter); 43 | } 44 | return icon; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/resources/icons/fontawesome/pen-to-square.svg: -------------------------------------------------------------------------------- 1 | 2 | 8 | 10 | 11 | 15 | 16 | --------------------------------------------------------------------------------